Search code examples
javaapache-tomeejakarta-migration

Migrating from Java8 EE Tomee8 to Java11+ Tomee9


I've run into a brick wall with this.

What I'm trying to do here, is migrate to Adoptium 17 JDK with Tomee9. Tomee9 here is relevant because otherwise I'd just be using javaEE libraries with a newer JDK target and call it a day. However, due to class names mismatching (mainly EJB interceptors), I get ClassNotFound exceptions when trying to deploy my WAR.

My app relies pretty heavily on old JavaEE code. I'm talking Ejb for injects, javax.ws.rs for webclients, javax.servlets, etc. The ejb migration was painless. Just had to swap the namespace and that was it. A few others required a dependency such as jakarta mail.

So one of the first things I did when trying to migrate, replaced the tomEE javaEE (so javaEE-api) with

    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>jakartaee-api</artifactId>
        <version>10.0-M1</version>
        <scope>compile</scope>
    </dependency>

This immediately caused issues, which makes sense. Red everywhere due to missing deps. I used the IntelliJ refactor tool, which replaces all Javax namespaces with Jakarta.

However, that's when I realized plenty of my libraries were still using Javax namespaces. To name a few, Auth0:

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>mvc-auth-commons</artifactId>
        <version>1.9.2</version>
    </dependency>

Is relying on Javax servlets and Javax HTTP requests. Adding:

    <dependency>
        <groupId>jakarta.ws.rs</groupId>
        <artifactId>jakarta.ws.rs-api</artifactId>
        <version>3.1.0</version>
        <type>jar</type>
    </dependency>

had no effect, I think I still need my old:

    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>javax.ws.rs-api</artifactId>
        <version>2.0</version>
    </dependency>

In any case, I've ended up in a goose chase of dependency hell (this is a pretty massive and old project), and I'm starting to second guess if my approach is the correct one.

Should I be importing the "necessary" Javax dependencies right back, next to the Jakarta ones? Is there a simple way to avoid all this pain? The libraries I'm using don't seem to care about Jakarta, and it's not really an option to go manually upgrade a bunch of them due to the number of regressions it might cause.

The ones on here have been easy to migrate: https://blogs.oracle.com/javamagazine/post/transition-from-java-ee-to-jakarta-ee https://foojay.io/today/migrating-from-java-ee-to-jakarta-ee-with-intellij-idea/

Meanwhile, some dependencies that kinda ship their own, or at least don't have a Jakarta version just don't seem to work:

https://github.com/auth0/auth0-java-mvc-common/issues/97

Now I know you guys hate general questions, and I'm bound to get so much negative engagement here, but this is eating me alive. I sadly need general guidance on how to do this. Am I really supposed to (I will probably just give up instead) port these deps, 1 by 1, hope newer versions fix it. And if there isn't, just do something else.

Mixing some Javax (namely servlet, ws rs client) and some Jakarta (mail, faces etc.) seems like a bad idea, but it's the only way I got it to even compile, while during the run time I get errors such as these:

13-Apr-2023 08:46:59.789 SEVERE [http-nio-8080-exec-4] org.apache.openejb.core.transaction.EjbTransactionUtil.handleSystemException EjbTransactionUtil.handleSystemException: java.lang.IllegalStateException: Error starting child
org.apache.openejb.OpenEJBRuntimeException: java.lang.IllegalStateException: Error starting child
    at org.apache.tomee.catalina.deployment.TomcatWebappDeployer.deploy(TomcatWebappDeployer.java:58)
    at org.apache.openejb.assembler.DeployerEjb.deploy(DeployerEjb.java:177)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:211)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:192)
    at org.apache.openejb.security.internal.InternalSecurityInterceptor.invoke(InternalSecurityInterceptor.java:35)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:211)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:192)
    at org.apache.openejb.monitoring.StatsInterceptor.record(StatsInterceptor.java:191)
    at org.apache.openejb.monitoring.StatsInterceptor.invoke(StatsInterceptor.java:101)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:211)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:95)
    at org.apache.openejb.core.singleton.SingletonContainer._invoke(SingletonContainer.java:272)
    at org.apache.openejb.core.singleton.SingletonContainer.invoke(SingletonContainer.java:221)
    at org.apache.openejb.server.ejbd.EjbRequestHandler.doEjbObject_BUSINESS_METHOD(EjbRequestHandler.java:371)
    at org.apache.openejb.server.ejbd.EjbRequestHandler.processRequest(EjbRequestHandler.java:182)
    at org.apache.openejb.server.ejbd.EjbDaemon.processEjbRequest(EjbDaemon.java:360)
    at org.apache.openejb.server.ejbd.EjbDaemon.service(EjbDaemon.java:247)
    at org.apache.openejb.server.ejbd.EjbServer.service(EjbServer.java:104)
    at org.apache.openejb.server.httpd.ServerServlet.service(ServerServlet.java:60)
    at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:587)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:870)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1762)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalStateException: Error starting child
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:729)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:698)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:747)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.deployWar(TomcatWebAppBuilder.java:687)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.deployWebApps(TomcatWebAppBuilder.java:616)
    at org.apache.tomee.catalina.deployment.TomcatWebappDeployer.deploy(TomcatWebappDeployer.java:47)
    ... 52 more
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/gtms-vps-0.0.0]]
    at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
    ... 57 more
Caused by: java.lang.NoClassDefFoundError: javax/ws/rs/ext/MessageBodyReader

Notice the no class def found error at the end. This is probably due to me still using javax classes.

Soon as I get rid of this one (although I'm not sure if it's just a coincidence), there's a similar error:

    13-Apr-2023 08:54:49.696 SEVERE [http-nio-8080-exec-4] org.apache.openejb.cdi.OpenEJBLifecycle.startApplication CDI Beans module deployment failed
        org.apache.webbeans.exception.WebBeansConfigurationException: Error while sending SystemEvent to a CDI Extension! org.apache.webbeans.portable.events.generics.GProcessAnnotatedType@48a3e14f
            at org.apache.webbeans.event.NotificationManager.onWebBeansException(NotificationManager.java:1079)
            at org.apache.webbeans.event.NotificationManager.doFireSync(NotificationManager.java:1026)
            at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:211)
            at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:192)
            at org.apache.openejb.security.internal.InternalSecurityInterceptor.invoke(InternalSecurityInterceptor.java:35)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at 
org.apache.webbeans.exception.WebBeansConfigurationException: Error while sending SystemEvent to a CDI Extension! org.apache.webbeans.portable.events.generics.GProcessAnnotatedType@48a3e14f
            at org.apache.webbeans.event.NotificationManager.onWebBeansException(NotificationManager.java:1079)
            at org.apache.webbeans.event.NotificationManager.doFireSync(NotificationManager.java:1026)
            at org.apache.webbeans.event.NotificationManager.doFireEvent(NotificationManager.java:952)
            at org.apache.webbeans.event.NotificationManager.fireEvent(NotificationManager.java:928)
        at org.apache.webbeans.container.BeanManagerImpl.fireEvent(BeanManagerImpl.java:495)
        at org.apache.webbeans.container.BeanManagerImpl.fireEvent(BeanManagerImpl.java:469)
        at org.apache.webbeans.util.WebBeansUtil.fireProcessAnnotatedTypeEvent(WebBeansUtil.java:741)
        at org.apache.webbeans.config.BeansDeployer.annotatedTypesFromBdaClassPath(BeansDeployer.java:1402)
        at org.apache.webbeans.config.BeansDeployer.annotatedTypesFromClassPath(BeansDeployer.java:1316)
        at org.apache.webbeans.config.BeansDeployer.deploy(BeansDeployer.java:249)
        at org.apache.openejb.cdi.OpenEJBLifecycle.startApplication(OpenEJBLifecycle.java:196)
        ... 68 more
    Caused by: org.apache.webbeans.exception.WebBeansException: java.lang.NoClassDefFoundError: javax/interceptor/InvocationContext
        at org.apache.webbeans.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:377)
        at org.apache.webbeans.event.NotificationManager.invokeObserverMethod(NotificationManager.java:1146)
        at org.apache.webbeans.event.NotificationManager.doFireSync(NotificationManager.java:1009)
        ... 77 more
    Caused by: java.lang.NoClassDefFoundError: javax/interceptor/InvocationContext

Solution

  • The new Tomee9 won't support the old javax.

    You have to change all libraries to jakarta or stay on Tomee8.

    Please look here:

    TomEE upgrade from 8.0.13 to 9.0.0 spring application : Caused by: java.lang.NoClassDefFoundError: javax/servlet/jsp/tagext/TryCatchFinally

    It's similar to yours.