Skip to content

Commit

Permalink
Change the behavior of InjectionPointInfo.getRequiredType()
Browse files Browse the repository at this point in the history
- InjectionPointInfo.getRequiredType() should return the type parameter
for programmatic lookup
- resolves quarkusio#17835
  • Loading branch information
mkouba committed Jun 11, 2021
1 parent f319507 commit 7a0ee7a
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,19 @@ void analyzeConfigPropertyInjectionPoints(BeanDiscoveryFinishedBuildItem beanDis
}

// Register a custom bean for injection points that are not handled by ConfigProducer
Type requiredType = injectionPoint.getRequiredType();
if (!isHandledByProducers(requiredType)) {
customBeanTypes.add(requiredType);
Type injectedType = injectionPoint.getType();
if (!isHandledByProducers(injectedType)) {
customBeanTypes.add(injectedType);
}

if (DotNames.OPTIONAL.equals(requiredType.name())
|| DotNames.OPTIONAL_INT.equals(requiredType.name())
|| DotNames.OPTIONAL_LONG.equals(requiredType.name())
|| DotNames.OPTIONAL_DOUBLE.equals(requiredType.name())
|| DotNames.PROVIDER.equals(requiredType.name())
|| SUPPLIER_NAME.equals(requiredType.name())
|| CONFIG_VALUE_NAME.equals(requiredType.name())
|| MP_CONFIG_VALUE_NAME.equals(requiredType.name())) {
if (DotNames.OPTIONAL.equals(injectedType.name())
|| DotNames.OPTIONAL_INT.equals(injectedType.name())
|| DotNames.OPTIONAL_LONG.equals(injectedType.name())
|| DotNames.OPTIONAL_DOUBLE.equals(injectedType.name())
|| DotNames.PROVIDER.equals(injectedType.name())
|| SUPPLIER_NAME.equals(injectedType.name())
|| CONFIG_VALUE_NAME.equals(injectedType.name())
|| MP_CONFIG_VALUE_NAME.equals(injectedType.name())) {
// Never validate container objects
continue;
}
Expand All @@ -143,7 +143,7 @@ void analyzeConfigPropertyInjectionPoints(BeanDiscoveryFinishedBuildItem beanDis
propertyDefaultValue = defaultValue.asString();
}

configProperties.produce(new ConfigPropertyBuildItem(propertyName, requiredType, propertyDefaultValue));
configProperties.produce(new ConfigPropertyBuildItem(propertyName, injectedType, propertyDefaultValue));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,6 @@ void discoverInjectedGrpcServices(BeanDiscoveryFinishedBuildItem beanDiscovery,
}

Type injectionType = injectionPoint.getRequiredType();

// Programmatic lookup - take the param type
if (DotNames.INSTANCE.equals(injectionType.name()) || DotNames.INJECTABLE_INSTANCE.equals(injectionType.name())) {
injectionType = injectionType.asParameterizedType().arguments().get(0);
}

if (injectionType.name().equals(GrpcDotNames.CHANNEL)) {
// No need to add the stub class for Channel
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ void registerOptionalClaimProducer(BeanRegistrationPhaseBuildItem beanRegistrati
continue;
}
AnnotationInstance claimQualifier = injectionPoint.getRequiredQualifier(CLAIM_NAME);
if (claimQualifier != null && injectionPoint.getRequiredType().name().equals(DotNames.PROVIDER)) {
if (claimQualifier != null && injectionPoint.getType().name().equals(DotNames.PROVIDER)) {
// Classes from javax.json are handled specially
Type actualType = injectionPoint.getRequiredType().asParameterizedType().arguments().get(0);
Type actualType = injectionPoint.getRequiredType();
if (actualType.name().equals(DotNames.OPTIONAL) && !actualType.name().toString()
.startsWith("javax.json")) {
additionalTypes.add(actualType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ void init(Consumer<BytecodeTransformer> bytecodeTransformerConsumer,
// Instance<Foo>
for (InjectionPointInfo injectionPoint : instanceInjectionPoints) {
if (Beans.hasQualifiers(bean, injectionPoint.getRequiredQualifiers()) && Beans.matchesType(bean,
injectionPoint.getRequiredType().asParameterizedType().arguments().get(0))) {
injectionPoint.getType().asParameterizedType().arguments().get(0))) {
continue test;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1007,7 +1007,7 @@ private ResultHandle newInstanceHandle(BeanInfo bean, ClassCreator beanCreator,

// 1. constructor injection points
for (int i = 0; i < injectionPoints.size(); i++) {
paramTypes.add(injectionPoints.get(i).getRequiredType().name().toString());
paramTypes.add(injectionPoints.get(i).getType().name().toString());
paramHandles.add(providerHandles.get(i));
}
// 2. ctx
Expand Down Expand Up @@ -1038,7 +1038,7 @@ private ResultHandle newInstanceHandle(BeanInfo bean, ClassCreator beanCreator,
ResultHandle argsArray = creator.newArray(Object.class, creator.load(providerHandles.size()));
for (int i = 0; i < injectionPoints.size(); i++) {
creator.writeArrayValue(paramTypesArray, i,
creator.loadClass(injectionPoints.get(i).getRequiredType().name().toString()));
creator.loadClass(injectionPoints.get(i).getType().name().toString()));
creator.writeArrayValue(argsArray, i, providerHandles.get(i));
}
registration.registerMethod(constructor);
Expand All @@ -1050,7 +1050,7 @@ private ResultHandle newInstanceHandle(BeanInfo bean, ClassCreator beanCreator,
String[] paramTypes = new String[injectionPoints.size()];
for (ListIterator<InjectionPointInfo> iterator = injectionPoints.listIterator(); iterator.hasNext();) {
InjectionPointInfo injectionPoint = iterator.next();
paramTypes[iterator.previousIndex()] = DescriptorUtils.typeToString(injectionPoint.getRequiredType());
paramTypes[iterator.previousIndex()] = DescriptorUtils.typeToString(injectionPoint.getType());
}
return creator.newInstance(MethodDescriptor.ofConstructor(providerTypeName, paramTypes),
providerHandles.toArray(new ResultHandle[0]));
Expand Down Expand Up @@ -1350,7 +1350,7 @@ void implementCreateForClassBean(ClassOutput classOutput, ClassCreator beanCreat
if (constructorInjection.isPresent()) {
List<String> paramTypes = new ArrayList<>();
for (InjectionPointInfo injectionPoint : constructorInjection.get().injectionPoints) {
paramTypes.add(injectionPoint.getRequiredType().name().toString());
paramTypes.add(injectionPoint.getType().name().toString());
}
ResultHandle[] paramsHandles = new ResultHandle[2];
paramsHandles[0] = create.loadClass(providerType.className());
Expand Down Expand Up @@ -1794,7 +1794,7 @@ private ResultHandle wrapCurrentInjectionPoint(ClassOutput classOutput, ClassCre
Supplier.class, java.lang.reflect.Type.class,
Set.class, Set.class, Member.class, int.class),
constructor.getThis(), constructor.getMethodParam(paramIdx),
Types.getTypeHandle(constructor, injectionPoint.getRequiredType(), tccl),
Types.getTypeHandle(constructor, injectionPoint.getType(), tccl),
requiredQualifiersHandle, annotationsHandle, javaMemberHandle, constructor.load(injectionPoint.getPosition()));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.arc.processor;

import java.util.Collection;
import org.jboss.jandex.DotName;

/**
Expand Down Expand Up @@ -45,6 +46,10 @@ default <T> BeanConfigurator<T> configure(Class<?> beanClass) {
*/
BeanStream beans();

default Collection<InjectionPointInfo> getInjectionPoints() {
return get(BuildExtension.Key.INJECTION_POINTS);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ static void resolveInjectionPoint(BeanDeployment deployment, InjectionTargetInfo
errors.add(new DefinitionException("EventMetadata can be only injected into an observer method: "
+ injectionPoint.getTargetInfo()));
} else if (BuiltinBean.INSTANCE == builtinBean
&& injectionPoint.getRequiredType().kind() != Kind.PARAMETERIZED_TYPE) {
&& injectionPoint.getType().kind() != Kind.PARAMETERIZED_TYPE) {
errors.add(
new DefinitionException("An injection point of raw type javax.enterprise.inject.Instance is defined: "
+ injectionPoint.getTargetInfo()));
Expand Down Expand Up @@ -510,7 +510,7 @@ static void resolveInjectionPoint(BeanDeployment deployment, InjectionTargetInfo

private static void addStandardErroneousDependencyMessage(InjectionTargetInfo target, InjectionPointInfo injectionPoint,
StringBuilder message) {
message.append(injectionPoint.getRequiredType());
message.append(injectionPoint.getType());
message.append(" and qualifiers ");
message.append(injectionPoint.getRequiredQualifiers());
message.append("\n\t- java member: ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ enum BuiltinBean {
ResultHandle qualifiers = BeanGenerator.collectInjectionPointQualifiers(ctx.classOutput, ctx.clazzCreator,
ctx.beanDeployment,
ctx.constructor, ctx.injectionPoint, ctx.annotationLiterals);
ResultHandle parameterizedType = Types.getTypeHandle(ctx.constructor, ctx.injectionPoint.getRequiredType());
ResultHandle parameterizedType = Types.getTypeHandle(ctx.constructor, ctx.injectionPoint.getType());
ResultHandle annotationsHandle = BeanGenerator.collectInjectionPointAnnotations(ctx.classOutput, ctx.clazzCreator,
ctx.beanDeployment,
ctx.constructor, ctx.injectionPoint, ctx.annotationLiterals, ctx.injectionPointAnnotationsPredicate);
Expand Down Expand Up @@ -149,7 +149,7 @@ enum BuiltinBean {
}
}
}
ResultHandle parameterizedType = Types.getTypeHandle(ctx.constructor, ctx.injectionPoint.getRequiredType());
ResultHandle parameterizedType = Types.getTypeHandle(ctx.constructor, ctx.injectionPoint.getType());
ResultHandle eventProvider = ctx.constructor.newInstance(
MethodDescriptor.ofConstructor(EventProvider.class, java.lang.reflect.Type.class,
Set.class),
Expand All @@ -175,7 +175,7 @@ enum BuiltinBean {
Types.getPackageName(ctx.clazzCreator.getClassName())));
}
}
ResultHandle parameterizedType = Types.getTypeHandle(ctx.constructor, ctx.injectionPoint.getRequiredType());
ResultHandle parameterizedType = Types.getTypeHandle(ctx.constructor, ctx.injectionPoint.getType());
ResultHandle resourceProvider = ctx.constructor.newInstance(
MethodDescriptor.ofConstructor(ResourceProvider.class, java.lang.reflect.Type.class,
Set.class),
Expand Down Expand Up @@ -283,7 +283,7 @@ private static boolean isCdiAndRawTypeMatches(InjectionPointInfo injectionPoint,
return false;
}
for (DotName rawTypeDotName : rawTypeDotNames) {
if (rawTypeDotName.equals(injectionPoint.getRequiredType().name())) {
if (rawTypeDotName.equals(injectionPoint.getType().name())) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,38 @@ InjectionPointKind getKind() {
return kind;
}

/**
* Note that for programmatic lookup, the required type is the type parameter specified at the injection point. For example,
* the required type for an injection point of type {@code Instance<org.acme.Foo>} is {@code org.acme.Foo}.
*
* @return the required type of this injection point
*/
public Type getRequiredType() {
Type requiredType = typeAndQualifiers.type;
if (isProgrammaticLookup() && requiredType.kind() == org.jboss.jandex.Type.Kind.PARAMETERIZED_TYPE) {
requiredType = requiredType.asParameterizedType().arguments().get(0);
}
return requiredType;
}

/**
* This method always returns the original type declared on the injection point, unlike {@link #getRequiredType()}.
*
* @return the type specified at the injection point
*/
public Type getType() {
return typeAndQualifiers.type;
}

/**
* @return <code>true</code> if this injection represents a dynamically obtained instance, <code>false</code> otherwise
*/
public boolean isProgrammaticLookup() {
DotName requiredTypeName = typeAndQualifiers.type.name();
return DotNames.INSTANCE.equals(requiredTypeName) || DotNames.INJECTABLE_INSTANCE.equals(requiredTypeName)
|| DotNames.PROVIDER.equals(requiredTypeName);
}

public Set<AnnotationInstance> getRequiredQualifiers() {
return typeAndQualifiers.qualifiers;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ protected void createConstructor(ClassOutput classOutput, ClassCreator observerC
Supplier.class, java.lang.reflect.Type.class,
Set.class, Set.class, Member.class, int.class),
constructor.loadNull(), delegateSupplier,
Types.getTypeHandle(constructor, injectionPoint.getRequiredType()),
Types.getTypeHandle(constructor, injectionPoint.getType()),
requiredQualifiersHandle, annotationsHandle, javaMemberHandle,
constructor.load(injectionPoint.getPosition()));
ResultHandle wrapSupplierHandle = constructor.newInstance(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ protected FieldDescriptor createConstructor(ClassOutput classOutput, BeanInfo be
Optional<Injection> constructorInjection = bean.getConstructorInjection();
if (constructorInjection.isPresent()) {
for (InjectionPointInfo injectionPoint : constructorInjection.get().injectionPoints) {
parameterTypes.add(injectionPoint.getRequiredType().name().toString());
parameterTypes.add(injectionPoint.getType().name().toString());
}
}
int superParamsSize = parameterTypes.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.quarkus.arc.processor.BeanDeploymentValidator;
import io.quarkus.arc.processor.BeanInfo;
import io.quarkus.arc.processor.BeanRegistrar;
import io.quarkus.arc.processor.InjectionPointInfo;
import io.quarkus.arc.processor.ObserverInfo;
import io.quarkus.arc.test.ArcTestContainer;
import java.util.Collection;
Expand All @@ -20,6 +21,7 @@
import javax.enterprise.context.Initialized;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
import javax.inject.Named;
import org.jboss.jandex.DotName;
Expand Down Expand Up @@ -56,6 +58,11 @@ static class TestValidator implements BeanDeploymentValidator {

@Override
public void validate(ValidationContext context) {
assertTrue(context.getInjectionPoints().stream().filter(InjectionPointInfo::isProgrammaticLookup)
.filter(ip -> ip.getTarget().kind() == org.jboss.jandex.AnnotationTarget.Kind.FIELD
&& ip.getTarget().asField().name().equals("foo"))
.findFirst().isPresent());

assertFalse(context.removedBeans().withBeanClass(UselessBean.class).isEmpty());

assertFalse(context.beans().classBeans().withBeanClass(Alpha.class).isEmpty());
Expand Down Expand Up @@ -88,6 +95,9 @@ static class Alpha {
@Inject
List<String> strings;

@Inject
Instance<String> foo;

void observeAppContextInit(@Observes @Initialized(ApplicationScoped.class) Object event) {
}

Expand Down

0 comments on commit 7a0ee7a

Please sign in to comment.