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));