diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java index c42aa1a1bb37a4..b883665f25ed11 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java @@ -24,6 +24,7 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.function.Consumer; @@ -78,6 +79,7 @@ public class BeanDeployment { private final List observers; final BeanResolverImpl beanResolver; + private final ConcurrentMap> nameToAssignables; private final InterceptorResolver interceptorResolver; @@ -180,6 +182,7 @@ public class BeanDeployment { this.beans = new CopyOnWriteArrayList<>(); this.observers = new CopyOnWriteArrayList<>(); + this.nameToAssignables = new ConcurrentHashMap<>(); this.beanResolver = new BeanResolverImpl(this); this.interceptorResolver = new InterceptorResolver(this); this.transformUnproxyableClasses = builder.transformUnproxyableClasses; @@ -1164,6 +1167,38 @@ public Set getQualifierNonbindingMembers(DotName name) { return qualifierNonbindingMembers.getOrDefault(name, Collections.emptySet()); } + boolean isAssignableFrom(Type type1, Type type2) { + // java.lang.Object is assignable from any type + if (type1.name().equals(DotNames.OBJECT)) { + return true; + } + // type1 is the same as type2 + if (type1.name().equals(type2.name())) { + return true; + } + // type1 is a superclass + return nameToAssignables.computeIfAbsent(type1.name(), this::getAssignables).contains(type2.name()); + } + + private Set getAssignables(DotName name) { + Set assignables = new HashSet<>(); + for (ClassInfo subclass : beanArchiveIndex.getAllKnownSubclasses(name)) { + assignables.add(subclass.name()); + } + for (ClassInfo implementor : beanArchiveIndex.getAllKnownImplementors(name)) { + assignables.add(implementor.name()); + } + if (applicationIndex != null) { + for (ClassInfo subclass : applicationIndex.getAllKnownSubclasses(name)) { + assignables.add(subclass.name()); + } + for (ClassInfo implementor : applicationIndex.getAllKnownImplementors(name)) { + assignables.add(implementor.name()); + } + } + return assignables; + } + private static class ValidationContextImpl implements ValidationContext { private final BuildContext buildContext; diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java index 90d60969b1d270..e76b927ea6b018 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanResolverImpl.java @@ -16,13 +16,9 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; import javax.enterprise.inject.AmbiguousResolutionException; import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.ClassInfo; import org.jboss.jandex.ClassType; -import org.jboss.jandex.DotName; import org.jboss.jandex.Type; import org.jboss.jandex.Type.Kind; import org.jboss.jandex.TypeVariable; @@ -32,33 +28,10 @@ class BeanResolverImpl implements BeanResolver { private final BeanDeployment beanDeployment; - private final ConcurrentMap> assignableFromMap; - - private final Function> assignableFromMapFunction; - private final Map> resolved; BeanResolverImpl(BeanDeployment beanDeployment) { this.beanDeployment = beanDeployment; - this.assignableFromMap = new ConcurrentHashMap<>(); - this.assignableFromMapFunction = name -> { - Set assignables = new HashSet<>(); - for (ClassInfo subclass : beanDeployment.getBeanArchiveIndex().getAllKnownSubclasses(name)) { - assignables.add(subclass.name()); - } - for (ClassInfo implementor : beanDeployment.getBeanArchiveIndex().getAllKnownImplementors(name)) { - assignables.add(implementor.name()); - } - if (beanDeployment.hasApplicationIndex()) { - for (ClassInfo subclass : beanDeployment.getApplicationIndex().getAllKnownSubclasses(name)) { - assignables.add(subclass.name()); - } - for (ClassInfo implementor : beanDeployment.getApplicationIndex().getAllKnownImplementors(name)) { - assignables.add(implementor.name()); - } - } - return assignables; - }; this.resolved = new ConcurrentHashMap<>(); } @@ -248,7 +221,7 @@ boolean parametersMatch(WildcardType requiredParameter, TypeVariable beanParamet boolean parametersMatch(Type requiredParameter, TypeVariable beanParameter) { for (Type bound : getUppermostTypeVariableBounds(beanParameter)) { - if (!isAssignableFrom(bound, requiredParameter)) { + if (!beanDeployment.isAssignableFrom(bound, requiredParameter)) { return false; } } @@ -271,7 +244,7 @@ boolean boundsMatch(List bounds, List stricterBounds) { stricterBounds = getUppermostBounds(stricterBounds); for (Type bound : bounds) { for (Type stricterBound : stricterBounds) { - if (!isAssignableFrom(bound, stricterBound)) { + if (!beanDeployment.isAssignableFrom(bound, stricterBound)) { return false; } } @@ -279,19 +252,6 @@ boolean boundsMatch(List bounds, List stricterBounds) { return true; } - boolean isAssignableFrom(Type type1, Type type2) { - // java.lang.Object is assignable from any type - if (type1.name().equals(DotNames.OBJECT)) { - return true; - } - // type1 is the same as type2 - if (type1.name().equals(type2.name())) { - return true; - } - // type1 is a superclass - return assignableFromMap.computeIfAbsent(type1.name(), assignableFromMapFunction).contains(type2.name()); - } - boolean lowerBoundsOfWildcardMatch(Type parameter, WildcardType requiredParameter) { return lowerBoundsOfWildcardMatch(singletonList(parameter), requiredParameter); } 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 d747ece6a63f7c..60f93a224816aa 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 @@ -143,7 +143,7 @@ static Set addInterceptedMethodCandidates(BeanDeployment beanDeploym List classLevelBindings, Consumer bytecodeTransformerConsumer, boolean transformUnproxyableClasses) { return addInterceptedMethodCandidates(beanDeployment, classInfo, candidates, classLevelBindings, - bytecodeTransformerConsumer, transformUnproxyableClasses, new SubclassSkipPredicate(), false); + bytecodeTransformerConsumer, transformUnproxyableClasses, new SubclassSkipPredicate(beanDeployment), false); } static Set addInterceptedMethodCandidates(BeanDeployment beanDeployment, ClassInfo classInfo, @@ -396,10 +396,15 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str */ static class SubclassSkipPredicate implements Predicate { + private final BeanDeployment beanDeployment; private ClassInfo clazz; private List regularMethods; private Set bridgeMethods = new HashSet<>(); + public SubclassSkipPredicate(BeanDeployment beanDeployment) { + this.beanDeployment = beanDeployment; + } + void startProcessing(ClassInfo clazz) { this.clazz = clazz; this.regularMethods = new ArrayList<>(); @@ -459,8 +464,7 @@ private boolean hasImplementation(MethodInfo bridge) { for (int i = 0; i < bridgeParams.size(); i++) { Type bridgeParam = bridgeParams.get(i); Type param = params.get(i); - if (param.name().equals(bridgeParam.name()) - || bridgeParam.name().equals(DotNames.OBJECT)) { + if (beanDeployment.isAssignableFrom(bridgeParam, param)) { continue; } else { paramsNotMatching = true; @@ -477,8 +481,8 @@ private boolean hasImplementation(MethodInfo bridge) { // both cases are a match return true; } else { - // as a last resort, we simply check equality of return Type - return bridge.returnType().name().equals(declaredMethod.returnType().name()); + // as a last resort, we simply check assignability of the return type + return beanDeployment.isAssignableFrom(bridge.returnType(), declaredMethod.returnType()); } } return true; diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/bridge/BridgeMethodInterceptionTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/bridge/BridgeMethodInterceptionTest.java index a36f16860f924f..e495c88c54dd79 100644 --- a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/bridge/BridgeMethodInterceptionTest.java +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/interceptors/bridge/BridgeMethodInterceptionTest.java @@ -72,7 +72,7 @@ public void testHierarchyWithInterface() { assertEquals(1, counter.get()); } - static class Base { + static class Base> { String echo(T payload) { return payload.toString().toUpperCase();