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 - log a warning when we detect wildcard as a bean type. #4756

Merged
merged 1 commit into from
Oct 22, 2019
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 @@ -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;
Expand All @@ -31,13 +32,16 @@
import org.jboss.jandex.Type.Kind;
import org.jboss.jandex.TypeVariable;
import org.jboss.jandex.WildcardType;
import org.jboss.logging.Logger;

/**
*
* @author Martin Kouba
*/
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() {
Expand Down Expand Up @@ -148,9 +152,9 @@ 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, 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);
Expand All @@ -174,9 +178,9 @@ 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, 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);
Expand All @@ -191,15 +195,16 @@ static Set<Type> getClassBeanTypeClosure(ClassInfo classInfo, BeanDeployment bea
Set<Type> types;
List<TypeVariable> 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<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> resolvedTypeParameters,
static Set<Type> getTypeClosure(ClassInfo classInfo, AnnotationTarget producerFieldOrMethod,
Map<TypeVariable, Type> resolvedTypeParameters,
BeanDeployment beanDeployment, BiConsumer<ClassInfo, Map<TypeVariable, Type>> resolvedTypeVariablesConsumer) {
Set<Type> types = new HashSet<>();
List<TypeVariable> typeParameters = classInfo.typeParameters();
Expand All @@ -210,8 +215,19 @@ static Set<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> 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<TypeVariable, Type> resolved = new HashMap<>();
Expand All @@ -220,7 +236,9 @@ static Set<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> 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()) {
Expand All @@ -231,7 +249,8 @@ static Set<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> 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
Expand All @@ -244,7 +263,8 @@ static Set<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> res
superClassInfo.typeParameters(),
resolvedTypeParameters, beanDeployment.getIndex());
}
types.addAll(getTypeClosure(superClassInfo, resolved, beanDeployment, resolvedTypeVariablesConsumer));
types.addAll(getTypeClosure(superClassInfo, producerFieldOrMethod, resolved, beanDeployment,
resolvedTypeVariablesConsumer));
}
}
return types;
Expand All @@ -253,7 +273,7 @@ static Set<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> res
static Map<ClassInfo, Map<TypeVariable, Type>> resolvedTypeVariables(ClassInfo classInfo,
BeanDeployment beanDeployment) {
Map<ClassInfo, Map<TypeVariable, Type>> resolvedTypeVariables = new HashMap<>();
getTypeClosure(classInfo, Collections.emptyMap(), beanDeployment, resolvedTypeVariables::put);
getTypeClosure(classInfo, null, Collections.emptyMap(), beanDeployment, resolvedTypeVariables::put);
return resolvedTypeVariables;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<ClassInfo, Map<TypeVariable, Type>> resolvedTypeVariables = new HashMap<>();

// Baz, Foo<String>, Object
Set<Type> bazTypes = Types.getTypeClosure(index.getClassByName(bazName),
Set<Type> bazTypes = Types.getTypeClosure(index.getClassByName(bazName), null,
Collections.emptyMap(),
new BeanDeployment(index, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), null,
Expand Down Expand Up @@ -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<Type> 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<Type> 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<T> {
Expand All @@ -69,4 +92,13 @@ static class Foo<T> {
static class Baz extends Foo<String> {

}

static class Producer {

public List<? extends Number> produce() {
return null;
}

List<? extends Number> produce;
}
}