Set the JAXB context factory initialization class to be used - java

I have updated our projects (Java EE based running on Websphere 8.5) to use a new release of a company internal framework (and Ejb 3.x deployment descriptors rather than the 2.x ones). Since then my integration Tests fail with the following exception:
[java.lang.ClassNotFoundException: com.ibm.xml.xlxp2.jaxb.JAXBContextFactory]
I can build the application with the previous framework release and everything works fine.
While debugging i noticed that within the ContextFinder (javax.xml.bind) there are two different behaviours:
Previous Version (Everything works just fine): None of the different places brings up a factory class so the default factory class gets loaded which is com.sun.xml.internal.bind.v2.ContextFactory (defined as String constant within the class).
Upgraded Version (ClassNotFound): There is a resource "META-INF/services/javax.xml.bind.JAXBContext" beeing loaded successfully and the first line read makes the ContextFinder attempt to load "com.ibm.xml.xlxp2.jaxb.JAXBContextFactory" which causes the error.
I now have two questions:
What sort is that resource? Because inside our EAR there is two WARs and none of those two contains a folder services in its
META-INF directory.
Where could that value be from otherwise? Because a filediff showed me no new or changed properties files.
No need to say i am going to read all about the JAXB configuration possibilities but if you have first insights on what could have gone wrong or help me out with that resource (is it a real file i have to look for?) id appreciate a lot. Many Thanks!
EDIT (according to comments Input/Questions):
Out of curiosity, does your framework include JAXB JARs? Did the old version of your framework include jaxb.properties?
Indeed (i am a bit surprised) the framework has a customized eclipselink-2.4.1-.jar inside the EAR that includes both a JAXB implementation and a jaxb.properties file that shows the following entry in both versions (the one that finds the factory as well as in the one that throws the exception):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
I think this is has nothing to do with the current issue since the jar stayed exactly the same in both EARs (the one that runs/ the one with the expection)
It's also not clear to me why the old version of the framework was ever selecting the com.sun implementation
There is a class javax.xml.bind.ContextFinder which is responsible for initializing the JAXBContextFactory. This class searches various placess for the existance of a jaxb.properties file or a "javax.xml.bind.JAXBContext" resource. If ALL of those places dont show up which Context Factory to use there is a deault factory loaded which is hardcoded in the class itself:
private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.internal.bind.v2.ContextFactory";
Now back to my problem:
Building with the previous version of the framework (and EJB 2.x deployment descriptors) everything works fine). While debugging i can see that there is no configuration found and thatfore above mentioned default factory is loaded.
Building with the new version of the framework (and EJB 3.x deployment descriptors so i can deploy) ONLY A TESTCASE fails but the rest of the functionality works (like i can send requests to our webservice and they dont trigger any errors). While debugging i can see that there is a configuration found. This resource is named "META-INF/services/javax.xml.bind.JAXBContext". Here are the most important lines of how this resource leads to the attempt to load 'com.ibm.xml.xlxp2.jaxb.JAXBContextFactory' which then throws the ClassNotFoundException. This is simplified source of the mentioned javax.xml.bind.ContextFinder class:
URL resourceURL = ClassLoader.getSystemResource("META-INF/services/javax.xml.bind.JAXBContext");
BufferedReader r = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "UTF-8"));
String factoryClassName = r.readLine().trim();
The field factoryClassName now has the value 'com.ibm.xml.xlxp2.jaxb.JAXBContextFactory'
Because this has become a super lager question i will also add a bounty :)
I will work the entire day on this and let you know if there is any news.
Update/ Solution
This question has been solved. The original problem has occured because misconfiguration of complexly build multi model maven projects which one dependency used a updated version of a customized eclipse link jar that contained a definition for a JAXBFactory not available in the component where the error occured. Setting the JAXB context factory in most cases is configured with a jaxb.propertie file or JAXBContext file that contains the same definition. Detailed loading process of the appropriate JAXBContextFactory happens in javax.xml.bind.ContextFinder.
The error has not yet been solved (during the fact over 4 major EE/SE Applications lead to the error) and there is no general answer but that defined JAXBContextFactorys must exist in your classpath (wow what a wonder...) so you either have a that ClassNotFound Error because youre missing resources (well thats the acctual cause) or because you have a wrong JAXBContextFactory defined in any of the above mentioned propertie files which contain a definition according to the below answer.
Very many thanks for your great comments and support, i realy appreciate!

You can include a jaxb.properties file in the same package as your domain model to specify the JAXB (JSR-222) implementation you wish to use. For example it would look like the following to specify EclipseLink MOXy as your JAXB provider.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
For More Information
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Another quick and dirty solution (a workaround, really) that worked for me is to explicitly include a JAXB implementation to the maven build. For example
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.7</version>
</dependency>
Note that this adds a somehow unnecessary dependency to your build, as JAXB obviously already is part of each JRE >= version 6.
Most likely this will only work when the WAS classloader is set to parent last.

Related

Possible to ignore configuration classes on the classpath?

I have a Spring Boot application that works as expected when ran with embedded tomcat, but I noticed that if I try to run it from an existing tomcat instance that I'm using with a previous project then it fails with a NoClassDefFoundError for a class that I don't use anywhere in my application.
I noticed in the /lib directory I had a single jar that contained a few Spring annotated classes, so as a test I cleaned out the /lib directory which resolved the issue. My assumption is that Spring is seeing some of the configurations/beans/imports on the classpath due to them existing in the /lib directory and either trying to autoconfigure something on its own, or is actually trying to instantiate some of these classes.
So then my question is - assuming I can't always fully control the contents of everything on the classpath, how can I prevent errors like this from occurring?
EDIT
For a little more detail - the class not being found is DefaultCookieSerializer which is part of the spring-session-implementation dependency. It is pulled into one of the classes in the jar located in /lib, but it is not any part of my application.
Check for features provided by #EnableAutoConfiguration. You can explicitly configure set of auto-configuration classes for your application. This tutorial can be a good starting point.
You can remove the #SpringBootApplication annotation from the main class and replace it with an #ComponentScan annotation and an #Import annotation that explicitly lists only the configuration classes you want to load. For example, in a Spring boot MVC app that uses metrics, web client, rest template, Jackson, etc, I was able to replace the #SpringBootApplication annotation with below code and get it working exactly as it was before, with all functional tests passing:
#Import({ MetricsAutoConfiguration.class,
InfluxMetricsExportAutoConfiguration.class,
ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class,
WebMvcAutoConfiguration.class,
JacksonAutoConfiguration.class,
WebClientAutoConfiguration.class,
RestTemplateAutoConfiguration.class,
RefreshAutoConfiguration.class,
ValidationAutoConfiguration.class
})
#ComponentScan
The likely culprit of mentioned exception are incompatible jars on the classpath.
As we don't know with what library you have the issue we cant tell you the exact reason, but the situation looks like that:
One of Spring-Boot autoconfiguration classes is being triggered by the presence of class on the classpath
Trigerred configuration tries to create some bean of class that is not present in the jar you have (but it is in the specific version mentioned in the Spring BOM)
Version incompatibilities may also cause MethodNotFound exceptions.
That's one of the reasons why it is good practice not to run Spring Boot applications inside the container (make jar not war), but as a runnable jar with an embedded container.
Even before Spring Boot it was preferred to take account of libraries being present on runtime classpath and mark them as provided inside your project. Having different versions of the library on a classpath may cause weird ClassCastExceptions where on both ends names match, but the rest doesn't.
You could resolve specific cases by disabling autoconfiguration that causes your issue. You can do that either by adding exclude to your #SpringBootApplication or using a property file.
Edit:
If you don't use very broad package scan (or use package name from outside of your project in package scan) in your Spring Boot application it is unlikely that Spring Boot simply imports configuration from the classpath.
As I have mentioned before it is rather some autoconfiguration that is being triggered by existence of a class in the classpath.
Theoretical solution:
You could use maven shade plugin to relocate all packages into your own package space: see docs.
The problems is you'd have face:
Defining very broad relocation pattern that would exclude JEE classes that need to be used so that container would know how to run your application.
Relocation most likely won't affect package names used as strings in the Spring Boot annotations (like annotations #PackageScan or #ConditionalOnClass). As far as I know it is not implemented yet. You'd have to implement that by yourself - maybe as some kind of shade plugin resource processor.
When relocating classes you'd have to replace package names in all relevant configuration located in the jars. Possibly also merge some of those.
You'd also have to take into account how libraries that you use, or spring uses use package names or files.
This is definitely not a trivial tasks with many traps ahead. But if done right, then it would possibly allow you to disregard what is on the containers classpath. Spring Boot would also look for classes in relocated packages, and you wouldn't have those in ordinary jars.

WFLYEE0040: A component named '...' is already defined in this module

I get this error in a Java maven project. The weird thing is, it doesn't appear on every machine so I assume it has something to do with a configuration issue.
The class RoleKeyCacheImpl is a #Startup #Singleton:
#Startup
#Singleton
public class RoleKeyCacheImpl implements RoleKeyCache { ... }
That's the error Wildfly triggers when deploying the service.
Caused by: java.lang.IllegalArgumentException: WFLYEE0040: A component
named 'RoleKeyCacheImpl' is already defined in this module at
org.jboss.as.ee.component.EEModuleDescription.addComponent(EEModuleDescription.java:167)
at
org.jboss.as.ejb3.deployment.processors.EJBComponentDescriptionFactory.addComponent(EJBComponentDescriptionFactory.java:58)
I've tried:
installing a new Wildfly (V10, V13) on the same machine -> doesn't help
installing a completely new Eclipse on this machine -> doesn't help
cleaning & rebuilding all related projects
making sure the deployments-folder is empty and doesn't contain old versions of the same WAR
read the related question here which also didn't help (they use Spring): A component named 'XXX' is already defined in this module in JBoss 7.1.1
read and tried this q&a: Wrong dependencies with EJB in JBoss Wildfly (server-clean) -> doesn't help
deleted and rebuilt the local maven rep (".m2") -> no effect
checking out the same source on another computer -> does work on one machine, on another it gives the same error
I have absolutely no clue what the issue is or even could be. On one machine, we check it out and it runs without errors. On others, the exact same error happens.
Does anybody have an idea?
I had this same issue multiple times with EAP 7.1 and now again with WildFly 21.0.0. I know by experience this is an issue caused by Eclipse who tries to deploy automatically to a configured WildFly instance. During the deployment (or undeployment) some concurrent file issue arises and files who should be removed, are still on the filesystem, causing this error that a component is already defined.
In fact it is not already defined, it is just WildFly that is confused because it finds in his temporary directories some old files which shouldn't be there and reference your exact same component.
Solution: remove in the WildFly standalone directory the content in the 'deployments' directory and the 'tmp' directory. Rest assured, all what is there is okay to remove safely. Reboot and the error message will be gone ;-)
You should pay attention to not have two #Stateless EJB annotations on top of two classes with the same name - in the same module.
You may differentiate them by using the name attribute in the annotation and put different values in each class
Looks like the class already exists. Check if it does...you may have to rewrite that part of EEModuleDescription to use its own private methods (which would be what you would write) rather than overriding methods in RoleKeyCacheImpl. If the class actually does not exist then right-click on the project -> Maven 2 Tools -> Generate Eclipse Artifacts (Check for Updates). That will regenerate all of the dependencies that the project uses. Also please be sure that you have not added any new projects to the classpath by mistake as that may also cause this error.
I just ran into this today when a colleague added a maven dependency.
Turns out this dependency was a jar with a nasty classpath entry or "../" in the manifest.
I edited the jar's manifest.mf that was cached in my local maven repository using 7-zip and removed the "../" classpath entry.
Then re-packaged my war file (maven clean install) and bingo, it works!
In my case it was caused by org.libreoffice jurt version 5.4.2 (but other versions I checked also have the classpath nastiness).
Unfortunately I was lucky we pinpointed it to a dependency, YMMV!

Hibernate and Jersey dependency conflict (javassist) - can anyone explain how this works?

I'm currently using hibernate-4.1.4 and jersey-2.22. These have javassist-3.15 and javassist-3.18 respectively.
I included both hibernate and jersey in my project and to my surprise, there were no dependency conflicts between the said javassists.
I was wondering how Java tells hibernate to use 3.15 and how it tell jersey to use 3.18 since both are in the build path. Is one javassist not being used?
Follow up question: Let's say that javassist-3.15 and javassist-3.18 have a conflict with each other. How do I resolve this? Do I disable both javassists and include one externally?
EDIT: My app is a web app that runs on Tomcat 7. We don't use Maven/Gradle. We just configure the dependencies by putting the jars in the build path using Eclipse.
JAVA loads classes through ClassLoaders ... Many applications servers, as Tomcat or Wildfly, implement and use their own class loaders (not the regular ones of the common JDK) ... So you must check the Tomcat documentation to read about its classloading behaviour...
After saying that, is very likely that Tomcat is loading libraries in alphabetical order. I Explain...
Suppose that you use a class named: Dummy, and this class is contained at the libraries: dummy-1.0.jar and dummy-1.1.jar ... when the class Dummy is requested, the Tomcat ClassLoader search for that class definition, looking first at dummy-1.0.jar and later at dummy-1.1.jar ... given that dummy-1.0.jar contains that class, Tomcat stops looking a returns that class version ... If dummy-1.0.jar would not have the target class, the dummy-1.1.jar class version would be returned instead...
(I suggest to try this to validate the container behaivour, it's not so hard to implement)...
And yes, if javassist-3.15 and javassist-3.18 conflicts with each other, you should remove them and pick the javassist JAR more
suitable for both libraries (jersey and hibernate).
As thumb rule, I tend to pick the newest library (the one with greater version), but this scheme not always work...

JAXB package-info.java declarations are ignored in separate maven modul

I use package-info.java to specify #XmlAccessorType(XmlAccessType.NONE) and some xml java adapters using #XmlJavaTypeAdapters. Model objects (with JAXB annotations) are placed in separate maven module shared by other modules. The configuration in package-info.java is not discovered if model objects are in separate maven module. If I move for testing purposes model objects to same maven module everything is OK. I think separate maven module can be considered equivalent to 3rd party lib from JAXBContext point of view. I use JDK1.7 JAXB reference implementation. Any ideas how configuration may differ?
I also encounter this problem, in my case qualified/unqualified property from package-info.java was ignored. I managed to find two way to workaround this:
like Pavla wrote, copy all JAXB classes with package-info.java locally
include module as a dependency with compile scope (which gives similar result that classes are in module. In my case I created separate jar lib with JAXB classes)
I also spotted that it do not work only in case of creating WebServices (creating object and sending to WS works fine in different modules).
I am using Jbossas7.1.1 and cxf 2.4.6. In the time of registering service Jboss created wsdl from JAXB (in my case path /opt/jboss/jboss-as-7.1.1.Final/standalone/data/wsdl/module.war/SubmitMessage.wsdl). In local setting file is generated properly.
Any ideas why creating WS behaves like this?
I hit this issue recently and the actual problem (with Java 8, i.e. no Java modules involved) was that I had on the classpath two *.jar files which both contained the same package - in one JAR, there was package-info.class with JAXB annotations and in the other one, there wasn't.
In that case, I guess that if package-info.class file is discovered depends on the classpath ordering (which is very brittle and only semi-deterministic).

XPath class resolution in JBoss5

I'm having a hard time figuring out where the problem is coming from, so I'm posting this in the hopes that others might have found something similar to this elsewhere and are kind enough to share their insight.
I'm using a JBoss 5.0.1.GA application server running on top of a Sun Java 1.6.0-13 JDK. For the WAR file in the generated Web Service, I use a Axis2 1.4 WS engine whose JAR files are inserted by Eclipse Galileo into the project's WEB-INF/lib directory when creating the Webservice from the given "worker" class in the Dynamic Web Project. The relevant code snippet follows:
String sUrl = "http://example.com/datafile.xml";
String sPath = "/some/xpath/string";
InputStream input = new URL(sUrl).openStream();
InputSource source = new InputSource(input);
DocumentBuilderFactory docFact = DocumentBuilderFactory.newInstance();
docFact.setNamespaceAware(false);
DocumentBuilder parser = docFact.newDocumentBuilder();
Document doc = parser.parse(source);
XPath xpath = XPathFactory.newInstance().newXPath();
// error occurs here:
String result = (String) xpath.evaluate(path,doc,XPathConstants.STRING);
input.close();
This is the error I'm getting from the JBoss log:
java.lang.LinkageError: loader constraint violation: when resolving field "STRING" the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of the referring class, javax/xml/xpath/XPathConstants, and the class loader (instance of <bootloader>) for the field's resolved type, javax/xml/namespace/QName, have different Class objects for that type
I could use the XPath.evaluate(String,Document) — however there are occasions where I need to get (for example) a XPathConstants.NODESET instead, so it's a no-go. I have also tried to fumble a little by littering some jboss-web.xml files here and there in the WAR file, but with no effect.
What I'm trying to understand is:
Where could the error be coming from? The JBoss class loader? Some weird interaction between JBoss and the Sun JDK? Some weirdness introduced by Eclipse when creating the Web Service? Maybe some confusion introduced by the Axis2 libraries deployed within the WAR?
I've found instances of compiled class files in what looks like a triple-whammie:
Sun JDK (file rt.jar);
JBoss libraries ($JBOSS_HOME/lib/endorsed/stax-api.jar); and
Axis2-deployed libraries ($JBOSS_HOME/server/deploy/MyProject.ear/MyProject.war/WEB-INF/lib/axis2-saaj-api-1.4.jar and woden-impl-dom-1.0M8.jar).
How exactly am I supposed to configure JBoss to tell it which classes it's OK to load from "other" libraries from? Specifically, the jaxax.xml.namespace.QName is is causing the grief.
Thank you in advance.
JBoss will throw a LinkageError when the application's classpath contains classes which JBoss considers "protected", i.e. it does not permit the application to contain its own copies of certain key APIs.
In this case, it looks like your appcontains its own copies of the javax.xml.xpath API, and possibly some others as well, as you mentioned.
You need to remove anything from your EAR/WAR's lib directories that clashes with JBoss's own libraries (e.g. axis2-saaj-api-1.4.jar).
It seems that the problem was solved by removing the javax.xml.namespace.* package and respective classes from the deployed Axis2 JAR files. Namely, using Axis2 1.4.1 (instead of 1.4), I repackaged these JAR files:
axis2-saaj-api-1.4.1.jar, by removing javax.xml.namespace
woden-impl-dom-1.0M8.jar, by removing javax
Also, Eclipse is extremely picky at the project configuration. So far, I've found that the Project Facet for the Dynamic Web Project has to be created with a Dynamic Web Module of version 2.4 (and not 2.5 as it suggests by default), but with a Java version 6 (same as the branch of the used JDK). I don't know why this happens, I suppose the Dynamic Web Module version 2.4 tying up by default with Java 1.4 in Eclipse is where all the confusion comes from. Some googling led me to believe that package javax.xml didn't become incorporated into the JDK until Java 5 or Java 6 -- hence the possible mixup! However, I'm not knowledgeable enough to investigate if the problem comes from how Eclipse packages the archive files for deployment so this is just a suspicion I have so far.

Categories