-1

I cannot see why the question is duplicate. If I debug the code then - when the button is clicked - no new value of projectSelected is being detected. Even the hashCode is the same. The equals method of the ProjectEntity only contains the id which is the same since it comes from the database and is not changed anywhere. Null values don't exist in the selection.

There was, however, too much code to reproduce the problem. I removed unnecessary code and the problem still persists.

Original question: In the following form with 3 <p:selectOneMenu> -fields if the submit button is clicked a valueChangeEvent is fired for the projectSelector field although it hasn't changed. Why is that? Like that the actual action behind the button is never called. I would expect a valueChangeEvent to be fired only in case the project changes.

Update: Trying to find the cause I replaced the ProjectEntity with String and then it worked. So I thought it must be the equals method of ProjectEntity but that only compares the id. I debugged further and found out that the selected value is being compared with a ProjectEntity with all fields set to null which gives a false and hence a valueChangeEvent. So the question is why is there a ProjectEntity with all fields set to null? I debugged into UIInput.compareValues which has that "null"-ProjectEntity being the previous value. That is being returned by UIOuput.getLocalValue. Where does it come from?

Update2: Even when using the equals and hashCode from selectOneMenu shows after submit always the last item in the list as selected item the behaviour does not change. I created an ear file readily to be deployed to e.g. a wildfly and would appreciate any help since I am stuck on this question.

<h:form>
    <p:outputLabel value="#{msgs.timeProject}"/>
    <p:selectOneMenu value="#{timeBean.model.projectSelected}"
                     converter="projectConverter"
                     onchange="submit()"
                     valueChangeListener="#{timeBean.projectChanged}"
                     immediate="true"
                     required="true">
        <f:selectItems value="#{timeBean.model.allProjects}"
                       var="singleProject"
                       itemValue="#{singleProject}"
                       itemLabel="#{singleProject.name}"/>
    </p:selectOneMenu>
    <p:commandButton value="#{msgs.send}"
                     action="#{timeBean.myAction}"
                     ajax="false"/>
    <p:outputLabel value="#{timeBean.model.resultValue}" 
                   rendered="#{not empty timeBean.model.resultValue}"/>
</h:form>

The converter

@FacesConverter(value = "projectConverter")
public class ProjectConverter implements Converter {

    @Inject
    private ProjectService projectService;

    @Override
    public Object getAsObject(final FacesContext facesContext, final UIComponent uiComponent, final String projectName) {
        if (StringUtils.isEmpty(projectName)) {
            return null;
        }
        final List<ProjectEntity> projects = projectService.findAll();
        for (ProjectEntity project : projects) {
            if (StringUtils.equals(projectName, project.getName())) {
                return project;
            }
        }
        return null;
    }

    @Override
    public String getAsString(final FacesContext facesContext, final UIComponent uiComponent, final Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof ProjectEntity) {
            return ((ProjectEntity) value).getName();
        }
        return "???projectName???";
    }
}

The equals-method of the ProjectEntity

@Override
public boolean equals(final Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;

    final ProjectEntity that = (ProjectEntity) o;

    return id != null ? id.equals(that.id) : that.id == null;
}

And the change listener inside the timeBean

public void projectChanged(final ValueChangeEvent event) {
    final ProjectEntity projectSelected = (ProjectEntity) event.getNewValue();
    model.setProjectSelected(projectSelected);
    final FacesContext context = FacesContext.getCurrentInstance();
    context.renderResponse();
}

The TimeModel

public class TimeModel {
    private ProjectEntity projectSelected;
    private List<ProjectEntity> allProjects;
    private String resultValue;
    ... getters and setters ...
Mfried
  • 57
  • 2
  • 9
  • 1
    Is this the absolute minimum amount of code required to reproduce your problem? – Athena Jul 19 '16 at 18:22
  • Have you confirmed that the value in fact did not change? It could happen even if you don't touch this particular select in UI. For example if the initial value of `#{timeBean.model.projectSelected}` is not among those in `#{timeBean.model.allProjects}` (eg. null), than the first POST will post the first item from `#{timeBean.model.allProjects}` and the ValueChangeListener will fire. – korolar Jul 19 '16 at 19:40
  • If the submit (commandButton) if being clicked, it will perform the same task, i.e., `submit()` the form. This is the same function that is called with the `onChange` event for the selectMenu – Esteban Rincon Jul 19 '16 at 21:44
  • I think your question is quite correct. Unfortunately, tag golden badge owners are doing things a little bit unpredictable. I suggest to examine the dupe, and check if it answers your question or not. If it doesn't, then explain it here in a comment very clearly! You got my reopen vote. – peterh Jul 23 '16 at 21:42
  • 1
    Your suggestion btw is very good! But... Tag golden badge owners don't do things unpredictable. On the contrary. 99.5% they are right. They read so many questions in their free (as in beer) time helping out others, that with all the knowledge they have, they can by just quickly scanning posts have a very high 'positive duplicate' rate. But yes, they are human, so an occasional error might slip in. This would most likely be even reduced further if an [mcve] was created from the beginning. Yet many do not since they expect others to be clairvoyant, which even the tag golden badge owners are not. – Kukeltje Jul 28 '16 at 07:17
  • The initial duplicate still answered the question: the old and new value are not `equals()`. A broken `equals()` implementation in the model is in turn unrelated to JSF. JSF is just doing its job with whatever model you supply to it. – BalusC Jul 28 '16 at 10:49
  • I prepared the sample as a pure ear file without any additional code. I really would appreciate it if someone could have a look at it. You could e.g. just deploy it to a wildfly. No viruses or anything else! https://www.sendspace.com/file/fv2own – Mfried Aug 09 '16 at 18:03

1 Answers1

0

I'll guess, that the problem resides inside the ProjectConverter class, cause it may run into troubles to assign a valid projectService instance. Maybe you remove the injection and try to compute the value programatically in the getAsObject, getAsString methods by explicit cdi-finders.

I remember to run in a similar situation, when i was injecting in a ServletFilter.

Groovieman
  • 31
  • 5