jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.86k stars 1.91k forks source link

Running embedded jetty in weld-junit5 context fails after upgrading to Jetty 12 #12285

Open jansohn opened 1 month ago

jansohn commented 1 month ago

Jetty version(s)

Jetty 12.0.13

Jetty Environment

ee10 

Java version/vendor

openjdk 21.0.2 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)

OS type/version

Microsoft Windows [Version 10.0.19045.4780]

Description Currently upgrading from Jetty 10 to Jetty 12, I'm unable to get the integration tests running again. I've set up a reproducer repo with different branches for you to test out:

I'd like to get rid of all the hacks and workarounds we used to get it running JNDI on Jetty 10 but I'm also happy for a (short-term) solution with the way we have done it in the past.

How to reproduce? Checkout repo and run the different branches (main, jndi and jndi-jetty10) with:

mvn clean verify

Output line 2024-09-18 17:00:31,774 INFO [main] com.test.ApplicationContextListener: web listener injected property: initialized! should be visible indicating a successful start-up.

joakime commented 1 month ago

Get rid of your jetty-env.xml, the initialization of weld has nothing to do with jndi.

Get rid of your jetty-context.xml - you cannot remove the Decorator, and your requestLog cannot be configured at the WebAppContext (only Server), and your NCSARequestLog doesn't exist in Jetty 12.

Next, ensure that you have the appropriate context init-parameters setup.

https://github.com/jetty/jetty-examples/blob/12.0.x/embedded/ee10-jersey-weld/src/main/java/examples/Main.java#L125-L131

Lastly, ensure that you are using weld 5.1.x for ee10 / servlet 6.0

jansohn commented 1 month ago

That's exactly what I tried in the main branch example?

jansohn commented 1 month ago

Next, ensure that you have the appropriate context init-parameters setup.

https://github.com/jetty/jetty-examples/blob/12.0.x/embedded/ee10-jersey-weld/src/main/java/examples/Main.java#L125-L131

I just tried all possible combinations mentioned in the linked code (with and without wrapping the system classloader). None of them work in my reproducer code. I hope someone can find the time to try it out themselves.

It seems to me that weld-junit5's CDI instance conflicts with the one started in the embedded jetty instance. I think that is why we used the JNDI workaround in the past...

Exception message: java.lang.ClassCastException: class org.jboss.weld.manager.BeanManagerImpl cannot be cast to class org.jboss.weld.manager.api.WeldManager (org.jboss.weld.manager.BeanManagerImpl is in unnamed module of loader 'app'; org.jboss.weld.manager.api.WeldManager is in unnamed module of loader org.eclipse.jetty.ee10.webapp.WebAppClassLoader @592e843a)

I'll add the output with stacktrace here just in case:

2024-09-19 08:32:27,595 INFO  [main] com.test.EmbeddedJettyIT: Starting embedded Jetty server...
2024-09-19 08:32:27,883 INFO  [main] org.eclipse.jetty.server.Server: jetty-12.0.13; built: 2024-09-03T03:04:05.240Z; git: 816018a420329c1cacd4116799cda8c8c60a57cd; jvm 21.0.2+13-LTS
2024-09-19 08:32:29,060 INFO  [main] org.eclipse.jetty.ee10.cdi.CdiServletContainerInitializer: CdiSpiDecorator enabled in ServletContext@oeje10w.WebAppContext@24be2d9c{Embedded Jetty with CDI Unit Test,/webapp,b=file:///C:/Users/xyz/git/playground/weld-junit5-embedded-jetty/target/webapp/,a=STOPPED,h=oeje10s.SessionHandler@50cf5a23{STOPPED}}
2024-09-19 08:32:29,076 INFO  [main] org.jboss.weld.environment.servletWeldServlet: WELD-ENV-001008: Initialize Weld using ServletContainerInitializer
2024-09-19 08:32:29,107 INFO  [main] org.jboss.weld.Version: WELD-000900: 5.1.2 (Final)
2024-09-19 08:32:29,419 INFO  [main] org.jboss.weld.Bootstrap: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
2024-09-19 08:32:29,630 INFO  [main] org.jboss.weld.environment.servletJetty: WELD-ENV-001213: Jetty CDI SPI support detected, CDI injection will be available in Listeners, Servlets and Filters.
2024-09-19 08:32:30,193 INFO  [main] org.jboss.weld.environment.servletWeldServlet: WELD-ENV-001008: Initialize Weld using ServletContainerInitializer
2024-09-19 08:32:30,219 WARN  [main] org.eclipse.jetty.ee10.webapp.WebAppContext: Failed startup of context oeje10w.WebAppContext@24be2d9c{Embedded Jetty with CDI Unit Test,/webapp,b=file:///C:/Users/xyz/git/playground/weld-junit5-embedded-jetty/target/webapp/,a=STOPPED,h=oeje10s.SessionHandler@50cf5a23{STOPPED}}
java.lang.ClassCastException: class org.jboss.weld.manager.BeanManagerImpl cannot be cast to class org.jboss.weld.manager.api.WeldManager (org.jboss.weld.manager.BeanManagerImpl is in unnamed module of loader 'app'; org.jboss.weld.manager.api.WeldManager is in unnamed module of loader org.eclipse.jetty.ee10.webapp.WebAppClassLoader @592e843a)
        at org.jboss.weld.environment.servlet.WeldServletLifecycle.initialize(WeldServletLifecycle.java:127) ~[weld-servlet-core-5.1.2.Final.jar:5.1.2.Final]
        at org.jboss.weld.environment.servlet.EnhancedListener.onStartup(EnhancedListener.java:66) ~[weld-servlet-core-5.1.2.Final.jar:5.1.2.Final]
        at org.eclipse.jetty.ee10.servlet.ServletContainerInitializerHolder.doStart(ServletContainerInitializerHolder.java:155) ~[jetty-ee10-servlet-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.servlet.ServletContextHandler$ServletContainerInitializerStarter.doStart(ServletContextHandler.java:3049) ~[jetty-ee10-servlet-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.servlet.ServletContextHandler.startContext(ServletContextHandler.java:1293) ~[jetty-ee10-servlet-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.webapp.WebAppContext.startWebapp(WebAppContext.java:1342) ~[jetty-ee10-webapp-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.webapp.WebAppContext.startContext(WebAppContext.java:1300) ~[jetty-ee10-webapp-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.servlet.ServletContextHandler.lambda$doStart$0(ServletContextHandler.java:1046) ~[jetty-ee10-servlet-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.server.handler.ContextHandler$ScopedContext.call(ContextHandler.java:1452) ~[jetty-server-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.servlet.ServletContextHandler.doStart(ServletContextHandler.java:1043) ~[jetty-ee10-servlet-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.ee10.webapp.WebAppContext.doStart(WebAppContext.java:499) ~[jetty-ee10-webapp-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.server.Server.start(Server.java:624) ~[jetty-server-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:120) ~[jetty-util-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.server.Handler$Abstract.doStart(Handler.java:491) ~[jetty-server-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.server.Server.doStart(Server.java:565) ~[jetty-server-12.0.13.jar:12.0.13]
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93) ~[jetty-util-12.0.13.jar:12.0.13]
        at com.test.EmbeddedJettyIT.startJettyServer(EmbeddedJettyIT.java:93) ~[test-classes/:?]
        at com.test.EmbeddedJettyIT.setUpBaseClass(EmbeddedJettyIT.java:54) ~[test-classes/:?]
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[?:?]
        at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[?:?]
        at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) ~[junit-platform-commons-1.10.2.jar:1.10.2]
        at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptLifecycleMethod(TimeoutExtension.java:128) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.extension.TimeoutExtension.interceptBeforeAllMethod(TimeoutExtension.java:70) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllMethods$13(ClassBasedTestDescriptor.java:412) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllMethods(ClassBasedTestDescriptor.java:410) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:216) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:85) ~[junit-jupiter-engine-5.10.2.jar:5.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:148) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) ~[?:?]
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[junit-platform-engine-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) ~[junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) ~[junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) ~[junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) ~[junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) [junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) [junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) [junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) [junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) [junit-platform-launcher-1.10.2.jar:1.10.2]
        at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) [surefire-junit-platform-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) [surefire-junit-platform-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) [surefire-junit-platform-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:122) [surefire-junit-platform-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) [surefire-booter-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) [surefire-booter-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.5.0.jar:3.5.0]
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.5.0.jar:3.5.0]

Depending on the used context init-parameters the exception might slightly change:

java.lang.IllegalStateException: Unable to access CDI
        at jakarta.enterprise.inject.spi.CDI.lambda$getCDIProvider$0(CDI.java:98) ~[jakarta.enterprise.cdi-api-4.0.1.jar:?]
        at java.base/java.util.Optional.orElseThrow(Optional.java:403) ~[?:?]
        at jakarta.enterprise.inject.spi.CDI.getCDIProvider(CDI.java:98) ~[jakarta.enterprise.cdi-api-4.0.1.jar:?]
        at jakarta.enterprise.inject.spi.CDI.current(CDI.java:65) ~[jakarta.enterprise.cdi-api-4.0.1.jar:?]
        at org.jboss.weld.module.web.servlet.WeldInitialListener.contextInitialized(WeldInitialListener.java:89) ~[weld-web-5.1.2.Final.jar:5.1.2.Final]
        at org.jboss.weld.servlet.api.helpers.ForwardingServletListener.contextInitialized(ForwardingServletListener.java:34) ~[weld-spi-5.0.SP3.jar:5.0.0.SP3]
        at org.jboss.weld.environment.servlet.EnhancedListener.onStartup(EnhancedListener.java:70) ~[weld-servlet-core-5.1.2.Final.jar:5.1.2.Final]
        at org.eclipse.jetty.ee10.servlet.ServletContainerInitializerHolder.doStart(ServletContainerInitializerHolder.java:155) ~[jetty-ee10-servlet-12.0.13.jar:12.0.13]
        [...]
joakime commented 1 month ago

It seems to me that weld-junit5's CDI instance conflicts with the one started in the embedded jetty instance. I think that is why we used the JNDI workaround in the past...

If you want server provided CDI, then you cannot include CDI in your dependencies (that includes your WEB-INF/lib in your war, or as a result of your test jars), it either all comes from the server, or it all comes from your webapp, mix and matching is not supported.

Jetty doesn't provide a JNDI layer for CDI. If it worked in the past, then that was entirely on Weld providing that feature-set.

You have to decide which way you want it to work.

For non-server provided CDI, you'll need to remove the jetty-ee10-cdi dependency, and use the CDI implementation from your WEB-INF/lib and go from there.

joakime commented 1 month ago

You should start paying attention to how CDI is evolving at the Jakarta EE. (subscribe to the project pages, and mailing lists). You'll want to stay ahead of the change coming to CDI, provide feedback, etc. Otherwise I fear you'll get blindsided by the CDI initialization changes in future EE releases.

jansohn commented 1 month ago

I did a test without jetty-ee10-cdi dependency but that does not work anymore (as you also pointed out in https://github.com/jetty/jetty.project/issues/10895#issuecomment-1812847647).

I then removed the weld-junit5 dependency completely (which I thought played a role here) and it is still failing with the exact same message.

Please take a look at the example here: https://github.com/jansohn/weld-junit5-embedded-jetty/tree/plain-jetty

If I replace the WebAppContext with ServletContextHandler then it's starting up correctly. Otherwise it's failing with:

java.lang.ClassCastException: class org.jboss.weld.manager.BeanManagerImpl cannot be cast to class org.jboss.weld.manager.api.WeldManager (org.jboss.weld.manager.BeanManagerImpl is in unnamed module of loader 'app'; org.jboss.weld.manager.api.WeldManager is in unnamed module of loader org.eclipse.jetty.ee10.webapp.WebAppClassLoader @28276e50)
janbartel commented 1 month ago

The other way to approach this is to take the existing working cdi demo webapp jetty-ee10-test-weld-cdi-webapp that can be deployed into a distribution and work outwards to your embedded scenario. The test webapp is deployed into jetty via a unit test here: https://github.com/jetty/jetty.project/blob/jetty-12.0.x/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java