Skip to content
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

Classloading issue involving JAXBContext and JAXBContextFactory with webProfile-10.0 #28414

Closed
yogregg opened this issue May 13, 2024 · 4 comments
Labels
Needs member attention release bug This bug is present in a released version of Open Liberty release:24006

Comments

@yogregg
Copy link

yogregg commented May 13, 2024

Describe the bug
I am having classloading problems with webProfile-10.0 and JAXB classes. My web application has jakarta.xml.bind-api 4.0.0 and jaxb-runtime 4.0.1 jars in its WEB-INF/lib. At startup, it attempts to create a JAXBContext using jakarta.xml.bind.JAXBContext.newInstance, but startup fails with an exception from there.

Here is the full stack trace from messages.log:

[5/13/24, 15:31:24:991 EDT] 00000055 com.ibm.ws.webcontainer.webapp                               E SRVE0276E: Error while initializing Servlet [helloServlet]: jakarta.servlet.ServletException: Failed to create JAXB context
	at com.example.liberty_problem_202405.HelloServlet.init(HelloServlet.java:23)
	at jakarta.servlet.GenericServlet.init(GenericServlet.java:178)
	at jakarta.servlet.http.HttpServlet.init(HttpServlet.java:107)
	at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:301)
	at com.ibm.ws.webcontainer.servlet.ServletWrapper.loadOnStartupCheck(ServletWrapper.java:1403)
	at com.ibm.ws.webcontainer.webapp.WebApp.doLoadOnStartupActions(WebApp.java:1228)
	at com.ibm.ws.webcontainer.webapp.WebApp.commonInitializationFinally(WebApp.java:1196)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1094)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6722)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:484)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:479)
	at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1208)
	at com.ibm.ws.webcontainer.osgi.WebContainer.access$100(WebContainer.java:113)
	at com.ibm.ws.webcontainer.osgi.WebContainer$3.run(WebContainer.java:996)
	at com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:280)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1595)
Caused by: jakarta.xml.bind.JAXBException: Error while searching for service [jakarta.xml.bind.JAXBContextFactory]
 - with linked exception:
[java.util.ServiceConfigurationError: jakarta.xml.bind.JAXBContextFactory: org.glassfish.jaxb.runtime.v2.JAXBContextFactory not a subtype]
	at jakarta.xml.bind.ContextFinder$1.createException(ContextFinder.java:85)
	at jakarta.xml.bind.ContextFinder$1.createException(ContextFinder.java:82)
	at jakarta.xml.bind.ServiceLoaderUtil.firstByServiceLoader(ServiceLoaderUtil.java:46)
	at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:319)
	at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:392)
	at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:349)
	at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:260)
	at com.example.liberty_problem_202405.HelloServlet.init(HelloServlet.java:20)
	... 19 more
Caused by: java.util.ServiceConfigurationError: jakarta.xml.bind.JAXBContextFactory: org.glassfish.jaxb.runtime.v2.JAXBContextFactory not a subtype
	at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:601)
	at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1263)
	at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1292)
	at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1328)
	at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1412)
	at jakarta.xml.bind.ServiceLoaderUtil.firstByServiceLoader(ServiceLoaderUtil.java:39)
	... 24 more

I turned on -verbose:class to see where classes are being loaded from, and here are the lines involving JAXBContextFactory (I've attached the full console.log and messages.log as liberty_problem_202405_with_jaxb_api_and_webprofile_feature_console.log and liberty_problem_202405_with_jaxb_api_and_webprofile_feature_messages.log):

class load: jakarta.xml.bind.JAXBContextFactory from: file:/c:/apps/liberty-24.0.0.4-jakarta-10-full/wlp/usr/servers/default/apps/expanded/liberty_problem_202405_with_jaxb_api.war/WEB-INF/lib/jakarta.xml.bind-api-4.0.0.jar

class load: jakarta.xml.bind.JAXBContextFactory from: file:/C:/apps/liberty-24.0.0.4-jakarta-10-full/wlp/lib/../dev/api/spec/io.openliberty.jakarta.xmlBinding.4.0_1.0.88.jar

class load: org.glassfish.jaxb.runtime.v2.JAXBContextFactory from: file:/C:/apps/liberty-24.0.0.4-jakarta-10-full/wlp/lib/io.openliberty.xmlBinding.4.0.internal.tools_1.0.88.jar

The first two lines are both loading the jaxb-api interface for JAXBContextFactory, but strangely from two different locations: first from the jar included in my WEB-INF/lib, and then from one of Liberty's own directories. Then it loads the implementation class from an internal Liberty location, instead of from the jaxb-runtime jar that is in my WEB-INF/lib directory, and which also contains this implementation class. I think the fact that the interface is loaded from WEB-INF/lib but the implementation from an internal jar is confusing it into thinking that the implementation doesn't implement the interface, even though the JAXBContextFactory interfaces from the two locations appear to actually be identical.

I would not have expected any Liberty interfaces or implementations to get loaded for this when using webProfile-10.0, because the Jakarta EE 10 XML Binding specification is not part of the Jakarta EE 10 Web Profile spec. I would have expected it to solely load classes from the jars where they are available in my WEB-INF/lib.

I tried a few variations, and it got stranger. First, I tried removing the jakarta.xml.bind-api jar from my WEB-INF/lib, in hopes that it would then only load the interface once, from Liberty's own files. But that's not what happened. This time, it didn't ever load the api interfaces from anywhere at all, not even from Liberty's files as it did in the first situation. Instead, I got this different exception, and the classloader trace never shows it loading any JAXBContext* class:

[5/13/24, 15:27:26:287 EDT] 00000052 com.ibm.ws.webcontainer.webapp                               E SRVE0276E: Error while initializing Servlet [helloServlet]: jakarta.servlet.ServletException: SRVE0207E: Uncaught initialization exception created by servlet
	at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:370)
	at com.ibm.ws.webcontainer.servlet.ServletWrapper.loadOnStartupCheck(ServletWrapper.java:1403)
	at com.ibm.ws.webcontainer.webapp.WebApp.doLoadOnStartupActions(WebApp.java:1228)
	at com.ibm.ws.webcontainer.webapp.WebApp.commonInitializationFinally(WebApp.java:1196)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1094)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6722)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:484)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:479)
	at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1208)
	at com.ibm.ws.webcontainer.osgi.WebContainer.access$100(WebContainer.java:113)
	at com.ibm.ws.webcontainer.osgi.WebContainer$3.run(WebContainer.java:996)
	at com.ibm.ws.threading.internal.ExecutorServiceImpl$RunnableWrapper.run(ExecutorServiceImpl.java:280)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1595)
Caused by: java.lang.NoClassDefFoundError: jakarta.xml.bind.JAXBContext
	at com.example.liberty_problem_202405.HelloServlet.init(HelloServlet.java:20)
	at jakarta.servlet.GenericServlet.init(GenericServlet.java:178)
	at jakarta.servlet.http.HttpServlet.init(HttpServlet.java:107)
	at com.ibm.ws.webcontainer.servlet.ServletWrapper.init(ServletWrapper.java:301)
	... 16 more
Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.JAXBContext
	at com.ibm.ws.classloading.internal.AppClassLoader.findClassCommonLibraryClassLoaders(AppClassLoader.java:742)
	at com.ibm.ws.classloading.internal.AppClassLoader.findClass(AppClassLoader.java:327)
	at com.ibm.ws.classloading.internal.AppClassLoader.findOrDelegateLoadClass(AppClassLoader.java:714)
	at com.ibm.ws.classloading.internal.AppClassLoader.loadClass(AppClassLoader.java:586)
	at com.ibm.ws.classloading.internal.AppClassLoader.loadClass(AppClassLoader.java:553)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:1104)
	... 20 more

So. in one case Liberty loaded the interface class from two places, and in the other case it didn't load it from anywhere at all.

Next, I changed the featureManager section to specify jakartaee-10.0 instead of webProfile-10.0. In this variation, the web application launched correctly, and a classloader trace showed it was loading both the interface and implementation jars from Liberty's files and it never loaded anything from either the jakarta.xml.jaxb-api or jaxb-runtime jars in my WEB-INF/lib.

Finally, I changed featureManager to just specify the minimal set of features that my web applicaiton actually needs: servlet-6.0, pages-3.1, ad websocket-2.1. The application also launched correctly in this configuration, but this time the classloader trace showed it loading all of the JAXBContext* classes from my WEB-INF/lib, and none of them from Liberty.

Steps to Reproduce
Build the attached small war file project using "mvn clean install" and Java 11 or later, then deploy it to a Liberty version in the range I mention in this problem report using the server.xml contents that appear later in this report (the important part is to have only the webProfile-10.0 feature enabled). The web application will not start correctly and you'll see the exceptions I described in messages.log and console.log, and if you enable classloader tracing by putting -verbose:class in jvm.options, you'll see classes being loaded from the multiple locations that I described above.

liberty_problem_202405.zip

Expected behavior
I expected the web application to start up without an exception, ideally by loading all of the classes involved from the jaxb-api and jaxb-runtime jars in my WEB-INF/lib, since XML Binding is not supposed to be included in Jakarta EE 10 Web Profile. But even if it did for some reason load classes from its own files (which are at the same spec level as in my war), I would have expected it to load without error.

Diagnostic information:

  • OpenLiberty Version: 24.0.0.4, with same symptoms in 23.0.0.7 and a few other versions I tried in between
  • Affected feature(s) webProfile-10.0
  • Java Version: IBM Semeru Runtime Open Edition (21.0.1+12-LTS) [also reproduced with Semeru and Oracle Java 17]
  • If it would be useful, upload the messages.log file found in $WLP_OUTPUT_DIR/messages.log: attached as liberty_problem_202405_with_jaxb_api_and_webprofile_feature_messages.log
  • server.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
    <featureManager>
        <feature>webProfile-10.0</feature>
    </featureManager>
    
    <basicRegistry id="basic" realm="BasicRealm"> 
        <!-- <user name="yourUserName" password="" />  --> 
    </basicRegistry>
    
    <httpEndpoint id="defaultHttpEndpoint"
                  host="*"
                  httpPort="9380"
                  httpsPort="9343" />
                  
    <applicationManager autoExpand="true"/>

    <ssl id="defaultSSLConfig" trustDefaultCerts="true" />
</server>

Additional context
liberty_problem_202405_with_jaxb_api_and_webprofile_feature_console.log
liberty_problem_202405_with_jaxb_api_and_webprofile_feature_messages.log

@yogregg yogregg added the release bug This bug is present in a released version of Open Liberty label May 13, 2024
@neuwerk
Copy link
Member

neuwerk commented May 13, 2024

Thanks for opening the issue, @yogregg, especially for providing such a deep background info. Its really really helpful.

That being said, we had a similar issue opened against our jaxb-2.2 feature, and ironically enough, I thought that the only EE platform that wouldn't have this issue is EE10. Looks like I thought wrong.

The cdi-4.0 feature has an dependency on the the XML Binding 4.0 specification APIs, and the cdi-4.0 feature is being pulled in automatically when you specify the webprofile-10.0 feature in your server.xml. This is why you were able to get it working when you specified only the features you needed from the webprofile-10.0, because you didn't need cdi-4.0. In EE 10, we stopped our internal XML Binding features (used by other features like 'cdi-4.0') from exposing its APIs to the application classpath. What I can't explain is why, now that we've stopped exposing them to the application classloader, you are even seeing this failure.

That being said, I would stick with using only the features you need for now as a temporary work around, and I will see what I can do to get a fix in for this.

@yogregg
Copy link
Author

yogregg commented May 14, 2024

Thanks for the quick response @neuwerk . I didn't want to clutter the problem report with them, but if the console logs with the behavior and classloader traces for the other scenario variations I mentioned would be helpful, I have them and could attach them.
I do hope you can fix it. While it is good that we can work around this, we of course don't like to tell our customers that they have to reconfigure their servers to use our products.

@neuwerk
Copy link
Member

neuwerk commented Jun 4, 2024

@yogregg if you haven't seen, I just wanted to let you know I was able to merge a fix (including tests that reproduced the failure). It should be included in the next release. I am going to close the issue for now, in the mean time you could also run against one of our nightly builds to verify the fix. If issue still persists let us know.

@neuwerk neuwerk closed this as completed Jun 4, 2024
@yogregg
Copy link
Author

yogregg commented Jun 5, 2024

@neuwerk thank you very much for the quick fix on this. I've verified it in a nightly build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs member attention release bug This bug is present in a released version of Open Liberty release:24006
Projects
None yet
Development

No branches or pull requests

3 participants