@javax.faces.view.ViewScoped call @PostConstruct o

2019-08-02 17:23发布

问题:

I have a primefaces datatable where the commandButton's action addItem within the columns header facet always fires the CDI @ViewScoped beans @PostConstruct method, while the commandButton's action editItem from the column does not?!

Curiously enough this happens only, if the action methods return a non-null string?! Means, if both methods return null, the @PostConstruct method is not called, but I use a non-null string, because clicking the buttons should show a new @ViewScoped page.

The main problem in my real application is, that I do some initialization stuff within @PostConstruct, which should really happen only once during page construction!

datatable.xhtml

<?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:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <p:messages autoUpdate="true" showDetail="true"/>
    <h:outputLabel value="Datatable Test"/>
    <h:form>
        <p:dataTable var="item" value="#{datatableBean.items}">
            <p:column>
                <f:facet name="header">
                    <p:commandButton value="Add Item" action="#{datatableBean.editItem(null)}"/>
                </f:facet>
                <p:commandButton value="Edit Item" action="#{datatableBean.editItem(item)}"/>
            </p:column>
            <p:column headerText="Id">
                <p:outputLabel value="#{item.id}"/>
            </p:column>
            <p:column headerText="Name">
                <p:outputLabel value="#{item.name}"/>
            </p:column>
        </p:dataTable>
    </h:form>
</f:view>
</html>

addItem.xhtml

<?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:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <h:outputLabel value="Add Item"/>
</f:view>
</html>

editItem.xhtml

<?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:p="http://primefaces.org/ui"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<f:view>
    <h:outputLabel value="Edit Item"/>
</f:view>
</html>

DatatableBean.java

package my.web.datatable;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@ViewScoped
@Named
public class DatatableBean implements Serializable {

    private List<Item> items = new ArrayList<>();

    @PostConstruct
    private void init() {
        System.out.println(DatatableBean.class.getName() + " -> init()");

        for (int i = 1; i <= 5; i++) {
            items.add(new Item(i, "Item " + i));
        }

        System.out.println(DatatableBean.class.getName() + " <- init()");
    }

    public List<Item> getItems() {
        return items;
    }

    public String editItem(Item item) {
        System.out.println(DatatableBean.class.getName() + " -> editItem(): " + item);
        if (item == null) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "add item", null));
            System.out.println(DatatableBean.class.getName() + " <- editItem()");
            return "addItem.xhtml";
        } else {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "edit item", item.toString()));
            System.out.println(DatatableBean.class.getName() + " <- editItem()");
            return "editItem.xhtml";    
        }
    }
}

Item.java

package my.web.datatable;

public class Item {
    private final int id;
    private final String name;

    public Item(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return String.format("[id=%d,name=%s]", id, name);
    }
}

Is this a bug regarding command button within datatable column header facet? Or is there a better way, to do what I want?

I am using primefaces 6.0 on wildfly-10.0.0.Final with Mojarra 2.2.12!

Update: removed logger; call same method for addItem / editItem; added redirect / forward pages