Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to inject custom qualified beans when creating them using SyntheticBeanBuildItem - Tests in deployment module are ok not in integration-tests module #45289

Closed
dcdh opened this issue Dec 26, 2024 · 6 comments
Labels
area/arc Issue related to ARC (dependency injection) kind/question Further information is requested

Comments

@dcdh
Copy link
Contributor

dcdh commented Dec 26, 2024

Describe the bug

I would like to create beans following the value of a Qualifier

The objective is to pass the value of this qualifier inside the bean and reuse it. Each qualifier will create is own bean.

Following this reproducer https://github.com/dcdh/qualifier-synthetic-bean

I would like to say hello name where name is peak up from the Person Qualifier.

Tests inside deployment module are working fines. However it is not the case in the integration-tests module.

To produce these beans I use this custom buildStep:

    @BuildStep
    @Record(ExecutionTime.RUNTIME_INIT)
    List<SyntheticBeanBuildItem> registerPersons(
            final ApplicationIndexBuildItem applicationIndexBuildItem,
            final HelloWorldServiceRecorder helloWorldServiceRecorder) {
        final Set<String> persons = applicationIndexBuildItem.getIndex()
                .getAnnotations(DotName.createSimple(Person.class))
                .stream()
                .map(qualifier -> qualifier.value("name").asString())
                .collect(Collectors.toSet());

        return persons.stream()
                .map(personName -> SyntheticBeanBuildItem.configure(HelloWorldService.class)
                        .scope(Singleton.class)
                        .createWith(helloWorldServiceRecorder.supplier(personName))
                        .addQualifier().annotation(DotName.createSimple(Person.class)).addValue("name", personName).done()
                        .unremovable()
                        .setRuntimeInit()
                        .done())
                .toList();
    }
@Recorder
public class HelloWorldServiceRecorder {

    public Function<SyntheticCreationalContext<HelloWorldService>, HelloWorldService> supplier(
            final String name) {
        return new Function<SyntheticCreationalContext<HelloWorldService>, HelloWorldService>() {
            @Override
            public HelloWorldService apply(final SyntheticCreationalContext<HelloWorldService> context) {
                return new HelloWorldService(name);
            }
        };
    }
}

Expected behavior

In integration-tests module endpoints should returned Hello Martin and Hello Guillaume.

Actual behavior

It fails to inject both beans. It seems that Arc is not able to find HelloWorldServices qualified with Person having Martin and Guillaume in name.

The following beans match by type, but none has matching qualifiers:
        - SYNTHETIC bean [types=[org.acme.qualifier.synthetic.bean.extension.runtime.HelloWorldService, java.lang.Object], qualifiers=[@org.acme.qualifier.synthetic.bean.extension.runtime.Person(name = "Martin"), @Any], target=n/a]
        - SYNTHETIC bean [types=[org.acme.qualifier.synthetic.bean.extension.runtime.HelloWorldService, java.lang.Object], qualifiers=[@Any, @org.acme.qualifier.synthetic.bean.extension.runtime.Person(name = "Guillaume")], target=n/a]

How to Reproduce?

  1. git clone https://github.com/dcdh/qualifier-synthetic-bean
  2. mvn clean install

Output of uname -a or ver

Linux fedora-2.home 6.11.6-300.fc41.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Nov 1 16:16:00 UTC 2024 x86_64 GNU/Linux

Output of java -version

openjdk version "21.0.5" 2024-10-15 OpenJDK Runtime Environment (Red_Hat-21.0.5.0.11-1) (build 21.0.5+11) OpenJDK 64-Bit Server VM (Red_Hat-21.0.5.0.11-1) (build 21.0.5+11, mixed mode, sharing)

Quarkus version or git rev

3.17.5

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.6 (Red Hat 3.9.6-7) Maven home: /usr/share/maven Java version: 21.0.5, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-21-openjdk-21.0.5.0.11-1.fc41.x86_64 Default locale: fr_FR, platform encoding: UTF-8 OS name: "linux", version: "6.11.6-300.fc41.x86_64", arch: "amd64", family: "unix"

Additional information

No response

@dcdh dcdh added the kind/bug Something isn't working label Dec 26, 2024
@dcdh dcdh changed the title Unable to inject custom qualified beans when creating using SyntheticBeanBuildItem Unable to inject custom qualified beans when creating them using SyntheticBeanBuildItem - Tests in deployment module are fined not in integration-tests module Dec 26, 2024
@dcdh dcdh changed the title Unable to inject custom qualified beans when creating them using SyntheticBeanBuildItem - Tests in deployment module are fined not in integration-tests module Unable to inject custom qualified beans when creating them using SyntheticBeanBuildItem - Tests in deployment module are ok not in integration-tests module Dec 26, 2024
@dcdh
Copy link
Contributor Author

dcdh commented Dec 26, 2024

Image

Regarding the integration testing, it tried to inject HelloWorldService using the @Default qualifier. I do not have one and I do not intent to have a default one.

@gsmet
Copy link
Member

gsmet commented Dec 26, 2024

So the error message actually gives you a good hint:

Suppressed: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.acme.qualifier.synthetic.bean.extension.runtime.HelloWorldService and qualifiers [@default]

  • injection target: org.acme.qualifier.synthetic.bean.extension.it.QualifierSyntheticBeanExtensionResource#helloWorldServiceMartin
  • declared on CLASS bean [types=[java.lang.Object, org.acme.qualifier.synthetic.bean.extension.it.QualifierSyntheticBeanExtensionResource], qualifiers=[@default, @Any], target=org.acme.qualifier.synthetic.bean.extension.it.QualifierSyntheticBeanExtensionResource]
    The following beans match by type, but none has matching qualifiers:
  • SYNTHETIC bean [types=[org.acme.qualifier.synthetic.bean.extension.runtime.HelloWorldService, java.lang.Object], qualifiers=[@org.acme.qualifier.synthetic.bean.extension.runtime.Person(name = "Martin"), @Any], target=n/a]
  • SYNTHETIC bean [types=[org.acme.qualifier.synthetic.bean.extension.runtime.HelloWorldService, java.lang.Object], qualifiers=[@Any, @org.acme.qualifier.synthetic.bean.extension.runtime.Person(name = "Guillaume")], target=n/a]

It looks for a bean with only the @Default qualifier and all it can find are the two beans with the @Person qualifiers.

What you're missing is that you need to add the qualifier as a bean. I'm not entirely sure why it works in deployment, maybe the index is built a bit differently but that fixes the issue.

PR to your repository to come.

Actually, given it's very simple, here is a diff:

diff --git a/deployment/src/main/java/org/acme/qualifier/synthetic/bean/extension/deployment/QualifierSyntheticBeanExtensionProcessor.java b/deployment/src/main/java/org/acme/qualifier/synthetic/bean/extension/deployment/QualifierSyntheticBeanExtensionProcessor.java
index 19678f9..3e189c9 100644
--- a/deployment/src/main/java/org/acme/qualifier/synthetic/bean/extension/deployment/QualifierSyntheticBeanExtensionProcessor.java
+++ b/deployment/src/main/java/org/acme/qualifier/synthetic/bean/extension/deployment/QualifierSyntheticBeanExtensionProcessor.java
@@ -1,6 +1,8 @@
 package org.acme.qualifier.synthetic.bean.extension.deployment;
 
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
 import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
+import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
 import io.quarkus.deployment.annotations.ExecutionTime;
 import io.quarkus.deployment.annotations.Record;
@@ -32,7 +34,11 @@ class QualifierSyntheticBeanExtensionProcessor {
     @Record(ExecutionTime.RUNTIME_INIT)
     List<SyntheticBeanBuildItem> registerPersons(
             final ApplicationIndexBuildItem applicationIndexBuildItem,
-            final HelloWorldServiceRecorder helloWorldServiceRecorder) {
+            final HelloWorldServiceRecorder helloWorldServiceRecorder,
+            BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
+        // add the qualifier as a bean
+        additionalBeans.produce(new AdditionalBeanBuildItem(Person.class));
+
         final Set<String> persons = applicationIndexBuildItem.getIndex()
                 .getAnnotations(DotName.createSimple(Person.class))
                 .stream()

@gsmet gsmet added kind/question Further information is requested and removed kind/bug Something isn't working labels Dec 26, 2024
@dcdh
Copy link
Contributor Author

dcdh commented Dec 26, 2024

@gsmet Thanks it works.

@geoand geoand added area/arc Issue related to ARC (dependency injection) and removed triage/needs-triage labels Dec 30, 2024
Copy link

quarkus-bot bot commented Dec 30, 2024

/cc @Ladicek (arc), @manovotn (arc), @mkouba (arc)

@manovotn
Copy link
Contributor

manovotn commented Jan 2, 2025

I think the issue here is that the resulting archive created from runtime module is not a bean archive so the qualifier is not discovered.
Guillaume's solution is perfectly valid and probably preferable since we are talking Quarkus extension which may intentionally not be bean archives.
Alternatively, you could also make it work by adding empty beans.xml file into runtime/src/main/resources/META-INF.

I'm not entirely sure why it works in deployment, maybe the index is built a bit differently but that fixes the issue.

My assumption would be the same although I didn't dig deeper.
Probably linked to how we build the index with QuarkusUnitTest.

@manovotn
Copy link
Contributor

manovotn commented Jan 2, 2025

Closing the issue as answered.
@dcdh feel free to reopen if you have further questions or think we didn't answer it properly :)

@manovotn manovotn closed this as completed Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/arc Issue related to ARC (dependency injection) kind/question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants