From 5808a62660262e0f7b0dd78f4a1465f68541e581 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 29 Aug 2023 11:00:50 +0200 Subject: [PATCH] Issue #10356 Update Weld integration (#10359) * Issue #10356 Update Weld integration Signed-off-by: Olivier Lamy Co-authored-by: Olivier Lamy --- .../jetty/ee10/cdi/CdiConfiguration.java | 17 ++++- .../jetty/ee10/cdi/CdiDecoratingListener.java | 7 ++- .../cdi/CdiServletContainerInitializer.java | 8 +-- .../jetty/ee10/cdi/CdiSpiDecorator.java | 63 +++++++++++-------- .../eclipse/jetty/test/ServerIDFilter.java | 2 +- .../ee10/cdi/tests/EmbeddedWeldTest.java | 22 ++++--- .../test/resources/jetty-logging.properties | 5 +- .../jetty-ee10-test-owb-cdi-webapp/pom.xml | 8 +-- ...akarta.servlet.ServletContainerInitializer | 1 - .../src/main/webapp/WEB-INF/web.xml | 14 ++++- .../cdi/{jetty-cdi.xml => jetty-ee9-cdi.xml} | 0 ...{cdi-decorate.mod => ee9-cdi-decorate.mod} | 5 +- .../modules/{cdi-spi.mod => ee9-cdi-spi.mod} | 5 +- .../config/modules/{cdi.mod => ee9-cdi.mod} | 6 +- .../jetty/ee9/cdi/CdiConfiguration.java | 4 ++ .../jetty/ee9/cdi/CdiDecoratingListener.java | 4 +- .../cdi/CdiServletContainerInitializer.java | 8 +-- .../jetty/ee9/cdi/CdiSpiDecorator.java | 63 +++++++++++-------- .../eclipse/jetty/test/ServerIDFilter.java | 2 +- .../jetty/ee9/cdi/tests/EmbeddedWeldTest.java | 20 +++--- .../test/resources/jetty-logging.properties | 4 +- .../src/main/webapp/WEB-INF/jetty-env.xml | 2 +- .../tests/hometester/JettyHomeTester.java | 15 +++-- .../test-distribution-common/pom.xml | 12 ++++ .../jetty/tests/distribution/CDITests.java | 32 +++++----- 25 files changed, 206 insertions(+), 123 deletions(-) delete mode 100644 jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer rename jetty-ee9/jetty-ee9-cdi/src/main/config/etc/cdi/{jetty-cdi.xml => jetty-ee9-cdi.xml} (100%) rename jetty-ee9/jetty-ee9-cdi/src/main/config/modules/{cdi-decorate.mod => ee9-cdi-decorate.mod} (92%) rename jetty-ee9/jetty-ee9-cdi/src/main/config/modules/{cdi-spi.mod => ee9-cdi-spi.mod} (92%) rename jetty-ee9/jetty-ee9-cdi/src/main/config/modules/{cdi.mod => ee9-cdi.mod} (91%) diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiConfiguration.java b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiConfiguration.java index d9bfe5e7b678..07370998d8d1 100644 --- a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiConfiguration.java +++ b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiConfiguration.java @@ -13,6 +13,8 @@ package org.eclipse.jetty.ee10.cdi; +import java.util.function.Predicate; + import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration; import org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration; import org.eclipse.jetty.ee10.webapp.AbstractConfiguration; @@ -20,7 +22,9 @@ /** *

CDI Configuration

*

This configuration configures the WebAppContext server/system classes to - * be able to see the {@link CdiServletContainerInitializer}. + * be able to see the {@link CdiServletContainerInitializer}. Also hides the + * jakarta cdi classes that are on the environment/server classpath and allows + * the webapp to provide their own. *

*/ public class CdiConfiguration extends AbstractConfiguration @@ -29,7 +33,16 @@ public CdiConfiguration() { super(new Builder() .protectAndExpose("org.eclipse.jetty.ee10.cdi.CdiServletContainerInitializer") + .hide(getHiddenClasses()) .addDependents(AnnotationConfiguration.class, PlusConfiguration.class)); } -} + private static String[] getHiddenClasses() + { + //Only hide the cdi api classes if there is not also an impl on the + //environment classpath - vital for embedded uses. + if (CdiConfiguration.class.getClassLoader().getResource("META-INF/services/jakarta.enterprise.inject.spi.CDIProvider") == null) + return new String[]{"jakarta.enterprise.", "jakarta.decorator."}; + return new String[0]; + } +} \ No newline at end of file diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiDecoratingListener.java b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiDecoratingListener.java index 47be74372e78..0d03f0d6ad3a 100644 --- a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiDecoratingListener.java +++ b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiDecoratingListener.java @@ -17,12 +17,15 @@ import org.eclipse.jetty.ee10.servlet.ServletContextHandler; /** - * A DecoratingListener that listens for "org.eclipse.jetty.ee10.cdi.decorator" + * A DecoratingListener that listens for "org.eclipse.jetty.cdi.decorator" */ public class CdiDecoratingListener extends DecoratingListener { public static final String MODE = "CdiDecoratingListener"; - public static final String ATTRIBUTE = "org.eclipse.jetty.ee10.cdi.decorator"; + /** + * Attribute used by Weld to communicate to Jetty that it has created a WeldDecorator + */ + public static final String ATTRIBUTE = "org.eclipse.jetty.cdi.decorator"; public CdiDecoratingListener(ServletContextHandler contextHandler) { diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiServletContainerInitializer.java b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiServletContainerInitializer.java index 5af700159537..adf4ae3d88b8 100644 --- a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiServletContainerInitializer.java +++ b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiServletContainerInitializer.java @@ -28,21 +28,21 @@ *

A {@link ServletContainerInitializer} that introspects for a CDI API * implementation within a web application and applies an integration * mode if CDI is found. CDI integration modes can be selected per webapp with - * the "org.eclipse.jetty.ee10.cdi" init parameter or default to the mode set by the - * "org.eclipse.jetty.ee10.cdi" server attribute. Supported modes are:

+ * the "org.eclipse.jetty.cdi" init parameter or default to the mode set by the + * "org.eclipse.jetty.cdi" server attribute. Supported modes are:

*
*
CdiSpiDecorator
*
Jetty will call the CDI SPI within the webapp to decorate objects (default).
*
CdiDecoratingLister
*
The webapp may register a decorator on the context attribute - * "org.eclipse.jetty.ee10.cdi.decorator".
+ * "org.eclipse.jetty.cdi.decorator". *
* * @see AnnotationConfiguration.ServletContainerInitializerOrdering */ public class CdiServletContainerInitializer implements ServletContainerInitializer { - public static final String CDI_INTEGRATION_ATTRIBUTE = "org.eclipse.jetty.ee10.cdi"; + public static final String CDI_INTEGRATION_ATTRIBUTE = "org.eclipse.jetty.cdi"; private static final Logger LOG = LoggerFactory.getLogger(CdiServletContainerInitializer.class); @Override diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiSpiDecorator.java b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiSpiDecorator.java index 37abeb3451e5..21bdb6ee9c80 100644 --- a/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiSpiDecorator.java +++ b/jetty-ee10/jetty-ee10-cdi/src/main/java/org/eclipse/jetty/ee10/cdi/CdiSpiDecorator.java @@ -14,12 +14,11 @@ package org.eclipse.jetty.ee10.cdi; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; +import java.lang.reflect.Method; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -32,7 +31,7 @@ * A Decorator that invokes the CDI provider within a webapp to decorate objects created by * the contexts {@link org.eclipse.jetty.util.DecoratedObjectFactory} * (typically Listeners, Filters and Servlets). - * The CDI provider is invoked using {@link MethodHandle}s to avoid any CDI instance + * The CDI provider is invoked using reflection to avoid any CDI instance * or dependencies within the server scope. The code invoked is equivalent to: *
  * public <T> T decorate(T o)
@@ -47,20 +46,25 @@
 public class CdiSpiDecorator implements Decorator
 {
     private static final Logger LOG = LoggerFactory.getLogger(CdiServletContainerInitializer.class);
+
+    private static final Object NULL_SINGLETON_ARG = null;
+    private static final Object[] NULL_ARRAY_ARG = new Object[]{null};
+
     public static final String MODE = "CdiSpiDecorator";
 
     private final ServletContextHandler _context;
     private final Map _decorated = new HashMap<>();
 
-    private final MethodHandle _current;
-    private final MethodHandle _getBeanManager;
-    private final MethodHandle _createAnnotatedType;
-    private final MethodHandle _createInjectionTarget;
-    private final MethodHandle _createCreationalContext;
-    private final MethodHandle _inject;
-    private final MethodHandle _dispose;
-    private final MethodHandle _release;
-    private final Set _undecorated = new HashSet<>(Collections.singletonList("org.jboss.weld.environment.servlet.Listener"));
+    private final Method _current;
+    private final Method _getBeanManager;
+    private final Method _createAnnotatedType;
+    private final Method _createInjectionTarget;
+    private final Method _getInjectionTargetFactory;
+    private final Method _createCreationalContext;
+    private final Method _inject;
+    private final Method _dispose;
+    private final Method _release;
+    private final Set _undecorated = new HashSet<>(List.of("org.jboss.weld.environment.servlet.Listener", "org.jboss.weld.environment.servlet.EnhancedListener"));
 
     public CdiSpiDecorator(ServletContextHandler context) throws UnsupportedOperationException
     {
@@ -73,21 +77,26 @@ public CdiSpiDecorator(ServletContextHandler context) throws UnsupportedOperatio
         try
         {
             Class cdiClass = classLoader.loadClass("jakarta.enterprise.inject.spi.CDI");
+            Class beanClass = classLoader.loadClass("jakarta.enterprise.inject.spi.Bean");
             Class beanManagerClass = classLoader.loadClass("jakarta.enterprise.inject.spi.BeanManager");
             Class annotatedTypeClass = classLoader.loadClass("jakarta.enterprise.inject.spi.AnnotatedType");
             Class injectionTargetClass = classLoader.loadClass("jakarta.enterprise.inject.spi.InjectionTarget");
+            Class injectionTargetFactoryClass = classLoader.loadClass("jakarta.enterprise.inject.spi.InjectionTargetFactory");
             Class creationalContextClass = classLoader.loadClass("jakarta.enterprise.context.spi.CreationalContext");
             Class contextualClass = classLoader.loadClass("jakarta.enterprise.context.spi.Contextual");
 
-            MethodHandles.Lookup lookup = MethodHandles.lookup();
-            _current = lookup.findStatic(cdiClass, "current", MethodType.methodType(cdiClass));
-            _getBeanManager = lookup.findVirtual(cdiClass, "getBeanManager", MethodType.methodType(beanManagerClass));
-            _createAnnotatedType = lookup.findVirtual(beanManagerClass, "createAnnotatedType", MethodType.methodType(annotatedTypeClass, Class.class));
-            _createInjectionTarget = lookup.findVirtual(beanManagerClass, "createInjectionTarget", MethodType.methodType(injectionTargetClass, annotatedTypeClass));
-            _createCreationalContext = lookup.findVirtual(beanManagerClass, "createCreationalContext", MethodType.methodType(creationalContextClass, contextualClass));
-            _inject = lookup.findVirtual(injectionTargetClass, "inject", MethodType.methodType(Void.TYPE, Object.class, creationalContextClass));
-            _dispose = lookup.findVirtual(injectionTargetClass, "dispose", MethodType.methodType(Void.TYPE, Object.class));
-            _release = lookup.findVirtual(creationalContextClass, "release", MethodType.methodType(Void.TYPE));
+            //Use reflection rather than MethodHandles. Reflection respects the classloader that loaded the class, which means
+            //that as it's a WebAppClassLoader it will do hiding of the cdi spi classes that are on the server classpath. MethodHandles
+            //see both the cdi api classes from the server classpath and the webapp classpath and throws an exception.
+            _current = cdiClass.getMethod("current", null);
+            _getBeanManager = cdiClass.getMethod("getBeanManager", null);
+            _createAnnotatedType = beanManagerClass.getMethod("createAnnotatedType", Class.class);
+            _getInjectionTargetFactory = beanManagerClass.getMethod("getInjectionTargetFactory", annotatedTypeClass);
+            _createInjectionTarget = injectionTargetFactoryClass.getMethod("createInjectionTarget", beanClass);
+            _createCreationalContext = beanManagerClass.getMethod("createCreationalContext", contextualClass);
+            _inject = injectionTargetClass.getMethod("inject", Object.class, creationalContextClass);
+            _dispose = injectionTargetClass.getMethod("dispose", Object.class);
+            _release = creationalContextClass.getMethod("release", null);
         }
         catch (Exception e)
         {
@@ -198,13 +207,15 @@ private class Decorated
         Decorated(Object o) throws Throwable
         {
             // BeanManager manager = CDI.current().getBeanManager();
-            Object manager = _getBeanManager.invoke(_current.invoke());
+            Object manager = _getBeanManager.invoke(_current.invoke(null));
             // AnnotatedType annotatedType = manager.createAnnotatedType((Class)o.getClass());
             Object annotatedType = _createAnnotatedType.invoke(manager, o.getClass());
             // CreationalContext creationalContext = manager.createCreationalContext(null);
-            _creationalContext = _createCreationalContext.invoke(manager, null);
-            // InjectionTarget injectionTarget = manager.createInjectionTarget();
-            _injectionTarget = _createInjectionTarget.invoke(manager, annotatedType);
+            _creationalContext = _createCreationalContext.invoke(manager, NULL_SINGLETON_ARG);
+            //InjectionTargetFactory injectionTargetFactory = manager.getInjectionTargetFactory(AnnotatedType
 
     
-    
+    
     
       jakarta.enterprise
       jakarta.enterprise.cdi-api
@@ -58,10 +58,10 @@
       openwebbeans-web
       ${openwebbeans.version}
     
-    
+    
   
 
diff --git a/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer b/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
deleted file mode 100644
index 166e86c328e1..000000000000
--- a/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
+++ /dev/null
@@ -1 +0,0 @@
-org.eclipse.jetty.ee10.cdi.owb.OwbServletContainerInitializer
diff --git a/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/webapp/WEB-INF/web.xml
index a4750192c192..381b9467524e 100644
--- a/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-owb-cdi-webapp/src/main/webapp/WEB-INF/web.xml
@@ -5,11 +5,19 @@
   version="6.0">
   OWB CDI Integration Test WebApp
 
-  
-  
+  
+  
+
+  
+  
+    org.apache.webbeans.servlet.WebBeansConfigurationListener
+  
 
   
     Object factory for the CDI Bean Manager
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/config/etc/cdi/jetty-cdi.xml b/jetty-ee9/jetty-ee9-cdi/src/main/config/etc/cdi/jetty-ee9-cdi.xml
similarity index 100%
rename from jetty-ee9/jetty-ee9-cdi/src/main/config/etc/cdi/jetty-cdi.xml
rename to jetty-ee9/jetty-ee9-cdi/src/main/config/etc/cdi/jetty-ee9-cdi.xml
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi-decorate.mod b/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi-decorate.mod
similarity index 92%
rename from jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi-decorate.mod
rename to jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi-decorate.mod
index 00eb26adcba2..d2855107fdb2 100644
--- a/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi-decorate.mod
+++ b/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi-decorate.mod
@@ -4,6 +4,9 @@
 Configures Jetty to use the "CdiDecoratingListener" as the default CDI mode.
 This mode that allows a webapp to register it's own CDI decorator.
 
+[environment]
+ee9
+
 [tag]
 cdi
 
@@ -11,7 +14,7 @@ cdi
 cdi-mode
 
 [depend]
-cdi
+ee9-cdi
 
 [ini]
 jetty.cdi.mode=CdiDecoratingListener
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi-spi.mod b/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi-spi.mod
similarity index 92%
rename from jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi-spi.mod
rename to jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi-spi.mod
index a82b2a98cb37..a46b9f8461c0 100644
--- a/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi-spi.mod
+++ b/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi-spi.mod
@@ -4,6 +4,9 @@
 Configures Jetty to use the "CdiSpiDecorator" as the default CDI mode.
 This mode uses the CDI SPI to integrate an arbitrary CDI implementation.
 
+[environment]
+ee9
+
 [tag]
 cdi
 
@@ -11,7 +14,7 @@ cdi
 cdi-mode
 
 [depend]
-cdi
+ee9-cdi
 
 [ini]
 jetty.cdi.mode=CdiSpiDecorator
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi.mod b/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi.mod
similarity index 91%
rename from jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi.mod
rename to jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi.mod
index c070092d8bec..45a8d13752c4 100644
--- a/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/cdi.mod
+++ b/jetty-ee9/jetty-ee9-cdi/src/main/config/modules/ee9-cdi.mod
@@ -12,6 +12,8 @@ CdiSpiDecorator     - Jetty will call the CDI SPI within the webapp to decorate
                       objects (default).
 CdiDecoratingLister - The webapp may register a decorator on the context attribute
                       "org.eclipse.jetty.ee9.cdi.decorator".
+[environment]
+ee9
 
 [tag]
 cdi
@@ -23,7 +25,7 @@ cdi
 deploy
 
 [xml]
-etc/cdi/jetty-cdi.xml
+etc/cdi/jetty-ee9-cdi.xml
 
 [lib]
-lib/jetty-cdi-${jetty.version}.jar
+lib/jetty-ee9-cdi-${jetty.version}.jar
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiConfiguration.java b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiConfiguration.java
index d6c444331264..c51d3b24ce9c 100644
--- a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiConfiguration.java
+++ b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiConfiguration.java
@@ -28,6 +28,10 @@ public class CdiConfiguration extends AbstractConfiguration
     public CdiConfiguration()
     {
         protectAndExpose("org.eclipse.jetty.ee9.cdi.CdiServletContainerInitializer");
+        //Only hide the cdi api classes if there is not also an impl on the
+        //environment classpath - vital for embedded uses.
+        if (CdiConfiguration.class.getClassLoader().getResource("META-INF/services/jakarta.enterprise.inject.spi.CDIProvider") == null)
+            hide("jakarta.enterprise.", "jakarta.decorator.");
         addDependents(AnnotationConfiguration.class, PlusConfiguration.class);
     }
 }
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiDecoratingListener.java b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiDecoratingListener.java
index ee4e4751b27e..2d535a7b29e6 100644
--- a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiDecoratingListener.java
+++ b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiDecoratingListener.java
@@ -17,12 +17,12 @@
 import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
 
 /**
- * A DecoratingListener that listens for "org.eclipse.jetty.ee9.cdi.decorator"
+ * A DecoratingListener that listens for "org.eclipse.jetty.cdi.decorator"
  */
 public class CdiDecoratingListener extends DecoratingListener
 {
     public static final String MODE = "CdiDecoratingListener";
-    public static final String ATTRIBUTE = "org.eclipse.jetty.ee9.cdi.decorator";
+    public static final String ATTRIBUTE = "org.eclipse.jetty.cdi.decorator";
 
     public CdiDecoratingListener(ServletContextHandler contextHandler)
     {
diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiServletContainerInitializer.java b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiServletContainerInitializer.java
index b49253883bf0..523af44fc64f 100644
--- a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiServletContainerInitializer.java
+++ b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiServletContainerInitializer.java
@@ -28,21 +28,21 @@
  * 

A {@link ServletContainerInitializer} that introspects for a CDI API * implementation within a web application and applies an integration * mode if CDI is found. CDI integration modes can be selected per webapp with - * the "org.eclipse.jetty.ee9.cdi" init parameter or default to the mode set by the - * "org.eclipse.jetty.ee9.cdi" server attribute. Supported modes are:

+ * the "org.eclipse.jetty.cdi" init parameter or default to the mode set by the + * "org.eclipse.jetty.cdi" server attribute. Supported modes are:

*
*
CdiSpiDecorator
*
Jetty will call the CDI SPI within the webapp to decorate objects (default).
*
CdiDecoratingLister
*
The webapp may register a decorator on the context attribute - * "org.eclipse.jetty.ee9.cdi.decorator".
+ * "org.eclipse.jetty.cdi.decorator". *
* * @see AnnotationConfiguration.ServletContainerInitializerOrdering */ public class CdiServletContainerInitializer implements ServletContainerInitializer { - public static final String CDI_INTEGRATION_ATTRIBUTE = "org.eclipse.jetty.ee9.cdi"; + public static final String CDI_INTEGRATION_ATTRIBUTE = "org.eclipse.jetty.cdi"; private static final Logger LOG = LoggerFactory.getLogger(CdiServletContainerInitializer.class); @Override diff --git a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiSpiDecorator.java b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiSpiDecorator.java index 676444b9fd92..f9cfee2fd4c5 100644 --- a/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiSpiDecorator.java +++ b/jetty-ee9/jetty-ee9-cdi/src/main/java/org/eclipse/jetty/ee9/cdi/CdiSpiDecorator.java @@ -14,12 +14,11 @@ package org.eclipse.jetty.ee9.cdi; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; +import java.lang.reflect.Method; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -32,7 +31,7 @@ * A Decorator that invokes the CDI provider within a webapp to decorate objects created by * the contexts {@link org.eclipse.jetty.util.DecoratedObjectFactory} * (typically Listeners, Filters and Servlets). - * The CDI provider is invoked using {@link MethodHandle}s to avoid any CDI instance + * The CDI provider is invoked using reflection to avoid any CDI instance * or dependencies within the server scope. The code invoked is equivalent to: *
  * public <T> T decorate(T o)
@@ -48,19 +47,22 @@ public class CdiSpiDecorator implements Decorator
 {
     private static final Logger LOG = LoggerFactory.getLogger(CdiServletContainerInitializer.class);
     public static final String MODE = "CdiSpiDecorator";
+    private static final Object NULL_SINGLETON_ARG = null;
+    private static final Object[] NULL_ARRAY_ARG = new Object[]{null};
 
     private final ServletContextHandler _context;
     private final Map _decorated = new HashMap<>();
 
-    private final MethodHandle _current;
-    private final MethodHandle _getBeanManager;
-    private final MethodHandle _createAnnotatedType;
-    private final MethodHandle _createInjectionTarget;
-    private final MethodHandle _createCreationalContext;
-    private final MethodHandle _inject;
-    private final MethodHandle _dispose;
-    private final MethodHandle _release;
-    private final Set _undecorated = new HashSet<>(Collections.singletonList("org.jboss.weld.environment.servlet.Listener"));
+    private final Method _current;
+    private final Method _getBeanManager;
+    private final Method _createAnnotatedType;
+    private final Method _createInjectionTarget;
+    private final Method _getInjectionTargetFactory;
+    private final Method _createCreationalContext;
+    private final Method _inject;
+    private final Method _dispose;
+    private final Method _release;
+    private final Set _undecorated = new HashSet<>(List.of("org.jboss.weld.environment.servlet.Listener", "org.jboss.weld.environment.servlet.EnhancedListener"));
 
     public CdiSpiDecorator(ServletContextHandler context) throws UnsupportedOperationException
     {
@@ -73,21 +75,26 @@ public CdiSpiDecorator(ServletContextHandler context) throws UnsupportedOperatio
         try
         {
             Class cdiClass = classLoader.loadClass("jakarta.enterprise.inject.spi.CDI");
+            Class beanClass = classLoader.loadClass("jakarta.enterprise.inject.spi.Bean");
             Class beanManagerClass = classLoader.loadClass("jakarta.enterprise.inject.spi.BeanManager");
             Class annotatedTypeClass = classLoader.loadClass("jakarta.enterprise.inject.spi.AnnotatedType");
             Class injectionTargetClass = classLoader.loadClass("jakarta.enterprise.inject.spi.InjectionTarget");
+            Class injectionTargetFactoryClass = classLoader.loadClass("jakarta.enterprise.inject.spi.InjectionTargetFactory");
             Class creationalContextClass = classLoader.loadClass("jakarta.enterprise.context.spi.CreationalContext");
             Class contextualClass = classLoader.loadClass("jakarta.enterprise.context.spi.Contextual");
-
-            MethodHandles.Lookup lookup = MethodHandles.lookup();
-            _current = lookup.findStatic(cdiClass, "current", MethodType.methodType(cdiClass));
-            _getBeanManager = lookup.findVirtual(cdiClass, "getBeanManager", MethodType.methodType(beanManagerClass));
-            _createAnnotatedType = lookup.findVirtual(beanManagerClass, "createAnnotatedType", MethodType.methodType(annotatedTypeClass, Class.class));
-            _createInjectionTarget = lookup.findVirtual(beanManagerClass, "createInjectionTarget", MethodType.methodType(injectionTargetClass, annotatedTypeClass));
-            _createCreationalContext = lookup.findVirtual(beanManagerClass, "createCreationalContext", MethodType.methodType(creationalContextClass, contextualClass));
-            _inject = lookup.findVirtual(injectionTargetClass, "inject", MethodType.methodType(Void.TYPE, Object.class, creationalContextClass));
-            _dispose = lookup.findVirtual(injectionTargetClass, "dispose", MethodType.methodType(Void.TYPE, Object.class));
-            _release = lookup.findVirtual(creationalContextClass, "release", MethodType.methodType(Void.TYPE));
+            
+            //Use reflection rather than MethodHandles. Reflection respects the classloader that loaded the class, which means
+            //that as it's a WebAppClassLoader it will do hiding of the cdi spi classes that are on the server classpath. MethodHandles
+            //see both the cdi api classes from the server classpath and the webapp classpath and throws an exception.
+            _current = cdiClass.getMethod("current", null);
+            _getBeanManager = cdiClass.getMethod("getBeanManager", null);
+            _createAnnotatedType = beanManagerClass.getMethod("createAnnotatedType", Class.class);
+            _getInjectionTargetFactory = beanManagerClass.getMethod("getInjectionTargetFactory", annotatedTypeClass);
+            _createInjectionTarget = injectionTargetFactoryClass.getMethod("createInjectionTarget", beanClass);
+            _createCreationalContext = beanManagerClass.getMethod("createCreationalContext", contextualClass);
+            _inject = injectionTargetClass.getMethod("inject", Object.class, creationalContextClass);
+            _dispose = injectionTargetClass.getMethod("dispose", Object.class);
+            _release = creationalContextClass.getMethod("release", null);
         }
         catch (Exception e)
         {
@@ -198,13 +205,15 @@ private class Decorated
         Decorated(Object o) throws Throwable
         {
             // BeanManager manager = CDI.current().getBeanManager();
-            Object manager = _getBeanManager.invoke(_current.invoke());
+            Object manager = _getBeanManager.invoke(_current.invoke(null));
             // AnnotatedType annotatedType = manager.createAnnotatedType((Class)o.getClass());
             Object annotatedType = _createAnnotatedType.invoke(manager, o.getClass());
             // CreationalContext creationalContext = manager.createCreationalContext(null);
-            _creationalContext = _createCreationalContext.invoke(manager, null);
-            // InjectionTarget injectionTarget = manager.createInjectionTarget();
-            _injectionTarget = _createInjectionTarget.invoke(manager, annotatedType);
+            _creationalContext = _createCreationalContext.invoke(manager, NULL_SINGLETON_ARG);
+            //InjectionTargetFactory injectionTargetFactory = manager.getInjectionTargetFactory(AnnotatedType
 
 
-  
+  
     
       
     
diff --git a/tests/jetty-home-tester/src/main/java/org/eclipse/jetty/tests/hometester/JettyHomeTester.java b/tests/jetty-home-tester/src/main/java/org/eclipse/jetty/tests/hometester/JettyHomeTester.java
index 715a7a9e13f0..f6d15f0c3034 100644
--- a/tests/jetty-home-tester/src/main/java/org/eclipse/jetty/tests/hometester/JettyHomeTester.java
+++ b/tests/jetty-home-tester/src/main/java/org/eclipse/jetty/tests/hometester/JettyHomeTester.java
@@ -24,6 +24,7 @@
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.URI;
+import java.nio.file.CopyOption;
 import java.nio.file.FileAlreadyExistsException;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
@@ -113,6 +114,8 @@ public class JettyHomeTester
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(JettyHomeTester.class);
 
+    private static final CopyOption[] EMPTY_OPTIONS = new CopyOption[]{};
+
     private final Config config;
 
     private JettyHomeTester(Config config)
@@ -206,18 +209,22 @@ public int freePort() throws IOException
     }
 
     /**
-     * Installs content from {@code src/test/resources/} into {@code ${jetty.base}/}
+     * Installs in {@code ${jetty.base}/webapps} the given war file under the given context path.
      *
      * @param testResourcePath the location of the source file in {@code src/test/resources}
      * @param baseResourcePath the location of the destination file in {@code ${jetty.base}}
-     * @throws IOException if unable to copy file
+     * @param options optional CopyOption
+     * @throws IOException if the installation fails
      */
-    public void installBaseResource(String testResourcePath, String baseResourcePath) throws IOException
+   public void installBaseResource(String testResourcePath, String baseResourcePath, CopyOption... options) throws IOException
     {
         Path srcFile = MavenTestingUtils.getTestResourcePath(testResourcePath);
         Path destFile = config.jettyBase.resolve(baseResourcePath);
+        Files.deleteIfExists(destFile);
+        if (!Files.exists(destFile.getParent()))
+            Files.createDirectories(destFile.getParent());
 
-        Files.copy(srcFile, destFile);
+        Files.copy(srcFile, destFile, options);
     }
 
     /**
diff --git a/tests/test-distribution/test-distribution-common/pom.xml b/tests/test-distribution/test-distribution-common/pom.xml
index d225430d38f2..b21353f8bba3 100644
--- a/tests/test-distribution/test-distribution-common/pom.xml
+++ b/tests/test-distribution/test-distribution-common/pom.xml
@@ -165,6 +165,18 @@
       mariadb-java-client
       test
     
+    
+      org.eclipse.jetty.ee9
+      jetty-ee9-test-badinit-webapp
+      ${project.version}
+      war
+    
+    
+      org.eclipse.jetty.ee10
+      jetty-ee10-test-badinit-webapp
+      ${project.version}
+      war
+    
   
 
   
diff --git a/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java b/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java
index 5bfe8ccd8837..db62ee40a699 100644
--- a/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java
+++ b/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java
@@ -17,6 +17,7 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.concurrent.TimeUnit;
@@ -27,7 +28,6 @@
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.tests.hometester.JettyHomeTester;
 import org.eclipse.jetty.util.StringUtil;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -37,7 +37,6 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-@Disabled("JAKARTA namespace for 3rd party libraries")
 public class CDITests extends AbstractJettyHomeTest
 {
     // Tests from here use these parameters
@@ -58,21 +57,14 @@ public static Stream tests()
         };
 
         return Stream.of(
-            //TODO enable ee9 tests
-            // -- Weld --
-            // Uses test-weld-cdi-webapp
-            //Arguments.of("ee9", "weld", "cdi-spi", null), // Weld >= 3.1.2            
-            Arguments.of("ee10", "weld", "cdi-spi", null), // Weld >= 3.1.2
-            //Arguments.of("ee9", "weld", "decorate", null), // Weld >= 3.1.2           
-            Arguments.of("ee10", "weld", "decorate", null), // Weld >= 3.1.2
-            //Arguments.of("ee9", "weld", "cdi-decorate", null), // Weld >= 3.1.3
-            Arguments.of("ee10", "weld", "cdi-decorate", null), // Weld >= 3.1.3
-            // -- Apache OpenWebBeans --
+            Arguments.of("ee9", "cdi-spi", "weld", null), // Weld >= 3.1.2
+            Arguments.of("ee10", "cdi-spi", "weld", null), // Weld >= 3.1.2
+            Arguments.of("ee9", "cdi-decorate", "weld", null), // Weld >= 3.1.3
+            Arguments.of("ee10", "cdi-decorate", "weld", null) // Weld >= 3.1.3
+            // -- Apache OpenWebBeans -- as of 2.0.27 was not ported to jakarta namespace
             // Uses test-owb-cdi-webapp
             //Arguments.of("ee9", "owb", "cdi-spi", null),
-            Arguments.of("ee10", "owb", "cdi-spi", null)
-            // Arguments.of("owb", "decorate", null), // Not supported
-            // Arguments.of("owb", "cdi-decorate", null) // Not supported
+            //Arguments.of("ee10", "cdi-spi", "owb", null)
         );
     }
 
@@ -84,10 +76,12 @@ public static Stream tests()
     @MethodSource("tests")
     public void testCDIIncludedInWebapp(String env, String implementation, String integration, Consumer configure) throws Exception
     {
+        Path jettyBase = newTestJettyBaseDirectory();
         String jettyVersion = System.getProperty("jettyVersion");
         String jvmArgs = System.getProperty("cdi.tests.jvmArgs");
         JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
             .jettyVersion(jettyVersion)
+            .jettyBase(jettyBase)
             .jvmArgs(jvmArgs == null ? Collections.emptyList() : Arrays.asList(jvmArgs.split("\\s+")))
             .build();
 
@@ -96,7 +90,7 @@ public void testCDIIncludedInWebapp(String env, String implementation, String in
             toEnvironment("annotations", env) + "," +
             toEnvironment("jsp", env);
         
-        if (!StringUtil.isBlank(implementation) && !("decorate".equals(implementation)))
+        if (!StringUtil.isBlank(implementation))
         {
             mods = mods + "," + toEnvironment(implementation, env);
         }
@@ -110,8 +104,10 @@ public void testCDIIncludedInWebapp(String env, String implementation, String in
             assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
             assertEquals(0, run1.getExitValue());
 
-            File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".tests:test-jetty-" + env + "-" + implementation + "-cdi-webapp:war:" + jettyVersion);
+            File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-" + integration + "-cdi-webapp:war:" + jettyVersion);
             distribution.installWarFile(war, "demo");
+
+            distribution.installBaseResource("jetty-logging.properties", "resources/jetty-logging.properties", StandardCopyOption.REPLACE_EXISTING);
             if (configure != null)
                 configure.accept(distribution);
 
@@ -126,7 +122,7 @@ public void testCDIIncludedInWebapp(String env, String implementation, String in
                 // Confirm Servlet based CDI
                 assertThat(response.getContentAsString(), containsString("Hello GreetingsServlet"));
                 // Confirm Listener based CDI (this has been a problem in the past, keep this for regression testing!)
-                assertThat(response.getHeaders().get("Server"), containsString("CDI-Demo-org.eclipse.jetty.test"));
+                assertThat(response.getHeaders().get("CDI-Server"), containsString("CDI-Demo-org.eclipse.jetty.test"));
 
                 run2.stop();
                 assertTrue(run2.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));