Search code examples
javajava-ee-6cdijboss-weldjsr299

How to inject objects of the same class with different scopes?


In terms of simplicity and correctness, what is the best way to inject objects of the same class with different scopes?

In a servlet I want to have injected objects of the same class with different scopes. Still don't know if going to use jsf.

  • Simplicity: Making a Qualifier and a producer method for each scope is too much; making an interface, two classes and adding and alternative in beans.xml is also too much; having an Address#isCurrent() method doesn't make sense.
  • Correctness: JSR299, 3.11 says: The use of @Named as an injection point qualifier is not recommended. Still don't know why.
    Though using @Named at injection point works with @ApplicationScoped and @RequestScoped but not with @SessionScoped. See named snippet below.

In spring it is very easy:
Spring snippet

<bean id="currentAddress" class="xxx.Address" scope="session" />
<bean id="newAddress" class="xxx.Address" scope="request" />
<bean id="servlet" class="xxx.MyServlet">
 <property name="currentAddress" ref="currentAddress" />
 <property name="newAddress" ref="newAddress" />
</bean>


named snippet

/* Address class */
@Produces @RequestScoped @Named(value="request")
 public Address getNewAddress(){
 return new Address();
}

@Produces @SessionScoped @Named(value="application")
 public Address getCurrentAddress(){
 return new Address();
}
/* Servlet */
@Inject @RequestScoped @Named("request")  private Address newAddress;
@Inject @ApplicationScoped @Named("application") private Address currentAddress;

Solution

  • Thanks to @nsfyn55 for pointing out that good article, after reading the section "The Right Way", I came up with what I think is the best way to achieve it in terms of simplicity and correctness.

    So I am using only one interface for the qualifier annotation.

    /* Qualifier annotation */
    @Qualifier
    @Retention(RUNTIME)
    @Target({FIELD,METHOD})
    public @interface Scope {
    
     Type value();
    
     enum Type { REQUEST, SESSION, APPLICATION };
    }
    
    
    /* Address class */
    @Produces @Scope(REQUEST) @RequestScoped
     public Address request() {
     return new Address();
    }
    
    @Produces @Scope(SESSION) @SessionScoped
     public Address session() {
     return new Address();
    }
    
    /* Servlet */
    @Inject @Scope(REQUEST)
    private Address newAddress;
    
    @Inject @Scope(SESSION)
    private Address currentAddress;