Skip to content

Commit

Permalink
Merge pull request quarkusio#30509 from Ladicek/arc-fixes
Browse files Browse the repository at this point in the history
ArC fixes for spec compatibility
  • Loading branch information
gsmet authored Jan 25, 2023
2 parents deb137e + b5d825a commit 6faf038
Show file tree
Hide file tree
Showing 17 changed files with 510 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ private List<BeanInfo> findBeans(Collection<DotName> beanDefiningAnnotations, Li
}
}

if (annotationStore.hasAnnotation(beanClass, DotNames.VETOED)) {
if (isVetoed(beanClass)) {
// Skip vetoed bean classes
continue;
}
Expand Down Expand Up @@ -1094,6 +1094,20 @@ private List<BeanInfo> findBeans(Collection<DotName> beanDefiningAnnotations, Li
return beans;
}

private boolean isVetoed(ClassInfo beanClass) {
if (annotationStore.hasAnnotation(beanClass, DotNames.VETOED)) {
return true;
}

// using immutable index, because we expect that if class is discovered,
// the whole package is indexed (otherwise we'd get a lot of warnings that
// package-info.class couldn't be loaded during on-demand indexing)
String packageName = beanClass.name().packagePrefix();
org.jboss.jandex.ClassInfo packageClass = beanArchiveImmutableIndex.getClassByName(
DotName.createSimple(packageName + ".package-info"));
return packageClass != null && annotationStore.hasAnnotation(packageClass, DotNames.VETOED);
}

private boolean isExcluded(ClassInfo beanClass) {
if (!excludeTypes.isEmpty()) {
for (Predicate<ClassInfo> exclude : excludeTypes) {
Expand Down Expand Up @@ -1250,7 +1264,7 @@ private List<InterceptorInfo> findInterceptors(List<InjectionPointInfo> injectio
}
List<InterceptorInfo> interceptors = new ArrayList<>();
for (ClassInfo interceptorClass : interceptorClasses.values()) {
if (annotationStore.hasAnnotation(interceptorClass, DotNames.VETOED) || isExcluded(interceptorClass)) {
if (isVetoed(interceptorClass) || isExcluded(interceptorClass)) {
// Skip vetoed interceptors
continue;
}
Expand All @@ -1277,7 +1291,7 @@ private List<DecoratorInfo> findDecorators(List<InjectionPointInfo> injectionPoi
}
List<DecoratorInfo> decorators = new ArrayList<>();
for (ClassInfo decoratorClass : decoratorClasses.values()) {
if (annotationStore.hasAnnotation(decoratorClass, DotNames.VETOED) || isExcluded(decoratorClass)) {
if (isVetoed(decoratorClass) || isExcluded(decoratorClass)) {
// Skip vetoed decorators
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -868,16 +868,19 @@ protected void implementDestroy(BeanInfo bean, ClassCreator beanCreator, Provide
if (i == disposedParamPosition) {
referenceHandles[i] = destroy.getMethodParam(0);
} else {
InjectionPointInfo injectionPoint = injectionPointsIterator.next();
ResultHandle childCtxHandle = destroy.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL,
declaringProviderHandle, ctxHandle);
ResultHandle providerSupplierHandle = destroy
.readInstanceField(FieldDescriptor.of(beanCreator.getClassName(),
injectionPointToProviderField.get(injectionPointsIterator.next()),
injectionPointToProviderField.get(injectionPoint),
Supplier.class.getName()), destroy.getThis());
ResultHandle providerHandle = destroy.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET,
providerSupplierHandle);
ResultHandle referenceHandle = destroy.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle);
AssignableResultHandle referenceHandle = destroy.createVariable(Object.class);
destroy.assign(referenceHandle, destroy.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle));
checkPrimitiveInjection(destroy, injectionPoint, referenceHandle);
referenceHandles[i] = referenceHandle;
}
}
Expand Down Expand Up @@ -998,8 +1001,10 @@ private void newProviderHandles(BeanInfo bean, ClassCreator beanCreator, MethodC
providerSupplierHandle);
ResultHandle childCtx = createMethod.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL,
providerHandle, createMethod.getMethodParam(0));
ResultHandle referenceHandle = createMethod.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtx);
AssignableResultHandle referenceHandle = createMethod.createVariable(Object.class);
createMethod.assign(referenceHandle, createMethod
.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET, providerHandle, childCtx));
checkPrimitiveInjection(createMethod, injectionPoint, referenceHandle);
injectableParamHandles.add(referenceHandle);
if (injectionPoint.isDependentTransientReference()) {
transientReferences.add(new TransientReference(providerHandle, referenceHandle, childCtx));
Expand Down Expand Up @@ -1033,6 +1038,24 @@ private void newProviderHandles(BeanInfo bean, ClassCreator beanCreator, MethodC
}
}

static void checkPrimitiveInjection(BytecodeCreator bytecode, InjectionPointInfo injectionPoint,
AssignableResultHandle referenceHandle) {
if (injectionPoint.getType().kind() == Type.Kind.PRIMITIVE) {
Type type = null;
if (injectionPoint.getResolvedBean().isProducerField()) {
type = injectionPoint.getResolvedBean().getTarget().get().asField().type();
} else if (injectionPoint.getResolvedBean().isProducerMethod()) {
type = injectionPoint.getResolvedBean().getTarget().get().asMethod().returnType();
}

if (type != null && Types.isPrimitiveWrapperType(type)) {
BytecodeCreator isNull = bytecode.ifNull(referenceHandle).trueBranch();
isNull.assign(referenceHandle,
Types.loadPrimitiveDefault(injectionPoint.getType().asPrimitiveType().primitive(), isNull));
}
}
}

private ResultHandle newInstanceHandle(BeanInfo bean, ClassCreator beanCreator, BytecodeCreator creator,
MethodCreator createMethod,
String providerTypeName, String baseName, List<ResultHandle> providerHandles, ReflectionRegistration registration,
Expand Down Expand Up @@ -1234,8 +1257,10 @@ void implementCreateForProducerMethod(ClassOutput classOutput, ClassCreator bean
providerSupplierHandle);
ResultHandle childCtxHandle = create.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL,
providerHandle, create.getMethodParam(0));
ResultHandle referenceHandle = create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle);
AssignableResultHandle referenceHandle = create.createVariable(Object.class);
create.assign(referenceHandle, create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle));
checkPrimitiveInjection(create, injectionPoint, referenceHandle);
referenceHandles[paramIdx++] = referenceHandle;
// We need to destroy dependent beans for @TransientReference injection points
if (injectionPoint.isDependentTransientReference()) {
Expand Down Expand Up @@ -1501,8 +1526,10 @@ void implementCreateForClassBean(ClassOutput classOutput, ClassCreator beanCreat
MethodDescriptors.SUPPLIER_GET, providerSupplierHandle);
ResultHandle childCtxHandle = tryBlock.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL,
providerHandle, tryBlock.getMethodParam(0));
ResultHandle referenceHandle = tryBlock.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle);
AssignableResultHandle referenceHandle = tryBlock.createVariable(Object.class);
tryBlock.assign(referenceHandle, tryBlock.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle));
checkPrimitiveInjection(tryBlock, injectionPoint, referenceHandle);

FieldInfo injectedField = fieldInjection.target.asField();
// only use reflection fallback if we are not performing transformation
Expand Down Expand Up @@ -1541,8 +1568,10 @@ void implementCreateForClassBean(ClassOutput classOutput, ClassCreator beanCreat
providerSupplierHandle);
ResultHandle childCtxHandle = create.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD_CONTEXTUAL,
providerHandle, create.getMethodParam(0));
ResultHandle referenceHandle = create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle);
AssignableResultHandle referenceHandle = create.createVariable(Object.class);
create.assign(referenceHandle, create.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle));
checkPrimitiveInjection(create, injectionPoint, referenceHandle);
referenceHandles[paramIdx++] = referenceHandle;
// We need to destroy dependent beans for @TransientReference injection points
if (injectionPoint.isDependentTransientReference()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;

import javax.enterprise.inject.spi.DefinitionException;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationTarget.Kind;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
Expand All @@ -31,12 +34,28 @@
*/
public class InjectionPointInfo {

private static boolean isNamedWithoutValue(AnnotationInstance annotation) {
if (annotation.name().equals(DotNames.NAMED)) {
AnnotationValue name = annotation.value();
return name == null || name.asString().isEmpty();
}
return false;
}

static InjectionPointInfo fromField(FieldInfo field, ClassInfo beanClass, BeanDeployment beanDeployment,
InjectionPointModifier transformer) {
Set<AnnotationInstance> qualifiers = new HashSet<>();
Collection<AnnotationInstance> annotations = beanDeployment.getAnnotations(field);
for (AnnotationInstance annotation : annotations) {
beanDeployment.extractQualifiers(annotation).forEach(qualifiers::add);
for (AnnotationInstance annotationInstance : beanDeployment.extractQualifiers(annotation)) {
// if the qualifier is `@Named` without value, replace it with `@Named(fieldName)
if (isNamedWithoutValue(annotationInstance)) {
annotationInstance = AnnotationInstance.builder(annotationInstance.name())
.value(field.name())
.buildWithTarget(annotationInstance.target());
}
qualifiers.add(annotationInstance);
}
}
Type type = resolveType(field.type(), beanClass, field.declaringClass(), beanDeployment);
return new InjectionPointInfo(type,
Expand Down Expand Up @@ -70,7 +89,12 @@ static List<InjectionPointInfo> fromMethod(MethodInfo method, ClassInfo beanClas
}
Set<AnnotationInstance> paramQualifiers = new HashSet<>();
for (AnnotationInstance paramAnnotation : paramAnnotations) {
beanDeployment.extractQualifiers(paramAnnotation).forEach(paramQualifiers::add);
for (AnnotationInstance annotationInstance : beanDeployment.extractQualifiers(paramAnnotation)) {
if (isNamedWithoutValue(annotationInstance)) {
throw new DefinitionException("@Named without value may not be used on method parameter: " + method);
}
paramQualifiers.add(annotationInstance);
}
}
Type type = resolveType(paramType, beanClass, method.declaringClass(), beanDeployment);
injectionPoints.add(new InjectionPointInfo(type,
Expand Down Expand Up @@ -259,7 +283,7 @@ public String toString() {
}

private static Type resolveType(Type type, ClassInfo beanClass, ClassInfo declaringClass, BeanDeployment beanDeployment) {
if (type.kind() == org.jboss.jandex.Type.Kind.CLASS) {
if (type.kind() == Type.Kind.PRIMITIVE || type.kind() == Type.Kind.CLASS) {
return type;
}
Map<ClassInfo, Map<String, Type>> resolvedTypeVariables = Types.resolvedTypeVariables(beanClass, beanDeployment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,15 +431,18 @@ protected void implementNotify(ObserverInfo observer, ClassCreator observerCreat
referenceHandles[i] = notify.invokeInterfaceMethod(MethodDescriptors.EVENT_CONTEXT_GET_METADATA,
notify.getMethodParam(0));
} else {
InjectionPointInfo injectionPoint = injectionPointsIterator.next();
ResultHandle childCtxHandle = notify.invokeStaticMethod(MethodDescriptors.CREATIONAL_CTX_CHILD, ctxHandle);
ResultHandle providerSupplierHandle = notify
.readInstanceField(FieldDescriptor.of(observerCreator.getClassName(),
injectionPointToProviderField.get(injectionPointsIterator.next()),
injectionPointToProviderField.get(injectionPoint),
Supplier.class.getName()), notify.getThis());
ResultHandle providerHandle = notify.invokeInterfaceMethod(MethodDescriptors.SUPPLIER_GET,
providerSupplierHandle);
ResultHandle referenceHandle = notify.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle);
AssignableResultHandle referenceHandle = notify.createVariable(Object.class);
notify.assign(referenceHandle, notify.invokeInterfaceMethod(MethodDescriptors.INJECTABLE_REF_PROVIDER_GET,
providerHandle, childCtxHandle));
BeanGenerator.checkPrimitiveInjection(notify, injectionPoint, referenceHandle);
referenceHandles[i] = referenceHandle;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;

Expand Down Expand Up @@ -55,18 +56,25 @@ public final class Types {

private static final Type OBJECT_TYPE = Type.create(DotNames.OBJECT, Kind.CLASS);

private static final Set<String> PRIMITIVE_CLASS_NAMES = new HashSet<>();

static {
PRIMITIVE_CLASS_NAMES.add("byte");
PRIMITIVE_CLASS_NAMES.add("char");
PRIMITIVE_CLASS_NAMES.add("double");
PRIMITIVE_CLASS_NAMES.add("float");
PRIMITIVE_CLASS_NAMES.add("int");
PRIMITIVE_CLASS_NAMES.add("long");
PRIMITIVE_CLASS_NAMES.add("short");
PRIMITIVE_CLASS_NAMES.add("boolean");
}
private static final Set<String> PRIMITIVE_CLASS_NAMES = Set.of(
"boolean",
"byte",
"short",
"int",
"long",
"float",
"double",
"char");

private static final Set<DotName> PRIMITIVE_WRAPPERS = Set.of(
DotNames.BOOLEAN,
DotNames.BYTE,
DotNames.SHORT,
DotNames.INTEGER,
DotNames.LONG,
DotNames.FLOAT,
DotNames.DOUBLE,
DotNames.CHARACTER);

// we ban these interfaces because they are new to Java 12 and are used by java.lang.String which
// means that they cannot be included in bytecode if we want to have application built with Java 12+ but targeting Java 8 - 11
Expand Down Expand Up @@ -744,6 +752,50 @@ static boolean isPrimitiveClassName(String className) {
return PRIMITIVE_CLASS_NAMES.contains(className);
}

static boolean isPrimitiveWrapperType(Type type) {
if (type.kind() == Kind.CLASS) {
return PRIMITIVE_WRAPPERS.contains(type.name());
}
return false;
}

/**
* Emits a bytecode instruction to load the default value of given {@code primitive} type
* into given {@code bytecode} creator and returns the {@link ResultHandle} of the loaded
* default value. The default primitive value is {@code 0} for integral types, {@code 0.0}
* for floating point types, {@code false} for {@code boolean} and the null character for
* {@code char}.
* <p>
* Can also be used to load a default primitive value of the corresponding wrapper type,
* because Gizmo will box automatically.
*
* @param primitive primitive type, must not be {@code null}
* @param bytecode bytecode creator that will receive the load instruction, must not be {@code null}
* @return a result handle of the loaded default primitive value
*/
static ResultHandle loadPrimitiveDefault(Primitive primitive, BytecodeCreator bytecode) {
switch (Objects.requireNonNull(primitive)) {
case BOOLEAN:
return bytecode.load(false);
case BYTE:
return bytecode.load((byte) 0);
case SHORT:
return bytecode.load((short) 0);
case INT:
return bytecode.load(0);
case LONG:
return bytecode.load(0L);
case FLOAT:
return bytecode.load(0.0F);
case DOUBLE:
return bytecode.load(0.0);
case CHAR:
return bytecode.load((char) 0);
default:
throw new IllegalArgumentException("Unknown primitive type: " + primitive);
}
}

static boolean containsTypeVariable(Type type) {
if (type.kind() == Kind.TYPE_VARIABLE) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public Object getReference(Bean<?> bean, Type beanType, CreationalContext<?> ctx
Objects.requireNonNull(bean, "Bean is null");
Objects.requireNonNull(beanType, "Bean type is null");
Objects.requireNonNull(ctx, "CreationalContext is null");
if (!BeanTypeAssignabilityRules.instance().matches(beanType, bean.getTypes())) {
throw new IllegalArgumentException("Type " + beanType + " is not a bean type of " + bean);
}
if (bean instanceof InjectableBean && ctx instanceof CreationalContextImpl) {
return ArcContainerImpl.instance().beanInstanceHandle((InjectableBean) bean, (CreationalContextImpl) ctx).get();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ protected boolean matches(Type requiredType, Type beanType) {
}

private boolean matchesNoBoxing(Type requiredType, Type beanType) {
if (Types.isArray(requiredType) && Types.isArray(beanType)) {
return matchesNoBoxing(Types.getArrayComponentType(requiredType), Types.getArrayComponentType(beanType));
}
if (requiredType instanceof Class<?>) {
if (beanType instanceof Class<?>) {
return matches((Class<?>) requiredType, (Class<?>) beanType);
Expand Down
Loading

0 comments on commit 6faf038

Please sign in to comment.