I would like to know how I can generate a bean having a dependency to an another bean (using generic Type).
I made a sample here: https://github.com/dcdh/quarkus-hello-world-playground
I've got this bean
@Singleton
public class DefaultHelloWorld extends HelloWorld<String> {
public DefaultHelloWorld(final HelloWorldDependency<String> helloWorldDependency) {
super(helloWorldDependency);
}
@Override
public String sayHello() {
return "DefaultHelloWorld";
}
}
And I am using this kind of code to generate the java code
@BuildStep(onlyIf = ShouldGenerateBean.class)
void helloWorldGenerator(final BuildProducer<GeneratedBeanBuildItem> generatedBeanBuildItemBuildProducer) {
final ClassOutput beansClassOutput = new GeneratedBeanGizmoAdaptor(generatedBeanBuildItemBuildProducer);
final ClassCreator beanClassCreator = ClassCreator.builder().classOutput(beansClassOutput)
.className(HelloWorld.class.getName() + "Generated")
.signature(
SignatureBuilder.forClass()
.setSuperClass(
Type.parameterizedType(
Type.classType(HelloWorld.class),
Type.classType(String.class))))
.build();
beanClassCreator.addAnnotation(Singleton.class);
beanClassCreator.addAnnotation(DefaultBean.class);
// constructor
final MethodCreator constructor = beanClassCreator.getMethodCreator(MethodDescriptor.INIT, void.class,
String.format("%s<%s>", HelloWorldDependency.class.getName(), String.class.getName()));
constructor.setModifiers(Modifier.PUBLIC);
ResultHandle supportHandle = getFromCDI(constructor, String.format("%s<%s>", HelloWorldDependency.class.getName(), String.class.getName()));
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(HelloWorld.class, HelloWorldDependency.class), constructor.getThis(), supportHandle);
constructor.returnValue(null);
// sayHello
final MethodCreator clazzMethod = beanClassCreator.getMethodCreator("sayHello", Object.class);
clazzMethod.setModifiers(Opcodes.ACC_PUBLIC);
clazzMethod.returnValue(clazzMethod.load("HelloWorldGenerated"));
beanClassCreator.close();
}
// https://github.com/quarkiverse/quarkus-langchain4j/blob/main/core/deployment/src/main/java/io/quarkiverse/langchain4j/deployment/AiServicesProcessor.java#L627 :)
private ResultHandle getFromCDI(final MethodCreator mc, final String className) {
// Arc.container().instance(className).get();
final ResultHandle containerHandle = mc.invokeStaticMethod(MethodDescriptor.ofMethod(Arc.class, "container", ArcContainer.class));
final ResultHandle instanceHandle = mc.invokeInterfaceMethod(
MethodDescriptor.ofMethod(ArcContainer.class, "instance", InstanceHandle.class, Class.class,
Annotation[].class),
containerHandle, mc.loadClassFromTCCL(className),
mc.newArray(Annotation.class, 0));
return mc.invokeInterfaceMethod(MethodDescriptor.ofMethod(InstanceHandle.class, "get", Object.class), instanceHandle);
}
If you have a look to the previous commit it is working fine when the HelloWorldDependency dependency is not a generic.
To make it work I am using Arc to retrieve the bean. However, the bean is resolved at runtime and so Generic is no more available. Should I generate and use Qualifier ?
Is there an another way to generate bean using a Quarkus build item ? I was expected to make it works without using Arc but it seems that it is not possible.
Regards, Damien
So when I look at the
quarkus-hello-world-playground
project it seems that the gizmo code for theHelloWorldGenerated
constructor is the problem.First, you need to set the method signature to reflect the generic parameters. Also the
HelloWorldPlaygroundProcessor#getFromCDI()
is useless because you don't need to lookup the bean programmatically if using constructor injection - the bean instance is injected in the constructor argument.The code should look like: