Skip to content

Commit

Permalink
ArC - handle types of removed beans more leniently
Browse files Browse the repository at this point in the history
- log a warning if unable to load a bean type of a removed bean
- previously the app failed at startup
- resolves #24338
  • Loading branch information
mkouba committed Mar 18, 2022
1 parent d557068 commit b0c73fa
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
import io.quarkus.arc.ComponentsProvider;
import io.quarkus.arc.InjectableBean;
import io.quarkus.arc.processor.ResourceOutput.Resource;
import io.quarkus.gizmo.AssignableResultHandle;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.CatchBlockCreator;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.gizmo.FieldDescriptor;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.gizmo.TryBlock;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -120,8 +124,10 @@ Collection<Resource> generate(String name, BeanDeployment beanDeployment, Map<Be

// Break removed beans processing into multiple addRemovedBeans() methods
ResultHandle removedBeansHandle = getComponents.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
ResultHandle typeCacheHandle = getComponents.newInstance(MethodDescriptor.ofConstructor(HashMap.class));
if (detectUnusedFalsePositives) {
processRemovedBeans(componentsProvider, getComponents, removedBeansHandle, beanDeployment, classOutput);
processRemovedBeans(componentsProvider, getComponents, removedBeansHandle, typeCacheHandle, beanDeployment,
classOutput);
}

// Qualifier non-binding members
Expand Down Expand Up @@ -232,9 +238,10 @@ private void processObservers(ClassCreator componentsProvider, MethodCreator get
}

private void processRemovedBeans(ClassCreator componentsProvider, MethodCreator getComponents,
ResultHandle removedBeansHandle, BeanDeployment beanDeployment, ClassOutput classOutput) {
ResultHandle removedBeansHandle, ResultHandle typeCacheHandle, BeanDeployment beanDeployment,
ClassOutput classOutput) {
try (RemovedBeanAdder removedBeanAdder = new RemovedBeanAdder(componentsProvider, getComponents, removedBeansHandle,
classOutput)) {
typeCacheHandle, classOutput)) {
for (BeanInfo remnovedBean : beanDeployment.getRemovedBeans()) {
removedBeanAdder.addComponent(remnovedBean);
}
Expand Down Expand Up @@ -385,43 +392,49 @@ void addComponentInternal(ObserverInfo observer) {
class RemovedBeanAdder extends ComponentAdder<BeanInfo> {

private final ResultHandle removedBeansHandle;
private final ResultHandle typeCacheHandle;
private final ClassOutput classOutput;
private ResultHandle tccl;
// Shared annotation literals for an individual addRemovedBeansX() method
private final Map<AnnotationInstanceKey, ResultHandle> sharedQualifers;
// Shared java.lang.reflect.Type instances for an individual addRemovedBeansX() method
private final Map<org.jboss.jandex.Type, ResultHandle> sharedTypes;

private final MapTypeCache typeCache;

public RemovedBeanAdder(ClassCreator componentsProvider, MethodCreator getComponentsMethod,
ResultHandle removedBeansHandle, ClassOutput classOutput) {
ResultHandle removedBeansHandle, ResultHandle typeCacheHandle, ClassOutput classOutput) {
super(getComponentsMethod, componentsProvider);
this.removedBeansHandle = removedBeansHandle;
this.typeCacheHandle = typeCacheHandle;
this.classOutput = classOutput;
this.sharedQualifers = new HashMap<>();
this.sharedTypes = new HashMap<>();
this.typeCache = new MapTypeCache();
}

@Override
MethodCreator newAddMethod() {
// Clear the shared maps for each addRemovedBeansX() method
sharedQualifers.clear();
sharedTypes.clear();

MethodCreator addMethod = componentsProvider.getMethodCreator(ADD_REMOVED_BEANS + group++, void.class, List.class)
// private void addRemovedBeans1(List removedBeans, List typeCache)
MethodCreator addMethod = componentsProvider
.getMethodCreator(ADD_REMOVED_BEANS + group++, void.class, List.class, Map.class)
.setModifiers(ACC_PRIVATE);
// Get the TCCL - we will use it later
ResultHandle currentThread = addMethod
.invokeStaticMethod(MethodDescriptors.THREAD_CURRENT_THREAD);
tccl = addMethod.invokeVirtualMethod(MethodDescriptors.THREAD_GET_TCCL, currentThread);

typeCache.initialize(addMethod);

return addMethod;
}

@Override
void invokeAddMethod() {
getComponentsMethod.invokeVirtualMethod(
MethodDescriptor.ofMethod(componentsProvider.getClassName(),
addMethod.getMethodDescriptor().getName(), void.class, List.class),
getComponentsMethod.getThis(), removedBeansHandle);
addMethod.getMethodDescriptor().getName(), void.class, List.class, Map.class),
getComponentsMethod.getThis(), removedBeansHandle, typeCacheHandle);
}

@Override
Expand All @@ -436,14 +449,20 @@ void addComponentInternal(BeanInfo removedBean) {
// Skip java.lang.Object
continue;
}
ResultHandle typeHandle;

TryBlock tryBlock = addMethod.tryBlock();
CatchBlockCreator catchBlock = tryBlock.addCatch(Throwable.class);
catchBlock.invokeStaticInterfaceMethod(
MethodDescriptors.COMPONENTS_PROVIDER_UNABLE_TO_LOAD_REMOVED_BEAN_TYPE,
catchBlock.load(type.toString()), catchBlock.getCaughtException());
AssignableResultHandle typeHandle = tryBlock.createVariable(Object.class);
try {
typeHandle = Types.getTypeHandle(addMethod, type, tccl, sharedTypes);
Types.getTypeHandle(typeHandle, tryBlock, type, tccl, typeCache);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(
"Unable to construct the type handle for " + removedBean + ": " + e.getMessage());
}
addMethod.invokeInterfaceMethod(MethodDescriptors.SET_ADD, typesHandle, typeHandle);
tryBlock.invokeInterfaceMethod(MethodDescriptors.SET_ADD, typesHandle, typeHandle);
}

// Qualifiers
Expand Down Expand Up @@ -513,6 +532,27 @@ void addComponentInternal(BeanInfo removedBean) {

}

static class MapTypeCache implements Types.TypeCache {

private ResultHandle mapHandle;

@Override
public void initialize(MethodCreator method) {
this.mapHandle = method.getMethodParam(1);
}

@Override
public ResultHandle get(org.jboss.jandex.Type type, BytecodeCreator bytecode) {
return bytecode.invokeInterfaceMethod(MethodDescriptors.MAP_GET, mapHandle, bytecode.load(type.toString()));
}

@Override
public void put(org.jboss.jandex.Type type, ResultHandle value, BytecodeCreator bytecode) {
bytecode.invokeInterfaceMethod(MethodDescriptors.MAP_PUT, mapHandle, bytecode.load(type.toString()), value);
}

}

static class BeanAdder extends ComponentAdder<BeanInfo> {

private final Set<BeanInfo> processedBeans;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.ClientProxy;
import io.quarkus.arc.ComponentsProvider;
import io.quarkus.arc.InjectableBean;
import io.quarkus.arc.InjectableBean.Kind;
import io.quarkus.arc.InjectableContext;
Expand Down Expand Up @@ -80,6 +81,8 @@ public final class MethodDescriptors {

public static final MethodDescriptor LIST_ADD = MethodDescriptor.ofMethod(List.class, "add", boolean.class, Object.class);

public static final MethodDescriptor LIST_GET = MethodDescriptor.ofMethod(List.class, "get", Object.class, int.class);

public static final MethodDescriptor OBJECT_EQUALS = MethodDescriptor.ofMethod(Object.class, "equals", boolean.class,
Object.class);

Expand Down Expand Up @@ -265,6 +268,10 @@ public final class MethodDescriptors {
.ofMethod(Instances.class, "listOfHandles", List.class, InjectableBean.class, Type.class, Type.class,
Set.class, CreationalContextImpl.class, Set.class, Member.class, int.class);

public static final MethodDescriptor COMPONENTS_PROVIDER_UNABLE_TO_LOAD_REMOVED_BEAN_TYPE = MethodDescriptor.ofMethod(
ComponentsProvider.class, "unableToLoadRemovedBeanType",
void.class, String.class, Throwable.class);

private MethodDescriptors() {
}

Expand Down
Loading

0 comments on commit b0c73fa

Please sign in to comment.