Конвертер JSF SelectOneMenu HashMap имеет неправильный экземпляр instanceOf

В моем классе Entity у меня есть HashMap. Теперь я пытаюсь создать выбор этой карты, чтобы иметь возможность выбирать объекты. Поэтому я создал следующие классы:

Конвертер лошадей:

@Named
public class HorseConverter implements Converter{

    @EJB
    private HorseBean bean;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        return bean.getHorse(Long.valueOf(value));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if(!(value instanceof Horse)){
            throw new ConverterException(new FacesMessage("Object is not a Horse"));
        } else {
            Horse h = (Horse) value;
            return Long.toString(h.getId());
        }
    }

}

Сущность гонки:

public Map<Horse, Integer> getHorses() {
        return horses;
    }

    public void setHorses(HashMap<Horse, Integer> horses) {
        this.horses = horses;
    }

И мое мнение:

Horse:
<h:selectOneMenu value="#{betController.horse}" converter="#{horseConverter}">
    <f:selectItems value="#{raceController.selectedRace.horses}" var="h" itemLabel="#{h.nickName}" itemValue="#{h}"/>
</h:selectOneMenu>

Похоже, что значение, которое я получаю, не является экземпляром Horse. Я проверил следующую ссылку: https://stackoverflow.com/tags/selectonemenu/info Итак, кажется, что ключ автоматически используется как значение. Но даже запись h.key ничего не меняет.

РЕДАКТИРОВАТЬ: Вот мой хэш и код равных из Horse Entity:

@Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + (int) (this.id ^ (this.id >>> 32));
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Horse other = (Horse) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

person VercauterenP    schedule 17.01.2013    source источник


Ответы (2)


Вы не можете использовать var для значения Map. Эта конкретная конструкция <f:selectItems> работает, только если вы используете List<Horse> вместо Map<Horse, Integer>.

public List<Horse> getHorses() {
    return horses;
}

Если вы действительно хотите использовать Map, вам следует вернуть Map<String, Horse>, где String — это псевдоним Horse.

public Map<String, Horse> getHorses() {
    return horses;
}

В случае использования значения Map не забудьте удалить var:

<f:selectItems value="#{raceController.selectedRace.horses}" />

Ключ карты становится меткой параметра, а значение карты становится значением параметра.


Не связанный с конкретной проблемой, HashMap по своей природе неупорядочен. Если вы хотите отобразить элементы раскрывающегося списка в порядке вставки, используйте LinkedHashMap.

person BalusC    schedule 17.01.2013
comment
Ну, я не уверен, что мой способ написания правильный, но карта, которую я возвращаю, взята из моего RaceController, который содержит объект «Лошадь» и сумму, на которую люди делали ставки на эту лошадь. Я полагаю, что вы говорите, что значение String (псевдоним), являющееся ключом (которое не является уникальным), заключается в том, что я не могу использовать объект в качестве ключа? - person VercauterenP; 17.01.2013
comment
Дело в том, что вы не можете использовать <f:selectItems var> в значении карты. Если вы хотите использовать var, вам нужно, например. List. Или, если вы хотите использовать Map, удалите var (а также itemLabel и itemValue) и исправьте структуру карты, чтобы она содержала именно те метки и значения, которые вам нужны. - person BalusC; 17.01.2013

Вы переопределили hashcode() и equals() в своем объекте Horse()?

Ваш конвертер нуждается в переопределении equals() для работы. Если вы этого не сделаете, только две ссылки на один и тот же экземпляр Horse() будут равны, а не два отдельных экземпляра, которые имеют точно такое же состояние. Коллекции создают неявную копию для сравнения, поэтому в этом случае у вас не будет ни одного экземпляра в куче.

Не забывайте, что аргументом объекта equals() является Object(), а НЕ Horse().

Если вы не переопределите hashcode(), хэш-код будет другим для каждого экземпляра Horse. Это означает, что вам будет сложно найти правильную лошадь для сравнения, даже если ваши лошади логически эквивалентны, потому что, опять же, у вас будет более одного экземпляра, который вы будете сравнивать, чтобы найти свою лошадь в своей HashMap.

Дополнительную информацию см. в этой главе Эффективная Java, Джошуа Блох.

person 8bitjunkie    schedule 17.01.2013
comment
Если их не переопределить, это приведет к Validation Error: value is not valid при отправке. ОП, похоже, не сталкивается с этой проблемой. ОП уже сталкивается с проблемой, когда представлена ​​только страница. Обратите внимание, что вызывается getAsString() преобразователя, а не getAsObject(). - person BalusC; 17.01.2013
comment
действительно, как заявил BalusC, equals и hash уже реализованы. Отредактировал сообщение. Спасибо хоть - person VercauterenP; 17.01.2013