What is the difference between jaxb-impl and jaxb-runtime? - java

Clearly the com.sun.xml.bind:jaxb-impl artifact is labelled "Old JAXB Runtime module" in the maven repository (see link below), and yet both of these artifacts are still getting new releases:
https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime
https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl
This answer Which artifacts should I use for JAXB RI in my Maven project?
does not clarify the difference.
The accepted answer to both the above question and this one How to resolve java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException conclude that for Java 9+ you should use: org.glassfish.jaxb:jaxb-runtime
But I have code using com.sun.xml.bind:jaxb-impl and it appears to be working fine. So what do I lose or gain by moving to jaxb-runtime?
Even the latest (3.0.2 at the time I write this) version is available for the "OLD" jaxb-impl module. If Oracle isn't doing this anymore, who makes the com.sun.xml.bind:jaxb-impl artifact? What is it for? Why doesn't it share the Maven group coordinates with jaxb-runtime?
Is there any central location that clearly documents what the current state of affairs is with JAXB?
There is just so much confusion with JAXB now.
P.S. I need to remain compatible with Java 8 for the time being - so I can't go to 3.x yet, and 2.4.x appears to be an abandoned attempt at fixing the modularity that they foolishly broke when it was split out of the JDK.

The only difference between jaxb-impl and jaxb-runtime is packaging: jaxb-impl bundles istack/txw2 inside the jar, whereas jaxb-runtime provides them via separate dependencies.
Version Compatibility and the JakartaEE Migration
I've been trying to make sense of this for the last day, and it's incredibly confusing. Particularly when you're trying to avoid the java.xml.bind to jakarta.xml.bind migration. There's out of date information everywhere and some broken releases in the jaxb-impl 2.3.x release line.
Best I can tell, GlassFish was providing the JAXB reference implementation. It's since moved to EE4J, but releases continue from that project against both sets of coordinates. Appears that com.sun.xml.bind:jaxb-ri is where the latest full bundles are released:
https://github.com/eclipse-ee4j/jaxb-ri/
Having figured out that piece of history, the real mess is that none of the artifacts reflect the javax.xml.bind to jakarta.xml.bind move in their artifact coordinates, only in the versions. This means if you're in ecosystem where you need both to exist, you're going to have a bad time.
For instance, the 2.3.3 release changed from depending on javax.xml.bind:jaxb-api to jakarta.xml.bind:jakarta.xml.bind-api because at 2.x, the jakarta artifacts provide the javax.xml.bind packages. At version 3.0.0 it provides jakarta.xml.bind.
The implementations are the same at 3.0.0 which means while the earlier versions could happily exist at runtime, you have no way of resolving them both in build tools and conflict resolution is going to break legacy uses of javax.xml.bind APIs.
Allow javax.xml.bind and jakarta.xml.bind to coexist
For projects that need both APIs to coexist without migrating the legacy code:
For javax.xml.bind use com.sun.xml.bind:jaxb-impl:2.3.6. Ignore the 3.0.0 and later releases. Add an explicit dependency on javax.xml.bind:jaxb-api:2.3.1 so that you have a package providing the javax.xml.bind API
For jakarta.xml.bind use the latest org.glassfish.jaxb:jaxb-runtime. Ignore the releases earlier than 3.0.0
Runtime compatibility with jakarta.xml.bind
Use the tomcat-jakartaee-migration tool to rewrite classes for deployment.
For Gradle projects, you can use the gradle-jakartaee-migration-plugin, and get the benefit of capabilities and transforms at development time too.
Migrate to jakarta.xml.bind
You can use either of the coordinates for the runtime based on your preferences for packaging:
com.sun.xml.bind:jaxb-impl:4.0.0
org.glassfish.jaxb:jaxb-runtime:4.0.0
Both depend on jakarta.xml.bind:jakarta.xml.bind-api with the jakarta.xml.bind package namespace.

Related

spring-boot, tomcat and java modules

I have migrated my OSS project (https://m-m-m.github.io) entirely to JPMS (modules). However, integrating with spring-boot now gives me really hard times.
First of all I stumbled over various issues with slf4j module support:
https://github.com/spring-projects/spring-boot/issues/12649
https://jira.qos.ch/browse/LOGBACK-1491?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel
But now I am entirely stuck with errors like:
[ERROR] error: the unnamed module reads package javax.servlet from both org.apache.tomcat.embed.core and java.servlet
Inside my modules, I am forced to require the code I am using and cannot access code from classpath/unnamed modules. Hence, I was forced to use modularized versions of servlet-api and slf4j.
However, spring-boot uses tomcat-embed and that contains servlet-api but is not using the official JPMS module from JakartaEE. I even tried to update to tomcat 10.0.0-M4 but this is not supported by spring-boot yet:
NoSuchMethodError: 'void org.apache.catalina.Context.addServletContainerInitializer(javax.servlet.ServletContainerInitializer, java.util.Set)'
Is there any magic trick left to get things like this solved? Or is the JPMS a closed shop and as the Java ecosystem is not moving fast enough for years (java9 was released 2017) I am more or less forced to reinvent the wheel and replace all such stuff with modularized code?

IBM SBT SDK 1.1.0 (Java) and Apache xerces

I am adding IC integration with IBM SBT SDK (Java) into an existing project which still uses xerces 2.4.0 (as of March 2009).
Using IBM SBT SDK 1.0.x did not cause any problems here, but the XML serialization implementation of 1.1.0 completely relies on org.w3c.xml.ls.DOMImplementationLS and such stuff which was introduced after moving xerces to "xercesImpl" about 2004.
However the project contains much code working with XML based on xerces and xml-apis, and it looks dangerous to move too fast to "more current" versions of these libraries. Thus I want to move "no further than absolutely required".
Thanks to maven no one can directly see which version of any artifact is loaded if it is not directly referenced in the pom.xml. Thus my question:
Which version of xercesImpl is "really" required by IBM SBT SDK 1.1.0? 2.4.0 is not sufficient, as some methods used in the SBT SDK are not yet implemented there...
xerces version in the dependency would be 2.9.0; looking at the DOMUtil.java#loadDriver() class however there are workarounds to avoid the SBTK to use xerces altogether:
if your container allows to control the classpath tree, shadowing the xerces library from the toolkit will have it default to some other driver. In alternative you can provide your own XercesDriver class compatible with old xerces versions and leverage the classloader to have it loaded in place of ours.
if you are in a osgi container you can also make sure the host application manifest declares a dependency to a version <=2.4.0 and load both xerces versions letting the container fix the dependencies for you
anyway, to answer the question, using:
mvn dependency:list
I get version 2.9.0 for xerces:
The following files have been resolved:
com.ibm.sbt:com.ibm.commons:eclipse-plugin:9.0.0:provided
p2.eclipse-plugin:javax.servlet:jar:3.0.0.v201112011016:system
p2.eclipse-plugin:javax.xml:jar:1.3.4.v201005080400:system
p2.eclipse-plugin:org.apache.xalan:jar:2.7.1.v201005080400:system
p2.eclipse-plugin:org.apache.xerces:jar:2.9.0.v201101211617:system
p2.eclipse-plugin:org.apache.xml.resolver:jar:1.2.0.v201005080400:system
p2.eclipse-plugin:org.apache.xml.serializer:jar:2.7.1.v201005080400:system
p2.eclipse-plugin:org.eclipse.core.contenttype:jar:3.4.200.v20120523-2004:system
p2.eclipse-plugin:org.eclipse.core.jobs:jar:3.5.300.v20120912-155018:system
p2.eclipse-plugin:org.eclipse.core.runtime:jar:3.8.0.v20120912-155025:system
p2.eclipse-plugin:org.eclipse.equinox.app:jar:1.3.100.v20120522-1841:system
p2.eclipse-plugin:org.eclipse.equinox.common:jar:3.6.100.v20120522-1841:system
p2.eclipse-plugin:org.eclipse.equinox.preferences:jar:3.5.1.v20121031-182809:system
p2.eclipse-plugin:org.eclipse.equinox.registry:jar:3.5.200.v20120522-1841:system
p2.eclipse-plugin:org.eclipse.osgi:jar:3.8.2.v20130124-134944:system

What about new versions of third party libraries?

I'm maintaining an open source java library which has itself some dependencies to third party libraries (e.g. commons-beanutils:commons-beanutils-1.8.3). During development I just added the most recent version of such libraries to my pom. Now I did some changes to my library and realized that those versions are no more recent.
I'm now wondering which strategy is best practice with such dependencies.
My feeling says run mvn versions:use-latest-releases test.
I would recommend using mvn versions:display-dependency-updates and updating relevant libraries by hand.
It is not necessary to always use the latest version of the library.
Usually, should update your dependencies if:
you need a feature of the new version (for major and minor releases)
the update resolves a known bug (that affects you)
the update fixes a security problem.
resolves an incompatibility with another dependency
Otherwise, consider staying on your current version.
You might, temporarily consider using version ranges commons-beanutils:commons-beanutils:[1.8.0,1.9.0) to always use the latest bugfix version. Note however, that this results in non-reproducable builds and must be changed before releasing your project.

Classpath issue using Ivy

I'm using Ivy to manage my dependencies, and It's causing me issues with easymock
my ivy.xml file has the following:
<dependency org="easymock" name="easymock" rev="2.5.+" conf="compile,test -> default" />
and then I follow with other library dependencies, hoping that in case some other library uses another version of easymock then at least my library gets the correct one.
but then after I resolve, in eclipse i can see that there are 2 versions of easymock (1.2 and 2.5) and then the 1.2 is listed first.
and when I run my unit test, I'm getting a java.lang.NoSuchMethodError on the contstructor of org.easymock.internal.RecordState which takes org.easymock.internal.IMocksBehavior.
which suggest I'm hitting the old version of EasyMock.
Any ideas how can I get around this issue?
Generate an ivy dependency report to see exactly what versions ivy is using, for each configuration:
<ivy:resolve/>
<ivy:report todir='${ivy.reports}' graph='false' xml='false'/>
Normally when ivy encounters two versions of the same library it will "evict" the older version.
To fix problems with incorrect conflict resolution I'd suggest reading the doco
Update
Ivy's conflict algorithms have always worked well for me in the past, but I must admit I never fully understood some of the complexities of transitive analysis. The following Maven article is worth reading:
http://guntherpopp.blogspot.com/2011/02/understanding-maven-dependency.html
The latest easymock I can see in the ibiblio mirrors is rev 2.0. That would mean, that 2.5 is not found and an older Version is used. Check your resolver settings and revisions.
It also helps to clean the cache once in a while (ivy:cleancache) so ivy is forced to search the repos for revisions.

Managing maven dependancies - New Versions and Non-Repo libraries

Warning: I have just picked up Maven, so things mentioned might be wrong or not best practice.
I have a medium size open source project that I am migrating to Maven from the basic
NetBeans project management. This is not a developer team sharing the same room, this is 1-5 people over the internet sharing a SVN repo. Reading over the how-tos on dependencies, it seems that the only way to get dependencies is to get them from an online repo or install them locally.
This is not what I was looking for. I want to keep all dependencies in the SVN for many reasons including portability (anybody can pass by, check out the repo, build, and use; all that simply without manual adding to local repo's and whatnot), getting newer versions (discussed below), and manual versioning.
The other issue I have with the maven repository is that they are quite behind in versions. Logback for example is 0.9.18 in mvnbrowser but 0.9.24 officially. PircBot is 1.4.6 in mvnbrowser but 1.5.0 officially. Why such old versions?
Issue 3 is that I have dependencies that don't even exist in the repos, like Easier Java Persistence.
So
How can I force all dependencies to come from /lib for example
On a related note, can mvn build from library's SVN repo directly? Just curious
Is there an automatic way to get the newest version directly from a dependencies site/svn repo if they also use Maven? IE libraries like commons-lang or logback
Is there a better way of managing dependencies? (IE Ivy or some weird POM option I'm missing)
FYI, this is a Java project with 3 modules, project global dependencies and module specific dependencies.
Bonus points if it can work with the bundled version of Maven that comes with NetBeans.
Not a duplicate of
Maven: add a dependency to a jar by relative path - Not wanting to install to local repository
maven compile fails because i have a non-maven jar - Don't think a System dependency is the right answer
maven look for new versions of dependencies - Still uses(?) repository, just the latest (old) version
This is not what I was looking for. I want to keep all dependencies in the SVN for many reasons (...)
I will come back on this but the solution I described in Maven: add a dependency to a jar by relative path (using a file-based repository) allows to implement such a solution.
The other issue I have with the maven repository is that they are quite behind in versions. Logback for example is 0.9.18 in mvnbrowser but 0.9.24 officially. PircBot is 1.4.6 in mvnbrowser but 1.5.0 officially. Why such old versions?
It looks like mvnbrowser indices are totally out of date (making it useless as repository search engine) because the maven central repository does have logback-core-0.9.24.jar (the logback project is doing what has to be done to make this happen) but only has an old pircbot-1.4.2.jar. Why? Ask the pircbot team. Anyway, you're right, the central repository might not always have ultimate versions.
Issue 3 is that I have dependencies that don't even exist in the repos, like Easier Java Persistence.
Yeah, this happens too.
How can I force all dependencies to come from /lib for example
As previously hinted, you should re-read carefully the solution suggested in Maven: add a dependency to a jar by relative path. This solution is not about installing libraries to the local repository but is about using a file-based repository (that could thus be stored in SVN). You might have missed the point, this matches your use case. And also check Brett's answer for a variation.
On a related note, can mvn build from library's SVN repo directly? Just curious
Didn't get that one. Can you clarify?
Is there an automatic way to get the newest version directly from a dependencies site/svn repo if they also use Maven? IE libraries like commons-lang or logback
Maven supports version ranges and you could use a syntax allowing to use "any version greater than X". But I do NOT recommend using version ranges at all, for the sake of build reproducibility. You don't want the build to suddenly fail because of some automatic update that happened on your back. Only upgrade if you need bug fixes or new features, but do it explicitly (if it ain't broke, don't fix it).
You might also find mentions of the LATEST and RELEASE version markers. I don't recommend them neither for the same reasons as above and even less since they're removed from Maven 3.x.
Is there a better way of managing dependencies? (IE Ivy or some weird POM option I'm missing)
Can't say for Ivy. But in the Maven land, if you can't host up a "corporate" repository for your project (Nexus, Archiva, Artifactory), then the file-based repository is IMO the best approach.
Setup your own Maven repository.
http://archiva.apache.org/

Categories

Resources