-
Notifications
You must be signed in to change notification settings - Fork 256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configuring classpath for a mixed use of Java XML Binding (javax.xml.bind.*
) plus Jakarta XML Binding (jakarta.xml.bind.*
)
#246
Comments
The JPMML upgrade from 1.5.X to 1.6.X (initiated in JPMML-Model library, propagated into JPMML-Evaluator library) was about replacing "old" As you can imagine, this is a major classpath change, and you should take a couple of minutes to check the project README for instructions. These instructions suggest that your Java application should depend on the Should work with all Java SE versions 1.8 and up - as demonstrated here using GitHub Actions CI (click on some CI run, and you'll see a list of ten Java versions, all green):
The It was providing a couple of Java-backed user-defined function classes, which now reside inside the
You only need this one dependency - A proper build manager (such as Apache Maven) should be able to import all transitive dependencies automatically. I'd strongly advise against importing any Jakarta XML Binding libraries manually. My module dependency declarations are correct, up-to-date and maximally short, so you won't be able to improve the situation in any way.
TLDR: replace |
Functional duplicate of #234 |
@vruusmann This is my submodule's build scripts's dependencies
And this is the result searching "metro" to IntelliJ dependency analyer |
@vruusmann |
@vruusmann build.gradleSpringBootApplication.javaLoadingModelEvaluatorBuilder.java |
TBH, your diagnostic tools - SBT(?) and IntelliJ dependency analyzer - are no authority for me. The fact of the matter is that Apache Maven is able to correctly traverse the dependency chain, and all Apache Maven-based builds compile and execute successfully. There are no classpath errors anywhere. For example, jump into the
The |
Maybe you need to rebuild your IntelliJ project after you change the dependency? There could be some dependency caching going on. |
I tried but it didn't work.
I don't know the reason. (Of course there's possibility there's some bug in IntelliJ) |
Update your toolchain to Apache Maven! :-) |
so you mean I replace my build tool to maven right?(use |
That would be a major change (bigger than upgrading JPMML-Evaluator from 1.5.X to 1.6.X), so you need to weight the pros and cons, and make a decision yourself. All I can say is that all JPMML family libraries/applications use Apache Maven. And I can't remember having any classpath issues, ever. With Apache Maven you can generate IDE project files automatically. For example, for Eclipse IDE you simply do I believe Apache Maven has similar helper plugin for IntellJ also. Try googling around, maybe that will help you get the project files correct. |
Thank you for your kind support. The same issue occurred as a result of the test, and the project cannot be started. I use OpenJDK17(Zulu) & Spring boot 2.6.7 using Spring-Initializer, just add metro dependency and check there's no compile error. Share the repository link. After cloning this project, please check if it builds & runs normally. |
@vruusmann |
I've cloned your repository, and indeed the build fails because of a missing
The problem is that the Spring framework overrides Jakarta XML Binding. See below - I'm expecting to see the
TLDR: my classpath definition has been sabotaged by the Spring framework! |
The solution, of course, is to tell the Spring framework to stop meddling with my classpath definition. You can try two things - maybe they work individually, maybe they work only when applied together:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- THIS -->
<exclusions>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency> Of course, the Spring framework itself may refuse to work with the updated I'll try to apply my suggestions to your repository to see what works. |
The following dependency declaration seems to work with Spring framework: <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator-metro</artifactId>
<version>1.6.3</version>
</dependency>
<!-- Override Jakarta XML Bind interface -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
<!-- Override Jakarta XML Bind implementation -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies> |
@doljae The lesson for you: When you encounter a classpath conflict then do the following:
|
@vruusmann If I use However, although it is not known exactly, if As a result of making and checking the same In conclusion, I confirmed that to use
I think the Spring team already knows this part and expects that it is deliberately eroding the current dependency structure. Nevertheless, I am going to ask the spring team about this issue. Separately, under the current situation, it is difficult to use jpml 1.6.x with spring projects. So I am considering Anyway, thanks to your comment, I learned a lot about dependency structure. Thank you again 🙇 |
Your spring application compiles without errors, but when you actually run it, it throws some classpath conflict error? In principle, it is possible to configure the build so that JPMML-Evaluator and Spring have their own Jakarta XML Binding library versions (all within the same uber-JAR file). This trick is called "package relocation", and it is rather easy to implement using Apache Maven: I don't have time to provide an example today, but maybe later this week. |
@vruusmann Anyway, I briefly looked up the concept of I found the PR below in the The milestone for this PR is As far as I know, there doesn't seem to be any way |
OK, if the Spring framework does not work with the The simplest workaround on the JPMML-Evaluator side is to simply switch Jakarta XML Bind implementations. Next to the (default-) In this setup, JPMML-Evaluator and Spring framework would be sharing JAXB interfaces as defined by the The following dependency configuration works fine with your sample project: <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator-moxy</artifactId>
<version>1.6.3</version>
</dependency>
<!-- Override Jakarta XML Bind interface -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies> |
@doljae Perform the above dependency change, and try to run your Spring Boot application. Does the model loading succeed, or not? There is a possibility that both components will be a little bit confused, because they see two JAXB implementations available at the same time, and cannot decide which one to use. In principle, it should be possible to "activate" one specific JAXB implementation (over all others) by specifying the |
@vruusmann 1
Maybe this error is occured because as you said, 2
This error means Spring ApplicationContext
|
@vruusmann
According to this link & article in the comment, Spring projects will use old version Glassfish until the release of Spring 6 & Boot 3, which mean the easiest way for using jpmml with Spring is to use jpmml 1.5.x with pmml-extension I guess. To be honest, I am a beginner in this area. So I don't know well. |
The problem is that The In the current case, it would be nice if we could tell to Something like this would be ideal: EvaluatorBuilder evaluatorBuilder = new LoadingModelEvaluatorBuilder()
.setJAXBContext(org.eclipse.persistence.jaxb.JAXBContext.class)
.load("mymodel.pmml");
Evaluator evaluator = evaluatorBuilder.build();
Looks like In principle your project should include these two dependencies (the former for Spering framework, the latter for JPMML-Model/JPMML-Evaluator). Unfortunately, this is not technically possible, because dependency names (as defined by So, the solution is to replace the Maybe |
@doljae Looks like you need to stick with JPMML-Evaluator 1.5.X a little bit longer, until I extend the Will probably happen in the 1.6.4 release. However, the ETA of 1.6.4 is currently unknown. |
@vruusmann
|
In comment #246 (comment) points 1, 2 and 4 are correct. Point 3 not so much. Let's elaborate a bit further: The The resolution of the
Note the different package prefix Now in principle, it whould be possible to have JAXB 2.3 and 3.0 versions peacefully co-exist in one Java application. Spring framework is hard-coded to work with the 2.3 version, and JPMML-Evaluator with the 3.0 version! That's the theory. In the current case the situation is a bit more complicated because we have a |
@doljae Can you develop your sample project a bit further to make it "do some Spring + PMML business logic" during unit testing? It would be much easier to suggest classpath workarounds when I have an instant feedback mechanism available. Right now I must rely on your comments. |
Thank you for your support. In fact, reproducing the error is simple. After writing only one class or method of jpmml as code, it can be reproduced by writing code using hibernate and DB of spring data jpa and testing, run and build. Anyway, I'll try to share a sample project as soon as possible. thank you. |
@vruusmann You can reproduce the error by testing in this order.
This way I can reproduce the 2nd error I commented on. |
This repository still contains a deficient However, it wasn't difficult to fix (as explained in #246 (comment)): <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!-- Free the 'jakarta.xml.bind:jakarta.xml.bind-api' dependency groupId:artifactId slot for re-definition -->
<exclusions>
<exclusion>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-evaluator-metro</artifactId>
<version>1.6.3</version>
</dependency>
<!-- Define Java XML Bind interface for Spring -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- Define Jakarta XML Bind interface for JPMML-Evaluator -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies> Please note that I didn't need to explicitly define the After this change, the project builds and tests cleanly:
|
OK, I tried using the pom.xml you commented and verified that my project works fine. I tried writing a gradle script with a similar configuration and it works equally well 🙂 The problem is that this is my test project and I still get the error in my main project 🙁 The error log is as follows.
It seems difficult for me to reproduce this in my test project. This error was occured when I try to add @Bean
public Evaluator mainEvaluator() throws Exception {
return loadEvaluator("XXXX.pmml"); // -> exception point!, jakarta.xml.bind.JAXBException: Implementation of Jakarta XML Binding-API has not been found on module path or classpath.
}
private Evaluator loadEvaluator(String pmmlFileName){
...
return evaluator;
} I also leaves the state of the dependency tree for confirmation.
|
I reproduced the error which I mentioned in the previous comment.
I changed test configuration from @DataJpaTest to @SpringBootTest, which scan all Java bean from Configuration file(in this case, JPMMLConfiguration) and register it to ApplicationContext. |
It means that the Spring framework cannot find JAXB implementation classes. Yesterday evening, I showed you how to fix your application classpath for JAXB interface classes. Now you need to do the same for JAXB implementations. Looks like the application classpath only contains "new" JAXB implementation ( Again, as explained in my above comments (yesterday), the easiest way to do so is to switch from GlassFish Metro to EclipseLink MOXy for the JPMML-Evaluator components. You haven't done so in your |
It is clear that I do not fully understand this classpath and xml related dependencies. However, even if any of the latest versions of jpmml including As I commented at the beginning, I can use the latest version of jpmml with Spring by adding a dependency that can catch errors that occur. (exclude xml api, add new xml api, add implementation, etc...) However, I am skeptical that this is a good choice in my current development environment compared to using the 1.5 version. And this will be the same for users who use other Spring. So I think it is a good choice to roll back to version 1.5 in my project environment considering the unpredictable side effects. As of Spring Boot 3, |
Apart from this, it would be good to add a guide to jpmml version selection for users using the Spring project to the README. If it's okay, I'll post a PR on the relevant part. |
This topic can be generalized further: "How to configure application classpath so that it would contains BOTH Java XML Binding ( Your concern is about the Spring framework. Yesterday, when I was performing JPMML-SparkML library upgrade, then I found a similar classpath conflict in Apache Spark ML 3.X versions as well. I'm currently thinking about doing a small blog post about diagnostics & workarounds & final resolution.
You can drop your "condensed resolution" into this thread. Later, it will be possible to pin this issue for better visibility for the next one-two years (until the world catches up with |
Sorry for the late reply.
I strongly agree with your opinion. I'm sure pinning this issue will help many jpmml users (including those using Spring). To be honest, I didn't think I would be able to comment and support this issue for this long. Thank you for your active support 👍 |
For users who use Spring Framework...
|
javax.xml.bind.*
) plus Jakarta XML Binding (jakarta.xml.bind.*
)
I maintain my position that it is possible for a single application to make use of both Java XML Binding and Jakarta XML Binding APIs, without any compile-time or run-time classpath conflicts. Attached is a small demo project Workflow:
Example runs:
The demo application class
A couple of things to pay attention to in
|
I checked your demo project. I'm leaving a comment because I think you have some misunderstanding. 1. I didn't say that it is impossible to use Java XML Binding, Jakarta XML Binding API without conflict.I also wrote in the first text of this issue that I left out that I solved the problem through a couple of dependency combinations. And with your explanation, I was able to raise my understanding and confirm it through the attached sample project. I learned a lot from your latest comment's explanation. 🙇 2. The latest version of current released jpmml has no problems by itself.For projects that do not use frameworks or do not have complex dependency relationships in build scripts, it is expected that there will be no problems using the latest version of jpmml. 3. However, there is a clear possibility that manual operation will create conflicts with other code and dependencies.As you better know, if it's a corporate project rather than an individual, small-scale project, you should be wary of work with a wide range of modifications. I think it's definitely justified to make a safer choice in this and this situation. Personally, I prefer to use the latest version. If it was my personal project, I would have applied the method you suggested to use the latest version. Anyway, it is true that it is inconvenient to use the latest version of jpmml from the perspective of a person using the Spring framework(or user who use some kind of dependency management plugins. Anyway, I'm sure that your comment on mixed use of Java XML Binding plus Jakarta XML Binding in detail will be helpful to many users. 👍 |
@doljae what did you finally end up doing? I am also stuck in a similar situation with 1.6.4 jpmml-evaluator. |
Hello, @paranjapeved15 🙂 So I kept the existing If you want to use the FYI, if you're using Spring Boot, I know that the Boot 3 version of dependency management changed |
@vruusmann did you extend the LoadingModelEvaluatorBuilder in 1.6.4? |
Description
jpmml-evaluator
is insufficient to use.1.6.3
LoadingModelEvaluatorBuilder.java
Question 1
Question 2
org.jpmml:pmml-evaluator-extension:1.5.16
. With this dependency alone, I was able to use all the functions I wanted.pmml-evaluator-extension
seems to have been discontinued, and I added 7 dependencies to use jpmml as the latest version 1.6.x as before. And I spent a lot of time trying to catch the error.The text was updated successfully, but these errors were encountered: