How to replace @ManagedBean / @ViewScope by CDI in JSF 2.0/2.1
Asked Answered
W

5

27

I'm currently evaluating Java EE 6 / JSF 2.1 with RichFaces.

A bean which is declared as

@ManagedBean
@ViewScoped
  1. Gets an ID set (to prepare e.g. a delete operation).
  2. Via JSF a confirmation popup is displayed.
  3. If the user confirms, the delete method is invoked and removes the row for which the ID was stored in step 1.

Since CDI beans don't have a ViewScope I tried to declare the bean as:

@Named
@ConversationScoped

Now the processing fails in step 3. because the value that was set in step 1 (checked that) is no longer available.

Do I have to use Conversation.begin() and Conversation.end() methods?

If so, where would be good place to invoke them?

Willawillabella answered 17/1, 2013 at 17:10 Comment(1)
For future reference: in JSF 2.2 there is a CDI compatible view scope in core JSF.Lascivious
W
55

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:

Whom answered 17/1, 2013 at 17:33 Comment(2)
Thanks for your quick response. What happens to conversations that have not been ended, e.g. the user simply navigates to another page?Willawillabella
It expires by end of session (like a @ViewScoped bean, by the way). Note that the conversation scope is identified by a specific request parameter (in Weld, that's cid), so it's not true that it behaves like a session scoped bean. If you create a new request with that dialog, a new conversation is started even though the old one has not ended yet.Whom
R
6

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 :
    1. Use Contextual to get your bean by its name from FacesContext ViewRoot Map and return it after each ajax call back
    2. Use CreationalContext if the bean name from first step is not found to create it in the FacesContext ViewRoot Map

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/

Rumilly answered 28/4, 2013 at 22:4 Comment(0)
B
3

Inject the conversation into your bean and in the @PostConstructor method start the conversation if the conversation is transient.

And after deleting the record, end your conversation and navigate to your destination page. When beginning a conversation. Here is an example

public class BaseWebBean implements Serializable {

private final static Logger logger = LoggerFactory.getLogger(BaseWebBean.class);
@Inject
protected Conversation conversation;

@PostConstruct
protected void initBean(){
}

public void continueOrInitConversation() {
        if (conversation.isTransient()) {
            conversation.begin();
            logger.trace("conversation with id {} has started by {}.", conversation.getId(), getClass().getName());
        }
    }

public void endConversationIfContinuing() {
        if (!conversation.isTransient()) {
            logger.trace("conversation with id {} has ended by {}.", conversation.getId(), getClass().getName());
            conversation.end();
        }
}

}

@ConversationScoped
@Named
public class yourBean extends BaseWebBean implements Serializable {
    @PostConstruct
    public void initBean() {
        super.initBean();
        continueOrInitConversation();
    }

    public String deleteRow(Row row)
    {
        /*delete your row here*/
        endConversationIfContinuing();
        return "yourDestinationPageAfter removal";
    }

}
Buskined answered 17/1, 2013 at 17:39 Comment(0)
H
0

There is a project which holds an extentions to the Java EE stack features: DeltaSpike. It is a consolidation of Seam 3, Apache CODI. Above others, it includes the @ViewScoped into CDI. This is an old article and by now it has reached version 1.3.0

Hymnal answered 6/5, 2015 at 13:19 Comment(0)
A
-1

You can use:

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class PageController implements Serializable {

    private String value;

    public void setValue(String value) {
    this.value = value;
    }

    public String getValue() {
    return value;
    }

    public void execute() {
    setValue("value");
    }

    @PostConstruct
    public void init() {
    System.out.println("postcontructor");
    }

}
Aparri answered 18/4, 2015 at 13:1 Comment(1)
You **can not ** for jsf 2.1 and that was the question. So please enhance your answer so it include JSF 2.2Millwork

© 2022 - 2024 — McMap. All rights reserved.