How to replace @ManagedBean / @ViewScope by CDI in JSF 2.0/2.1
If you can upgrade to JSF 2.2, immediately do it. It offers a native @ViewScoped
annotation for CDI.
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
Alternatively, install OmniFaces which brings its own CDI compatible @ViewScoped
, including a working @PreDestroy
(which is broken on JSF @ViewScoped
).
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
Another alternative is to install MyFaces CODI which transparently bridges JSF 2.0/2.1 @ViewScoped
to CDI. This only adds an autogenerated request parameter to the URL (like @ConversationScoped
would do).
import javax.faces.bean.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class Bean implements Serializable {
// ...
}
If you really need to use @ConversationScoped
, then you indeed need to manually begin and end it. You need to @Inject
a Conversation
and invoke begin()
in the @PostConstruct
and end()
in the latest step of the conversation, usually an action method which redirects to a new view.
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
@Named
@ConversationScoped
public class Bean implements Serializable {
@Inject
private Conversation conversation;
// ...
@PostConstruct
public void init() {
conversation.begin();
}
public String submit() {
// ...
conversation.end();
return "some.xhtml?faces-redirect=true";
}
}
See also:
- How to choose the right bean scope?
I think you can benefit from CDI extension to create your own scope so you can implement the context and use the @NormalScope
.
- CDI fires an event
AfterBeanDiscovery
after each bean call - You can use CDI extension to
@Observes
this event and add your context implementation - In your scope implementation you can :
- Use
Contextual
to get your bean by its name fromFacesContext
ViewRoot
Map
and return it after each ajax call back - Use
CreationalContext
if the bean name from first step is not found to create it in theFacesContext
ViewRoot
Map
- Use
For a more in-depth explanation, I recommend this link : http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/