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

ArC fails to construct bean with self-referencing generic constraint #17147

Closed
Felk opened this issue May 11, 2021 · 8 comments · Fixed by #29450
Closed

ArC fails to construct bean with self-referencing generic constraint #17147

Felk opened this issue May 11, 2021 · 8 comments · Fixed by #29450
Assignees
Labels
area/arc Issue related to ARC (dependency injection) kind/bug Something isn't working
Milestone

Comments

@Felk
Copy link
Contributor

Felk commented May 11, 2021

ArC appears to be unable to generate beans if they have a generic parameter and a constraint referencing the generic parameter, as is common for e.g. T extends Comparable<T>. The issue can be reproduced as follows:

public class CdiProducers {
    @Produces
    public <T extends Comparable<T>> List<T> getSpecificList() {
        return new ArrayList<>();
    }
}

which results in the following error at build time:

[ERROR] Failed to execute goal io.quarkus:quarkus-maven-plugin:1.13.3.Final:build (default) on project my-project: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR]         [error]: Build step io.quarkus.arc.deployment.ArcProcessor#generateResources threw an exception: java.lang.IllegalStateException: Unable to construct the type handle for PRODUCER METHOD bean [types=[java.util.List<T extends java.util.List>, java.util.Collection<T extends java.util.List>, java.lang.Object, java.lang.Iterable<T extends java.util.List>], qualifiers=[@Default, @Any], target=java.util.List<T extends java.util.List> getSpecificList(), declaringBean=me.demo.CdiProducers]: Unsupported bean type: UNRESOLVED_TYPE_VARIABLE, T
[ERROR]         at io.quarkus.arc.processor.BeanGenerator.initConstructor(BeanGenerator.java:671)
[ERROR]         at io.quarkus.arc.processor.BeanGenerator.createConstructor(BeanGenerator.java:566)
[ERROR]         at io.quarkus.arc.processor.BeanGenerator.generateProducerMethodBean(BeanGenerator.java:398)
[ERROR]         at io.quarkus.arc.processor.BeanGenerator.generate(BeanGenerator.java:115)
[ERROR]         at io.quarkus.arc.processor.BeanProcessor.generateResources(BeanProcessor.java:181)
[ERROR]         at io.quarkus.arc.deployment.ArcProcessor.generateResources(ArcProcessor.java:458)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[ERROR]         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[ERROR]         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[ERROR]         at java.base/java.lang.reflect.Method.invoke(Method.java:566)
[ERROR]         at io.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:920)
[ERROR]         at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2415)
[ERROR]         at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
[ERROR]         at java.base/java.lang.Thread.run(Thread.java:829)
[ERROR]         at org.jboss.threads.JBossThread.run(JBossThread.java:501)

with a prettyfied error message:

Build step io.quarkus.arc.deployment.ArcProcessor#generateResources threw an exception:
java.lang.IllegalStateException: Unable to construct the type handle for PRODUCER METHOD bean [
    types=[
        java.util.List<T extends java.util.List>,
        java.util.Collection<T extends java.util.List>,
        java.lang.Object,
        java.lang.Iterable<T extends java.util.List>
    ],
    qualifiers=[@Default, @Any],
    target=java.util.List<T extends java.util.List> getSpecificList(),
    declaringBean=me.demo.CdiProducers
]: Unsupported bean type: UNRESOLVED_TYPE_VARIABLE, T

A few more examples:

  • does not work: <T extends List<T>>
  • does work: <T extends Serializable>
  • does work: <T>

I have attached a sample project to reproduce the problem: arc-selfreferencing-generic-constraint.zip

@Felk Felk added the kind/bug Something isn't working label May 11, 2021
@quarkus-bot
Copy link

quarkus-bot bot commented May 11, 2021

/cc @manovotn, @mkouba

@quarkus-bot quarkus-bot bot added the area/arc Issue related to ARC (dependency injection) label May 11, 2021
@mkouba
Copy link
Contributor

mkouba commented May 12, 2021

Hi @Felk, thanks for reporting this problem. It's a known issue - see also smallrye/jandex#88 and we can't do much until this jandex issue is resolved.

@Felk
Copy link
Contributor Author

Felk commented May 12, 2021

Thanks for letting me know, I'll watch that issue

@mkouba
Copy link
Contributor

mkouba commented Nov 23, 2022

@Ladicek would you care to take a look at the ArC part? You fixed the Jandex issue, hence a perfect candidate 😉 .

@Ladicek
Copy link
Contributor

Ladicek commented Nov 23, 2022

Sure thing!

@Ladicek Ladicek self-assigned this Nov 23, 2022
@Ladicek
Copy link
Contributor

Ladicek commented Nov 23, 2022

So the reproducer actually builds and runs just fine (I believe due to #27631), but I can't inject the produced bean anywhere, nor can I look it up programmatically -- and I don't even have an idea how to express such injection or programmatic lookup. I'm trying this:

@Dependent
static class Producer {
    @Produces
    @Dependent
    public <T extends Comparable<T>> List<T> produce() {
        return new ArrayList<>();
    }
}

// inject
@Dependent
static class Target<T extends Comparable<T>> {
    @Inject
    List<T> list;

    public List<T> getList() {
        return list;
    }
}

// lookup
public <T extends Comparable<T>> void test() {
    ArcContainer arc = Arc.container();
    InstanceHandle<List<T>> handle = arc.instance(new TypeLiteral<List<T>>() {});
}

But I'm not exactly sure if that's supposed to work or not. Any opinions? :-)

@Felk
Copy link
Contributor Author

Felk commented Nov 23, 2022

In my original usecase I think I injected a concrete type, e.g.

@Inject
List<String> stringList;

@Ladicek
Copy link
Contributor

Ladicek commented Nov 23, 2022

Yeah, I originally thought about that, but I'm not sure that's supposed to work as well. If I'm reading Assignability of raw and parameterized types, it probably should. It currently doesn't, because our AssignabilityCheck.findAssignables relies on presence of the types in Jandex -- I'll try to figure something out there, but getAllKnownSubclasses or getAllKnownImplementors can't really work well with on-demand indexing.

My attempts in the previous comment are most likely wrong, because those Ts are different type variables, even if they have the same name.

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/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants