This site is currently read-only as we are migrating to Oracle Forums for an improved community experience. You will not be able to initiate activity until January 30th, when you will be able to use this site as normal.

    Forum Stats

  • 3,889,825 Users
  • 2,269,775 Discussions
  • 7,916,823 Comments

Discussions

UI Component (h:selectOneMenu) showing old value not matching backing bean

jmsjr
jmsjr Member Posts: 93
edited Jun 2, 2013 11:43PM in JavaServer Faces
Mojarra 2.1.7-jbossorg-1

I'm out of my wits trying to figure out what is going on here.
I have broken down the problem that I am seeing to something smaller test case that is easily reproducable.

Two <h:selectOneRadio> ( Approved and Notified )
One <h:selectOneMenu> wrapped in a <h:panelGroup>
One <h:commandButton>

The list of contents of the <h:selectOneMenu> is dependent on the value of the "Approved" <h:selectOneRadio>, and the list is obtained from the viewBean.

Apart from the "required" attribute, the only other validation is a validator method in the bean that:
If "Approved" radio button is Yes, and "Notified" radio button is No, then a ValidatorException is thrown and is shown on the <h:messages>

Now the issue:
1) Select Approved "Yes"
2) Select Notified "No"
3) Select dropdown to PEND
4) Select Submit button
5) <h:messages> show "Notified must be true when action is PEND". All good.
6) Change Approved to "No" ... Note that there is a listener on change of Approved ... and the listener will always set the value of the dropdown to null.
Because I changed the value of the Approved radio button, the dropdown selection is then changed to the "- Select- " item, which is what I am expecting as that is what the listener method does ... and the dropdown is re-rendered.
7) Change Approved back to "Yes" ... dropdown changes back to PEND ... This is what I do not understand.

Why was it being changed back to PEND when:
A) The listener on the Approved radio button always sets the value of the dropdown to null in the backend.. and
B) The Approved render attribute always re-render the dropdown
???
<!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:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"> 

<h:head></h:head> 
<body>

<h:form>
       <h:outputLabel value="Approved:"/>
       <h:selectOneRadio id="approved" value="#{viewBean.approved}"
            required="true"
            requiredMessage="Approved is required.">
            <f:selectItem itemValue="true" itemLabel="Yes"/>
            <f:selectItem itemValue="false" itemLabel="No"/>
            <f:ajax 
                event="valueChange" 
                execute="@this" 
                render="nextActionPanel" 
                listener="#{viewBean.triggerApprovedChange()}"/>
       </h:selectOneRadio>
       
       <h:outputLabel value="Notified:"/>
       <h:selectOneRadio id="notified" value="#{viewBean.notified}"
            required="true"
            requiredMessage="Notified is required."
			validator="#{viewBean.validateNotified}">
            <f:selectItem itemValue="true" itemLabel="Yes"/>
            <f:selectItem itemValue="false" itemLabel="No"/>
            <f:ajax 
                event="valueChange" 
                execute="@this" 
                render="@none"/>
       </h:selectOneRadio>
       
	   <h:panelGroup id="nextActionPanel">
       <h:selectOneMenu id="nextAction"
	        required="true"
	        requiredMessage="Next Action is required."
	        value="#{viewBean.nextAction}">
	        <f:selectItem itemValue="" itemLabel="- Select -" />
	        <f:selectItems 
	            value="#{viewBean.availableNextActions}" var="target"
	            itemValue="#{target.value}" 
	            itemLabel="#{target.label}"/>
			<f:ajax 
                event="valueChange" 
                execute="@this" 
                render="@none"/>
       </h:selectOneMenu> 
	   </h:panelGroup>
       <h:commandButton id="submit" value="Submit"/><br/>
       <h:messages/>
</h:form> 

</body> 
</html>
package test;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;

@ManagedBean
@ViewScoped
public class ViewBean implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private Boolean approved;
	private Boolean notified;
	
	private String nextAction;
	private List<NextAction> availableNextActions;
	
	public Boolean getApproved() {
		return approved;
	}

	public void setApproved(Boolean selection) {
		this.approved = selection;
	}
	
	public Boolean getNotified() {
		return notified;
	}

	public void setNotified(Boolean selection2) {
		this.notified = selection2;
	}

	public String getNextAction() {
		return nextAction;
	}

	public void setNextAction(String nextAction) {
		this.nextAction = nextAction;
	}
	
	public void triggerApprovedChange() {
		changeAvailableNextActions();
		setNextAction(null);
	}
	
	public List<NextAction> getAvailableNextActions() {
		return availableNextActions;
	}
	
	private void setAvailableNextActions(List<NextAction> availableNextActions) {
		this.availableNextActions = availableNextActions;
	}
	
	public void changeAvailableNextActions() {
		List<NextAction> nextActions = new ArrayList<NextAction>();
		
		if( Boolean.TRUE.equals( getApproved() )) {
			nextActions.add( new NextAction("PEND", "Pend"));
		}
		nextActions.add( new NextAction("REQADVICE", "Request Advice"));
		nextActions.add( new NextAction("FIN", "Finish"));
		setAvailableNextActions(nextActions);
	}
	
	@PostConstruct
	public void init() {
		changeAvailableNextActions();
	}
	
	public void validateNotified(
		FacesContext context,
        UIComponent toValidate, 
        Object value) 
		throws Exception
	{
		List<FacesMessage> messages = new ArrayList<FacesMessage>();
		Boolean isNotified = (Boolean) value;

		if( Boolean.FALSE.equals( isNotified ) && "PEND".equals( nextAction )) {
			FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
				"Notified must be true when action is PEND", null);
			messages.add( message );
		}
		
		if( messages.size() > 0 ) {
			throw new ValidatorException(messages);
		}		
	}
	
	public class NextAction implements Serializable {
		private static final long serialVersionUID = 1L;
		private String label;
		private String value;
		
		public NextAction(String aValue, String aLabel) {
			value = aValue;
			label = aLabel;
		}

		public String getLabel() {
			return label;
		}

		public String getValue() {
			return value;
		}
		
		
	}

}
«13

Answers

  • r035198x
    r035198x Member Posts: 2,499
    ViewScoped beans have pitfalls where they start behaving as request scoped beans but I don't see any code that would cause that. Is the current behavior what you would expect if the bean were request scoped?
  • jmsjr
    jmsjr Member Posts: 93
    edited May 30, 2013 2:51AM
    By adding <ui:debug/> ... and doing Ctrl+Shift+D after step [6] but before step [7], the viewState shows that the value of the <h:selectOneMenu> is STILL PEND.
    <HtmlSelectOneMenu disabled="false" id="nextAction" immediate="false" inView="true" localValueSet="true" readonly="false" rendered="true" required="true" requiredMessage="Next Action is required." transient="false" valid="true" value="PEND">
    But the question is ... why ???

    1) The value for the dropdown on the bean has been changed to null ( via the method on the listener attribute of the h:selectOneRadio) ... and ...
    2) The h:selectOneMenu has been re-rendered.

    Edited by: jmsjr on 29-May-2013 23:51
  • gimbal2
    gimbal2 Senior software engineer NetherlandsMember Posts: 11,949 Gold Trophy
    edited May 30, 2013 2:57AM
    r035198x wrote:
    ViewScoped beans have pitfalls where they start behaving as request scoped beans but I don't see any code that would cause that. Is the current behavior what you would expect if the bean were request scoped?
    Most of the viewscoped issues have been resolved actually, but this is quite an old version of JSF which will still have some of them.

    OP: You might want to consider trying upgrading JSF to a more recent version, if only to see if that changes anything in the behavior. If it does it is quite futile to keep trying to make your current code work and you'd perhaps need to drop the usage of viewscoped. You -should- be able to just deploy a newer JSF with your application and that should then be used in stead of the server default.
  • jmsjr
    jmsjr Member Posts: 93
    gimbal2 wrote:
    r035198x wrote:
    ViewScoped beans have pitfalls where they start behaving as request scoped beans but I don't see any code that would cause that. Is the current behavior what you would expect if the bean were request scoped?
    Most of the viewscoped issues have been resolved actually, but this is quite an old version of JSF which will still have some of them.

    OP: You might want to consider trying upgrading JSF to a more recent version, if only to see if that changes anything in the behavior. If it does it is quite futile to keep trying to make your current code work and you'd perhaps need to drop the usage of viewscoped. You -should- be able to just deploy a newer JSF with your application and that should then be used in stead of the server default.
    I just tried it now with 2.1.11-jbossorg-3 ( that comes with JBoss 7.1.3 ) ... same problem.
    Trying now with the latest 2.1.x mojarra implementation
  • jmsjr
    jmsjr Member Posts: 93
    edited May 30, 2013 3:29AM
    jmsjr wrote:
    gimbal2 wrote:
    r035198x wrote:
    ViewScoped beans have pitfalls where they start behaving as request scoped beans but I don't see any code that would cause that. Is the current behavior what you would expect if the bean were request scoped?
    Most of the viewscoped issues have been resolved actually, but this is quite an old version of JSF which will still have some of them.

    OP: You might want to consider trying upgrading JSF to a more recent version, if only to see if that changes anything in the behavior. If it does it is quite futile to keep trying to make your current code work and you'd perhaps need to drop the usage of viewscoped. You -should- be able to just deploy a newer JSF with your application and that should then be used in stead of the server default.
    I just tried it now with 2.1.11-jbossorg-3 ( that comes with JBoss 7.1.3 ) ... same problem.
    Trying now with the latest 2.1.x mojarra implementation
    Same problem with the latest Mojarra implementation 2.1.22 ( from https://javaserverfaces.java.net/nonav/2.1/download.html )
    Initializing Mojarra 2.1.22 ( 20130508-2000 https://svn.java.net/svn/mojarra~svn/tags/[email protected])
    Edited by: jmsjr on 30-May-2013 00:28
  • gimbal2
    gimbal2 Senior software engineer NetherlandsMember Posts: 11,949 Gold Trophy
    well, that at least gives some security that it is an issue in the usage of JSF and not a bug in the implementation.

    Unfortunately these kind of problems stem from the fact that JSF is quite complex under the hood and the only real solution is to experiment and fiddle in my opinion. I tend to start to add System.out statements to the code, including in setters, to know what is executed where. I also add a phase listener to System.out when a phase starts and ends, to know what is changed in which life cycle phase. That usually gives a good enough picture to figure out where things are happening in the wrong order.
  • jmsjr
    jmsjr Member Posts: 93
    gimbal2 wrote:
    well, that at least gives some security that it is an issue in the usage of JSF and not a bug in the implementation.

    Unfortunately these kind of problems stem from the fact that JSF is quite complex under the hood and the only real solution is to experiment and fiddle in my opinion. I tend to start to add System.out statements to the code, including in setters, to know what is executed where. I also add a phase listener to System.out when a phase starts and ends, to know what is changed in which life cycle phase. That usually gives a good enough picture to figure out where things are happening in the wrong order.
    Ok .. I am confused by what you just said .. as I did say that the same problem STILL exists in Mojarra 2.1.22.
    ergo .. It is not an issue with the usage of JSF but appears to be a bug in the implementation.

    The <ui:debug> shows that the value of the component is still showing the old value, not the value that I have in the backing bean ( which I was also debugging and can confirm that the getxxx() method is returning null instead of PEND ).
  • jmsjr
    jmsjr Member Posts: 93
    It might be the same as this one:

    https://java.net/jira/browse/JAVASERVERFACES-1974

    ... which is still open.
  • gimbal2
    gimbal2 Senior software engineer NetherlandsMember Posts: 11,949 Gold Trophy
    jmsjr wrote:
    Ok .. I am confused by what you just said .. as I did say that the same problem STILL exists in Mojarra 2.1.22.
    ergo .. It is not an issue with the usage of JSF but appears to be a bug in the implementation.
    I meant a bug in the old version that JBoss ships with. But I also mean in general; as you can see JSF 2.x is already on release 22 - the chance of you finding such an easy to trigger bug has become relatively slim. So no, I must assume it is actually a problem with not understanding how JSF ticks properly. Which is understandable since after using it for 5 years it still surprises me occasionally.

    The bug you link to is about values staying the same, not reverting back to a previous state.
  • jmsjr
    jmsjr Member Posts: 93
    gimbal2 wrote:
    jmsjr wrote:
    Ok .. I am confused by what you just said .. as I did say that the same problem STILL exists in Mojarra 2.1.22.
    ergo .. It is not an issue with the usage of JSF but appears to be a bug in the implementation.
    I meant a bug in the old version that JBoss ships with. But I also mean in general; as you can see JSF 2.x is already on release 22 - the chance of you finding such an easy to trigger bug has become relatively slim. So no, I must assume it is actually a problem with not understanding how JSF ticks properly. Which is understandable since after using it for 5 years it still surprises me occasionally.

    The bug you link to is about values staying the same, not reverting back to a previous state.
    OK .. Maybe this will be more convincing (?). I change the xhtml so that it also displays ( via h:outputText ) .. the value of the backing bean that is the same value used for the h:selectOneMenu.
    <!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:f="http://java.sun.com/jsf/core"
          xmlns:ui="http://java.sun.com/jsf/facelets"> 
     
    <h:head></h:head> 
    <h:body>
     
    <h:form>
           <h:outputLabel value="Approved:"/>
           <h:selectOneRadio id="approved" value="#{viewBean.approved}"
                required="true"
                requiredMessage="Approved is required.">
                <f:selectItem itemValue="true" itemLabel="Yes"/>
                <f:selectItem itemValue="false" itemLabel="No"/>
                <f:ajax 
                    event="valueChange" 
                    execute="@this" 
                    render="nextActionPanel" 
                    listener="#{viewBean.triggerApprovedChange()}"/>
           </h:selectOneRadio>
           
           <h:outputLabel value="Notified:"/>
           <h:selectOneRadio id="notified" value="#{viewBean.notified}"
                required="true"
                requiredMessage="Notified is required."
    			validator="#{viewBean.validateNotified}">
                <f:selectItem itemValue="true" itemLabel="Yes"/>
                <f:selectItem itemValue="false" itemLabel="No"/>
                <f:ajax 
                    event="valueChange" 
                    execute="@this" 
                    render="@none"/>
           </h:selectOneRadio>
           
    	   <h:panelGroup id="nextActionPanel">
    	   Backing Bean value for nextAction is '<h:outputText value="#{viewBean.nextAction}"/>'<br/>
           <h:selectOneMenu id="nextAction"
    	        required="true"
    	        requiredMessage="Next Action is required."
    	        value="#{viewBean.nextAction}">
    	        <f:selectItem itemValue="" itemLabel="- Select -" />
    	        <f:selectItems 
    	            value="#{viewBean.availableNextActions}" var="target"
    	            itemValue="#{target.value}" 
    	            itemLabel="#{target.label}"/>
    			<f:ajax 
                    event="valueChange" 
                    execute="@this" 
                    render="nextActionPanel"/>
           </h:selectOneMenu> 
    	   </h:panelGroup>
           <h:commandButton id="submit" value="Submit" render="@form"/><br/>
           <h:messages/>
    	   <ui:debug/>
    </h:form> 
     
    </h:body> 
    </html>
    All I changed was

    1) Added the following:
     Backing Bean value for nextAction is '<h:outputText value="#{viewBean.nextAction}"/>'<br/>
    .. which is in the same panel ( <h:panelGroup id="nextActionPanel"> ) as the <h:selectOneMenu>

    2) Changed the render attribute of the h:selectOneMenu so that instead of @none, it is now:
    			<f:ajax 
                    event="valueChange" 
                    execute="@this" 
                    render="nextActionPanel"/>
    3) Repeated the same steps as before ... and after step [6]:

    3a) The h:outputText says:
    Backing Bean value for nextAction is ''
    3b) But the h:selectOneMenu still has the PEND option selected.
This discussion has been closed.