Cómo reemplazar @ManagedBean / @ViewScope por CDI en JSF 2.0 / 2.1

Actualmente estoy evaluando Java EE 6 / JSF 2.1 con RichFaces.

Un frijol que se declara como

@ManagedBean @ViewScoped 
  1. Obtiene un conjunto de ID (para preparar, por ejemplo, una operación de eliminación).
  2. A través de JSF se muestra una ventana emergente de confirmación.
  3. Si el usuario confirma, se invoca el método de eliminación y elimina la fila para la que se almacenó el ID en el paso 1.

Como los beans CDI no tienen un ViewScope, traté de declarar el bean como:

 @Named @ConversationScoped 

Ahora el procesamiento falla en el paso 3. porque el valor que se estableció en el paso 1 (verificado) ya no está disponible.

¿Tengo que usar los métodos Conversation.begin() y Conversation.end() ?

Si es así, ¿dónde sería un buen lugar para invocarlos?

Si puede actualizar a JSF 2.2, hágalo inmediatamente. Ofrece una anotación @ViewScoped nativa para CDI.

 import javax.faces.view.ViewScoped; import javax.inject.Named; @Named @ViewScoped public class Bean implements Serializable { // ... } 

Alternativamente, instale OmniFaces que trae su propio CDI compatible @ViewScoped , incluyendo un trabajo @PreDestroy (que está roto en JSF @ViewScoped ).

 import javax.inject.Named; import org.omnifaces.cdi.ViewScoped; @Named @ViewScoped public class Bean implements Serializable { // ... } 

Otra alternativa es instalar MyFaces CODI que une de forma transparente JSF 2.0 / 2.1 @ViewScoped con CDI. Esto solo agrega un parámetro de solicitud autogenerado a la URL (como @ConversationScoped haría @ConversationScoped ).

 import javax.faces.bean.ViewScoped; import javax.inject.Named; @Named @ViewScoped public class Bean implements Serializable { // ... } 

Si realmente necesita usar @ConversationScoped , entonces realmente necesita comenzar y finalizarlo. Necesita @Inject a Conversation e invocar a begin() en @PostConstruct y end() en el último paso de la conversación, generalmente un método de acción que redirige a una nueva vista.

 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"; } } 

Ver también:

  • ¿Cómo elegir el scope del frijol correcto?

Creo que puede beneficiarse de la extensión CDI para crear su propio scope para que pueda implementar el contexto y usar @NormalScope .

  • CDI AfterBeanDiscovery un evento AfterBeanDiscovery después de cada llamada de bean
  • Puede usar la extensión CDI para @Observes este evento y agregar su implementación de contexto
  • En su implementación de scope, puede:
    1. Usa Contextual para obtener tu bean por su nombre de FacesContext ViewRoot Map y ViewRoot después de cada llamada a Ajax.
    2. Use CreationalContext si el nombre del bean del primer paso no se encuentra para crearlo en el Map FacesContext ViewRoot

Para una explicación más detallada, recomiendo este enlace: http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/

Inyecte la conversación en su bean y en el método @PostConstructor comience la conversación si la conversación es transitoria.

Y después de eliminar el registro, finalice su conversación y navegue a su página de destino. Al comenzar una conversación. Aquí hay un ejemplo

 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"; } } 

Hay un proyecto que tiene una extensión para las características de la stack Java EE: DeltaSpike . Es una consolidación de Seam 3, Apache CODI. Por encima de otros, incluye @ViewScoped en CDI. Este es un artículo antiguo y ahora ha llegado a la versión 1.3.0

Puedes usar:

 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"); } }