vineri, 15 ianuarie 2016

JSF 2.2 [usage pitfall] - Dependency injection wasn't done when the flow is in the bean constructor

The @PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. This rule is sometimes "omitted" by novices who need to perform initialization stuff based on the injected artifacts. For example, let's suppose that we have the following session scoped CDI bean:

@Named
@SessionScoped
public class Buzz implements Serializable {
   
 private static final long serialVersionUID = 1L;
 private String buzz = "BUZZ!";

 // getter and setter for buzz
}

An instance of this bean is further injected into another session bean, and it will serve for some initialization stuff. Now, the wrong approach will consist in placing the initialization stuff in the bean constructor, instead of using a separate method annotated with @PostConstruct as below:

@Named
@SessionScoped
public class Foo implements Serializable {

 private static final Logger LOG = Logger.getLogger(Foo.class.getName());
 private static final long serialVersionUID = 1L;

 @Inject
 private Buzz buzz;

 // WRONG - buzz is not available yet!
 public Foo() {
  LOG.log(Level.INFO, "Foo() - The injected buzz is: {0}", buzz);
 }

 // CORRECT - dependency injection was done, so buzz is available!
 @PostConstruct
 private void init() {
  LOG.log(Level.INFO, "init() - The injected buzz is: {0}", buzz);
 }

 // CORRECT - just some bean method action
 public void fooAction() {
  LOG.log(Level.INFO, "fooAction() - The injected buzz is: {0}", buzz);
 }
}

The output will reveal (check out the constructor null output):

Foo() - The injected buzz is: null
init() - The injected buzz is: beans.Buzz@5b9370d8
fooAction() - The injected buzz is: beans.Buzz@5b9370d8

Since Buzz is session scoped the init() method is called only once per session. Using a request scoped bean will cause the initialization to take place at each request.

Niciun comentariu:

Trimiteți un comentariu