-
Bug
-
Resolution: Done
-
Minor
-
4.0.3.Final, 5.1.1.SP1, 6.0.0.Beta1
-
None
When using Weld as part of Open Liberty, if I inject a `ServletContext` and then call `context.getClass().getDeclaredMethods()`, I get a NoClassDefFoundError for jakarta.servlet.descriptor.JspConfigDescriptor. (Stack trace below)
Doing some investigation, I see that the classloader of the proxy is the Weld OSGi bundle, which indeed does not import `jakarta.servlet.descriptor`.
Trying to determine why the classloader is the Weld OSGi bundle, I found that when Weld calls `ProxyServices.defineClass` for this bean, the value passed in for "originalClass" is org.jboss.weld.module.web.ServletContextBean, and not jakarta.servlet.ServletContext.
We therefore use the classloader of ServletContextBean to define the proxy class.
I can see a few ways to fix this, but I'm not sure which would be correct or how this is intended to work:
- Special case the built-in beans in our ProxyServices implementation to use the classloader for the interface, rather than the bean class, for the proxy
- Add the import of jakarta.servlet.descriptor to the weld-osgi-bundle
- Change the class that Weld passes to ProxyServices.defineClass
Other notes:
- We first saw this issue in session persistence. When a ServletContext proxy is serialized, the serialization code was looking for a "writeObject" method, and as part of that process was getting the declared methods for the proxy which provoked this error.
- I wasn't getting the error in my session persistence test locally but I was seeing it in CI, I'm not sure what the difference was. By calling getDeclaredMethods myself directly, I was able to reproduce the problem more easily.
- I can't reproduce the problem on Weld 3 and I'm not sure why, on the surface it looks like it should have the same issue. I would guess that maybe there's some other route that these methods can be initialized which does allow the JspConfigDescriptor class to be found? That would explain both it working on Weld 3 and not appearing reliably when the session is persisted.
- Tested with IBM Semeru Runtime Certified Edition (17.0.7+7) and OpenJDK Runtime Environment (17.0.7+7)
Stack trace:
java.lang.NoClassDefFoundError: jakarta.servlet.descriptor.JspConfigDescriptor
at java.base/java.lang.Class.getVirtualMethodsImpl(Native Method)
at java.base/java.lang.Class.getMethodSet(Class.java:1811)
at java.base/java.lang.Class.getMethods(Class.java:1774)
at com.ibm.ws.cdi.jee.session.app.MySessionBean.pokeBeans(MySessionBean.java:81)
at com.ibm.ws.cdi.jee.session.app.MySessionBean$Proxy$_$$_WeldClientProxy.pokeBeans(Unknown Source)
[... lots of test framework and application server frames ...]
Caused by: java.lang.ClassNotFoundException: jakarta.servlet.descriptor.JspConfigDescriptor cannot be found by io.openliberty.org.jboss.weld5_1.0.93.202408191114
at org.eclipse.osgi.internal.loader.BundleLoader.generateException(BundleLoader.java:541)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass0(BundleLoader.java:536)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:416)
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:168)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:1094)
... 38 more
Note that io.openliberty.org.jboss.weld5_1.0.93.202408191114 is a rebundling of weld-osgi-bundle. We do import and export a few additional packages, but neither bundle imports jakarta.servlet.descriptor.