Skip to content

Commit

Permalink
Arc - remove wildcard types from bean types of class-based beans
Browse files Browse the repository at this point in the history
  • Loading branch information
manovotn committed Jan 18, 2023
1 parent d72072c commit 0c3c7e1
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -433,17 +433,15 @@ static List<Type> getResolvedParameters(ClassInfo classInfo, Map<String, Type> r
}

/**
* Detects wildcard for given producer method/field.
* Based on the boolean parameter, it either throws a {@link DefinitionException} of performs logging.
* Detects wildcard for given type.
* In case this is related to a producer field or method, it either logs or throws a {@link DefinitionException}
* based on the boolean parameter.
* Returns true if a wildcard is detected, false otherwise.
*/
static boolean isProducerWithWildcard(Type type, AnnotationTarget producerFieldOrMethod, boolean throwIfDetected) {
if (producerFieldOrMethod == null) {
// not a producer, no further analysis required
return false;
}
static boolean containsWildcard(Type type, AnnotationTarget producerFieldOrMethod, boolean throwIfDetected) {
if (type.kind().equals(Kind.WILDCARD_TYPE)) {
if (throwIfDetected) {
if (throwIfDetected && producerFieldOrMethod != null) {
// a producer method that has wildcard directly in its return type
throw new DefinitionException("Producer " +
(producerFieldOrMethod.kind().equals(AnnotationTarget.Kind.FIELD) ? "field " : "method ") +
producerFieldOrMethod +
Expand All @@ -454,18 +452,22 @@ static boolean isProducerWithWildcard(Type type, AnnotationTarget producerFieldO
+
" contains a parameterized type with a wildcard. This type is not a legal bean type" +
" according to CDI specification.");
} else {
} else if (producerFieldOrMethod != null) {
// a producer method with wildcard in the type hierarchy of the return type
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.");
return true;
} else {
// wildcard detection for class-based beans, these still need to be skipped as they aren't valid bean types
return true;
}
} else if (type.kind().equals(Kind.PARAMETERIZED_TYPE)) {
for (Type t : type.asParameterizedType().arguments()) {
// recursive check of all parameterized types
return isProducerWithWildcard(t, producerFieldOrMethod, throwIfDetected);
return containsWildcard(t, producerFieldOrMethod, throwIfDetected);
}
}
return false;
Expand All @@ -491,7 +493,7 @@ private static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget pr
// for producers, wildcard is not a legal bean type and results in a definition error
// see https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#legal_bean_types
// NOTE: wildcard can be nested, such as List<Set<? extends Number>>
skipThisType = isProducerWithWildcard(typeParams[i], producerFieldOrMethod, throwOnProducerWildcard);
skipThisType = containsWildcard(typeParams[i], producerFieldOrMethod, throwOnProducerWildcard);
}
if (resolvedTypeVariablesConsumer != null) {
Map<String, Type> resolved = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -82,10 +83,24 @@ public void testGetTypeClosure() throws IOException {
// now assert following ones do NOT throw, the wildcard in the hierarchy is just ignored
final String wildcardInTypeHierarchy = "eagleProducer";
assertDoesNotThrow(
() -> Types.getProducerMethodTypeClosure(producerClass.method(wildcardInTypeHierarchy), dummyDeployment));
() -> verifyEagleTypes(
Types.getProducerMethodTypeClosure(producerClass.method(wildcardInTypeHierarchy), dummyDeployment)));
assertDoesNotThrow(
() -> Types.getProducerFieldTypeClosure(producerClass.field(wildcardInTypeHierarchy), dummyDeployment));
() -> verifyEagleTypes(
Types.getProducerFieldTypeClosure(producerClass.field(wildcardInTypeHierarchy), dummyDeployment)));
// now do the same for a non-producer scenario with Eagle class
assertDoesNotThrow(
() -> verifyEagleTypes(Types.getClassBeanTypeClosure(index.getClassByName(DotName.createSimple(Eagle.class)),
dummyDeployment)));
}

private void verifyEagleTypes(Set<Type> types) {
for (Type type : types) {
if (type.kind().equals(Kind.PARAMETERIZED_TYPE)) {
assertNotEquals(DotName.createSimple(AnimalHolder.class), type.name());
}
}
assertEquals(3, types.size());
}

static class Foo<T> {
Expand Down

0 comments on commit 0c3c7e1

Please sign in to comment.