Details
-
Bug
-
Status: Resolved
-
Major
-
Resolution: Auto Closed
-
7.0.5, 7.1.0, 8.0.0-M1
-
None
-
None
Description
war files that rely on Jersey instead of Apache CXF package their own JAX-RS related jars in the .war and can declare the following in their web.xml:
<servlet> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.myapp.JaxRSApp</param-value> </init-param> </servlet>
TomEE has some logic to deal with apps that deploy their own JAX-RS as shown by the following code in in the DiscoverAnnotatedBeans class in AnnotationDeployer.java:
boolean restHandledByTheWebApp; try { restHandledByTheWebApp = webModule.getClassLoader().loadClass(Application.class.getName()) != Application.class; } catch (final Throwable e) { // ClassNotFoundException or NoClassDefFoundError restHandledByTheWebApp = false; }
However, to trigger that, one must set the following in system.properties:
openejb.classloader.forced-load = javax.ws.rs
So assume that's been set.
Deploying such an app then results in the following exception in catalina.log on startup of the webapp:
09-Dec-2018 10:19:29.372 SEVERE [localhost-startStop-1] org.apache.openejb.observer.ObserverManager$MethodInvocation.invoke error invoking org.apache.tomee.webservices.TomeeJaxRsService@4f4c4b1a org.apache.openejb.server.rest.OpenEJBRestRuntimeException: can't create class com.myapp.JaxRSApp at org.apache.openejb.server.rest.RESTService.afterApplicationCreated(RESTService.java:165) at org.apache.tomee.webservices.TomeeJaxRsService.afterApplicationCreated(TomeeJaxRsService.java:53) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.openejb.observer.ObserverManager$MethodInvocation.invoke(ObserverManager.java:406) at org.apache.openejb.observer.ObserverManager$InvocationList.invoke(ObserverManager.java:521) at org.apache.openejb.observer.ObserverManager.doFire(ObserverManager.java:111) at org.apache.openejb.observer.ObserverManager.fireEvent(ObserverManager.java:100) at org.apache.openejb.loader.SystemInstance.fireEvent(SystemInstance.java:134) at org.apache.tomee.catalina.TomcatWebAppBuilder.afterStart(TomcatWebAppBuilder.java:1773) at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:116) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:94) at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:395) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:160) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:754) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:730) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734) at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:629) at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1839) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.ClassCastException: Cannot cast com.myapp.JaxRSApp to javax.ws.rs.core.Application at java.lang.Class.cast(Class.java:3369) at org.apache.openejb.server.rest.RESTService.afterApplicationCreated(RESTService.java:156) ... 25 more
With some limited debugging, this appears to be because ProcessAnnotatedBeans class' public WebModule deploy(final WebModule webModule) method processes servlets and handles javax.ws.rs.core.Application declarations - but doesn't do the 'restHandledByTheWebApp' check as DiscoverAnnotatedBeans does.
// if the servlet is a rest init servlet don't deploy rest classes automatically for (final ParamValue param : servlet.getInitParam()) { if (param.getParamName().equals(Application.class.getName()) || param.getParamName().equals("javax.ws.rs.Application")) { webModule.getRestApplications().clear(); webModule.getRestApplications().add(param.getParamValue()); break; } }
Related to this - there is also the following in RESTService.java to let apps opt-out of container's JAX-RS:
final AppInfo appInfo = event.getApp(); if ("false".equalsIgnoreCase(appInfo.properties.getProperty("openejb.jaxrs.on", "true"))) { return; }
However, this is only checked in
public void afterApplicationCreated(@Observes final AssemblerAfterApplicationCreated event)
but the other overload of this method does not check it:
public void afterApplicationCreated(final AppInfo appInfo, final WebAppInfo webApp)
If it did, the exception would also be avoided.