In CDI, I am able to inject a bean with a particular scope, the scope with which the bean class was defined. But what if I create the bean class without any scope and I give scope to that bean at the point of injection. My requirement is to make injection-time-scoping possible in the latter case. Problem is that injection is happening with dependent scope instead of the desired annotated scope unless I use a producer.
For Example:
CASE 1:
When I declare scope of a bean in its class declaration like this:
@ApplicationScoped
class UserDetails {
...
}
And injected like this:
@ViewScoped
class UserView {
@Inject
UserDetails userDetails;
.
.
}
It works as expected. The bean injected in application scope is available throughout the application in all other beans.
CASE 2:
But when I give no scope in class declaration:
class UserDetails {
...
}
And injected like this (giving scope at the point of injection):
@ViewScoped
class UserView {
@Inject @ApplicationScoped
UserDetails userDetails;
.
.
}
This failed!.. The injected bean did not inject in application scope but got dependent scope instead (View Scope in my case).
I had to create a Producer & a Qualifier where @Produces method is providing the bean in desired application scope. I feel this producer/qualifier extension turns out to be an overhead if I have to inject bean class UserDetails in application scope in this case.
Thing is, UserDetails class is part of a third party jar. This class does not have any scope declared and is a POJO. I can not change its source code.
Based on the above discussion, I have two questions:
Why someone would create bean classes defined with no scope when they know that the beans are to be injected under a particular scope? Would this practice do any good in terms of design?
As I do not have control over the source code of the bean classes and as they are not associated with any scope, Is producer/qualifier extension the only good way to inject such beans in the desired scope?
1. Object without scope defined - @Dependent used
CDI will treat Object wihout scope as @Dependent scope.
An instance of a dependent bean is never shared between different clients or different injection points. It is strictly a dependent object of some other object. It is instantiated when the object it belongs to is created, and destroyed when the object it belongs to is destroyed.
Beans with scope @Dependent don’t need a proxy object. The client holds a direct reference to its instance.
Spring IoC dev: CDI @Dependent scope is similar to Spring IoC Prototype scope.
2. No @Produces & just use @Inject
CDI will create new instance of UserDetails for each injection (@Dependent scope). No sharing data here! You can't define scope as you did (when inject).
3. Use @Produces & use @Inject
You can control the scope of UserDetails object (ApplicationScoped, SessionScoped, or RequestScoped)
public class Producers {
@Produces @ApplicationScoped
public UserDetails createUserDetails() {
// Initialize UserDetails
}
public void release(@Disposes UserDetails userDetails) {
// Release userDetails if you have to
}
}
4. Another way: Extend UserDetails if possible
@ApplicationScoped // Or @SessionScoped, @RequestScoped
public class UserDetailsImpl extends UserDetails {
//
}
If you want ApplicationScoped for UserDetails. Way 3 or way 4 can be used.
The scope is always defined on the bean, not on the injection point.
An injection point cannot change the scope of the injected bean.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With