Skip to content

Commit

Permalink
ArC: add validation for array-typed producers
Browse files Browse the repository at this point in the history
  • Loading branch information
Ladicek committed Jan 27, 2023
1 parent aca5144 commit f348463
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,7 @@ private static void getTypeHandle(AssignableResultHandle variable, BytecodeCreat

} else if (Kind.ARRAY.equals(type.kind())) {
ArrayType array = type.asArrayType();
Type elementType = array.component();
while (elementType.kind() == Kind.ARRAY) {
elementType = elementType.asArrayType().component();
}
Type elementType = getArrayElementType(array);

ResultHandle arrayHandle;
if (elementType.kind() == Kind.PRIMITIVE || elementType.kind() == Kind.CLASS) {
Expand Down Expand Up @@ -351,13 +348,24 @@ static Type getProviderType(ClassInfo classInfo) {
}
}

static Type getArrayElementType(ArrayType array) {
Type elementType = array.component();
while (elementType.kind() == Kind.ARRAY) {
elementType = elementType.asArrayType().component();
}
return elementType;
}

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);
}
if (returnType.kind() == Kind.ARRAY) {
checkArrayType(returnType.asArrayType(), producerMethod);
}
if (returnType.kind() == Kind.PRIMITIVE || returnType.kind() == Kind.ARRAY) {
types = new HashSet<>();
types.add(returnType);
Expand Down Expand Up @@ -393,6 +401,9 @@ static Set<Type> getProducerFieldTypeClosure(FieldInfo producerField, BeanDeploy
if (fieldType.kind() == Kind.TYPE_VARIABLE) {
throw new DefinitionException("A type variable is not a legal bean type: " + producerField);
}
if (fieldType.kind() == Kind.ARRAY) {
checkArrayType(fieldType.asArrayType(), producerField);
}
if (fieldType.kind() == Kind.PRIMITIVE || fieldType.kind() == Kind.ARRAY) {
types = new HashSet<>();
types.add(fieldType);
Expand Down Expand Up @@ -482,6 +493,18 @@ static List<Type> getResolvedParameters(ClassInfo classInfo, Map<String, Type> r
}
}

/**
* Throws {@code DefinitionException} if given {@code producerFieldOrMethod},
* whose type is given {@code arrayType}, is invalid due to the rules for arrays.
*/
static void checkArrayType(ArrayType arrayType, AnnotationTarget producerFieldOrMethod) {
Type elementType = getArrayElementType(arrayType);
if (elementType.kind() == Kind.TYPE_VARIABLE) {
throw new DefinitionException("A type variable array is not a legal bean type: " + producerFieldOrMethod);
}
containsWildcard(elementType, producerFieldOrMethod, true);
}

/**
* Detects wildcard for given type.
* In case this is related to a producer field or method, it either logs or throws a {@link DefinitionException}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -69,18 +70,13 @@ public void testGetTypeClosure() throws IOException {
}
}
ClassInfo producerClass = index.getClassByName(producerName);
final String producersName = "produce";
assertThrows(DefinitionException.class,
() -> Types.getProducerMethodTypeClosure(producerClass.method(producersName), dummyDeployment));
assertThrows(DefinitionException.class,
() -> Types.getProducerFieldTypeClosure(producerClass.field(producersName), dummyDeployment));

// now assert the same with nested wildcard
final String nestedWildCardProducersName = "produceNested";
assertThrows(DefinitionException.class,
() -> Types.getProducerMethodTypeClosure(producerClass.method(nestedWildCardProducersName), dummyDeployment));
assertThrows(DefinitionException.class,
() -> Types.getProducerFieldTypeClosure(producerClass.field(nestedWildCardProducersName), dummyDeployment));
for (String name : Arrays.asList("produce", "produceNested", "produceTypeVar",
"produceArray", "produceNestedArray", "produceTypeVarArray")) {
assertThrows(DefinitionException.class,
() -> Types.getProducerMethodTypeClosure(producerClass.method(name), dummyDeployment));
assertThrows(DefinitionException.class,
() -> Types.getProducerFieldTypeClosure(producerClass.field(name), dummyDeployment));
}

// now assert following ones do NOT throw, the wildcard in the hierarchy is just ignored
final String wildcardInTypeHierarchy = "eagleProducer";
Expand Down Expand Up @@ -140,10 +136,34 @@ public List<Set<? extends Number>> produceNested() {
return null;
}

public T produceTypeVar() {
return null;
}

public List<? extends Number>[][] produceArray() {
return null;
}

public List<Set<? extends Number>>[][] produceNestedArray() {
return null;
}

public T[][] produceTypeVarArray() {
return null;
}

List<? extends Number> produce;

List<Set<? extends Number>> produceNested;

public T produceTypeVar;

List<? extends Number>[] produceArray;

List<Set<? extends Number>>[] produceNestedArray;

public T[] produceTypeVarArray;

// following producer should NOT throw an exception because the return types doesn't contain wildcard
// but the hierarchy of the return type actually contains one
// taken from CDI TCK setup, see https://github.com/jakartaee/cdi-tck/blob/4.0.7/impl/src/main/java/org/jboss/cdi/tck/tests/definition/bean/types/illegal/BeanTypesWithIllegalTypeTest.java
Expand Down

0 comments on commit f348463

Please sign in to comment.