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

2

1

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;
Barracks answered 29/4, 2012 at 16:3 Comment(0)
B
3

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;
Barracks answered 4/5, 2012 at 18:14 Comment(1)
Long time ago but : Is "@RequestScoped" and "@SessionScoped" realy needed ? Or is it enough to use "@Scope" as qualifier ?Pornography
U
4

The reason for the inclusion of this recommendation is the same reason one would prefer Enumeration over arbitrary strings for constants and that is because its not type-safe. You can easily mistype the name of the class and it would compile fine and fail at runtime. The recommendation is included because in most cases @named makes your application unnecessarily fragile when you have the ability force these constraints at compile time.

Here is a good article that outlines the reasons:

The preferred way to handle this situation is using @Qualifiers with enumerated values. Checkout the section entitled "String Qualifiers are Legacy" and "The Right Way" for the steps to handle this.

Unpeopled answered 29/4, 2012 at 17:37 Comment(3)
thank you very much for your answer. I can see the reasons to discourage the practice of @Named("string"). After reading the article you suggested I came with a new idea that I like more: having only one qualifier for both methods. I will try it later.Barracks
I edited that post I have noted to @Qualifier annotation as the preferred way to handle this.Unpeopled
Thank you, I just added my answer with snippetBarracks
B
3

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;
Barracks answered 4/5, 2012 at 18:14 Comment(1)
Long time ago but : Is "@RequestScoped" and "@SessionScoped" realy needed ? Or is it enough to use "@Scope" as qualifier ?Pornography

© 2022 - 2024 — McMap. All rights reserved.