Это действительно "задумано" и, возможно, немного опущено в спецификации JSF.Теоретически вы можете избежать этого, извлекая элементы из аргумента UIComponent
и сравнивая их.Это, однако, немного работы.Мой коллега Арджан Тиймс написал блог об этом: Автоматическое преобразование объектов в JSF selectOneMenu & Co.
Вот выдержка из статьи;ниже приведен базовый конвертер, который вам нужно вместо этого расширить:
public abstract class SelectItemsBaseConverter implements Converter {
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return SelectItemsUtils.findValueByStringConversion(context, component, value, this);
}
}
Вот класс SelectItemsUtils
, который частично скопирован из источника Мохарры:
public final class SelectItemsUtils {
private SelectItemsUtils() {}
public static Object findValueByStringConversion(FacesContext context, UIComponent component, String value, Converter converter) {
return findValueByStringConversion(context, component, new SelectItemsIterator(context, component), value, converter);
}
private static Object findValueByStringConversion(FacesContext context, UIComponent component, Iterator<SelectItem> items, String value, Converter converter) {
while (items.hasNext()) {
SelectItem item = items.next();
if (item instanceof SelectItemGroup) {
SelectItem subitems[] = ((SelectItemGroup) item).getSelectItems();
if (!isEmpty(subitems)) {
Object object = findValueByStringConversion(context, component, new ArrayIterator(subitems), value, converter);
if (object != null) {
return object;
}
}
} else if (!item.isNoSelectionOption() && value.equals(converter.getAsString(context, component, item.getValue()))) {
return item.getValue();
}
}
return null;
}
public static boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
/**
* This class is based on Mojarra version
*/
static class ArrayIterator implements Iterator<SelectItem> {
public ArrayIterator(SelectItem items[]) {
this.items = items;
}
private SelectItem items[];
private int index = 0;
public boolean hasNext() {
return (index < items.length);
}
public SelectItem next() {
try {
return (items[index++]);
}
catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
Вот как выследует использовать его для собственного конвертера, вам нужно только реализовать getAsString()
(getAsObject()
уже обработан):
@FacesConverter("someEntitySelectItemsConverter")
public class SomeEntitySelectItemsConverter extends SelectItemsBaseConverter {
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((SomeEntity) value).getId().toString();
}
}
Обновление вышеупомянутая концепция закончиласьв служебной библиотеке JSF OmniFaces во вкусе следующих преобразователей: