2
votes

For my project i want to implement a combobox with h:selectOneMenu. I read many posts about how to handle the selectOneMenu properly and how to implement a custom converter. The combobox shall store the ID (Long) from a different DB Table (named fk_ID) for which a constrain is in place. So far everything seems to function as planned. Now to my problem:

The column fk_ID is optional, so the first option in the combobox is a f:selectItem with no value labeled "choose ...". When I save the form and change the value everything is OK, except if I set it back to "choose ...". The error I get is a constraint integrity violation.

I found the problem too: The converter returns null as intended but the bean receives the Long 0.

The XHTML:

<h:selectOneMenu value="#{userBean.selectedModel.fk_id}"
    id="combobox">
    <f:selectItem itemLabel="choose ..." />
    <f:selectItems
        value="#{userBean.items}"
        var="item"
        itemLabel="#{item.value}"
        itemValue="#{item.id}"
    />
    <f:converter converterId="userConverter" />
</h:selectOneMenu>

The custom converter:

@FacesConverter(value = "userConverter")
public class UserConverter implements Converter {
    @Override
    public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
        if (arg2 != null && !arg2.equals("null"))
            return Long.valueOf(arg2);

        return null;
    }
    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
        return String.valueOf(arg2);
    }
}

The bean (very short version):

@Named(value = "userBean")
public class UserController implements Serializable {

    @Getter
    @Setter
    private UserModel selectedModel;

    @Getter
    @Setter
    private List<UserModel> items;

    public void saveModel() {
        selectedModel = userService.saveModel(selectedModel);
    }
}

The problem is that the fk_id is Long 0, but should be null. I can solve the problem by writing

if (selectedModel.getFk_id() == 0)
    selectedModel.setFk_id(null);

, but thats not a solution I am comfortable with.

My Question: Why is the value null, which the converter returns, the Long 0 inside the saveModel() method?

1

1 Answers

5
votes

This converter is unnecessary and makes no sense (I'd expect an UserConverter to convert between User and String, not between Long and String). Remove it.

Now, you need to tell JSF to interpret empty string submitted values as null. Add the following to your web.xml:

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>

This should solve the problem on most containers. But if you're using Tomcat or a fork/clone of it (JBoss AS, WebSphere AS, etc) and/or the container uses the Apache EL parser implementation, then you also need to add the following argument to its VM startup arguments:

-Dorg.apache.el.parser.COERCE_TO_ZERO=false

This will prevent the Apache EL parser from coercing the submitted value to the primitive's default, even though you're using a primitive wrapper type as property.

See also:


Unrelated to the concrete problem, you don't have a combobox there. That's just a simple dropdownlist. A combobox is an editable dropdownlist. Get your terms right ;)