null

Primefaces SelectOneMenu и null значение

Доброе утречко!

Сегодня рассмотрим такую задачу, как выбор null значения в компоненте p:SelectOneMenu

Что у нас имеется:

Форма с selectOneMenu

<p:selectOneMenu id="parent-unit-selector" value="#{unitBean.selectedParentUnit}"
                                     converter="#{unitConverter}">
            <f:selectItem itemLabel="-" itemValue=""/>
            <f:selectItems value="#{unitBean.parents}" var="p"
                           itemLabel="#{p.name}"
                           itemValue="#{p}"/>
</p:selectOneMenu>

Конвертер:

@FacesConverter("unitConverter")
@ManagedBean(name = "unitConverter")
@ApplicationScoped
public class UnitConverter implements Converter {
    @ManagedProperty(value = "#{unitUtil}")
    @Getter
    @Setter
    private UnitUtill unitUtill;

    public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
        if (value != null && value.trim().length() > 0) {
            try {
                return unitUtil.getUnit(Long.parseLong(value));
            } catch (NumberFormatException e) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid unit."));
            }
        } else {
            return null;
        }
    }

    public String getAsString(FacesContext fc, UIComponent uic, Object object) {
        if (object != null) {
            return String.valueOf(((Unit) object).getId());
        } else {
            return null;
        }
    }
}

Ну и бин, код которого, в общем то, ни на что не влияет.

В Primefaces 6.2 данная комбиная f:selectItem с itemalue="" и конвертера работает прекрасно, однако в версии 7.0 мы получаем такую ошибку при рендере страницы.

 class java.lang.String cannot be cast to class com.tuneit.Unit

Заменим значение itemValue с "" на "#{null}". Проблемма с класс-кастом пропала, однако теперь в конвертер приходит значение не itemValue, а itemLabel.

Это происходит потому, что наш конвертер null значение в методе getAsString преобразовывает к null, в результате чего JSF не рендерит аттрибут value у тега option и браузер при выборе значения отправляет на сервер значение лейбла. Дабы этого избежать немножко подправим наш конвертер, чтобы вместо null он возвращал пустую строку.

@FacesConverter("unitConverter")
@ManagedBean(name = "unitConverter")
@ApplicationScoped
public class UnitConverter implements Converter {
    @ManagedProperty(value = "#{unitUtil}")
    @Getter
    @Setter
    private UnitUtill unitUtill;

    public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
        if (value != null && value.trim().length() > 0) {
            try {
                return unitUtil.getUnit(Long.parseLong(value));
            } catch (NumberFormatException e) {
                throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid unit."));
            }
        } else {
            return null;
        }
    }

    public String getAsString(FacesContext fc, UIComponent uic, Object object) {
        if (object != null) {
            return String.valueOf(((Unit) object).getId());
        } else {
            return "";
        }
    }
}

После данных нехитрых манипуляций, наш компонент заработает как и ожидается.