Search code examples
cdi

In CDI, how to give scope to a bean at the point of injection?


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:

  1. 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?

  2. 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?


Solution

  • 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.