Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arc - compare types declared by @Typed with unrestricted bean types instead of actual types #30544

Merged
merged 1 commit into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ static Type getProviderType(ClassInfo classInfo) {

static Set<Type> getProducerMethodTypeClosure(MethodInfo producerMethod, BeanDeployment beanDeployment) {
Set<Type> types;
Set<Type> 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);
Expand All @@ -347,22 +348,25 @@ static Set<Type> 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<Type> getProducerFieldTypeClosure(FieldInfo producerField, BeanDeployment beanDeployment) {
Set<Type> types;
Set<Type> 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);
Expand All @@ -377,30 +381,34 @@ static Set<Type> 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<Type> getClassBeanTypeClosure(ClassInfo classInfo, BeanDeployment beanDeployment) {
Set<Type> types;
Set<Type> unrestrictedBeanTypes = new HashSet<>();
List<TypeVariable> 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);
}

Expand Down Expand Up @@ -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;
Expand All @@ -496,7 +508,8 @@ static boolean containsWildcard(Type type, AnnotationTarget producerFieldOrMetho
private static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod,
boolean throwOnProducerWildcard,
Map<String, Type> resolvedTypeParameters,
BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<String, Type>> resolvedTypeVariablesConsumer) {
BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<String, Type>> resolvedTypeVariablesConsumer,
Set<Type> unrestrictedBeanTypes) {
Set<Type> types = new HashSet<>();
List<TypeVariable> typeParameters = classInfo.typeParameters();

Expand Down Expand Up @@ -524,6 +537,8 @@ private static Set<Type> 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
Expand All @@ -539,7 +554,7 @@ private static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget pr
interfaceClassInfo.typeParameters(), resolvedTypeParameters, beanDeployment.getBeanArchiveIndex());
}
types.addAll(getTypeClosure(interfaceClassInfo, producerFieldOrMethod, false, resolved, beanDeployment,
resolvedTypeVariablesConsumer));
resolvedTypeVariablesConsumer, unrestrictedBeanTypes));
}
}
// Superclass
Expand All @@ -553,21 +568,24 @@ private static Set<Type> 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<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod,
Map<String, Type> resolvedTypeParameters,
BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<String, Type>> resolvedTypeVariablesConsumer) {
BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<String, Type>> resolvedTypeVariablesConsumer,
Set<Type> unrestrictedBeanTypes) {
return getTypeClosure(classInfo, producerFieldOrMethod, true, resolvedTypeParameters, beanDeployment,
resolvedTypeVariablesConsumer);
resolvedTypeVariablesConsumer, unrestrictedBeanTypes);
}

static Set<Type> getDelegateTypeClosure(InjectionPointInfo delegateInjectionPoint, BeanDeployment beanDeployment) {
Set<Type> types;
Set<Type> unrestrictedBeanTypes = new HashSet<>();
Type delegateType = delegateInjectionPoint.getRequiredType();
if (delegateType.kind() == Kind.TYPE_VARIABLE
|| delegateType.kind() == Kind.PRIMITIVE
Expand All @@ -580,12 +598,12 @@ static Set<Type> 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");
}
Expand All @@ -595,11 +613,12 @@ static Set<Type> getDelegateTypeClosure(InjectionPointInfo delegateInjectionPoin
static Map<ClassInfo, Map<String, Type>> resolvedTypeVariables(ClassInfo classInfo,
BeanDeployment beanDeployment) {
Map<ClassInfo, Map<String, Type>> 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<Type> restrictBeanTypes(Set<Type> types, Collection<AnnotationInstance> annotations, IndexView index,
static Set<Type> restrictBeanTypes(Set<Type> types, Set<Type> unrestrictedBeanTypes,
Collection<AnnotationInstance> annotations, IndexView index,
AnnotationTarget target) {
AnnotationInstance typed = null;
for (AnnotationInstance a : annotations) {
Expand All @@ -621,12 +640,20 @@ static Set<Type> restrictBeanTypes(Set<Type> types, Collection<AnnotationInstanc
}
}
}
// check if all classes declared in @Typed match some class in the unrestricted bean type set
for (DotName typeName : typedClasses) {
if (!unrestrictedBeanTypes.stream().anyMatch(type -> 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<Type> 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;
}
Expand All @@ -639,12 +666,6 @@ static Set<Type> restrictBeanTypes(Set<Type> types, Collection<AnnotationInstanc
}
}
}
// if the set of types we gathered from @Typed annotation isn't now empty, there are some illegal types in it
if (!typedClasses.isEmpty()) {
throw new DefinitionException(
"Cannot limit bean types to types outside of the transitive closure of bean types. Bean: " + target
+ " illegal bean types: " + typedClasses);
}
return types;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -42,7 +43,7 @@ public void testGetTypeClosure() throws IOException {
Set<Type> 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,
Expand Down