From 4dfb573d17a90f99db67e5d815a760784a7f1bfd Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 13 Aug 2020 20:54:51 +0200 Subject: [PATCH] =?UTF-8?q?Support=20for=20bean=20producers=20in=20differe?= =?UTF-8?q?nt=20package=20than=20beans=20that=20have=20=E2=80=A6=20(#2241)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Support for bean producers in different package than beans that have package local methods. * Update to proxy services - name is generated with super interface first - proxy classes are defined using private lookup - proxy classes are defined using a class loader for weld specific packages Signed-off-by: Tomas Langer --- .../src/main/java/module-info.java | 2 +- .../access-log/src/main/java/module-info.java | 2 +- .../cdi/HelidonProxyServices.java | 116 +++++++++++++----- .../config/src/main/java/module-info.java | 2 +- .../src/main/java/module-info.java | 2 +- .../health/src/main/java/module-info.java | 2 +- .../jwt-auth/src/main/java/module-info.java | 2 +- .../openapi/src/main/java/module-info.java | 2 +- .../security/src/main/java/module-info.java | 2 +- .../server/src/main/java/module-info.java | 2 +- .../tracing/src/main/java/module-info.java | 2 +- .../websocket/src/main/java/module-info.java | 2 +- .../jboss/weld/bean/proxy/ProxyFactory.java | 44 ++++++- .../jersey/src/main/java/module-info.java | 2 +- .../security/src/main/java/module-info.java | 2 +- .../common/src/main/java/module-info.java | 2 +- .../nativeimage/mp1/BeanProducer.java | 33 +++++ .../integration/nativeimage/mp1/Mp1Main.java | 3 + .../integration/nativeimage/mp1/TestBean.java | 11 +- .../nativeimage/mp1/other/BeanProcessor.java | 36 ++++++ .../nativeimage/mp1/other/ProducedBean.java | 58 +++++++++ .../nativeimage/mp1/other/package-info.java | 20 +++ .../mp-1/src/main/java/module-info.java | 2 + 23 files changed, 298 insertions(+), 53 deletions(-) create mode 100644 tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java create mode 100644 tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java create mode 100644 tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java create mode 100644 tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java diff --git a/health/health-checks/src/main/java/module-info.java b/health/health-checks/src/main/java/module-info.java index 22bb21e36..651e69c20 100644 --- a/health/health-checks/src/main/java/module-info.java +++ b/health/health-checks/src/main/java/module-info.java @@ -33,5 +33,5 @@ module io.helidon.health.checks { exports io.helidon.health.checks; // required for CDI - opens io.helidon.health.checks to weld.core.impl; + opens io.helidon.health.checks to weld.core.impl, io.helidon.microprofile.cdi; } diff --git a/microprofile/access-log/src/main/java/module-info.java b/microprofile/access-log/src/main/java/module-info.java index 9d49455b8..b4673d9af 100644 --- a/microprofile/access-log/src/main/java/module-info.java +++ b/microprofile/access-log/src/main/java/module-info.java @@ -29,7 +29,7 @@ module io.helidon.microprofile.accesslog { exports io.helidon.microprofile.accesslog; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.accesslog to weld.core.impl; + opens io.helidon.microprofile.accesslog to weld.core.impl, io.helidon.microprofile.cdi; provides Extension with io.helidon.microprofile.accesslog.AccessLogCdiExtension; } diff --git a/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonProxyServices.java b/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonProxyServices.java index 5ecb9e814..67031991e 100644 --- a/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonProxyServices.java +++ b/microprofile/cdi/src/main/java/io/helidon/microprofile/cdi/HelidonProxyServices.java @@ -23,6 +23,7 @@ import java.security.ProtectionDomain; import java.util.Collections; import java.util.IdentityHashMap; import java.util.Map; +import java.util.logging.Level; import java.util.logging.Logger; import io.helidon.common.NativeImageHelper; @@ -32,6 +33,9 @@ import org.jboss.weld.serialization.spi.ProxyServices; class HelidonProxyServices implements ProxyServices { private static final Logger LOGGER = Logger.getLogger(HelidonProxyServices.class.getName()); + private static final String WELD_JAVAX_PREFIX = "org.jboss.weldx."; + private static final String WELD_JAVA_PREFIX = "org.jboss.weld."; + // a cache of all classloaders (this should be empty in most cases, as we use a single class loader in Helidon) private final Map classLoaders = Collections.synchronizedMap(new IdentityHashMap<>()); private final ClassLoader contextCl; @@ -69,14 +73,20 @@ class HelidonProxyServices implements ProxyServices { public Class defineClass(Class originalClass, String className, byte[] classBytes, int off, int len) throws ClassFormatError { - if (samePackage(originalClass, className)) { - // when we need to define a class in the same package (to see package local fields and methods) - // we cannot use a classloader, as the new class would be in the same package, but in a different - // classloader, preventing it from seeing these fields/methods - return defineClassSamePackage(originalClass, className, classBytes, off, len); - } else { - // use a custom classloader to define classes in a new package - return wrapCl(originalClass.getClassLoader()).doDefineClass(originalClass, className, classBytes, off, len); + if (weldInternalProxyClassName(className)) { + // this is special case - these classes are defined in a non-existent package + // and we need to use a classloader (public lookup will not allow this, and private lookup is not + // possible for an empty package) + return wrapCl(originalClass.getClassLoader()) + .doDefineClass(originalClass, className, classBytes, off, len); + } + // any other class should be defined using a private lookup + try { + return defineClassPrivateLookup(originalClass, className, classBytes, off, len); + } catch (Exception e) { + LOGGER.log(Level.FINEST, "Failed to create class " + className + " using private lookup", e); + + throw e; } } @@ -88,12 +98,21 @@ class HelidonProxyServices implements ProxyServices { int len, ProtectionDomain protectionDomain) throws ClassFormatError { - if (samePackage(originalClass, className)) { - return defineClassSamePackage(originalClass, className, classBytes, off, len); - } else { + if (weldInternalProxyClassName(className)) { + // this is special case - these classes are defined in a non-existent package + // and we need to use a classloader (public lookup will not allow this, and private lookup is not + // possible for an empty package) return wrapCl(originalClass.getClassLoader()) .doDefineClass(originalClass, className, classBytes, off, len, protectionDomain); } + // any other class should be defined using a private lookup + try { + return defineClassPrivateLookup(originalClass, className, classBytes, off, len); + } catch (Exception e) { + LOGGER.log(Level.FINEST, "Failed to create class " + className + " using private lookup", e); + + throw e; + } } @Override @@ -101,7 +120,11 @@ class HelidonProxyServices implements ProxyServices { return wrapCl(originalClass.getClassLoader()).loadClass(classBinaryName); } - private Class defineClassSamePackage(Class originalClass, String className, byte[] classBytes, int off, int len) { + private boolean weldInternalProxyClassName(String className) { + return className.startsWith(WELD_JAVAX_PREFIX) || className.startsWith(WELD_JAVA_PREFIX); + } + + private Class defineClassPrivateLookup(Class originalClass, String className, byte[] classBytes, int off, int len) { if (NativeImageHelper.isRuntime()) { throw new IllegalStateException("Cannot define class in native image. Class name: " + className + ", original " + "class: " + originalClass @@ -110,39 +133,64 @@ class HelidonProxyServices implements ProxyServices { LOGGER.finest("Defining class " + className + " original class: " + originalClass.getName()); + MethodHandles.Lookup lookup; + try { - Module classModule = originalClass.getModule(); - if (!myModule.canRead(classModule)) { + // lookup class name "guessed" from the class name of the proxy + // proxy name must contain the $ - if it does not, we just use the originalClass as that is safe + int index = className.indexOf('$'); + + Class lookupClass; + if (index < 0) { + LOGGER.finest(() -> "Attempt to define a proxy class without a $ in its name. Class name: " + className + "," + + " original class name: " + originalClass.getName()); + lookupClass = originalClass; + } else { + // I would like to create a private lookup in the same package as the proxied class, so let's do it + // use the "extracted" lookup class name, if that fails, use the original class + lookupClass = tryLoading(originalClass, className.substring(0, index)); + } + + Module lookupClassModule = lookupClass.getModule(); + if (!myModule.canRead(lookupClassModule)) { // we need to read the module to be able to create a private lookup in it // it also needs to open the package we are doing the lookup in - myModule.addReads(classModule); + myModule.addReads(lookupClassModule); } + // next line would fail if the module does not open its package, with a very meaningful error message - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(originalClass, MethodHandles.lookup()); - if (classBytes.length == len) { - return lookup.defineClass(classBytes); - } else { - byte[] bytes = new byte[len]; - System.arraycopy(classBytes, off, bytes, 0, len); - return lookup.defineClass(bytes); - } + lookup = MethodHandles.privateLookupIn(lookupClass, MethodHandles.lookup()); } catch (IllegalAccessException e) { throw new RuntimeException("Failed to define class " + className, e); } + + return defineClass(lookup, className, classBytes, off, len); } - private boolean samePackage(Class originalClass, String className) { - String origPackage = originalClass.getPackageName(); - String newPackage = packageName(className); - return newPackage.equals(origPackage); - } - - private String packageName(String className) { - int index = className.lastIndexOf('.'); - if (index > 0) { - return className.substring(0, index); + private Class tryLoading(Class originalClass, String className) { + try { + return originalClass.getClassLoader().loadClass(className); + } catch (Exception e) { + LOGGER.log(Level.FINEST, "Attempt to load class " + className + " failed.", e); + return originalClass; + } + } + + private Class defineClass(MethodHandles.Lookup lookup, String className, byte[] classBytes, int off, int len) { + try { + byte[] definitionBytes; + + if (classBytes.length == len) { + definitionBytes = classBytes; + } else { + definitionBytes = new byte[len]; + System.arraycopy(classBytes, off, definitionBytes, 0, len); + } + + return lookup.defineClass(definitionBytes); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to define class " + className, e); } - return ""; } private ClassDefiningCl wrapCl(ClassLoader origCl) { diff --git a/microprofile/config/src/main/java/module-info.java b/microprofile/config/src/main/java/module-info.java index 15ce3099d..5d59995be 100644 --- a/microprofile/config/src/main/java/module-info.java +++ b/microprofile/config/src/main/java/module-info.java @@ -31,7 +31,7 @@ module io.helidon.microprofile.config { exports io.helidon.microprofile.config; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.config to weld.core.impl; + opens io.helidon.microprofile.config to weld.core.impl, io.helidon.microprofile.cdi; provides javax.enterprise.inject.spi.Extension with io.helidon.microprofile.config.ConfigCdiExtension; } diff --git a/microprofile/fault-tolerance/src/main/java/module-info.java b/microprofile/fault-tolerance/src/main/java/module-info.java index 5cd0370e3..78facb8d3 100644 --- a/microprofile/fault-tolerance/src/main/java/module-info.java +++ b/microprofile/fault-tolerance/src/main/java/module-info.java @@ -42,7 +42,7 @@ module io.helidon.microprofile.faulttolerance { exports io.helidon.microprofile.faulttolerance; // needed when running with modules - to make private methods accessible - opens io.helidon.microprofile.faulttolerance to weld.core.impl; + opens io.helidon.microprofile.faulttolerance to weld.core.impl, io.helidon.microprofile.cdi; provides javax.enterprise.inject.spi.Extension with io.helidon.microprofile.faulttolerance.FaultToleranceExtension; } diff --git a/microprofile/health/src/main/java/module-info.java b/microprofile/health/src/main/java/module-info.java index 323e2d571..30c7076bd 100644 --- a/microprofile/health/src/main/java/module-info.java +++ b/microprofile/health/src/main/java/module-info.java @@ -38,7 +38,7 @@ module io.helidon.microprofile.health { exports io.helidon.microprofile.health; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.health to weld.core.impl; + opens io.helidon.microprofile.health to weld.core.impl, io.helidon.microprofile.cdi; uses io.helidon.microprofile.health.HealthCheckProvider; diff --git a/microprofile/jwt-auth/src/main/java/module-info.java b/microprofile/jwt-auth/src/main/java/module-info.java index 73732a840..4365a72b8 100644 --- a/microprofile/jwt-auth/src/main/java/module-info.java +++ b/microprofile/jwt-auth/src/main/java/module-info.java @@ -41,7 +41,7 @@ module io.helidon.microprofile.jwt.auth { exports io.helidon.microprofile.jwt.auth; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.jwt.auth to weld.core.impl; + opens io.helidon.microprofile.jwt.auth to weld.core.impl, io.helidon.microprofile.cdi; provides io.helidon.security.providers.common.spi.AnnotationAnalyzer with io.helidon.microprofile.jwt.auth.JwtAuthAnnotationAnalyzer; provides io.helidon.security.spi.SecurityProviderService with io.helidon.microprofile.jwt.auth.JwtAuthProviderService; diff --git a/microprofile/openapi/src/main/java/module-info.java b/microprofile/openapi/src/main/java/module-info.java index aa07c3bcc..c9181c6eb 100644 --- a/microprofile/openapi/src/main/java/module-info.java +++ b/microprofile/openapi/src/main/java/module-info.java @@ -33,7 +33,7 @@ module io.helidon.microprofile.openapi { exports io.helidon.microprofile.openapi; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.openapi to weld.core.impl; + opens io.helidon.microprofile.openapi to weld.core.impl, io.helidon.microprofile.cdi; provides Extension with OpenApiCdiExtension; } diff --git a/microprofile/security/src/main/java/module-info.java b/microprofile/security/src/main/java/module-info.java index 878860ffb..1eafa54a6 100644 --- a/microprofile/security/src/main/java/module-info.java +++ b/microprofile/security/src/main/java/module-info.java @@ -31,7 +31,7 @@ module io.helidon.microprofile.security { exports io.helidon.microprofile.security; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.security to weld.core.impl; + opens io.helidon.microprofile.security to weld.core.impl, io.helidon.microprofile.cdi; provides javax.enterprise.inject.spi.Extension with io.helidon.microprofile.security.SecurityCdiExtension; } diff --git a/microprofile/server/src/main/java/module-info.java b/microprofile/server/src/main/java/module-info.java index 5158ce58f..c04977b3a 100644 --- a/microprofile/server/src/main/java/module-info.java +++ b/microprofile/server/src/main/java/module-info.java @@ -46,5 +46,5 @@ module io.helidon.microprofile.server { io.helidon.microprofile.server.JaxRsCdiExtension; // needed when running with modules - to make private methods accessible - opens io.helidon.microprofile.server to weld.core.impl; + opens io.helidon.microprofile.server to weld.core.impl, io.helidon.microprofile.cdi; } diff --git a/microprofile/tracing/src/main/java/module-info.java b/microprofile/tracing/src/main/java/module-info.java index 45e4a048c..34fcccec7 100644 --- a/microprofile/tracing/src/main/java/module-info.java +++ b/microprofile/tracing/src/main/java/module-info.java @@ -47,7 +47,7 @@ module io.helidon.microprofile.tracing { exports io.helidon.microprofile.tracing; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.tracing to weld.core.impl,hk2.utils; + opens io.helidon.microprofile.tracing to weld.core.impl,hk2.utils, io.helidon.microprofile.cdi; provides Extension with io.helidon.microprofile.tracing.TracingCdiExtension; provides org.glassfish.jersey.internal.spi.AutoDiscoverable with io.helidon.microprofile.tracing.MpTracingAutoDiscoverable; diff --git a/microprofile/websocket/src/main/java/module-info.java b/microprofile/websocket/src/main/java/module-info.java index 3ff030326..3938e79f3 100644 --- a/microprofile/websocket/src/main/java/module-info.java +++ b/microprofile/websocket/src/main/java/module-info.java @@ -36,7 +36,7 @@ module io.helidon.microprofile.tyrus { exports io.helidon.microprofile.tyrus; // this is needed for CDI extensions that use non-public observer methods - opens io.helidon.microprofile.tyrus to weld.core.impl; + opens io.helidon.microprofile.tyrus to weld.core.impl, io.helidon.microprofile.cdi; provides javax.enterprise.inject.spi.Extension with io.helidon.microprofile.tyrus.WebSocketCdiExtension; } diff --git a/microprofile/weld/weld-core-impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java b/microprofile/weld/weld-core-impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java index f5f5e667d..827691c06 100644 --- a/microprofile/weld/weld-core-impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java +++ b/microprofile/weld/weld-core-impl/src/main/java/org/jboss/weld/bean/proxy/ProxyFactory.java @@ -79,13 +79,16 @@ import static org.jboss.weld.util.reflection.Reflections.cast; /* * This class is copied from Weld sources. - * The only modified method is createCompoundProxyName. + * Modified methods: + * - getProxyName + * - createCompoundProxyName + * * Why? * In original Weld, the name is generated with bean identifier that is based on identity hashCode - and that is OK as * long as you run in a single JVM (which is the case with hotspot). * When running in native image, we go through the process of generating proxies at build time (in GraalVM when building the * native image) and then running them from the native image. - * As these are two separate instances of JVM, we get different identity has codes, and as a result different class names + * As these are two separate instances of JVM, we get different identity hash codes, and as a result different class names * at compile time and at runtime. The Helidon change ensures these names are equal and we can reuse the generated proxy * classes. * @@ -271,8 +274,14 @@ public class ProxyFactory implements PrivilegedAction { if (typeInfo.getSuperClass() == Object.class) { final StringBuilder name = new StringBuilder(); - //interface only bean. - className = createCompoundProxyName(contextId, bean, typeInfo, name) + PROXY_SUFFIX; + + // for classes that do not have an enclosing class, we want the super interface to be first + if (proxiedBeanType.getEnclosingClass() == null) { + return createProxyName(typeInfo) + PROXY_SUFFIX; + } else { + //interface only bean. + className = createCompoundProxyName(contextId, bean, typeInfo, name) + PROXY_SUFFIX; + } } else { boolean typeModified = false; for (Class iface : typeInfo.getInterfaces()) { @@ -308,6 +317,33 @@ public class ProxyFactory implements PrivilegedAction { /* * Helidon modification + * + * This is used when there is no enclosing type and we may have multiple interfaces + * This method ensures the superinterface is the base of the name + */ + private static String createProxyName(TypeInfo typeInfo) { + Class superInterface = typeInfo.getSuperInterface(); + StringBuilder name = new StringBuilder(); + List interfaces = new ArrayList(); + for (Class type : typeInfo.getInterfaces()) { + if (!type.equals(superInterface)) { + interfaces.add(uniqueName(type)); + } + } + + Collections.sort(interfaces); + for (final String iface : interfaces) { + name.append(iface); + name.append('$'); + } + + return superInterface.getName() + '$' + name; + } + + /* + * Helidon modification + * + * Compound name is used when more than one interface needs to be proxied. */ private static String createCompoundProxyName(String contextId, Bean bean, TypeInfo typeInfo, StringBuilder name) { final List interfaces = new ArrayList(); diff --git a/security/integration/jersey/src/main/java/module-info.java b/security/integration/jersey/src/main/java/module-info.java index fcf00aeca..2b72a1c1e 100644 --- a/security/integration/jersey/src/main/java/module-info.java +++ b/security/integration/jersey/src/main/java/module-info.java @@ -39,7 +39,7 @@ module io.helidon.security.integration.jersey { exports io.helidon.security.integration.jersey; // needed for jersey injection - opens io.helidon.security.integration.jersey to hk2.locator,hk2.utils,weld.core.impl; + opens io.helidon.security.integration.jersey to hk2.locator,hk2.utils,weld.core.impl, io.helidon.microprofile.cdi; uses io.helidon.security.providers.common.spi.AnnotationAnalyzer; } diff --git a/security/security/src/main/java/module-info.java b/security/security/src/main/java/module-info.java index 900c2054b..99df07d3f 100644 --- a/security/security/src/main/java/module-info.java +++ b/security/security/src/main/java/module-info.java @@ -43,7 +43,7 @@ module io.helidon.security { exports io.helidon.security.internal to io.helidon.security.integration.jersey, io.helidon.security.integration.webserver, io.helidon.security.integration.grpc; // needed for CDI integration - opens io.helidon.security to weld.core.impl; + opens io.helidon.security to weld.core.impl, io.helidon.microprofile.cdi; uses io.helidon.security.spi.SecurityProviderService; } diff --git a/tests/apps/bookstore/common/src/main/java/module-info.java b/tests/apps/bookstore/common/src/main/java/module-info.java index 9a2a6761e..6873d9193 100644 --- a/tests/apps/bookstore/common/src/main/java/module-info.java +++ b/tests/apps/bookstore/common/src/main/java/module-info.java @@ -21,7 +21,7 @@ module io.helidon.tests.apps.bookstore.common { requires jakarta.enterprise.cdi.api; - opens io.helidon.tests.apps.bookstore.common to weld.core.impl; + opens io.helidon.tests.apps.bookstore.common to weld.core.impl, io.helidon.microprofile.cdi; exports io.helidon.tests.apps.bookstore.common; } diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java new file mode 100644 index 000000000..a5125d597 --- /dev/null +++ b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/BeanProducer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.tests.integration.nativeimage.mp1; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; + +import io.helidon.tests.integration.nativeimage.mp1.other.ProducedBean; + +@ApplicationScoped +public class BeanProducer { + public static final String VALUE = "hi there"; + + @Produces + @ApplicationScoped + public ProducedBean produceBean() { + return new ProducedBean(VALUE); + } +} diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java index 5671c175f..50bcc65a0 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java +++ b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/Mp1Main.java @@ -177,6 +177,9 @@ public final class Mp1Main { // CDI - (tested indirectly by other tests) // Server - capability to start JAX-RS (tested indirectly by other tests) + // produce a bean with package local method + invoke(collector, "Produced bean", BeanProducer.VALUE, aBean::produced); + // Configuration invoke(collector, "Config injection", "Properties message", aBean::config); diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java index f9714b871..72dc7ddba 100644 --- a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java +++ b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/TestBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020 Oracle and/or its affiliates. */ package io.helidon.tests.integration.nativeimage.mp1; @@ -14,6 +14,8 @@ import javax.enterprise.inject.spi.BeanManager; import javax.inject.Inject; import io.helidon.microprofile.server.ServerCdiExtension; +import io.helidon.tests.integration.nativeimage.mp1.other.BeanProcessor; +import io.helidon.tests.integration.nativeimage.mp1.other.ProducedBean; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.faulttolerance.Asynchronous; @@ -40,6 +42,9 @@ public class TestBean { @Inject private BeanManager beanManager; + @Inject + private ProducedBean producedBean; + private final AtomicInteger retries = new AtomicInteger(); @Timed @@ -109,4 +114,8 @@ public class TestBean { public CompletionStage asynchronous() { return CompletableFuture.completedFuture("Async response"); } + + public String produced() { + return BeanProcessor.getProducedName(producedBean); + } } diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java new file mode 100644 index 000000000..04438ca07 --- /dev/null +++ b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/BeanProcessor.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.tests.integration.nativeimage.mp1.other; + +public final class BeanProcessor { + + public static String getProducedName(ProducedBean bean) { + Class sampleClass = ProducedBean.class; + Class proxyClass = bean.getClass(); + + Package samplePackage = sampleClass.getPackage(); + Package proxyPackage = proxyClass.getPackage(); + + System.out.println(samplePackage); + System.out.println(proxyPackage); + System.out.println("Equals: " + samplePackage.equals(proxyPackage)); + + String name = bean.getName(); + return name; + } + +} diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java new file mode 100644 index 000000000..710c60ce8 --- /dev/null +++ b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/ProducedBean.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.tests.integration.nativeimage.mp1.other; + +import java.util.Objects; + +/** + * A bean produced by a producer in a different package. + */ +public class ProducedBean { + + private final String name; + + /** + * Constructor to create a new instance outside of CDI. + * + * @param name name to use + */ + public ProducedBean(final String name) { + this.name = Objects.requireNonNull(name); + } + + // Add public to make it work + String getName() { + return name; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ProducedBean myClass = (ProducedBean) o; + return Objects.equals(name, myClass.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java new file mode 100644 index 000000000..e2c09cfbd --- /dev/null +++ b/tests/integration/native-image/mp-1/src/main/java/io/helidon/tests/integration/nativeimage/mp1/other/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This package exists to make sure we can do proxies that have working + * package local + */ +package io.helidon.tests.integration.nativeimage.mp1.other; \ No newline at end of file diff --git a/tests/integration/native-image/mp-1/src/main/java/module-info.java b/tests/integration/native-image/mp-1/src/main/java/module-info.java index c554275ec..292c029f1 100644 --- a/tests/integration/native-image/mp-1/src/main/java/module-info.java +++ b/tests/integration/native-image/mp-1/src/main/java/module-info.java @@ -37,9 +37,11 @@ module helidon.tests.nimage.mp { requires io.helidon.health.checks; exports io.helidon.tests.integration.nativeimage.mp1; + exports io.helidon.tests.integration.nativeimage.mp1.other; // opens is needed to inject private fields, create classes in the same package (proxy) opens io.helidon.tests.integration.nativeimage.mp1 to weld.core.impl, hk2.utils, io.helidon.microprofile.cdi; + opens io.helidon.tests.integration.nativeimage.mp1.other to weld.core.impl, io.helidon.microprofile.cdi; // we need to open the static resource on classpath directory to everybody, as otherwise // static content will not see it