【问题标题】:JSF SelectOneMenu HashMap Converter has wrong instanceOfJSF SelectOneMenu HashMap Converter 有错误的 instanceOf
【发布时间】:2013-01-17 13:18:06
【问题描述】:

在我的实体类中,我有一个 HashMap。现在我正在尝试创建此 Map 的 Select 以便能够选择对象。所以我创建了以下类:

HorseConverter:

@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 也无济于事。

编辑: 这是我的马实体的哈希和等于代码:

@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;
    }

【问题讨论】:

    标签: jsf selectonemenu


    【解决方案1】:

    您不能在 Map 值上使用 var。这个特定的&lt;f:selectItems&gt; 结构只有在您使用List&lt;Horse&gt; 而不是Map&lt;Horse, Integer&gt; 时才有效。

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

    如果您真的想使用Map,那么您应该返回Map&lt;String, Horse&gt;,其中String 是Horse 的昵称。

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

    如果使用Map 值,请不要忘记删除var:

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

    地图的键成为选项标签,地图的值成为选项值。


    与具体问题无关,HashMap 本质上是无序的。如果您想按插入顺序显示下拉项目,请使用LinkedHashMap。

    【讨论】:

    • 好吧,我不确定我的写作方式是否正确,但我返回的地图来自我的 RaceController,其中包含 Horse 对象和人们对该马下注的金额。我想你用字符串值(昵称)作为键(不是唯一的)来告诉我我不能使用对象作为键?
    • 要点是,您不能在地图值上使用&lt;f:selectItems var&gt;。如果你想使用var,那么你需要例如List。或者,如果您想使用 Map,则删除 var(以及 itemLabel 和 itemValue)并修复映射结构,使其准确包含您需要的标签和值。
    【解决方案2】:

    您是否在 Horse() 对象中覆盖了 hashcode() 和 equals()?

    您的转换器需要重写 equals() 才能工作。如果您不这样做,则只有对同一 Horse() 实例的两个引用是相等的,而不是两个具有完全相同状态的单独实例。集合会创建一个隐式副本以进行比较,因此在这种情况下,堆上不会有单个实例。

    不要忘记 equals() 对象中的参数是 Object(),而不是 Horse()。

    如果您不覆盖 hashcode(),则每个 Horse 实例的 hashcode 都会不同。这意味着您将很难找到合适的 Horse 进行比较,即使您的 Horses 在逻辑上是等效的,因为同样,您将有多个实例进行比较,以便在 HashMap 中找到您的 Horse。

    更多信息,请参阅Effective Java by Joshua Bloch的这一章。

    【讨论】:

    • 不覆盖它们会在提交时产生Validation Error: value is not valid。 OP似乎没有面临这个问题。仅显示页面时,OP 已经面临问题。请注意,调用转换器的getAsString(),而不是getAsObject()。
    • 确实正如 BalusC 所说的那样,已经实现了等号和散列。编辑了消息。不过谢谢
    猜你喜欢
    • 2021-05-12
    • 2022-06-13
    • 2012-07-14
    • 2013-08-04
    • 2013-08-27
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 2011-06-01
    相关资源
    最近更新 更多