Skip to content

Conversation

@Ladicek
Copy link
Member

@Ladicek Ladicek commented Jan 28, 2026

The specification of InjectionPoint contains a small number of holes that are arguably corner cases, but they should be specified nevertheless.

The most important one is dynamically obtained instance (Instance) that is not injected. This can happen through several means:

  • BeanContainer.createInstance()
  • CDI.current()
  • SeContainer

The specification didn't say what multiple methods should return in this case; it didn't even explicitly say that an InjectionPoint should exist and indeed it doesn't on one existing implementation. With this commit, the behavior is clear: an InjectionPoint must exist and all methods besides getType() and getQualifiers() return null (or false).

Further, it is not clear what the getBean() method should return in case of a synthetic bean. Such injection points should, in portable extensions, be created using BeanManager.createInjectionPoint(), but these methods do not take a Bean and cannot figure out on their own which bean is the injection point created for. So on all existing implementations that support portable extensions, this method returns null. This is now explicitly allowed.

Finally, this commit allows synthetic beans to have injection points that do not correspond to a field or parameter. Currently, such injection points should never exist, because injection points of synthetic beans should be created using BeanManager.createInjectionPoint(), but it is not hard to imagine people implementing InjectionPoint manually and returning null from getMember() or getAnnotated(). We also plan to introduce specifying injection points for synthetic beans in the build compatible extensions API, where one is supposed to only specify the required type and required qualifiers and it is entirely conceivable that no field or parameter can possibly be determined upfront. So an InjectionPoint of a synthetic bean is now explicitly allowed to return null from the getMember() and getAnnotated() methods.

Fixes #779
Related to #833

@Ladicek Ladicek added this to the CDI 5.0 milestone Jan 28, 2026
@Ladicek Ladicek requested review from Azquelt and manovotn January 28, 2026 14:31
@Ladicek
Copy link
Member Author

Ladicek commented Jan 28, 2026

I will submit a TCK PR in the next few days, but the spec text should be done IMHO.

@Ladicek Ladicek changed the title improve specification of InjectionPoint improve specification of InjectionPoint Jan 28, 2026
@Ladicek
Copy link
Member Author

Ladicek commented Jan 28, 2026

For the record, I'm not entirely sure if this perhaps doesn't somehow interact with passivation. I looked at the relevant part of the spec and what implementations do and didn't find anything obvious, but I admittedly don't know much about the topic, so I might be missing something.

Copy link
Member

@Azquelt Azquelt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the comments, this looks good to me.

Comment on lines 26 to 28
* An initial required type of the {@code Instance} is {@code java.lang.Object} and there are
* initially no required qualifiers. If no qualifier is passed to {@code Instance.select()},
* there is one required qualifier: {@code @Default}.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* An initial required type of the {@code Instance} is {@code java.lang.Object} and there are
* initially no required qualifiers. If no qualifier is passed to {@code Instance.select()},
* there is one required qualifier: {@code @Default}.
* The initial required type of the {@code Instance} is {@code java.lang.Object} and there are
* initially no required qualifiers. If no qualifier is passed to {@code Instance.select()},
* there is one required qualifier: {@code @Default}.

Also in other places where this text is used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, will change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


`CDI` implements `jakarta.enterprise.inject.Instance` and therefore might be used to perform programmatic lookup as defined in <<dynamic_lookup>>.
If no qualifier is passed to `CDI.select()` method, the `@Default` qualifier is assumed.
An initial required type of the `Instance` is `java.lang.Object` and there are initially no required qualifiers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
An initial required type of the `Instance` is `java.lang.Object` and there are initially no required qualifiers.
Initially, the required type is `java.lang.Object` and there are no required qualifiers.

Just trying to avoid saying "initial" twice in one sentence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, will use this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

The specification of `InjectionPoint` contains a small number of holes that
are arguably corner cases, but they should be specified nevertheless.

The most important one is dynamically obtained instance (`Instance`)
that is not injected. This can happen through several means:

- `BeanContainer.createInstance()`
- `CDI.current()`
- `SeContainer`

The specification didn't say what multiple methods should return in this case;
it didn't even explicitly say that an `InjectionPoint` should exist and indeed
it doesn't on one existing implementation. With this commit, the behavior is
clear: an `InjectionPoint` must exist and all methods besides `getType()` and
`getQualifiers()` return `null` (or `false`).

Further, it is not clear what the `getBean()` method should return in case
of a synthetic bean. Such injection points should, in portable extensions,
be created using `BeanManager.createInjectionPoint()`, but these methods
do not take a `Bean` and cannot figure out on their own which bean is
the injection point created for. So on all existing implementations that
support portable extensions, this method returns `null`. This is now
explicitly allowed.

Finally, this commit allows synthetic beans to have injection points that
do not correspond to a field or parameter. Currently, such injection points
should never exist, because injection points of synthetic beans should
be created using `BeanManager.createInjectionPoint()`, but it is not hard
to imagine people implementing `InjectionPoint` manually and returning
`null` from `getMember()` or `getAnnotated()`. We also plan to introduce
specifying injection points for synthetic beans in the build compatible
extensions API, where one is supposed to only specify the required type
and required qualifiers and it is entirely conceivable that no field or
parameter can possibly be determined upfront. So an `InjectionPoint`
of a synthetic bean is now explicitly allowed to return `null` from
the `getMember()` and `getAnnotated()` methods.
…not injected

An `Instance` that is not injected (or, in other words, that is obtained
programmatically) has initially a required type of `java.lang.Object`
and has initially no requried qualifiers. If no qualifier is passed to
`Instance.select()`, there is one required qualifier: `@Default`.

This has all been previously specified implicitly or using slightly imprecise
wording. This commit is more explicit and more precise.
@Ladicek Ladicek force-pushed the improve-injection-point branch from cf48a70 to c9a8544 Compare February 3, 2026 16:15
Copy link
Contributor

@manovotn manovotn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@manovotn manovotn merged commit ff86ca5 into jakartaee:main Feb 4, 2026
4 checks passed
@Ladicek Ladicek deleted the improve-injection-point branch February 4, 2026 15:33
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

Successfully merging this pull request may close these issues.

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

3 participants