Skip to content

Commit

Permalink
Make it possible to initialize a synthetic bean during RUNTIME_INIT
Browse files Browse the repository at this point in the history
- follows up on quarkusio#5938
  • Loading branch information
mkouba authored and gsmet committed Mar 26, 2020
1 parent 6c87815 commit 1951f44
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.quarkus.arc.processor.BeanConfigurator;
import io.quarkus.arc.processor.BeanConfiguratorBase;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.runtime.RuntimeValue;

/**
Expand Down Expand Up @@ -36,16 +37,22 @@ public ExtendedBeanConfigurator configurator() {
return configurator;
}

public boolean isStaticInit() {
return configurator.staticInit;
}

/**
* This construct is not thread-safe and should not be reused.
*/
public static class ExtendedBeanConfigurator extends BeanConfiguratorBase<ExtendedBeanConfigurator, Object> {

Supplier<?> supplier;
RuntimeValue<?> runtimeValue;
boolean staticInit;

ExtendedBeanConfigurator(DotName implClazz) {
super(implClazz);
this.staticInit = true;
}

/**
Expand Down Expand Up @@ -73,6 +80,18 @@ public ExtendedBeanConfigurator runtimeValue(RuntimeValue<?> runtimeValue) {
return this;
}

/**
* By default, synthetic beans are initialized during {@link ExecutionTime#STATIC_INIT}. It is possible to mark a
* synthetic bean to be initialized during {@link ExecutionTime#RUNTIME_INIT}. However, in such case a client that
* attempts to obtain such bean during {@link ExecutionTime#STATIC_INIT} will receive an exception.
*
* @return self
*/
public ExtendedBeanConfigurator setRuntimeInit() {
this.staticInit = false;
return this;
}

public DotName getImplClazz() {
return implClazz;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import javax.enterprise.inject.CreationException;

import org.jboss.jandex.DotName;

import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem;
Expand Down Expand Up @@ -71,21 +73,42 @@ void build(ArcRecorder recorder, List<RuntimeBeanBuildItem> runtimeBeans, List<S
}

for (SyntheticBeanBuildItem bean : syntheticBeans) {
DotName implClazz = bean.configurator().getImplClazz();
String name = createName(implClazz.toString(), bean.configurator().getQualifiers().toString());
if (bean.configurator().runtimeValue != null) {
suppliersMap.put(name, recorder.createSupplier(bean.configurator().runtimeValue));
} else {
suppliersMap.put(name, bean.configurator().supplier);
if (bean.isStaticInit()) {
initSyntheticBean(recorder, suppliersMap, beanRegistration, bean);
}
beanRegistration.getContext().configure(implClazz)
.read(bean.configurator())
.creator(creator(name))
.done();
}

// Init the map of bean instances
recorder.initSupplierBeans(suppliersMap);
recorder.initStaticSupplierBeans(suppliersMap);
}

@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
void build(ArcRecorder recorder, List<SyntheticBeanBuildItem> syntheticBeans,
BeanRegistrationPhaseBuildItem beanRegistration, BuildProducer<BeanConfiguratorBuildItem> configurators) {

Map<String, Supplier<?>> suppliersMap = new HashMap<>();

for (SyntheticBeanBuildItem bean : syntheticBeans) {
if (!bean.isStaticInit()) {
initSyntheticBean(recorder, suppliersMap, beanRegistration, bean);
}
}
recorder.initRuntimeSupplierBeans(suppliersMap);
}

private void initSyntheticBean(ArcRecorder recorder, Map<String, Supplier<?>> suppliersMap,
BeanRegistrationPhaseBuildItem beanRegistration, SyntheticBeanBuildItem bean) {
DotName implClazz = bean.configurator().getImplClazz();
String name = createName(implClazz.toString(), bean.configurator().getQualifiers().toString());
if (bean.configurator().runtimeValue != null) {
suppliersMap.put(name, recorder.createSupplier(bean.configurator().runtimeValue));
} else {
suppliersMap.put(name, bean.configurator().supplier);
}
beanRegistration.getContext().configure(implClazz)
.read(bean.configurator())
.creator(creator(name))
.done();
}

private String createName(String beanClass, String qualifiers) {
Expand All @@ -102,6 +125,9 @@ public void accept(MethodCreator m) {
ResultHandle supplier = m.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Map.class, "get", Object.class, Object.class), staticMap,
m.load(name));
// Throw an exception if no supplier is found
m.ifNull(supplier).trueBranch().throwException(CreationException.class,
"Synthetic bean instance not initialized yet: " + name);
ResultHandle result = m.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Supplier.class, "get", Object.class),
supplier);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,14 @@ public void initExecutor(ExecutorService executor) {
Arc.setExecutor(executor);
}

public void initSupplierBeans(Map<String, Supplier<?>> beans) {
public void initStaticSupplierBeans(Map<String, Supplier<?>> beans) {
supplierMap = new ConcurrentHashMap<>(beans);
}

public void initRuntimeSupplierBeans(Map<String, Supplier<?>> beans) {
supplierMap.putAll(beans);
}

public BeanContainer initBeanContainer(ArcContainer container, List<BeanContainerListener> listeners,
Collection<String> removedBeanTypes)
throws Exception {
Expand Down

0 comments on commit 1951f44

Please sign in to comment.