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

Define how InjectionPoint works when a bean is obtained via CDI.current() #779

Open
Azquelt opened this issue Feb 28, 2024 · 4 comments
Open
Milestone

Comments

@Azquelt
Copy link
Contributor

Azquelt commented Feb 28, 2024

The InjectionPoint Javadoc says this:

Provides access to metadata about an injection point. May represent an injected field or a parameter of a bean constructor, initializer method, producer method, disposer method or observer method.

If the injection point is a dynamically selected reference obtained then the metadata obtain reflects the injection point of the Instance, with the required type and any additional required qualifiers defined by Instance.select().

This doesn't cover the case where a bean is looked up using CDI.current().select(...).get() because there is no injection point for the Instance.

For example if I have a qualifier:

@Qualifier
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
public interface @MyQualifier {
    @Nonbinding String value()
    public class MyQualifierLiteral ...
}

and a managed bean class:

@Dependent
@MyQualifier("")
public class MyBean {

    @Inject
    InjectionPoint ip;

    public String getQualifierValue() {
        return ip.getQualifiers().stream()
                        .filter(a -> a.annotationType() == MyQualifier.class)
                        .map(MyQualifier.class::cast)
                        .map(MyQualifier::value)
                        .findFirst()
                        .orElseThrow(() -> new IllegalStateException("No qualifier found"));
    }
}

I can inject this bean like this and get its qualifiers:

@Inject @MyQualifier("foo") private MyBean fooBean;
@Inject @MyQualifier("bar") private Instance<MyBean> barBeanInstance;
@Inject @Any private Instance<Object> objectInstance;

void test() {
    assert fooBean.getQualifierValue().equals("foo");
    assert barBeanInstance.get().getQualifierValue().equals("bar");
    assert objectInstance.select(MyBean.class, new MyQualifier.MyQualifierLiteral("baz")).get().getQualifierValue().equals("baz");
}

However, I don't think it's defined what happens when I do this:

void test() {
    MyBean bean = CDI.current().select(MyBean.class, new MyQualifier.MyQualifierLiteral("qux")).get();
    assert bean.getQualifierValue().equals("qux");
}

Would it make sense to define how the InjectionPoint should work here? I don't think there's any sensible value for getAnnotated(), getBean() or getMember(), but getQualifiers() and getType() would still be helpful in this scenario.

This came to my attention because the Jakarta Batch spec gave an example of looking up a bean like this but getting the injection point isn't supported on open web beans for a bean obtained via CDI.select(): jakartaee/batch-tck#69

@Ladicek
Copy link
Contributor

Ladicek commented Feb 28, 2024

Correct observation. CDI.current(), or BeanContainer.createInstance() for what it's worth, basically gives you an Instance<Object> which was not obtained by injection. Looking up an InjectionPoint from that, or a @Dependent bean that injects InjectionPoint, ends up in an unspecified territory.

I agree that getType() and getQualifiers() can easily be supported, the remaining methods can just return null (or false). That's what we do in ArC (Weld probably does the same, though I didn't look).

@Ladicek Ladicek added this to the CDI 5.0 milestone Feb 28, 2024
@Ladicek
Copy link
Contributor

Ladicek commented Feb 28, 2024

I took the liberty of creating a CDI 5.0 milestone and assigning this issue to it. This is something that should be specified IMHO. Of course, my preference would be to specify it the way we do it :-), but that's TBD.

@manovotn
Copy link
Contributor

Yea, this is sensible, Weld does this too.
I did a quick scan and found this test - https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/injectionPoint/InjectionPointTest.java#L111-L127

@rmannibucau
Copy link

My 2cts would be that it can be to add a BaseInjectionPoint class - please find a better name ;), maybe QualifiedType or just make it extends Annotated and getAnnotated defaulting to this. This would avoid all the broken cases where a not null value would not be allowed to get a null value which can break programmatic cases for no real gain IMHO so letting Annotated be injected in a @Dependent producer method parameter looks saner to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants