diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml index 987b90c4120..a71aac9f143 100644 --- a/.github/workflows/ci-actions.yml +++ b/.github/workflows/ci-actions.yml @@ -45,6 +45,10 @@ jobs: # Caching is an automated pre/post action that installs the cache if the key exists and exports the cache # after the job is done. In this case we refresh the cache monthly (by changing key) to avoid unlimited growth. key: q2maven-main-${{ steps.get-date.outputs.date }} + - name: Build Weld API SNAPSHOT + run: | + git clone --branch jpms-migration --depth 1 https://github.com/manovotn/api.git /tmp/weld-api + mvn -f /tmp/weld-api/pom.xml clean install -DskipTests -Dno-format -B -V - name: Build Weld SNAPSHOT run: mvn clean install -DskipTests -Dno-format -B -V -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 - name: Patch WildFly diff --git a/bom/pom.xml b/bom/pom.xml index db17051879e..69165741ef2 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -30,7 +30,7 @@ - 7.0.Beta2 + 7.0-SNAPSHOT 3.2.8 1.7.0 https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/ diff --git a/bundles/osgi/pom.xml b/bundles/osgi/pom.xml index 247652246db..4ed7be200a4 100644 --- a/bundles/osgi/pom.xml +++ b/bundles/osgi/pom.xml @@ -245,6 +245,13 @@ META-INF/services/** + + *:* + + module-info.class + META-INF/versions/*/module-info.class + + diff --git a/environments/common/pom.xml b/environments/common/pom.xml index fd3cf1b2349..74280cd9454 100644 --- a/environments/common/pom.xml +++ b/environments/common/pom.xml @@ -48,4 +48,30 @@ + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -proc:full + + + + org.jboss.logging + jboss-logging-processor + ${jboss.logging.processor.version} + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + + + + diff --git a/environments/common/src/main/java/module-info.java b/environments/common/src/main/java/module-info.java new file mode 100644 index 00000000000..bc6d93832a7 --- /dev/null +++ b/environments/common/src/main/java/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.environment.common { + requires transitive org.jboss.weld.core; + requires org.jboss.logging; + requires static org.jboss.logging.annotations; + requires static org.jboss.jandex; + + opens org.jboss.weld.environment.logging to org.jboss.logging; + + exports org.jboss.weld.environment to + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.environment.deployment to + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.environment.deployment.discovery to + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.environment.deployment.discovery.jandex to + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.environment.logging to + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.environment.util to + org.jboss.weld.se, org.jboss.weld.servlet; +} diff --git a/environments/se/build/pom.xml b/environments/se/build/pom.xml index 6bc143dc5d0..bf1e131a89a 100644 --- a/environments/se/build/pom.xml +++ b/environments/se/build/pom.xml @@ -90,6 +90,15 @@ + + + *:* + + module-info.class + META-INF/versions/*/module-info.class + + + diff --git a/environments/se/core/pom.xml b/environments/se/core/pom.xml index 344f0829736..4c617a32531 100644 --- a/environments/se/core/pom.xml +++ b/environments/se/core/pom.xml @@ -164,6 +164,23 @@ org.apache.maven.plugins maven-compiler-plugin + + + -proc:full + + + + org.jboss.logging + jboss-logging-processor + ${jboss.logging.processor.version} + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + compile diff --git a/environments/se/core/src/main/java/module-info.java b/environments/se/core/src/main/java/module-info.java new file mode 100644 index 00000000000..00a02d75af1 --- /dev/null +++ b/environments/se/core/src/main/java/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.se { + requires transitive org.jboss.weld.core; + requires org.jboss.weld.environment.common; + requires org.jboss.weld.lite.extension.translator; + requires org.jboss.logging; + requires static org.jboss.logging.annotations; + + opens org.jboss.weld.environment.se.logging to org.jboss.logging; + + exports org.jboss.weld.environment.se; + exports org.jboss.weld.environment.se.bindings; + exports org.jboss.weld.environment.se.contexts; + exports org.jboss.weld.environment.se.events; + + provides jakarta.enterprise.inject.se.SeContainerInitializer + with org.jboss.weld.environment.se.Weld; + provides jakarta.enterprise.inject.spi.CDIProvider + with org.jboss.weld.environment.se.WeldSEProvider; + provides jakarta.enterprise.inject.spi.Extension + with org.jboss.weld.environment.se.WeldSEBeanRegistrant; +} diff --git a/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java b/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java index 9f948b4b8d9..d7086079cdd 100644 --- a/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java +++ b/environments/se/core/src/main/java/org/jboss/weld/environment/se/Weld.java @@ -831,6 +831,7 @@ public WeldContainer initialize() { } final WeldBootstrap bootstrap = new WeldBootstrap(); + bootstrap.setModuleAccessForwarder((source, pkg, target) -> source.addOpens(pkg, target)); // load possible additional BDA parseAdditionalBeanDefiningAnnotations(); final Deployment deployment = createDeployment(resourceLoader, bootstrap); diff --git a/environments/servlet/build/pom.xml b/environments/servlet/build/pom.xml index 7cb043ae6bf..8c53c9b75f5 100644 --- a/environments/servlet/build/pom.xml +++ b/environments/servlet/build/pom.xml @@ -106,6 +106,15 @@ jakarta.el:el-api + + + *:* + + module-info.class + META-INF/versions/*/module-info.class + + + diff --git a/environments/servlet/core/pom.xml b/environments/servlet/core/pom.xml index f829370b05d..066f8e52f41 100644 --- a/environments/servlet/core/pom.xml +++ b/environments/servlet/core/pom.xml @@ -151,4 +151,32 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -proc:full + --add-reads + org.jboss.weld.servlet=ALL-UNNAMED + + + + org.jboss.logging + jboss-logging-processor + ${jboss.logging.processor.version} + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + + + + + diff --git a/environments/servlet/core/src/main/java/module-info.java b/environments/servlet/core/src/main/java/module-info.java new file mode 100644 index 00000000000..ee29bc49a1d --- /dev/null +++ b/environments/servlet/core/src/main/java/module-info.java @@ -0,0 +1,22 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.servlet { + requires transitive org.jboss.weld.core; + requires org.jboss.weld.environment.common; + requires org.jboss.weld.lite.extension.translator; + requires org.jboss.logging; + requires static org.jboss.logging.annotations; + requires jakarta.servlet; + requires static org.apache.tomcat.catalina; + + opens org.jboss.weld.environment.servlet.logging to org.jboss.logging; + + exports org.jboss.weld.environment.servlet; + + provides jakarta.servlet.ServletContainerInitializer + with org.jboss.weld.environment.servlet.EnhancedListener; + provides jakarta.enterprise.inject.spi.CDIProvider + with org.jboss.weld.environment.servlet.WeldProvider; +} diff --git a/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java b/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java index 55653e71f9d..b2ddfb2a84b 100644 --- a/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java +++ b/environments/servlet/core/src/main/java/org/jboss/weld/environment/servlet/WeldServletLifecycle.java @@ -148,6 +148,7 @@ boolean initialize(ServletContext context) { } final CDI11Bootstrap bootstrap = new WeldBootstrap(); + bootstrap.setModuleAccessForwarder((source, pkg, target) -> source.addOpens(pkg, target)); if (isBootstrapNeeded) { final CDI11Deployment deployment = createDeployment(context, bootstrap); diff --git a/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/UndertowContainer.java b/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/UndertowContainer.java index db67df29748..f150ffa749b 100644 --- a/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/UndertowContainer.java +++ b/environments/servlet/core/src/main/java/org/jboss/weld/environment/undertow/UndertowContainer.java @@ -29,7 +29,14 @@ public class UndertowContainer implements Container { @Override public boolean touch(ResourceLoader resourceLoader, ContainerContext context) throws Exception { - return context.getServletContext().getClass().getName().startsWith(UDT_SERVLET_PREFIX); + boolean isUndertow = context.getServletContext().getClass().getName().startsWith(UDT_SERVLET_PREFIX); + if (isUndertow) { + Module servletModule = this.getClass().getModule(); + if (servletModule.isNamed()) { + servletModule.addReads(context.getServletContext().getClass().getModule()); + } + } + return isUndertow; } @Override diff --git a/impl/pom.xml b/impl/pom.xml index 74b09709ca8..e04e8278f8d 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -124,6 +124,29 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + -proc:full + --add-reads + org.jboss.weld.core=ALL-UNNAMED + + + + org.jboss.logging + jboss-logging-processor + ${jboss.logging.processor.version} + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + + org.apache.maven.plugins maven-surefire-plugin diff --git a/impl/src/main/java/module-info.java b/impl/src/main/java/module-info.java new file mode 100644 index 00000000000..8a3760ee87f --- /dev/null +++ b/impl/src/main/java/module-info.java @@ -0,0 +1,131 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.core { + requires transitive org.jboss.weld.spi; + requires org.jboss.classfilewriter; + requires org.jboss.logging; + requires java.logging; + requires static org.jboss.logging.annotations; + requires static jakarta.cdi.el; + requires static jakarta.el; + requires static jakarta.persistence; + requires static java.naming; + requires static jdk.unsupported; + + exports org.jboss.weld to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.module.jta, org.jboss.weld.module.jsf, + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.module; + + // Proxy packages — exported unqualified because proxy bytecode defined in + // user modules via Lookup.defineClass() references these types and the JVM + // resolves supertypes eagerly at class-linking time + exports org.jboss.weld.bean.proxy; + exports org.jboss.weld.bean.proxy.util; + exports org.jboss.weld.interceptor.proxy; + exports org.jboss.weld.interceptor.util.proxy; + + // Qualified exports for sibling Weld modules + exports org.jboss.weld.annotated.enhanced to + org.jboss.weld.module.ejb; + exports org.jboss.weld.annotated.enhanced.jlr to + org.jboss.weld.module.ejb; + exports org.jboss.weld.annotated.slim to + org.jboss.weld.module.ejb; + exports org.jboss.weld.bean to + org.jboss.weld.module.ejb, org.jboss.weld.lite.extension.translator; + exports org.jboss.weld.bean.attributes to + org.jboss.weld.module.ejb; + exports org.jboss.weld.bean.builtin to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.bean.builtin.ee to + org.jboss.weld.module.jta; + exports org.jboss.weld.bean.interceptor to + org.jboss.weld.module.ejb; + exports org.jboss.weld.bootstrap to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.bootstrap.events to + org.jboss.weld.lite.extension.translator, org.jboss.weld.se; + exports org.jboss.weld.config to + org.jboss.weld.module.web, org.jboss.weld.environment.common, + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.contexts to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.se; + exports org.jboss.weld.contexts.beanstore to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.se; + exports org.jboss.weld.contexts.cache to + org.jboss.weld.module.ejb, org.jboss.weld.module.web; + exports org.jboss.weld.event to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.module.jta, org.jboss.weld.se; + exports org.jboss.weld.exceptions to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.lite.extension.translator, org.jboss.weld.environment.common, + org.jboss.weld.se; + exports org.jboss.weld.executor to + org.jboss.weld.se; + exports org.jboss.weld.injection to + org.jboss.weld.module.ejb, org.jboss.weld.module.jta; + exports org.jboss.weld.injection.producer to + org.jboss.weld.module.ejb; + exports org.jboss.weld.interceptor.spi.model to + org.jboss.weld.module.ejb; + exports org.jboss.weld.invokable to + org.jboss.weld.lite.extension.translator; + exports org.jboss.weld.literal to + org.jboss.weld.environment.common; + exports org.jboss.weld.logging to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.module.jta, org.jboss.weld.lite.extension.translator; + exports org.jboss.weld.manager to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.module.jta, org.jboss.weld.module.jsf, + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.metadata to + org.jboss.weld.se; + exports org.jboss.weld.metadata.cache to + org.jboss.weld.module.ejb; + exports org.jboss.weld.resolution to + org.jboss.weld.module.jta; + exports org.jboss.weld.resources to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.module.jsf, org.jboss.weld.environment.common, + org.jboss.weld.se, org.jboss.weld.servlet; + exports org.jboss.weld.serialization to + org.jboss.weld.module.ejb, org.jboss.weld.module.web; + exports org.jboss.weld.util to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.module.jta, org.jboss.weld.module.jsf, + org.jboss.weld.environment.common, org.jboss.weld.se, + org.jboss.weld.servlet; + exports org.jboss.weld.util.annotated to + org.jboss.weld.se; + exports org.jboss.weld.util.bytecode to + org.jboss.weld.module.ejb; + exports org.jboss.weld.util.cache to + org.jboss.weld.environment.common, org.jboss.weld.se, + org.jboss.weld.servlet; + exports org.jboss.weld.util.collections to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.environment.common, org.jboss.weld.se, + org.jboss.weld.servlet; + exports org.jboss.weld.util.reflection to + org.jboss.weld.module.ejb, org.jboss.weld.module.web, + org.jboss.weld.lite.extension.translator, org.jboss.weld.se, + org.jboss.weld.servlet; + exports org.jboss.weld.xml to + org.jboss.weld.environment.common; + + opens org.jboss.weld.logging to org.jboss.logging; + + uses org.jboss.weld.module.WeldModule; + uses jakarta.enterprise.inject.spi.Extension; + uses jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; +} diff --git a/impl/src/main/java/org/jboss/weld/annotated/runtime/InvokableAnnotatedMethod.java b/impl/src/main/java/org/jboss/weld/annotated/runtime/InvokableAnnotatedMethod.java index c913220226a..a8a3cbc91ef 100644 --- a/impl/src/main/java/org/jboss/weld/annotated/runtime/InvokableAnnotatedMethod.java +++ b/impl/src/main/java/org/jboss/weld/annotated/runtime/InvokableAnnotatedMethod.java @@ -49,6 +49,7 @@ public InvokableAnnotatedMethod(AnnotatedMethod annotatedMethod) { Method method = annotatedMethod.getJavaMember(); this.methods = Collections., Method> singletonMap(method.getDeclaringClass(), method); if (method != null && !method.isAccessible()) { + Reflections.ensureModuleAccess(method.getDeclaringClass()); method.setAccessible(true); } } @@ -83,6 +84,7 @@ public X invokeOnInstance(Object instance, Object... parameters) throws Ille Method delegate = annotatedMethod.getJavaMember(); method = Reflections.lookupMethod(instance.getClass(), delegate.getName(), delegate.getParameterTypes()); if (method != null && !method.canAccess(instance)) { + Reflections.ensureModuleAccess(method.getDeclaringClass()); method.setAccessible(true); } synchronized (this) { diff --git a/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java b/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java index 9737f16b6ed..67c15c35264 100644 --- a/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java +++ b/impl/src/main/java/org/jboss/weld/bean/proxy/util/WeldDefaultProxyServices.java @@ -40,6 +40,7 @@ import org.jboss.weld.logging.BeanLogger; import org.jboss.weld.proxy.WeldClientProxy; import org.jboss.weld.serialization.spi.ProxyServices; +import org.jboss.weld.util.reflection.Reflections; /** * This class is a default implementation of ProxyServices that will only be loaded if no other implementation is detected. @@ -149,51 +150,40 @@ private WeldProxyDeclaringCL returnWeldCL(ClassLoader loader) { */ private Class defineWithMethodLookup(String classToDefineName, byte[] classBytes, Class originalClass, ClassLoader loader) { - Module thisModule = WeldDefaultProxyServices.class.getModule(); - Module apiModule = WeldClientProxy.class.getModule(); - try { Class lookupBaseClass; try { - // In case of decorators, it looks like we sometimes need the original class instead lookupBaseClass = loader.loadClass(classToDefineName.substring(0, classToDefineName.indexOf("$"))); } catch (Exception e) { lookupBaseClass = originalClass; } - // Ensure we can read the other module, and the other module can read us + Reflections.ensureModuleAccess(lookupBaseClass); + Module thisModule = WeldDefaultProxyServices.class.getModule(); + Module apiModule = WeldClientProxy.class.getModule(); Module lookupClassModule = lookupBaseClass.getModule(); - if (!thisModule.canRead(lookupClassModule)) { - // we need to read the other module in order to have privateLookup access - // see javadoc for MethodHandles.privateLookupIn() - thisModule.addReads(lookupClassModule); - } - - try { - // the other module needs to read us, since the proxy we are - // about to generate inside that module uses our classes + if (lookupClassModule.isNamed()) { MethodHandle ensureReadsMethod = null; if (!lookupClassModule.canRead(thisModule)) { ensureReadsMethod = generateEnsureReadsMethod(lookupBaseClass); ensureReadsMethod.invoke(thisModule); } - if (!lookupClassModule.canRead(apiModule)) { if (ensureReadsMethod == null) { ensureReadsMethod = generateEnsureReadsMethod(lookupBaseClass); } ensureReadsMethod.invoke(apiModule); } - } catch (Throwable t) { - throw new RuntimeException(t); } MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(lookupBaseClass, MethodHandles.lookup()); return lookup.defineClass(classBytes); } catch (IllegalAccessException e) { throw new RuntimeException(e); + } catch (Throwable t) { + throw new RuntimeException(t); } } diff --git a/impl/src/main/java/org/jboss/weld/bootstrap/WeldBootstrap.java b/impl/src/main/java/org/jboss/weld/bootstrap/WeldBootstrap.java index 214a26d2da4..72116f1edae 100644 --- a/impl/src/main/java/org/jboss/weld/bootstrap/WeldBootstrap.java +++ b/impl/src/main/java/org/jboss/weld/bootstrap/WeldBootstrap.java @@ -23,6 +23,7 @@ import org.jboss.weld.bootstrap.api.Bootstrap; import org.jboss.weld.bootstrap.api.CDI11Bootstrap; import org.jboss.weld.bootstrap.api.Environment; +import org.jboss.weld.bootstrap.api.ModuleAccessForwarder; import org.jboss.weld.bootstrap.api.TypeDiscoveryConfiguration; import org.jboss.weld.bootstrap.api.helpers.RegistrySingletonProvider; import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive; @@ -34,6 +35,7 @@ import org.jboss.weld.logging.BootstrapLogger; import org.jboss.weld.manager.BeanManagerImpl; import org.jboss.weld.util.ServiceLoader; +import org.jboss.weld.util.reflection.Reflections; import org.jboss.weld.xml.BeansXmlParser; import org.jboss.weld.xml.BeansXmlStreamParser; import org.jboss.weld.xml.BeansXmlValidator; @@ -58,6 +60,12 @@ public WeldBootstrap() { beansXmlValidator = SystemPropertiesConfiguration.INSTANCE.isXmlValidationDisabled() ? null : new BeansXmlValidator(); } + @Override + public void setModuleAccessForwarder(ModuleAccessForwarder forwarder) { + String moduleName = forwarder.getClass().getModule().getName(); + Reflections.setModuleAccessForwarder(forwarder, moduleName); + } + @Override public synchronized TypeDiscoveryConfiguration startExtensions(Iterable> extensions) { return weldStartup.startExtensions(extensions); @@ -115,6 +123,7 @@ public synchronized void shutdown() { weldRuntime.shutdown(); weldRuntime = null; } + Reflections.clearModuleAccessForwarder(); } @Override @@ -160,4 +169,4 @@ private void checkInitializationNotAlreadyEnded() { throw BootstrapLogger.LOG.callingBootstrapMethodAfterContainerHasBeenInitialized(); } } -} \ No newline at end of file +} diff --git a/impl/src/main/java/org/jboss/weld/invokable/MethodHandleUtils.java b/impl/src/main/java/org/jboss/weld/invokable/MethodHandleUtils.java index 7e35f7a746c..2f254e2afd5 100644 --- a/impl/src/main/java/org/jboss/weld/invokable/MethodHandleUtils.java +++ b/impl/src/main/java/org/jboss/weld/invokable/MethodHandleUtils.java @@ -17,6 +17,7 @@ import jakarta.enterprise.invoke.Invoker; import org.jboss.weld.logging.InvokerLogger; +import org.jboss.weld.util.reflection.Reflections; class MethodHandleUtils { private MethodHandleUtils() { @@ -86,17 +87,8 @@ private static MethodHandles.Lookup lookupFor(Executable method) throws IllegalA return MethodHandles.publicLookup(); } - // to create a method handle for a `protected`, package-private or `private` method, - // we need a private lookup in the declaring class - Module thisModule = MethodHandleUtils.class.getModule(); - Class targetClass = method.getDeclaringClass(); - Module targetModule = targetClass.getModule(); - if (!thisModule.canRead(targetModule)) { - // we need to read the other module in order to have privateLookup access - // see javadoc for MethodHandles.privateLookupIn() - thisModule.addReads(targetModule); - } - return MethodHandles.privateLookupIn(targetClass, MethodHandles.lookup()); + Reflections.ensureModuleAccess(method.getDeclaringClass()); + return MethodHandles.privateLookupIn(method.getDeclaringClass(), MethodHandles.lookup()); } static MethodHandle createMethodHandle(Method method) { diff --git a/impl/src/main/java/org/jboss/weld/util/BeanMethods.java b/impl/src/main/java/org/jboss/weld/util/BeanMethods.java index 76bc5a28e3e..834ed0a1653 100644 --- a/impl/src/main/java/org/jboss/weld/util/BeanMethods.java +++ b/impl/src/main/java/org/jboss/weld/util/BeanMethods.java @@ -51,6 +51,7 @@ import org.jboss.weld.util.collections.ImmutableList; import org.jboss.weld.util.collections.ImmutableSet; import org.jboss.weld.util.reflection.Formats; +import org.jboss.weld.util.reflection.Reflections; public class BeanMethods { @@ -360,6 +361,7 @@ public void processMethod(EnhancedAnnotatedMethod method) { if (methodMetadata == null) { methodMetadata = new LinkedList(); } + Reflections.ensureModuleAccess(javaMethod.getDeclaringClass()); javaMethod.setAccessible(true); methodMetadata.add(method.getJavaMember()); } diff --git a/impl/src/main/java/org/jboss/weld/util/reflection/Reflections.java b/impl/src/main/java/org/jboss/weld/util/reflection/Reflections.java index f96ca93fb3a..a259cb60dd8 100644 --- a/impl/src/main/java/org/jboss/weld/util/reflection/Reflections.java +++ b/impl/src/main/java/org/jboss/weld/util/reflection/Reflections.java @@ -38,7 +38,10 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; +import org.jboss.weld.bootstrap.api.ModuleAccessForwarder; import org.jboss.weld.exceptions.WeldException; import org.jboss.weld.logging.ReflectionLogger; import org.jboss.weld.resources.spi.ResourceLoader; @@ -545,6 +548,78 @@ public static boolean hasDeclaredField(Class javaClass, String name) { return false; } + private static final ConcurrentHashMap forwardedPackages = new ConcurrentHashMap<>(); + private static volatile ModuleAccessForwarder moduleAccessForwarder; + private static volatile String entryPointModuleName; + + public static void setModuleAccessForwarder(ModuleAccessForwarder forwarder, String moduleName) { + moduleAccessForwarder = forwarder; + entryPointModuleName = moduleName; + } + + public static void clearModuleAccessForwarder() { + forwardedPackages.clear(); + moduleAccessForwarder = null; + entryPointModuleName = null; + } + + public static void ensureModuleAccess(Class targetClass) { + Module coreModule = Reflections.class.getModule(); + if (!coreModule.isNamed()) { + return; + } + Module targetModule = targetClass.getModule(); + if (!targetModule.isNamed()) { + return; + } + String moduleName = targetModule.getName(); + if (moduleName.startsWith("java.") || moduleName.startsWith("jdk.")) { + return; + } + if (!coreModule.canRead(targetModule)) { + coreModule.addReads(targetModule); + } + String pkg = targetClass.getPackageName(); + if (targetModule.isOpen(pkg, coreModule)) { + return; + } + ModuleAccessForwarder forwarder = moduleAccessForwarder; + if (forwarder == null) { + return; + } + // ConcurrentBeanDeployer processes beans in parallel, so multiple threads + // may need access to the same package simultaneously. A CountDownLatch + // ensures only one thread calls addOpens() while others wait for it to + // complete before proceeding to setAccessible(). + String key = targetModule.getName() + "/" + pkg; + CountDownLatch latch = new CountDownLatch(1); + CountDownLatch existing = forwardedPackages.putIfAbsent(key, latch); + if (existing != null) { + try { + existing.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return; + } + try { + forwarder.forwardAccess(targetModule, pkg, coreModule); + } catch (Exception e) { + forwardedPackages.remove(key); + String target = entryPointModuleName != null + ? entryPointModuleName + : coreModule.getName(); + throw new RuntimeException( + "Cannot access package '" + pkg + "' in module '" + + targetModule.getName() + "'. Add 'opens " + pkg + + " to " + target + ";' to your module-info.java" + + " to allow CDI bean discovery and injection.", + e); + } finally { + latch.countDown(); + } + } + /** * Set the {@code accessible} flag for this accessible object. * Uses {@link AccessibleObject#isAccessible()} to check accessibility. @@ -564,6 +639,9 @@ public static void ensureAccessible(AccessibleObject accessibleObject) { */ public static void ensureAccessible(AccessibleObject accessibleObject, Object instance) { if (accessibleObject != null) { + if (accessibleObject instanceof Member member) { + ensureModuleAccess(member.getDeclaringClass()); + } if (instance != null) { if (!accessibleObject.canAccess(instance)) { accessibleObject.setAccessible(true); @@ -584,6 +662,7 @@ public static void ensureAccessible(AccessibleObject accessibleObject, Object in * @param */ public static T getAccessibleCopyOfMember(T member) { + ensureModuleAccess(member.getDeclaringClass()); T copy = copyMember(member); copy.setAccessible(true); return copy; diff --git a/modules/ejb/src/main/java/module-info.java b/modules/ejb/src/main/java/module-info.java new file mode 100644 index 00000000000..41a24edf4ed --- /dev/null +++ b/modules/ejb/src/main/java/module-info.java @@ -0,0 +1,14 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.module.ejb { + requires org.jboss.weld.core; + requires org.jboss.weld.spi; + requires org.jboss.classfilewriter; + requires static jakarta.ejb; + requires static jakarta.transaction; + + provides org.jboss.weld.module.WeldModule + with org.jboss.weld.module.ejb.WeldEjbModule; +} diff --git a/modules/jsf/src/main/java/module-info.java b/modules/jsf/src/main/java/module-info.java new file mode 100644 index 00000000000..c49c704a1bd --- /dev/null +++ b/modules/jsf/src/main/java/module-info.java @@ -0,0 +1,10 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.module.jsf { + requires org.jboss.weld.core; + requires org.jboss.weld.spi; + requires static jakarta.faces; + requires static jakarta.servlet; +} diff --git a/modules/jta/src/main/java/module-info.java b/modules/jta/src/main/java/module-info.java new file mode 100644 index 00000000000..72eba1e08f7 --- /dev/null +++ b/modules/jta/src/main/java/module-info.java @@ -0,0 +1,12 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.module.jta { + requires org.jboss.weld.core; + requires org.jboss.weld.spi; + requires static jakarta.transaction; + + provides org.jboss.weld.module.WeldModule + with org.jboss.weld.module.jta.WeldTransactionsModule; +} diff --git a/modules/web/pom.xml b/modules/web/pom.xml index c9948f6b6c4..aca5e002a67 100644 --- a/modules/web/pom.xml +++ b/modules/web/pom.xml @@ -80,6 +80,34 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -proc:full + --add-reads + org.jboss.weld.module.web=ALL-UNNAMED + + + + org.jboss.logging + jboss-logging-processor + ${jboss.logging.processor.version} + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + + + + + findbugs diff --git a/modules/web/src/main/java/module-info.java b/modules/web/src/main/java/module-info.java new file mode 100644 index 00000000000..1b58d04cd99 --- /dev/null +++ b/modules/web/src/main/java/module-info.java @@ -0,0 +1,18 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.module.web { + requires org.jboss.weld.core; + requires org.jboss.weld.spi; + requires org.jboss.logging; + requires static org.jboss.logging.annotations; + requires static jakarta.cdi.el; + requires static jakarta.el; + requires static jakarta.servlet; + + opens org.jboss.weld.module.web.logging to org.jboss.logging; + + provides org.jboss.weld.module.WeldModule + with org.jboss.weld.module.web.WeldWebModule; +} diff --git a/pom.xml b/pom.xml index ce4b3466720..3164d02544c 100644 --- a/pom.xml +++ b/pom.xml @@ -85,12 +85,13 @@ 4.0.0 3.0.2 4.13.2 + 6.1.2 1.2.6 3.3.7 4.10.2.0 4.10.2 7.9.0 - 7.0.Beta2 + 7.0-SNAPSHOT 5.1.0.Final @@ -469,6 +470,12 @@ + + maven-surefire-plugin + + false + + @@ -509,6 +516,7 @@ lang-model-tck tests-arquillian inject-tck-runner + tests-jpms diff --git a/tests-jpms/pom.xml b/tests-jpms/pom.xml new file mode 100644 index 00000000000..96a04d91952 --- /dev/null +++ b/tests-jpms/pom.xml @@ -0,0 +1,62 @@ + + + + org.jboss.weld + weld-core-parent + 7.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + weld-tests-jpms + Weld JPMS Integration Tests + jar + + + + org.jboss.weld.se + weld-se-core + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + + + + maven-compiler-plugin + + + -proc:none + + + + + maven-surefire-plugin + + true + + + + maven-failsafe-plugin + ${surefire.version} + + true + + + + + integration-test + verify + + + + + + + diff --git a/tests-jpms/src/main/java/module-info.java b/tests-jpms/src/main/java/module-info.java new file mode 100644 index 00000000000..a71996138d7 --- /dev/null +++ b/tests-jpms/src/main/java/module-info.java @@ -0,0 +1,8 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module weld.tests.jpms { + requires org.jboss.weld.se; + opens org.jboss.weld.tests.jpms.beans to org.jboss.weld.se; +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/ApplicationScopedBean.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/ApplicationScopedBean.java new file mode 100644 index 00000000000..dc2a407114c --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/ApplicationScopedBean.java @@ -0,0 +1,14 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ApplicationScopedBean { + public String hello() { + return "hello"; + } +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/ConstructorInjectedBean.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/ConstructorInjectedBean.java new file mode 100644 index 00000000000..af1d0026062 --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/ConstructorInjectedBean.java @@ -0,0 +1,22 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class ConstructorInjectedBean { + private final DependentBean dependent; + + @Inject + public ConstructorInjectedBean(DependentBean dependent) { + this.dependent = dependent; + } + + public String delegated() { + return dependent.value(); + } +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/DependentBean.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/DependentBean.java new file mode 100644 index 00000000000..a1f9059e0f1 --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/DependentBean.java @@ -0,0 +1,14 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import jakarta.enterprise.context.Dependent; + +@Dependent +public class DependentBean { + public String value() { + return "dependent"; + } +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/FieldInjectedBean.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/FieldInjectedBean.java new file mode 100644 index 00000000000..1281af6359f --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/FieldInjectedBean.java @@ -0,0 +1,18 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class FieldInjectedBean { + @Inject + private DependentBean dependent; + + public String delegated() { + return dependent.value(); + } +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/InterceptedBean.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/InterceptedBean.java new file mode 100644 index 00000000000..45e4ecce306 --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/InterceptedBean.java @@ -0,0 +1,15 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +@Logged +public class InterceptedBean { + public String work() { + return "intercepted"; + } +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/Logged.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/Logged.java new file mode 100644 index 00000000000..21dbb1b3b9e --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/Logged.java @@ -0,0 +1,20 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import jakarta.interceptor.InterceptorBinding; + +@InterceptorBinding +@Retention(RUNTIME) +@Target({ METHOD, TYPE }) +public @interface Logged { +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/LoggingInterceptor.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/LoggingInterceptor.java new file mode 100644 index 00000000000..190e206eef5 --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/beans/LoggingInterceptor.java @@ -0,0 +1,22 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.beans; + +import jakarta.interceptor.AroundInvoke; +import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InvocationContext; + +@Interceptor +@Logged +public class LoggingInterceptor { + + public static boolean invoked = false; + + @AroundInvoke + public Object log(InvocationContext ctx) throws Exception { + invoked = true; + return ctx.proceed(); + } +} diff --git a/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/closed/ClosedPackageBean.java b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/closed/ClosedPackageBean.java new file mode 100644 index 00000000000..64ab4fc9838 --- /dev/null +++ b/tests-jpms/src/main/java/org/jboss/weld/tests/jpms/closed/ClosedPackageBean.java @@ -0,0 +1,14 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms.closed; + +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ClosedPackageBean { + public String value() { + return "closed"; + } +} diff --git a/tests-jpms/src/test/java/org/jboss/weld/tests/jpms/JpmsIntegrationIT.java b/tests-jpms/src/test/java/org/jboss/weld/tests/jpms/JpmsIntegrationIT.java new file mode 100644 index 00000000000..bcef5db77c2 --- /dev/null +++ b/tests-jpms/src/test/java/org/jboss/weld/tests/jpms/JpmsIntegrationIT.java @@ -0,0 +1,81 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.jboss.weld.tests.jpms; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import jakarta.enterprise.inject.se.SeContainer; + +import org.jboss.weld.environment.se.Weld; +import org.jboss.weld.tests.jpms.beans.ApplicationScopedBean; +import org.jboss.weld.tests.jpms.beans.ConstructorInjectedBean; +import org.jboss.weld.tests.jpms.beans.DependentBean; +import org.jboss.weld.tests.jpms.beans.FieldInjectedBean; +import org.jboss.weld.tests.jpms.beans.InterceptedBean; +import org.jboss.weld.tests.jpms.beans.LoggingInterceptor; +import org.jboss.weld.tests.jpms.closed.ClosedPackageBean; +import org.junit.jupiter.api.Test; + +public class JpmsIntegrationIT { + + @Test + public void testBeansOnModulePath() { + Weld weld = new Weld().disableDiscovery() + .packages(ApplicationScopedBean.class) + .interceptors(LoggingInterceptor.class); + try (SeContainer container = weld.initialize()) { + ApplicationScopedBean appScoped = container.select(ApplicationScopedBean.class).get(); + assertEquals("hello", appScoped.hello()); + assertNotEquals(ApplicationScopedBean.class, appScoped.getClass(), + "ApplicationScoped bean should be a proxy"); + + DependentBean dependent = container.select(DependentBean.class).get(); + assertEquals("dependent", dependent.value()); + + FieldInjectedBean fieldInjected = container.select(FieldInjectedBean.class).get(); + assertEquals("dependent", fieldInjected.delegated()); + + ConstructorInjectedBean ctorInjected = container.select(ConstructorInjectedBean.class).get(); + assertEquals("dependent", ctorInjected.delegated()); + + LoggingInterceptor.invoked = false; + InterceptedBean intercepted = container.select(InterceptedBean.class).get(); + assertEquals("intercepted", intercepted.work()); + assertTrue(LoggingInterceptor.invoked, "Interceptor should have been invoked"); + } + } + + @Test + public void testMissingOpensGivesClearErrorMessage() { + try { + Weld weld = new Weld().disableDiscovery() + .packages(ClosedPackageBean.class); + try (SeContainer container = weld.initialize()) { + container.select(ClosedPackageBean.class).get(); + fail("Should have thrown — package is not opened"); + } + } catch (Exception e) { + String msgs = collectMessages(e); + assertTrue(msgs.contains("opens"), + "Error chain should mention 'opens' directive, got: " + msgs); + assertTrue(msgs.contains("org.jboss.weld.tests.jpms.closed"), + "Error chain should mention the closed package, got: " + msgs); + } + } + + private String collectMessages(Throwable t) { + StringBuilder sb = new StringBuilder(); + while (t != null) { + if (t.getMessage() != null) { + sb.append(t.getMessage()).append(" "); + } + t = t.getCause(); + } + return sb.toString(); + } +} diff --git a/weld-lite-extension-translator/pom.xml b/weld-lite-extension-translator/pom.xml index 7aa1da10a28..5bad32893ec 100644 --- a/weld-lite-extension-translator/pom.xml +++ b/weld-lite-extension-translator/pom.xml @@ -33,6 +33,32 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + + -proc:full + + + + org.jboss.logging + jboss-logging-processor + ${jboss.logging.processor.version} + + + org.jboss.logging + jboss-logging + ${jboss.logging.version} + + + + + + + findbugs diff --git a/weld-lite-extension-translator/src/main/java/module-info.java b/weld-lite-extension-translator/src/main/java/module-info.java new file mode 100644 index 00000000000..966b8b2a6f8 --- /dev/null +++ b/weld-lite-extension-translator/src/main/java/module-info.java @@ -0,0 +1,20 @@ +/* + * Copyright The Weld Authors + * SPDX-License-Identifier: Apache-2.0 + */ +module org.jboss.weld.lite.extension.translator { + requires org.jboss.weld.core; + requires org.jboss.weld.spi; + requires org.jboss.logging; + requires static org.jboss.logging.annotations; + + opens org.jboss.weld.lite.extension.translator.logging to org.jboss.logging; + + exports org.jboss.weld.lite.extension.translator to + org.jboss.weld.se, org.jboss.weld.servlet; + + uses jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension; + + provides jakarta.enterprise.inject.build.compatible.spi.BuildServices + with org.jboss.weld.lite.extension.translator.BuildServicesImpl; +}