Skip to content

Commit

Permalink
Merge pull request #24353 from mkouba/arc-validate-type-params
Browse files Browse the repository at this point in the history
ArC - injection point validation
  • Loading branch information
mkouba authored Mar 18, 2022
2 parents b3e2cf0 + 58eada9 commit 1b07b91
Show file tree
Hide file tree
Showing 13 changed files with 449 additions and 174 deletions.
2 changes: 2 additions & 0 deletions docs/src/main/asciidoc/cdi-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,8 @@ public class Processor {
}
----

NOTE: Neither a type variable nor a wildcard is a legal type parameter for an `@All List<>` injection point, i.e. `@Inject @All List<?> all` is not supported and results in a deployment error.

=== Ignoring Class-Level Interceptor Bindings for Methods and Constructors

If a managed bean declares interceptor binding annotations on the class level, the corresponding `@AroundInvoke` interceptors will apply to all business methods.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.AmbiguousResolutionException;
import javax.enterprise.inject.UnsatisfiedResolutionException;
import javax.enterprise.inject.spi.DefinitionException;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
Expand Down Expand Up @@ -422,7 +423,8 @@ public ObserverRegistrationPhaseBuildItem registerSyntheticObservers(BeanRegistr
List<BeanConfiguratorBuildItem> beanConfigurators,
BuildProducer<ReflectiveMethodBuildItem> reflectiveMethods,
BuildProducer<ReflectiveFieldBuildItem> reflectiveFields,
BuildProducer<UnremovableBeanBuildItem> unremovableBeans) {
BuildProducer<UnremovableBeanBuildItem> unremovableBeans,
BuildProducer<ValidationPhaseBuildItem.ValidationErrorBuildItem> validationErrors) {

for (BeanConfiguratorBuildItem configurator : beanConfigurators) {
// Just make sure the configurator is processed
Expand All @@ -435,6 +437,18 @@ public ObserverRegistrationPhaseBuildItem registerSyntheticObservers(BeanRegistr
// Register a synthetic bean for each List<?> with qualifier @All
List<InjectionPointInfo> listAll = beanRegistrationPhase.getInjectionPoints().stream()
.filter(this::isListAllInjectionPoint).collect(Collectors.toList());
for (InjectionPointInfo injectionPoint : listAll) {
// Note that at this point we can be sure that the required type is List<>
Type typeParam = injectionPoint.getType().asParameterizedType().arguments().get(0);
if (typeParam.kind() == Type.Kind.WILDCARD_TYPE) {
validationErrors.produce(new ValidationErrorBuildItem(
new DefinitionException(
"Wildcard is not a legal type argument for " + injectionPoint.getTargetInfo())));
} else if (typeParam.kind() == Type.Kind.TYPE_VARIABLE) {
validationErrors.produce(new ValidationErrorBuildItem(new DefinitionException(
"Type variable is not a legal type argument for " + injectionPoint.getTargetInfo())));
}
}
if (!listAll.isEmpty()) {
registerListInjectionPointsBeans(beanRegistrationPhase, listAll, reflectiveMethods, reflectiveFields,
unremovableBeans);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.quarkus.arc.test.lookup;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.enterprise.inject.spi.DeploymentException;
import javax.inject.Inject;
import javax.inject.Singleton;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.All;
import io.quarkus.runtime.util.ExceptionUtil;
import io.quarkus.test.QuarkusUnitTest;

public class ListInvalidTypeParamTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot(root -> root.addClasses(Foo.class)).assertException(t -> {
Throwable rootCause = ExceptionUtil.getRootCause(t);
assertTrue(rootCause instanceof DeploymentException);
String suppressedMessage = Arrays.stream(rootCause.getSuppressed()).map(Throwable::getMessage)
.collect(Collectors.joining("::"));
assertTrue(suppressedMessage.contains("Type variable is not a legal type argument"), rootCause.toString());
assertTrue(suppressedMessage.contains("Wildcard is not a legal type argument"), rootCause.toString());
});

@Test
public void testFailure() {
fail();
}

@Singleton
static class Foo<T> {

@Inject
@All
List<T> services;

@All
List<?> counters;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class InjectionFailedTest {
assertTrue(s.getMessage().contains(
"No template found for path [foo] defined at io.quarkus.qute.deployment.inject.InjectionFailedTest#foo")
|| s.getMessage().contains(
"No template found for path [alpha] defined at io.quarkus.qute.deployment.inject.InjectionFailedTest$Client().alpha"),
"No template found for path [alpha] defined at io.quarkus.qute.deployment.inject.InjectionFailedTest$Client()"),
s.getMessage());
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,8 +520,12 @@ void init(List<Throwable> errors, Consumer<BytecodeTransformer> bytecodeTransfor
if (injectionPoint.isDelegate() && !isDecorator()) {
errors.add(new DeploymentException(String.format(
"Only decorators can declare a delegate injection point: %s", this)));
} else if (injectionPoint.getType().kind() == org.jboss.jandex.Type.Kind.TYPE_VARIABLE) {
errors.add(new DefinitionException(String.format("Type variable is not a legal injection point type: %s",
injectionPoint.getTargetInfo())));
} else {
Beans.resolveInjectionPoint(beanDeployment, this, injectionPoint, errors);
}
Beans.resolveInjectionPoint(beanDeployment, this, injectionPoint, errors);
}
}
if (disposer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static io.quarkus.arc.processor.IndexClassLookupUtils.getClassByName;

import io.quarkus.arc.processor.InjectionPointInfo.TypeAndQualifiers;
import io.quarkus.arc.processor.InjectionTargetInfo.TargetKind;
import io.quarkus.gizmo.Gizmo;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
Expand Down Expand Up @@ -387,20 +386,7 @@ static void resolveInjectionPoint(BeanDeployment deployment, InjectionTargetInfo
}
BuiltinBean builtinBean = BuiltinBean.resolve(injectionPoint);
if (builtinBean != null) {
if (BuiltinBean.INJECTION_POINT == builtinBean
&& (target.kind() != TargetKind.BEAN || !BuiltinScope.DEPENDENT.is(target.asBean().getScope()))) {
errors.add(new DefinitionException("Only @Dependent beans can access metadata about an injection point: "
+ injectionPoint.getTargetInfo()));
} else if (BuiltinBean.EVENT_METADATA == builtinBean
&& target.kind() != TargetKind.OBSERVER) {
errors.add(new DefinitionException("EventMetadata can be only injected into an observer method: "
+ injectionPoint.getTargetInfo()));
} else if (BuiltinBean.INSTANCE == builtinBean
&& injectionPoint.getType().kind() != Kind.PARAMETERIZED_TYPE) {
errors.add(
new DefinitionException("An injection point of raw type javax.enterprise.inject.Instance is defined: "
+ injectionPoint.getTargetInfo()));
}
builtinBean.validate(target, injectionPoint, errors::add);
// Skip built-in beans
return;
}
Expand Down
Loading

0 comments on commit 1b07b91

Please sign in to comment.