This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit b116f8de306a9d01219a04642861a1bf45e95885 Author: opencode <[email protected]> AuthorDate: Fri Nov 6 17:25:58 2026 +0100 Start OWB from ServletContainerInitializer for listener injection Activate the OWB ServletContainerInitializer when CDI support starts so that application listeners are instantiated after the container is available and can receive field injection. Remove duplicate WebBeansConfigurationListener registration and update tests and documentation. --- modules/owb/README.md | 5 +---- .../tomcat/OpenWebBeansContextLifecycleListener.java | 18 ++++-------------- .../webbeans/web/tomcat/OpenWebBeansRedeployIT.java | 6 +++++- .../web/tomcat/OpenWebBeansTomcatIntegrationIT.java | 7 +++++-- .../web/tomcat/testapp/LifecycleContextListener.java | 8 ++++---- webapps/docs/cdi.xml | 7 ++----- 6 files changed, 21 insertions(+), 30 deletions(-) diff --git a/modules/owb/README.md b/modules/owb/README.md index 94a2455b5d..a228912fc8 100644 --- a/modules/owb/README.md +++ b/modules/owb/README.md @@ -140,7 +140,7 @@ provided through the test/common classpath, matching the production | `TomcatPluginTest` | Servlet spec class handling, managed-bean rejection, injection support and security service registration | | `OpenWebBeansInstanceManagerTest` | Delegation for all `InstanceManager` creation variants and destruction fallback | | `OpenWebBeansCdi41IT` | CDI injection, request/session scope, `isMatchingBean`, `isMatchingEvent`, `getContexts`, interceptor bindings, method invoker | -| `OpenWebBeansTomcatIntegrationIT` | Server/context listener modes, `startWithoutBeansXml` positive and negative behavior, alternate `beans.xml` location, security valve configuration, dynamic deployment, filter/listener/servlet injection and lifecycle callbacks | +| `OpenWebBeansTomcatIntegrationIT` | Server/context listener modes, `startWithoutBeansXml` positive and negative behavior, alternate `beans.xml` location, security valve configuration, dynamic deployment, filter/listener/servlet field injection and lifecycle callbacks | | `OpenWebBeansSecurityIT` | BASIC authentication, `@Inject Principal`, security valve principal, principal proxy modes and custom proxy APIs | | `OpenWebBeansSecurityFilterIT` | Webapp-level `OpenWebBeansSecurityFilter` | | `OpenWebBeansJspIT` | JSP/EL resolution through OWB | @@ -172,9 +172,6 @@ try (OwbTestServer server = OwbTestServer.start(webapp, ## Known limitations -- Field injection into `ServletContextListener` is not supported because - Tomcat instantiates listeners before the CDI container starts. Use - `CDI.current().select(...)` inside the listener instead. - Producer-level `@Priority` on competing alternative producers is not covered. OpenWebBeans reports an ambiguous resolution for that scenario, so no failing gate test is included. diff --git a/modules/owb/src/main/java/org/apache/webbeans/web/tomcat/OpenWebBeansContextLifecycleListener.java b/modules/owb/src/main/java/org/apache/webbeans/web/tomcat/OpenWebBeansContextLifecycleListener.java index e926cd7775..648a1885a0 100644 --- a/modules/owb/src/main/java/org/apache/webbeans/web/tomcat/OpenWebBeansContextLifecycleListener.java +++ b/modules/owb/src/main/java/org/apache/webbeans/web/tomcat/OpenWebBeansContextLifecycleListener.java @@ -18,8 +18,6 @@ */ package org.apache.webbeans.web.tomcat; -import java.util.LinkedList; - import org.apache.catalina.Context; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; @@ -27,7 +25,6 @@ import org.apache.catalina.LifecycleListener; import org.apache.catalina.Pipeline; import org.apache.catalina.Valve; import org.apache.tomcat.InstanceManager; -import org.apache.webbeans.servlet.WebBeansConfigurationListener; /** @@ -84,17 +81,10 @@ public class OpenWebBeansContextLifecycleListener implements LifecycleListener { || context.getResources().getResource("/WEB-INF/classes/META-INF/beans.xml").exists()) { // Registering ELResolver with JSP container System.setProperty("org.apache.webbeans.application.jsp", "true"); - // Add Listeners - String[] oldListeners = context.findApplicationListeners(); - LinkedList<String> listeners = new LinkedList<>(); - listeners.addFirst(WebBeansConfigurationListener.class.getName()); - for (String listener : oldListeners) { - listeners.add(listener); - context.removeApplicationListener(listener); - } - for (String listener : listeners) { - context.addApplicationListener(listener); - } + // Start the CDI container from the ServletContainerInitializer. + // This happens before listeners are instantiated, allowing + // listener field injection to work. + context.addParameter("openwebbeans.web.sci.active", "true"); Pipeline pipeline = context.getPipeline(); // Add to the corresponding pipeline to get a notification once configure is done if (pipeline instanceof Lifecycle) { diff --git a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansRedeployIT.java b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansRedeployIT.java index 943c0754fb..88de0a9412 100644 --- a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansRedeployIT.java +++ b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansRedeployIT.java @@ -98,8 +98,12 @@ class OpenWebBeansRedeployIT { } private static int listenerCount(OwbTestServer server) { - return (int) Arrays.stream(server.context("/owb-redeploy").findApplicationListeners()) + int classCount = (int) Arrays.stream(server.context("/owb-redeploy").findApplicationListeners()) .filter(WebBeansConfigurationListener.class.getName()::equals) .count(); + int instanceCount = (int) Arrays.stream(server.context("/owb-redeploy").getApplicationLifecycleListeners()) + .filter(WebBeansConfigurationListener.class::isInstance) + .count(); + return classCount + instanceCount; } } diff --git a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java index 4abb80cc79..62b2147b19 100644 --- a/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java +++ b/modules/owb/src/test/java/org/apache/webbeans/web/tomcat/OpenWebBeansTomcatIntegrationIT.java @@ -176,8 +176,11 @@ class OpenWebBeansTomcatIntegrationIT { } private static void assertWebBeansListener(OwbTestServer server, boolean expected) { - boolean found = Arrays.asList(server.context().findApplicationListeners()) + boolean classListener = Arrays.asList(server.context().findApplicationListeners()) .contains(WebBeansConfigurationListener.class.getName()); - assertEquals(expected, found, "Unexpected WebBeansConfigurationListener presence"); + boolean instanceListener = Arrays.stream(server.context().getApplicationLifecycleListeners()) + .anyMatch(WebBeansConfigurationListener.class::isInstance); + assertEquals(expected, classListener || instanceListener, + "Unexpected WebBeansConfigurationListener presence"); } } diff --git a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java index eb7147f16a..526893d355 100644 --- a/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java +++ b/modules/owb/src/test/webapp/lifecycle/src/org/apache/webbeans/web/tomcat/testapp/LifecycleContextListener.java @@ -21,7 +21,7 @@ import java.nio.file.Files; import java.nio.file.Path; import jakarta.annotation.PreDestroy; -import jakarta.enterprise.inject.spi.CDI; +import jakarta.inject.Inject; import jakarta.servlet.ServletContextEvent; import jakarta.servlet.ServletContextListener; import jakarta.servlet.annotation.WebListener; @@ -29,11 +29,11 @@ import jakarta.servlet.annotation.WebListener; @WebListener public class LifecycleContextListener implements ServletContextListener { + @Inject + private LifecycleGreeting greeting; + @Override public void contextInitialized(ServletContextEvent event) { - // Listeners are instantiated before the CDI container is started, so - // use programmatic lookup rather than field injection here. - LifecycleGreeting greeting = CDI.current().select(LifecycleGreeting.class).get(); event.getServletContext().setAttribute("owb.listener.greeting", greeting.message()); } diff --git a/webapps/docs/cdi.xml b/webapps/docs/cdi.xml index 0150dd5d57..2cf3fc4148 100644 --- a/webapps/docs/cdi.xml +++ b/webapps/docs/cdi.xml @@ -145,11 +145,8 @@ mvn clean verify]]></source> <section name="Known limitations"> <p> - Servlet and filter injection are supported. A - <code>ServletContextListener</code> is instantiated before the CDI - container starts, so field injection into a listener is not available. - Use programmatic lookup with <code>CDI.current().select(...)</code> inside - a listener instead. + Servlet, filter and <code>ServletContextListener</code> field injection + are supported when CDI support is enabled. </p> <p> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
