Skip to content

Commit

Permalink
ArC - support interception of static methods with repeatable bindings
Browse files Browse the repository at this point in the history
- related to #32786
  • Loading branch information
mkouba committed Apr 20, 2023
1 parent 48002fc commit 1f27002
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package io.quarkus.arc.deployment;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;

Expand All @@ -17,13 +19,14 @@
public final class InterceptorResolverBuildItem extends SimpleBuildItem {

private final InterceptorResolver resolver;

private final Set<DotName> interceptorBindings;
private final BeanDeployment beanDeployment;

InterceptorResolverBuildItem(BeanDeployment beanDeployment) {
this.resolver = beanDeployment.getInterceptorResolver();
this.interceptorBindings = Collections.unmodifiableSet(
beanDeployment.getInterceptorBindings().stream().map(ClassInfo::name).collect(Collectors.toSet()));
beanDeployment.getInterceptorBindings().stream().map(ClassInfo::name).collect(Collectors.toUnmodifiableSet()));
this.beanDeployment = beanDeployment;
}

public InterceptorResolver get() {
Expand All @@ -38,4 +41,14 @@ public Set<DotName> getInterceptorBindings() {
return interceptorBindings;
}

/**
*
* @param annotation
* @return the collection of interceptor bindings
* @see BeanDeployment#extractInterceptorBindings(AnnotationInstance)
*/
public Collection<AnnotationInstance> extractInterceptorBindings(AnnotationInstance annotation) {
return beanDeployment.extractInterceptorBindings(annotation);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ void collectInterceptedStaticMethods(BeanArchiveIndexBuildItem beanArchiveIndex,
BuildProducer<InterceptedStaticMethodBuildItem> interceptedStaticMethods,
InterceptorResolverBuildItem interceptorResolver, TransformedAnnotationsBuildItem transformedAnnotations,
BuildProducer<UnremovableBeanBuildItem> unremovableBeans) {

// In this step we collect all intercepted static methods, i.e. static methods annotated with interceptor bindings
Set<DotName> interceptorBindings = interceptorResolver.getInterceptorBindings();

for (ClassInfo clazz : beanArchiveIndex.getIndex().getKnownClasses()) {
for (MethodInfo method : clazz.methods()) {
Expand All @@ -107,12 +105,15 @@ void collectInterceptedStaticMethods(BeanArchiveIndexBuildItem beanArchiveIndex,
// Only method-level bindings are considered due to backwards compatibility
Set<AnnotationInstance> methodLevelBindings = null;
for (AnnotationInstance annotationInstance : annotations) {
if (annotationInstance.target().kind() == Kind.METHOD
&& interceptorBindings.contains(annotationInstance.name())) {
if (methodLevelBindings == null) {
methodLevelBindings = new HashSet<>();
if (annotationInstance.target().kind() == Kind.METHOD) {
Collection<AnnotationInstance> bindings = interceptorResolver
.extractInterceptorBindings(annotationInstance);
if (!bindings.isEmpty()) {
if (methodLevelBindings == null) {
methodLevelBindings = new HashSet<>();
}
methodLevelBindings.addAll(bindings);
}
methodLevelBindings.add(annotationInstance);
}
}
if (methodLevelBindings == null || methodLevelBindings.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.quarkus.arc.test.interceptor.staticmethods;

import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import jakarta.annotation.Priority;
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.test.QuarkusUnitTest;

public class RepeatingBindingStaticMethodTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot(root -> root
.addClasses(InterceptMe.class, SimpleBean.class, InterceptMeAlpha.class, InterceptMeBravo.class));

@Test
public void testInterceptor() {
assertEquals("a/b/PONG/b/a", SimpleBean.ping("pong"));
}

public static class SimpleBean {

@InterceptMe("alpha")
@InterceptMe("bravo")
public static String ping(String val) {
return val.toUpperCase();
}
}

@Priority(1)
@Interceptor
@InterceptMe("alpha")
static class InterceptMeAlpha {

@AroundInvoke
Object aroundInvoke(InvocationContext ctx) throws Exception {
return "a/" + ctx.proceed() + "/a";
}

}

@Priority(2)
@Interceptor
@InterceptMe("bravo")
static class InterceptMeBravo {

@AroundInvoke
Object aroundInvoke(InvocationContext ctx) throws Exception {
return "b/" + ctx.proceed() + "/b";
}

}

@Repeatable(InterceptMe.List.class)
@InterceptorBinding
@Target({ TYPE, METHOD, CONSTRUCTOR })
@Retention(RUNTIME)
@interface InterceptMe {

String value();

@Target({ TYPE, METHOD, CONSTRUCTOR })
@Retention(RUNTIME)
@interface List {
InterceptMe[] value();
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@ Map<DotName, Set<String>> getQualifierNonbindingMembers() {
return qualifierNonbindingMembers;
}

/**
*
* @return the collection of interceptor bindings; the container annotations of repeating interceptor binding are not
* included
* @see #extractInterceptorBindings(AnnotationInstance)
*/
public Collection<ClassInfo> getInterceptorBindings() {
return Collections.unmodifiableCollection(interceptorBindings.values());
}
Expand Down Expand Up @@ -614,7 +620,7 @@ Collection<AnnotationInstance> extractQualifiers(AnnotationInstance annotation)
* @param annotation annotation to be inspected
* @return a collection of interceptor bindings or an empty collection
*/
Collection<AnnotationInstance> extractInterceptorBindings(AnnotationInstance annotation) {
public Collection<AnnotationInstance> extractInterceptorBindings(AnnotationInstance annotation) {
return extractAnnotations(annotation, interceptorBindings, repeatingInterceptorBindingAnnotations);
}

Expand Down

0 comments on commit 1f27002

Please sign in to comment.