¿Por qué @PostConstruct callback se dispara cada vez a pesar de que bean está @ ViewScoped? JSF


Estoy usando datatable en la página y usando el atributo de enlace para vincularlo a mi frijol de respaldo. Este es mi código :-

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.prime.com.tr/ui">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
            <h:form prependId="false">

                <h:dataTable var="item" value="#{testBean.stringCollection}" binding="#{testBean.dataTable}">
                    <h:column>
                        <h:outputText value="#{item}"/>
                    </h:column>
                    <h:column>
                        <h:commandButton value="Click" actionListener="#{testBean.action}"/>
                    </h:column>
                </h:dataTable>

            </h:form>

    </h:body>
</html>

Este es mi frijol: -

package managedBeans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlDataTable;

@ManagedBean(name="testBean")
@ViewScoped
public class testBean implements Serializable {

    private List<String> stringCollection;

    public List<String> getStringCollection() {
        return stringCollection;
    }

    public void setStringCollection(List<String> stringCollection) {
        this.stringCollection = stringCollection;
    }

    private HtmlDataTable dataTable;

    public HtmlDataTable getDataTable() {
        return dataTable;
    }

    public void setDataTable(HtmlDataTable dataTable) {
        this.dataTable = dataTable;
    }

    @PostConstruct
    public void init(){
        System.out.println("Post Construct fired!!");
        stringCollection = new ArrayList<String>();
        stringCollection.add("a");
        stringCollection.add("b");
        stringCollection.add("c");

    }

    public void action(){
        System.out.println("Clicked!!");

    }
}

Por favor dime por qué el @PostConstruct dispara cada vez que hago clic en el botón? Debería dispararse solo una vez mientras esté en la misma página porque mi frijol está @ViewScoped. Además, si elimino el atributo binding, todo funciona bien y @PostConstruct callback se dispara solo una vez. Entonces, ¿por qué cada vez que uso encuadernación atributo? Necesito el atributo binding y quiero realizar tareas de inicialización como recuperar datos de webservice, etc. solo una vez. ¿Qué debo hacer? ¿Dónde debo escribir mi tarea de inicialización?

Author: BalusC, 2010-05-09

5 answers

Interesante, cuando se utiliza el enlace de componentes en un bean con ámbito de vista, el ámbito de vista se rompe.

No estoy seguro si eso es un error en JSF2, tendría que leer toda la especificación JSF2 primero. Hasta ahora, su mejor apuesta es eliminar el enlace de componentes por ahora y pasar el elemento seleccionado a través de la nueva sintaxis del argumento del método EL 2.2:

<h:dataTable var="item" value="#{testBean.stringCollection}">
    <h:column>
        <h:outputText value="#{item}"/>
    </h:column>
    <h:column>
        <h:commandButton value="Click" action="#{testBean.action(item)}"/>
    </h:column>
</h:dataTable>

Véase también:


Actualización (Dic 2012): esto es un error en JSF2. Es un problema de huevos de gallina. Los granos con alcance de vista se almacenan en el estado de vista JSF. Por lo tanto, los frijoles con alcance de vista solo están disponibles después de la fase de vista de restauración. Sin embargo, el atributo binding se ejecuta durante la fase de restauración de la vista, mientras que los frijoles con ámbito de vista no están disponibles todavía. Esto causa la creación de una nueva instancia de vista scoped bean, que luego es reemplazada por la vista real scoped bean que se almacenó en el estado de vista JSF restaurado.

Esto se informa como JSF issue 1492 y JSF spec isssue 787 que se corregirá para JSF 2.2. Hasta entonces, su mejor opción es utilizar binding a petición de granos de alcance exclusivamente, o para buscar formas alternativas para el requisito funcional particular.


Actualización (Mar 2015): La revisión de JSF 2.2 fue puesto Mojarra 2.1.18. Así que si todavía estás usando JSF 2.0 / 2.1, es mejor que actualices a al menos esa versión. Véase también a. o. ¿Qué es el enlace de componentes en JSF? ¿Cuándo se prefiere utilizar? and JSTL in JSF2 Facelets... tiene sentido?

 32
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:28

Como otros dijeron, yo diría que lo mejor que puede hacer es eliminar el enlace de componentes (no lo necesita aquí).

Pero yo añadiría que se puede lograr lo mismo que se está tratando de hacer de una manera más orientada a objetos mediante el uso de parámetros de acción, como este:

<h:commandButton value="Click" action="#{testBean.action(item)}"/>

... y en su código java:

  public void action(Item item){
    System.out.println("Clicked!!" + item);
}
 4
Author: ymajoros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-16 15:10:16

Si tiene un bean con viewscoped y desea conservar los valores que se ingresaron en el formulario o no desea que se dispare postconstruct, debe devolver null desde su método de acción.

Si devuelve algún resultado (por ejemplo, no válido) y luego apunta el resultado no válido a la misma página usando faces-config.xml, a continuación, el frijol viewscoped se recrea y por lo tanto hace postconstruct para disparar de nuevo.

 0
Author: Pramod Kankure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-26 17:39:20

Otra solución:

  • Enlazar el HtmlDataTable en un ámbito de solicitud bean.
  • Inyecte este ámbito de solicitud bean en la vista ámbito bean.

JBoss Seam utilice esta solución para vincular componentes JSF a un componente de ámbito de conversación.

 0
Author: Juan Miguel Bernal González,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-16 15:50:49

La respuesta del balusc me ayudó mucho, me gustaría decir que tenía ese error con mojarra versión 2.1.7, actualmente estoy usando 2.1.29-01 lanzado en enero-2015 y este error está solucionado, mi problema era vincular una tabview a un bean con viewscoped. Con esta versión no tengo ese bug y binding y postconstruct está funcionando bien. Uso Jboss 5.2 y tengo que usar mojarra 2.1.x así que espero que esta respuesta ayude a otras personas en el mismo situación.

Http://mvnrepository.com/artifact/com.sun.faces/jsf-api/2.1.29-01 http://mvnrepository.com/artifact/com.sun.faces/jsf-impl/2.1.29-01

 0
Author: Luis Vidal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-20 12:54:40