From b53f45d30b21d9b227254b62de079c0b49348cab Mon Sep 17 00:00:00 2001 From: Ladislav Thon Date: Fri, 19 May 2023 14:15:33 +0200 Subject: [PATCH] ArC: fix inheriting method-level interceptor binding annotations Method-level annotations are never inherited. This means that the lowest override of a method determines whether method-level interceptor binding annotations are present. ArC used to behave differently. If a method on a class had no interceptor binding annotations but overrode a method from a superclass that _did_ have interceptor binding annotations, the method-level annotations from the superclass were inherited. This commit fixes that. --- .../io/quarkus/arc/processor/Methods.java | 14 ++-- .../src/test/resources/testng.xml | 10 --- ...evelInterceptorBindingInheritanceTest.java | 72 +++++++++++++++++++ 3 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/inheritance/method/MethodLevelInterceptorBindingInheritanceTest.java diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java index c6c3c7e4df94a..5f57163fe681e 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Methods.java @@ -183,18 +183,20 @@ private static Set addInterceptedMethodCandidates(BeanDeployment bea skipPredicate.startProcessing(classInfo, originalClassInfo); for (MethodInfo method : classInfo.methods()) { + MethodKey key = new MethodKey(method); + if (candidates.containsKey(key)) { + continue; + } + // Note that we must merge the bindings first Set bindings = mergeBindings(beanDeployment, originalClassInfo, classLevelBindings, ignoreMethodLevelBindings, method, noClassInterceptorsMethods); - if (bindings.isEmpty() && !targetHasAroundInvokes) { - // No bindings found and target class does not declare around invoke interceptor methods - continue; - } + boolean possiblyIntercepted = !bindings.isEmpty() || targetHasAroundInvokes; if (skipPredicate.test(method)) { continue; } boolean addToCandidates = true; - if (Modifier.isFinal(method.flags())) { + if (Modifier.isFinal(method.flags()) && possiblyIntercepted) { if (transformUnproxyableClasses && !isNoninterceptableKotlinMethod(method)) { methodsFromWhichToRemoveFinal.add(NameAndDescriptor.fromMethodInfo(method)); } else { @@ -203,7 +205,7 @@ private static Set addInterceptedMethodCandidates(BeanDeployment bea } } if (addToCandidates) { - candidates.computeIfAbsent(new Methods.MethodKey(method), key -> bindings); + candidates.putIfAbsent(key, bindings); } } skipPredicate.methodsProcessed(); diff --git a/independent-projects/arc/tcks/cdi-tck-runner/src/test/resources/testng.xml b/independent-projects/arc/tcks/cdi-tck-runner/src/test/resources/testng.xml index 08f5a9f8f05d1..bd5e206ab1c72 100644 --- a/independent-projects/arc/tcks/cdi-tck-runner/src/test/resources/testng.xml +++ b/independent-projects/arc/tcks/cdi-tck-runner/src/test/resources/testng.xml @@ -52,16 +52,6 @@ - - - - - - - - - - diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/inheritance/method/MethodLevelInterceptorBindingInheritanceTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/inheritance/method/MethodLevelInterceptorBindingInheritanceTest.java new file mode 100644 index 0000000000000..20ddc480263ca --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/inheritance/method/MethodLevelInterceptorBindingInheritanceTest.java @@ -0,0 +1,72 @@ +package io.quarkus.arc.test.interceptors.inheritance.method; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import jakarta.annotation.Priority; +import jakarta.enterprise.context.Dependent; +import jakarta.interceptor.AroundInvoke; +import jakarta.interceptor.Interceptor; +import jakarta.interceptor.InterceptorBinding; +import jakarta.interceptor.InvocationContext; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.test.ArcTestContainer; + +public class MethodLevelInterceptorBindingInheritanceTest { + @RegisterExtension + ArcTestContainer container = new ArcTestContainer(MyBean.class, MyInterceptorBinding.class, MyInterceptor.class); + + @Test + public void test() { + MyBean bean = Arc.container().instance(MyBean.class).get(); + assertEquals("foobar", bean.foobar()); + assertEquals("intercepted: foobar", bean.foobarNotInherited()); + } + + static class MySuperclass { + @MyInterceptorBinding + String foobar() { + return "this should be ignored"; + } + + @MyInterceptorBinding + String foobarNotInherited() { + return "foobar"; + } + } + + @Dependent + static class MyBean extends MySuperclass { + @Override + String foobar() { + return "foobar"; + } + } + + @Target({ ElementType.TYPE, ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @InterceptorBinding + @interface MyInterceptorBinding { + } + + @MyInterceptorBinding + @Priority(1) + @Interceptor + static class MyInterceptor { + @AroundInvoke + public Object intercept(InvocationContext ctx) throws Exception { + return "intercepted: " + ctx.proceed(); + } + } + +}