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]

Reply via email to