0
votes

I am in the process of upgrading from GlassFish 4.1.2 to GlassFish 5.1.0 and encountered an issue where the Update Model phase of the JSF lifecycle is setting the value of the ID property of my @ViewScoped CDI backing beans to null. The following is my simplified view.

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
template="/WEB-INF/templates/modena.xhtml">
<ui:define name="title">Location Editor2</ui:define>
<ui:define name="content">
    <f:metadata>
        <f:viewParam name="id" value="#{locationEditor2.location.id}" />
        <f:viewAction action="#{locationEditor2.setLocationById}" />
    </f:metadata>
    <h:form id="location-editor-form">
        <p:commandButton value="Update" styleClass="RaisedButton"
            action="#{locationEditor2.updateLocation}" update="@form" />
    </h:form>
</ui:define>
</ui:composition>

The following is my simplified CDI backing bean.

import java.io.Serializable;

import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.elliottlogic.elis.ejb.location.Location;
import com.elliottlogic.elis.ejb.location.LocationManager;
import com.elliottlogic.elis.ejb.security.AuthorizationException;
import com.elliottlogic.elis.wa.core.ExceptionTools;

/**
 * The <code>LocationEditor2</code> class TODO Complete Type Description
 *
 * @author jre
 * @version $Id: $
 *
 */
@Named
@ViewScoped
public class LocationEditor2 implements Serializable {

final static Logger logger = LoggerFactory.getLogger(LocationEditor2.class.getName());

static final long serialVersionUID = 1L;

private Location location = new Location();

@EJB
private LocationManager locationManager;

/**
 * Configures model using persisted values.
 * 
 * @throws AuthorizationException
 */
public void setLocationById() throws AuthorizationException {

    try {

        location = locationManager.readLocationByID(location.getId());

    } catch (EJBException e) {

        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Location not found.", "Location not found."));

        ExceptionTools.unwrapEJBException(FacesContext.getCurrentInstance(), e);

    }

}

/**
 * Saves the changes to the location.
 * 
 * @return
 */
public String updateLocation() {

    logger.debug("Location ID: {}", location.getId());

    return null;

}

/**
 * @return the location
 */
public Location getLocation() {
    return location;
}

/**
 * @param location
 *            the location to set
 */
public void setLocation(Location location) {
    this.location = location;
}

}

The following demonstrates the issue:

  1. Point Browser at LocationEditor2.xhtml?id=1
  2. Select the [Update] button.
  3. The updateLocation method logs "Location ID: 1"
  4. Select the [Update] button
  5. The updateLocation method logs "Location ID: null"

I verified that the view is not being recreated and that something is calling the setId(Long id) method with a value of null during the Update Model JSF phase.

Why is the JSF Update Model phase setting the ID of my entity to null during the second and addition postbacks?

1
I'm using a LifeCycleListener to analyze the JSF phases at the momemt.Reed Elliott
Using a LifeCycleListener, I see the setId method being called during the Update Model Phase. In the successful case, the existing ID and the new ID are the same but in the unsuccessful case, the existing ID is correct but the new ID is null. I'm not sending the ID in form so I don't understand why JSF wants to change it.Reed Elliott
I assume that you are complaining about my example code. I am in the process of building a simplified client from scratch in order to understand what has changed in GlassFish between version 4.1.2 and 5.1.0 to break my code and will update the above code once I'm finished.Reed Elliott
I edited the original post by simplifying the code as requested by @Kukeltje.Reed Elliott
Hi tgabksor the attempt. But it is not about 'simplifying', it is about a minimal reproducible example. See also stackoverflow.com/tags/jsf/infoKukeltje

1 Answers

0
votes

The root cause of the issue is that something is calling the setId(null) method on my entity during the update model phase of the JSF lifecycle. I used the StackTraceElement[] array within my setId() method to review the calling methods and determined that the updateModel method of the UIViewParameter class was the culprit.

After a little googling, I found the OmniFaces viewParam Showcase which provides "Stateless mode to avoid unnecessary conversion, validation and model updating on postbacks". After changing my code to use the OmniFaces viewParam component, the JSF Update Model infrastructure stopped calling the setId() method on my entity during postback and everything worked as it did in GlassFish 4.1.2.

The solutions is to move from the standard f:viewParam to the OmniFaces o:viewParam.