From ca19197b82c1018d8781b9a2575266abc6a9c016 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Tue, 22 Oct 2019 14:53:05 +0200 Subject: [PATCH] Arc - log a warning when we detect wildcard as a bean type. --- .../java/io/quarkus/arc/processor/Types.java | 42 ++++++++++++++----- .../io/quarkus/arc/processor/TypesTest.java | 36 +++++++++++++++- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java index c558f547e226f..2ed59da87a336 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java @@ -19,6 +19,7 @@ import java.util.Set; import java.util.function.BiConsumer; import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; @@ -31,6 +32,7 @@ import org.jboss.jandex.Type.Kind; import org.jboss.jandex.TypeVariable; import org.jboss.jandex.WildcardType; +import org.jboss.logging.Logger; /** * @@ -38,6 +40,8 @@ */ final class Types { + static final Logger LOGGER = Logger.getLogger(Types.class); + private static final Type OBJECT_TYPE = Type.create(DotNames.OBJECT, Kind.CLASS); private Types() { @@ -148,9 +152,9 @@ static Set getProducerMethodTypeClosure(MethodInfo producerMethod, BeanDep "Producer method return type not found in index: " + producerMethod.returnType().name()); } if (Kind.CLASS.equals(returnType.kind())) { - types = getTypeClosure(returnTypeClassInfo, Collections.emptyMap(), beanDeployment, null); + types = getTypeClosure(returnTypeClassInfo, producerMethod, Collections.emptyMap(), beanDeployment, null); } else if (Kind.PARAMETERIZED_TYPE.equals(returnType.kind())) { - types = getTypeClosure(returnTypeClassInfo, + types = getTypeClosure(returnTypeClassInfo, producerMethod, buildResolvedMap(returnType.asParameterizedType().arguments(), returnTypeClassInfo.typeParameters(), Collections.emptyMap(), beanDeployment.getIndex()), beanDeployment, null); @@ -174,9 +178,9 @@ static Set getProducerFieldTypeClosure(FieldInfo producerField, BeanDeploy throw new IllegalArgumentException("Producer field type not found in index: " + producerField.type().name()); } if (Kind.CLASS.equals(fieldType.kind())) { - types = getTypeClosure(fieldClassInfo, Collections.emptyMap(), beanDeployment, null); + types = getTypeClosure(fieldClassInfo, producerField, Collections.emptyMap(), beanDeployment, null); } else if (Kind.PARAMETERIZED_TYPE.equals(fieldType.kind())) { - types = getTypeClosure(fieldClassInfo, + types = getTypeClosure(fieldClassInfo, producerField, buildResolvedMap(fieldType.asParameterizedType().arguments(), fieldClassInfo.typeParameters(), Collections.emptyMap(), beanDeployment.getIndex()), beanDeployment, null); @@ -191,15 +195,16 @@ static Set getClassBeanTypeClosure(ClassInfo classInfo, BeanDeployment bea Set types; List typeParameters = classInfo.typeParameters(); if (typeParameters.isEmpty()) { - types = getTypeClosure(classInfo, Collections.emptyMap(), beanDeployment, null); + types = getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, null); } else { - types = getTypeClosure(classInfo, buildResolvedMap(typeParameters, typeParameters, + types = getTypeClosure(classInfo, null, buildResolvedMap(typeParameters, typeParameters, Collections.emptyMap(), beanDeployment.getIndex()), beanDeployment, null); } return restrictBeanTypes(types, beanDeployment.getAnnotations(classInfo)); } - static Set getTypeClosure(ClassInfo classInfo, Map resolvedTypeParameters, + static Set getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod, + Map resolvedTypeParameters, BeanDeployment beanDeployment, BiConsumer> resolvedTypeVariablesConsumer) { Set types = new HashSet<>(); List typeParameters = classInfo.typeParameters(); @@ -210,8 +215,19 @@ static Set getTypeClosure(ClassInfo classInfo, Map res } else { // Canonical ParameterizedType with unresolved type variables Type[] typeParams = new Type[typeParameters.size()]; + boolean skipThisType = false; for (int i = 0; i < typeParameters.size(); i++) { typeParams[i] = resolvedTypeParameters.get(typeParameters.get(i)); + // this should only be the case for producers; wildcard is not a legal bean type + // see https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#legal_bean_types + if (typeParams[i].kind().equals(Kind.WILDCARD_TYPE) && producerFieldOrMethod != null) { + LOGGER.info("Producer " + + (producerFieldOrMethod.kind().equals(AnnotationTarget.Kind.FIELD) ? "field " : "method ") + + producerFieldOrMethod + + " contains a parameterized typed with a wildcard. This type is not a legal bean type" + + " according to CDI specification and will be ignored during bean resolution."); + skipThisType = true; + } } if (resolvedTypeVariablesConsumer != null) { Map resolved = new HashMap<>(); @@ -220,7 +236,9 @@ static Set getTypeClosure(ClassInfo classInfo, Map res } resolvedTypeVariablesConsumer.accept(classInfo, resolved); } - types.add(ParameterizedType.create(classInfo.name(), typeParams, null)); + if (!skipThisType) { + types.add(ParameterizedType.create(classInfo.name(), typeParams, null)); + } } // Interfaces for (Type interfaceType : classInfo.interfaceTypes()) { @@ -231,7 +249,8 @@ static Set getTypeClosure(ClassInfo classInfo, Map res resolved = buildResolvedMap(interfaceType.asParameterizedType().arguments(), interfaceClassInfo.typeParameters(), resolvedTypeParameters, beanDeployment.getIndex()); } - types.addAll(getTypeClosure(interfaceClassInfo, resolved, beanDeployment, resolvedTypeVariablesConsumer)); + types.addAll(getTypeClosure(interfaceClassInfo, producerFieldOrMethod, resolved, beanDeployment, + resolvedTypeVariablesConsumer)); } } // Superclass @@ -244,7 +263,8 @@ static Set getTypeClosure(ClassInfo classInfo, Map res superClassInfo.typeParameters(), resolvedTypeParameters, beanDeployment.getIndex()); } - types.addAll(getTypeClosure(superClassInfo, resolved, beanDeployment, resolvedTypeVariablesConsumer)); + types.addAll(getTypeClosure(superClassInfo, producerFieldOrMethod, resolved, beanDeployment, + resolvedTypeVariablesConsumer)); } } return types; @@ -253,7 +273,7 @@ static Set getTypeClosure(ClassInfo classInfo, Map res static Map> resolvedTypeVariables(ClassInfo classInfo, BeanDeployment beanDeployment) { Map> resolvedTypeVariables = new HashMap<>(); - getTypeClosure(classInfo, Collections.emptyMap(), beanDeployment, resolvedTypeVariables::put); + getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, resolvedTypeVariables::put); return resolvedTypeVariables; } diff --git a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java index 562b147b9a9aa..b47ed0a32a6b6 100644 --- a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java +++ b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java @@ -4,13 +4,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; +import org.jboss.jandex.FieldInfo; import org.jboss.jandex.IndexView; +import org.jboss.jandex.MethodInfo; import org.jboss.jandex.ParameterizedType; import org.jboss.jandex.Type; import org.jboss.jandex.Type.Kind; @@ -21,14 +25,16 @@ public class TypesTest { @Test public void testGetTypeClosure() throws IOException { - IndexView index = Basics.index(Foo.class, Baz.class, Object.class); + IndexView index = Basics.index(Foo.class, Baz.class, Producer.class, Object.class, List.class, Collection.class, + Iterable.class); DotName bazName = DotName.createSimple(Baz.class.getName()); DotName fooName = DotName.createSimple(Foo.class.getName()); + DotName producerName = DotName.createSimple(Producer.class.getName()); ClassInfo fooClass = index.getClassByName(fooName); Map> resolvedTypeVariables = new HashMap<>(); // Baz, Foo, Object - Set bazTypes = Types.getTypeClosure(index.getClassByName(bazName), + Set bazTypes = Types.getTypeClosure(index.getClassByName(bazName), null, Collections.emptyMap(), new BeanDeployment(index, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), null, @@ -58,6 +64,23 @@ public void testGetTypeClosure() throws IOException { assertEquals(DotNames.OBJECT, fooType.arguments().get(0).asTypeVariable().bounds().get(0).name()); } } + ClassInfo producerClass = index.getClassByName(producerName); + String producersName = "produce"; + MethodInfo producerMethod = producerClass.method(producersName); + // Object is the sole type + Set producerMethodTypes = Types.getProducerMethodTypeClosure(producerMethod, + new BeanDeployment(index, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), + Collections.emptyList(), null, + false, Collections.emptyList(), Collections.emptyMap(), Collections.emptyList())); + assertEquals(1, producerMethodTypes.size()); + + // Object is the sole type + FieldInfo producerField = producerClass.field(producersName); + Set producerFieldTypes = Types.getProducerFieldTypeClosure(producerField, + new BeanDeployment(index, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), + Collections.emptyList(), null, + false, Collections.emptyList(), Collections.emptyMap(), Collections.emptyList())); + assertEquals(1, producerFieldTypes.size()); } static class Foo { @@ -69,4 +92,13 @@ static class Foo { static class Baz extends Foo { } + + static class Producer { + + public List produce() { + return null; + } + + List produce; + } }