From 4c4fca6917e3e28a21fc37412af2fe629337a50c Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Fri, 5 Nov 2021 16:32:49 +0100 Subject: [PATCH] ArC - fix regression with repeatable interceptor bindings - register all interceptor bindings for reflection so that javax.enterprise.util.AnnotationLiteral.equals(Object) works in a native image - do not use java.util.Set#of(Object...) directly because it throws an IAE if there are duplicate elements - resolves #21174 --- .../quarkus/arc/deployment/ArcProcessor.java | 6 +++ .../arc/processor/AbstractGenerator.java | 8 +++- .../processor/AnnotationLiteralGenerator.java | 6 +-- .../quarkus/arc/processor/BeanGenerator.java | 43 ++++++++----------- .../arc/processor/ClientProxyGenerator.java | 4 +- .../arc/processor/DecoratorGenerator.java | 5 +-- .../arc/processor/InterceptorGenerator.java | 2 +- .../arc/processor/MethodDescriptors.java | 3 +- .../arc/processor/ObserverGenerator.java | 6 +-- .../arc/processor/SubclassGenerator.java | 8 ++-- .../main/java/io/quarkus/arc/impl/Sets.java | 33 ++++++++++++++ .../io/quarkus/it/arc/interceptor/Simple.java | 33 ++++++++++++++ .../it/arc/interceptor/SimpleBean.java | 14 ++++++ .../it/arc/interceptor/SimpleInterceptor.java | 17 ++++++++ .../interceptor/TestSimpleBeanEndpoint.java | 19 ++++++++ .../io/quarkus/it/main/SimpleBeanITCase.java | 8 ++++ .../quarkus/it/main/SimpleBeanTestCase.java | 19 ++++++++ 17 files changed, 186 insertions(+), 48 deletions(-) create mode 100644 independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Sets.java create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/Simple.java create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleBean.java create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleInterceptor.java create mode 100644 integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/TestSimpleBeanEndpoint.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanITCase.java create mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanTestCase.java diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java index 81675ec3e0b48..b0a77e6b6cb8b 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java @@ -469,6 +469,7 @@ public void registerMethod(MethodInfo methodInfo) { public void registerField(FieldInfo fieldInfo) { reflectiveFields.produce(new ReflectiveFieldBuildItem(fieldInfo)); } + }, existingClasses.existingClasses, bytecodeTransformerConsumer, config.shouldEnableBeanRemoval() && config.detectUnusedFalsePositives); for (ResourceOutput.Resource resource : resources) { @@ -497,6 +498,11 @@ public void registerField(FieldInfo fieldInfo) { reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, qualifier.name().toString())); } + // Register all interceptor bindings for reflection so that AnnotationLiteral.equals() works in a native image + for (ClassInfo binding : beanProcessor.getBeanDeployment().getInterceptorBindings()) { + reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, binding.name().toString())); + } + ArcContainer container = recorder.getContainer(shutdown); BeanContainer beanContainer = recorder.initBeanContainer(container, beanContainerListenerBuildItems.stream().map(BeanContainerListenerBuildItem::getBeanContainerListener) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AbstractGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AbstractGenerator.java index d4c828174829f..3d7126208a1bf 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AbstractGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AbstractGenerator.java @@ -14,9 +14,15 @@ abstract class AbstractGenerator { static final String SYNTHETIC_SUFFIX = "Synthetic"; protected final boolean generateSources; + protected final ReflectionRegistration reflectionRegistration; - public AbstractGenerator(boolean generateSources) { + public AbstractGenerator(boolean generateSources, ReflectionRegistration reflectionRegistration) { this.generateSources = generateSources; + this.reflectionRegistration = reflectionRegistration; + } + + public AbstractGenerator(boolean generateSources) { + this(generateSources, null); } /** diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java index 17fd59d90605b..94e5e2d0e5327 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralGenerator.java @@ -48,11 +48,8 @@ public class AnnotationLiteralGenerator extends AbstractGenerator { private static final Logger LOGGER = Logger.getLogger(AnnotationLiteralGenerator.class); - private final boolean generateSources; - AnnotationLiteralGenerator(boolean generateSources) { super(generateSources); - this.generateSources = generateSources; } /** @@ -72,7 +69,7 @@ Collection generate(String name, BeanDeployment beanDeployment, return resources; } - static void createSharedAnnotationLiteral(ClassOutput classOutput, Key key, Literal literal, Set existingClasses) { + void createSharedAnnotationLiteral(ClassOutput classOutput, Key key, Literal literal, Set existingClasses) { // Ljavax/enterprise/util/AnnotationLiteral;Lcom/foo/MyQualifier; String signature = String.format("Ljavax/enterprise/util/AnnotationLiteral;L%1$s;", key.annotationName.toString().replace('.', '/')); @@ -113,6 +110,7 @@ static void createSharedAnnotationLiteral(ClassOutput classOutput, Key key, Lite generateStaticFieldsWithDefaultValues(annotationLiteral, defaultOfClassType); annotationLiteral.close(); + LOGGER.debugf("Shared annotation literal generated: %s", literal.className); } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java index f287c5b7a76bc..808e54fe682d2 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanGenerator.java @@ -86,7 +86,6 @@ public class BeanGenerator extends AbstractGenerator { protected final AnnotationLiteralProcessor annotationLiterals; protected final Predicate applicationClassPredicate; protected final PrivateMembersCollector privateMembers; - protected final ReflectionRegistration reflectionRegistration; protected final Set existingClasses; protected final Map beanToGeneratedName; protected final Predicate injectionPointAnnotationsPredicate; @@ -97,11 +96,10 @@ public BeanGenerator(AnnotationLiteralProcessor annotationLiterals, Predicate existingClasses, Map beanToGeneratedName, Predicate injectionPointAnnotationsPredicate, List>> suppressConditionGenerators) { - super(generateSources); + super(generateSources, reflectionRegistration); this.annotationLiterals = annotationLiterals; this.applicationClassPredicate = applicationClassPredicate; this.privateMembers = privateMembers; - this.reflectionRegistration = reflectionRegistration; this.existingClasses = existingClasses; this.beanToGeneratedName = beanToGeneratedName; this.injectionPointAnnotationsPredicate = injectionPointAnnotationsPredicate; @@ -222,13 +220,11 @@ Collection generateSyntheticBean(BeanInfo bean) { implementGetIdentifier(bean, beanCreator); implementSupplierGet(beanCreator); if (!bean.hasDefaultDestroy()) { - implementDestroy(bean, beanCreator, providerType, Collections.emptyMap(), reflectionRegistration, - isApplicationClass, baseName); + implementDestroy(bean, beanCreator, providerType, Collections.emptyMap(), isApplicationClass, baseName); } implementCreate(classOutput, beanCreator, bean, providerType, baseName, Collections.emptyMap(), Collections.emptyMap(), - Collections.emptyMap(), reflectionRegistration, - targetPackage, isApplicationClass); + Collections.emptyMap(), targetPackage, isApplicationClass); implementGet(bean, beanCreator, providerType, baseName); implementGetTypes(beanCreator, beanTypes.getFieldDescriptor()); @@ -312,15 +308,14 @@ Collection generateClassBean(BeanInfo bean, ClassInfo beanClass) { implementGetIdentifier(bean, beanCreator); implementSupplierGet(beanCreator); if (!bean.hasDefaultDestroy()) { - implementDestroy(bean, beanCreator, providerType, injectionPointToProviderSupplierField, - reflectionRegistration, - isApplicationClass, baseName); + implementDestroy(bean, beanCreator, providerType, injectionPointToProviderSupplierField, isApplicationClass, + baseName); } implementCreate(classOutput, beanCreator, bean, providerType, baseName, injectionPointToProviderSupplierField, interceptorToProviderSupplierField, decoratorToProviderSupplierField, - reflectionRegistration, targetPackage, isApplicationClass); + targetPackage, isApplicationClass); implementGet(bean, beanCreator, providerType, baseName); implementGetTypes(beanCreator, beanTypes.getFieldDescriptor()); @@ -416,13 +411,12 @@ Collection generateProducerMethodBean(BeanInfo bean, MethodInfo produc implementGetIdentifier(bean, beanCreator); implementSupplierGet(beanCreator); if (!bean.hasDefaultDestroy()) { - implementDestroy(bean, beanCreator, providerType, injectionPointToProviderField, reflectionRegistration, - isApplicationClass, baseName); + implementDestroy(bean, beanCreator, providerType, injectionPointToProviderField, isApplicationClass, baseName); } implementCreate(classOutput, beanCreator, bean, providerType, baseName, injectionPointToProviderField, Collections.emptyMap(), Collections.emptyMap(), - reflectionRegistration, targetPackage, isApplicationClass); + targetPackage, isApplicationClass); implementGet(bean, beanCreator, providerType, baseName); implementGetTypes(beanCreator, beanTypes.getFieldDescriptor()); @@ -505,13 +499,11 @@ Collection generateProducerFieldBean(BeanInfo bean, FieldInfo producer implementGetIdentifier(bean, beanCreator); implementSupplierGet(beanCreator); if (!bean.hasDefaultDestroy()) { - implementDestroy(bean, beanCreator, providerType, null, reflectionRegistration, isApplicationClass, - baseName); + implementDestroy(bean, beanCreator, providerType, null, isApplicationClass, baseName); } implementCreate(classOutput, beanCreator, bean, providerType, baseName, Collections.emptyMap(), Collections.emptyMap(), - Collections.emptyMap(), reflectionRegistration, - targetPackage, isApplicationClass); + Collections.emptyMap(), targetPackage, isApplicationClass); implementGet(bean, beanCreator, providerType, baseName); implementGetTypes(beanCreator, beanTypes.getFieldDescriptor()); @@ -727,7 +719,7 @@ protected MethodCreator initConstructor(ClassOutput classOutput, ClassCreator be constructor.writeInstanceField( FieldDescriptor.of(beanCreator.getClassName(), FIELD_NAME_BEAN_TYPES, Set.class.getName()), constructor.getThis(), - constructor.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, + constructor.invokeStaticMethod(MethodDescriptors.SETS_OF, typesArray)); // Qualifiers @@ -750,7 +742,7 @@ protected MethodCreator initConstructor(ClassOutput classOutput, ClassCreator be constructor.writeInstanceField( FieldDescriptor.of(beanCreator.getClassName(), FIELD_NAME_QUALIFIERS, Set.class.getName()), constructor.getThis(), - constructor.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, + constructor.invokeStaticMethod(MethodDescriptors.SETS_OF, qualifiersArray)); } @@ -765,15 +757,14 @@ protected MethodCreator initConstructor(ClassOutput classOutput, ClassCreator be constructor.writeInstanceField( FieldDescriptor.of(beanCreator.getClassName(), FIELD_NAME_STEREOTYPES, Set.class.getName()), constructor.getThis(), - constructor.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, + constructor.invokeStaticMethod(MethodDescriptors.SETS_OF, stereotypesArray)); } return constructor; } protected void implementDestroy(BeanInfo bean, ClassCreator beanCreator, ProviderType providerType, - Map injectionPointToProviderField, ReflectionRegistration reflectionRegistration, - boolean isApplicationClass, String baseName) { + Map injectionPointToProviderField, boolean isApplicationClass, String baseName) { MethodCreator destroy = beanCreator .getMethodCreator("destroy", void.class, providerType.descriptorName(), CreationalContext.class) @@ -908,7 +899,7 @@ protected void implementCreate(ClassOutput classOutput, ClassCreator beanCreator Map injectionPointToProviderSupplierField, Map interceptorToProviderSupplierField, Map decoratorToProviderSupplierField, - ReflectionRegistration reflectionRegistration, String targetPackage, boolean isApplicationClass) { + String targetPackage, boolean isApplicationClass) { MethodCreator create = beanCreator.getMethodCreator("create", providerType.descriptorName(), CreationalContext.class) .setModifiers(ACC_PUBLIC); @@ -1410,7 +1401,7 @@ void implementCreateForClassBean(ClassOutput classOutput, ClassCreator beanCreat ResultHandle invocationContextHandle = create.invokeStaticMethod( MethodDescriptors.INVOCATION_CONTEXTS_AROUND_CONSTRUCT, constructorHandle, aroundConstructsHandle, func.getInstance(), - create.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, bindingsArray)); + create.invokeStaticMethod(MethodDescriptors.SETS_OF, bindingsArray)); TryBlock tryCatch = create.tryBlock(); CatchBlockCreator exceptionCatch = tryCatch.addCatch(Exception.class); // throw new RuntimeException(e) @@ -1542,7 +1533,7 @@ void implementCreateForClassBean(ClassOutput classOutput, ClassCreator beanCreat // InvocationContextImpl.postConstruct(instance,postConstructs).proceed() ResultHandle invocationContextHandle = create.invokeStaticMethod( MethodDescriptors.INVOCATION_CONTEXTS_POST_CONSTRUCT, instanceHandle, - postConstructsHandle, create.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, bindingsArray)); + postConstructsHandle, create.invokeStaticMethod(MethodDescriptors.SETS_OF, bindingsArray)); TryBlock tryCatch = create.tryBlock(); CatchBlockCreator exceptionCatch = tryCatch.addCatch(Exception.class); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java index 7eb5be95ff0ce..6c3579973921a 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ClientProxyGenerator.java @@ -57,15 +57,13 @@ public class ClientProxyGenerator extends AbstractGenerator { private final Predicate applicationClassPredicate; private final boolean mockable; - private final ReflectionRegistration reflectionRegistration; private final Set existingClasses; public ClientProxyGenerator(Predicate applicationClassPredicate, boolean generateSources, boolean mockable, ReflectionRegistration reflectionRegistration, Set existingClasses) { - super(generateSources); + super(generateSources, reflectionRegistration); this.applicationClassPredicate = applicationClassPredicate; this.mockable = mockable; - this.reflectionRegistration = reflectionRegistration; this.existingClasses = existingClasses; } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/DecoratorGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/DecoratorGenerator.java index f09fe856d0a26..57ac3de61bc4b 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/DecoratorGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/DecoratorGenerator.java @@ -106,9 +106,8 @@ Collection generate(DecoratorInfo decorator) { implementGetIdentifier(decorator, decoratorCreator); implementSupplierGet(decoratorCreator); implementCreate(classOutput, decoratorCreator, decorator, providerType, baseName, - injectionPointToProviderField, - Collections.emptyMap(), Collections.emptyMap(), - reflectionRegistration, targetPackage, isApplicationClass); + injectionPointToProviderField, Collections.emptyMap(), Collections.emptyMap(), + targetPackage, isApplicationClass); implementGet(decorator, decoratorCreator, providerType, baseName); implementGetTypes(decoratorCreator, beanTypes.getFieldDescriptor()); implementGetBeanClass(decorator, decoratorCreator); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorGenerator.java index 9847643e41c6f..ea624b9a01d01 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorGenerator.java @@ -101,7 +101,7 @@ Collection generate(InterceptorInfo interceptor) { implementCreate(classOutput, interceptorCreator, interceptor, providerType, baseName, injectionPointToProviderField, Collections.emptyMap(), Collections.emptyMap(), - reflectionRegistration, targetPackage, isApplicationClass); + targetPackage, isApplicationClass); implementGet(interceptor, interceptorCreator, providerType, baseName); implementGetTypes(interceptorCreator, beanTypes.getFieldDescriptor()); implementGetBeanClass(interceptor, interceptorCreator); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java index 01a932fbb31e4..56ba2b55cc1e0 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java @@ -20,6 +20,7 @@ import io.quarkus.arc.impl.Objects; import io.quarkus.arc.impl.Reflections; import io.quarkus.arc.impl.RemovedBeanImpl; +import io.quarkus.arc.impl.Sets; import io.quarkus.gizmo.MethodDescriptor; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -223,7 +224,7 @@ public final class MethodDescriptors { public static final MethodDescriptor COLLECTIONS_EMPTY_MAP = MethodDescriptor.ofMethod(Collections.class, "emptyMap", Map.class); - public static final MethodDescriptor SET_OF = MethodDescriptor.ofMethod(Set.class, "of", Set.class, Object[].class); + public static final MethodDescriptor SETS_OF = MethodDescriptor.ofMethod(Sets.class, "of", Set.class, Object[].class); public static final MethodDescriptor ARC_CONTAINER = MethodDescriptor.ofMethod(Arc.class, "container", ArcContainer.class); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java index 3f31a6fcf1759..076ce3a404142 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java @@ -64,7 +64,6 @@ public class ObserverGenerator extends AbstractGenerator { private final AnnotationLiteralProcessor annotationLiterals; private final Predicate applicationClassPredicate; private final PrivateMembersCollector privateMembers; - private final ReflectionRegistration reflectionRegistration; private final Set existingClasses; private final Map observerToGeneratedName; private final Predicate injectionPointAnnotationsPredicate; @@ -74,11 +73,10 @@ public ObserverGenerator(AnnotationLiteralProcessor annotationLiterals, Predicat PrivateMembersCollector privateMembers, boolean generateSources, ReflectionRegistration reflectionRegistration, Set existingClasses, Map observerToGeneratedName, Predicate injectionPointAnnotationsPredicate, boolean mockable) { - super(generateSources); + super(generateSources, reflectionRegistration); this.annotationLiterals = annotationLiterals; this.applicationClassPredicate = applicationClassPredicate; this.privateMembers = privateMembers; - this.reflectionRegistration = reflectionRegistration; this.existingClasses = existingClasses; this.observerToGeneratedName = observerToGeneratedName; this.injectionPointAnnotationsPredicate = injectionPointAnnotationsPredicate; @@ -567,7 +565,7 @@ protected void createConstructor(ClassOutput classOutput, ClassCreator observerC constructor.writeInstanceField( FieldDescriptor.of(observerCreator.getClassName(), "qualifiers", Set.class.getName()), constructor.getThis(), - constructor.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, + constructor.invokeStaticMethod(MethodDescriptors.SETS_OF, qualifiersArray)); } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java index c67091df75ad1..6660fa113fba7 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/SubclassGenerator.java @@ -77,7 +77,6 @@ public class SubclassGenerator extends AbstractGenerator { "bindings", Set.class); private final Predicate applicationClassPredicate; - private final ReflectionRegistration reflectionRegistration; private final Set existingClasses; static String generatedName(DotName providerTypeName, String baseName) { @@ -90,10 +89,9 @@ static String generatedName(DotName providerTypeName, String baseName) { public SubclassGenerator(AnnotationLiteralProcessor annotationLiterals, Predicate applicationClassPredicate, boolean generateSources, ReflectionRegistration reflectionRegistration, Set existingClasses) { - super(generateSources); + super(generateSources, reflectionRegistration); this.applicationClassPredicate = applicationClassPredicate; this.annotationLiterals = annotationLiterals; - this.reflectionRegistration = reflectionRegistration; this.existingClasses = existingClasses; } @@ -259,7 +257,7 @@ public ResultHandle apply(List keys) { constructor.writeArrayValue(bindingsArray, bindingsIndex++, bindingsLiterals.computeIfAbsent(binding, bindingsLiteralFun)); } - return constructor.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, bindingsArray); + return constructor.invokeStaticMethod(MethodDescriptors.SETS_OF, bindingsArray); } } }; @@ -817,7 +815,7 @@ protected void createDestroy(ClassOutput classOutput, BeanInfo bean, ClassCreato // InvocationContextImpl.preDestroy(this,predestroys) ResultHandle invocationContext = tryCatch.invokeStaticMethod(MethodDescriptors.INVOCATION_CONTEXTS_PRE_DESTROY, tryCatch.getThis(), predestroysHandle, - tryCatch.invokeStaticInterfaceMethod(MethodDescriptors.SET_OF, bindingsArray)); + tryCatch.invokeStaticMethod(MethodDescriptors.SETS_OF, bindingsArray)); // InvocationContext.proceed() tryCatch.invokeInterfaceMethod(MethodDescriptors.INVOCATION_CONTEXT_PROCEED, invocationContext); diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Sets.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Sets.java new file mode 100644 index 0000000000000..15d9d4cdeffad --- /dev/null +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Sets.java @@ -0,0 +1,33 @@ +package io.quarkus.arc.impl; + +import java.util.Arrays; +import java.util.Set; + +public final class Sets { + + private Sets() { + } + + /** + * Unlike {@link Set#of(Object...)} this method does not throw an {@link IllegalArgumentException} if there are duplicate + * elements. + * + * @param + * @param elements + * @return the set + */ + @SafeVarargs + public static Set of(E... elements) { + switch (elements.length) { + case 0: + return Set.of(); + case 1: + return Set.of(elements[0]); + case 2: + return elements[0].equals(elements[1]) ? Set.of(elements[0]) : Set.of(elements[0], elements[1]); + default: + return Set.copyOf(Arrays.asList(elements)); + } + } + +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/Simple.java b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/Simple.java new file mode 100644 index 0000000000000..dcf3722c6173a --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/Simple.java @@ -0,0 +1,33 @@ +package io.quarkus.it.arc.interceptor; + +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.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.enterprise.util.Nonbinding; +import javax.interceptor.InterceptorBinding; + +@Repeatable(Simple.List.class) +@Target({ TYPE, METHOD }) +@Retention(RUNTIME) +@InterceptorBinding +public @interface Simple { + + @Nonbinding + String name(); + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @interface List { + + Simple[] value(); + + } + +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleBean.java b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleBean.java new file mode 100644 index 0000000000000..99312bdf61075 --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleBean.java @@ -0,0 +1,14 @@ +package io.quarkus.it.arc.interceptor; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class SimpleBean { + + @Simple(name = "foo") + @Simple(name = "bar") + public String ping() { + return "OK"; + } + +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleInterceptor.java b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleInterceptor.java new file mode 100644 index 0000000000000..ab254d6292dba --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/SimpleInterceptor.java @@ -0,0 +1,17 @@ +package io.quarkus.it.arc.interceptor; + +import javax.annotation.Priority; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; + +@Simple(name = "") +@Priority(1) +@Interceptor +public class SimpleInterceptor { + + @AroundInvoke + Object mySuperCoolAroundInvoke(InvocationContext ctx) throws Exception { + return ctx.proceed(); + } +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/TestSimpleBeanEndpoint.java b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/TestSimpleBeanEndpoint.java new file mode 100644 index 0000000000000..455fac19c197a --- /dev/null +++ b/integration-tests/main/src/main/java/io/quarkus/it/arc/interceptor/TestSimpleBeanEndpoint.java @@ -0,0 +1,19 @@ +package io.quarkus.it.arc.interceptor; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +@Path("/simple-bean") +public class TestSimpleBeanEndpoint { + + @Inject + SimpleBean simpleBean; + + @GET + public String manualValidation() { + return simpleBean.ping(); + + } + +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanITCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanITCase.java new file mode 100644 index 0000000000000..6189a98d1c314 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanITCase.java @@ -0,0 +1,8 @@ +package io.quarkus.it.main; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class SimpleBeanITCase extends SimpleBeanTestCase { + +} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanTestCase.java new file mode 100644 index 0000000000000..6b8f9b0561586 --- /dev/null +++ b/integration-tests/main/src/test/java/io/quarkus/it/main/SimpleBeanTestCase.java @@ -0,0 +1,19 @@ +package io.quarkus.it.main; + +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +@QuarkusTest +public class SimpleBeanTestCase { + + @Test + public void testRequestScope() { + RestAssured.when().get("/simple-bean").then() + .body(is("OK")); + } + +}