From 7b70ded73f5729b840074bbafa40948e9df42f74 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Mon, 23 Jan 2023 13:07:22 +0100 Subject: [PATCH] Arc - compare types declared by @Typed with unrestricted bean types instead of actual types --- .../java/io/quarkus/arc/processor/Types.java | 73 ++++++++++++------- .../io/quarkus/arc/processor/TypesTest.java | 3 +- 2 files changed, 49 insertions(+), 27 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 ce05ad8207ad9..f6a97250338d7 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 @@ -331,6 +331,7 @@ static Type getProviderType(ClassInfo classInfo) { static Set getProducerMethodTypeClosure(MethodInfo producerMethod, BeanDeployment beanDeployment) { Set types; + Set unrestrictedBeanTypes = new HashSet<>(); Type returnType = producerMethod.returnType(); if (returnType.kind() == Kind.TYPE_VARIABLE) { throw new DefinitionException("A type variable is not a legal bean type: " + producerMethod); @@ -347,22 +348,25 @@ 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, producerMethod, Collections.emptyMap(), beanDeployment, null); + types = getTypeClosure(returnTypeClassInfo, producerMethod, Collections.emptyMap(), beanDeployment, null, + unrestrictedBeanTypes); } else if (Kind.PARAMETERIZED_TYPE.equals(returnType.kind())) { types = getTypeClosure(returnTypeClassInfo, producerMethod, buildResolvedMap(returnType.asParameterizedType().arguments(), returnTypeClassInfo.typeParameters(), Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), - beanDeployment, null); + beanDeployment, null, unrestrictedBeanTypes); } else { throw new IllegalArgumentException("Unsupported return type"); } } - return restrictBeanTypes(types, beanDeployment.getAnnotations(producerMethod), beanDeployment.getBeanArchiveIndex(), + return restrictBeanTypes(types, unrestrictedBeanTypes, beanDeployment.getAnnotations(producerMethod), + beanDeployment.getBeanArchiveIndex(), producerMethod); } static Set getProducerFieldTypeClosure(FieldInfo producerField, BeanDeployment beanDeployment) { Set types; + Set unrestrictedBeanTypes = new HashSet<>(); Type fieldType = producerField.type(); if (fieldType.kind() == Kind.TYPE_VARIABLE) { throw new DefinitionException("A type variable is not a legal bean type: " + producerField); @@ -377,30 +381,34 @@ 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, producerField, Collections.emptyMap(), beanDeployment, null); + types = getTypeClosure(fieldClassInfo, producerField, Collections.emptyMap(), beanDeployment, null, + unrestrictedBeanTypes); } else if (Kind.PARAMETERIZED_TYPE.equals(fieldType.kind())) { types = getTypeClosure(fieldClassInfo, producerField, buildResolvedMap(fieldType.asParameterizedType().arguments(), fieldClassInfo.typeParameters(), Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), - beanDeployment, null); + beanDeployment, null, unrestrictedBeanTypes); } else { throw new IllegalArgumentException("Unsupported return type"); } } - return restrictBeanTypes(types, beanDeployment.getAnnotations(producerField), beanDeployment.getBeanArchiveIndex(), + return restrictBeanTypes(types, unrestrictedBeanTypes, beanDeployment.getAnnotations(producerField), + beanDeployment.getBeanArchiveIndex(), producerField); } static Set getClassBeanTypeClosure(ClassInfo classInfo, BeanDeployment beanDeployment) { Set types; + Set unrestrictedBeanTypes = new HashSet<>(); List typeParameters = classInfo.typeParameters(); if (typeParameters.isEmpty()) { - types = getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, null); + types = getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, null, unrestrictedBeanTypes); } else { types = getTypeClosure(classInfo, null, buildResolvedMap(typeParameters, typeParameters, - Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), beanDeployment, null); + Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), beanDeployment, null, unrestrictedBeanTypes); } - return restrictBeanTypes(types, beanDeployment.getAnnotations(classInfo), beanDeployment.getBeanArchiveIndex(), + return restrictBeanTypes(types, unrestrictedBeanTypes, beanDeployment.getAnnotations(classInfo), + beanDeployment.getBeanArchiveIndex(), classInfo); } @@ -485,9 +493,13 @@ static boolean containsWildcard(Type type, AnnotationTarget producerFieldOrMetho return true; } } else if (type.kind().equals(Kind.PARAMETERIZED_TYPE)) { + boolean wildcardFound = false; for (Type t : type.asParameterizedType().arguments()) { // recursive check of all parameterized types - return containsWildcard(t, producerFieldOrMethod, throwIfDetected); + wildcardFound = containsWildcard(t, producerFieldOrMethod, throwIfDetected); + if (wildcardFound) { + return true; + } } } return false; @@ -496,7 +508,8 @@ static boolean containsWildcard(Type type, AnnotationTarget producerFieldOrMetho private static Set getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod, boolean throwOnProducerWildcard, Map resolvedTypeParameters, - BeanDeployment beanDeployment, BiConsumer> resolvedTypeVariablesConsumer) { + BeanDeployment beanDeployment, BiConsumer> resolvedTypeVariablesConsumer, + Set unrestrictedBeanTypes) { Set types = new HashSet<>(); List typeParameters = classInfo.typeParameters(); @@ -524,6 +537,8 @@ private static Set getTypeClosure(ClassInfo classInfo, AnnotationTarget pr } if (!skipThisType) { types.add(ParameterizedType.create(classInfo.name(), typeParams, null)); + } else { + unrestrictedBeanTypes.add(ParameterizedType.create(classInfo.name(), typeParams, null)); } } // Interfaces @@ -539,7 +554,7 @@ private static Set getTypeClosure(ClassInfo classInfo, AnnotationTarget pr interfaceClassInfo.typeParameters(), resolvedTypeParameters, beanDeployment.getBeanArchiveIndex()); } types.addAll(getTypeClosure(interfaceClassInfo, producerFieldOrMethod, false, resolved, beanDeployment, - resolvedTypeVariablesConsumer)); + resolvedTypeVariablesConsumer, unrestrictedBeanTypes)); } } // Superclass @@ -553,21 +568,24 @@ private static Set getTypeClosure(ClassInfo classInfo, AnnotationTarget pr resolvedTypeParameters, beanDeployment.getBeanArchiveIndex()); } types.addAll(getTypeClosure(superClassInfo, producerFieldOrMethod, false, resolved, beanDeployment, - resolvedTypeVariablesConsumer)); + resolvedTypeVariablesConsumer, unrestrictedBeanTypes)); } } + unrestrictedBeanTypes.addAll(types); return types; } static Set getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod, Map resolvedTypeParameters, - BeanDeployment beanDeployment, BiConsumer> resolvedTypeVariablesConsumer) { + BeanDeployment beanDeployment, BiConsumer> resolvedTypeVariablesConsumer, + Set unrestrictedBeanTypes) { return getTypeClosure(classInfo, producerFieldOrMethod, true, resolvedTypeParameters, beanDeployment, - resolvedTypeVariablesConsumer); + resolvedTypeVariablesConsumer, unrestrictedBeanTypes); } static Set getDelegateTypeClosure(InjectionPointInfo delegateInjectionPoint, BeanDeployment beanDeployment) { Set types; + Set unrestrictedBeanTypes = new HashSet<>(); Type delegateType = delegateInjectionPoint.getRequiredType(); if (delegateType.kind() == Kind.TYPE_VARIABLE || delegateType.kind() == Kind.PRIMITIVE @@ -580,12 +598,12 @@ static Set getDelegateTypeClosure(InjectionPointInfo delegateInjectionPoin } if (Kind.CLASS.equals(delegateType.kind())) { types = getTypeClosure(delegateTypeClass, delegateInjectionPoint.getTarget(), Collections.emptyMap(), - beanDeployment, null); + beanDeployment, null, unrestrictedBeanTypes); } else if (Kind.PARAMETERIZED_TYPE.equals(delegateType.kind())) { types = getTypeClosure(delegateTypeClass, delegateInjectionPoint.getTarget(), buildResolvedMap(delegateType.asParameterizedType().arguments(), delegateTypeClass.typeParameters(), Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), - beanDeployment, null); + beanDeployment, null, unrestrictedBeanTypes); } else { throw new IllegalArgumentException("Unsupported return type"); } @@ -595,11 +613,12 @@ static Set getDelegateTypeClosure(InjectionPointInfo delegateInjectionPoin static Map> resolvedTypeVariables(ClassInfo classInfo, BeanDeployment beanDeployment) { Map> resolvedTypeVariables = new HashMap<>(); - getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, resolvedTypeVariables::put); + getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, resolvedTypeVariables::put, new HashSet<>()); return resolvedTypeVariables; } - static Set restrictBeanTypes(Set types, Collection annotations, IndexView index, + static Set restrictBeanTypes(Set types, Set unrestrictedBeanTypes, + Collection annotations, IndexView index, AnnotationTarget target) { AnnotationInstance typed = null; for (AnnotationInstance a : annotations) { @@ -621,12 +640,20 @@ static Set restrictBeanTypes(Set types, Collection type.name().equals(typeName))) { + throw new DefinitionException( + "Cannot limit bean types to types outside of the transitive closure of bean types. Bean: " + target + + " illegal bean types: " + typedClasses); + } + } for (Iterator it = types.iterator(); it.hasNext();) { Type next = it.next(); if (DotNames.OBJECT.equals(next.name())) { continue; } - if (typed != null && !typedClasses.remove(next.name())) { + if (typed != null && !typedClasses.contains(next.name())) { it.remove(); continue; } @@ -639,12 +666,6 @@ static Set restrictBeanTypes(Set types, Collection bazTypes = Types.getTypeClosure(index.getClassByName(bazName), null, Collections.emptyMap(), dummyDeployment, - resolvedTypeVariables::put); + resolvedTypeVariables::put, new HashSet<>()); assertEquals(3, bazTypes.size()); assertTrue(bazTypes.contains(Type.create(bazName, Kind.CLASS))); assertTrue(bazTypes.contains(ParameterizedType.create(fooName,