【问题标题】:Converter for list of objects that have as unique id a tuple of 2 member variables具有唯一 id 2 个成员变量元组的对象列表的转换器
【发布时间】:2019-11-05 15:13:14
【问题描述】:

我正在尝试将list of objects 映射到<p:selectOneMenu(代码如下所示):

Attribute.java

public class Attribute implements Serializable {
 private String name;
 private String type;
 private String value; //getters setters constructors ommitted

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Attribute attribute = (Attribute) o;
    return Objects.equals(name, attribute.name) &&
            Objects.equals(type, attribute.type);
}

@Override
public int hashCode() {
    return Objects.hash(name, type, value);
}

p:selectOneMenu 代码

 <p:selectOneMenu label="Existing Attributes" value="#{cellBean.selectedAttributeFromExistings}"
                                                 converter="attrConverter">
      <f:selectItem itemLabel="Existing attribute" itemValue="#{null}" itemDisabled="true"/>
      <f:selectItems value="#{cellBean.allAttributes}" var="attr" itemLabel="#{attr.name}" itemValue="#{attr}"/>
  <p:ajax event="change" update="@form" process="@form"/>
  </p:selectOneMenu>

属性转换器(attrConverter)代码

@FacesConverter(forClass=Attribute.class,  value = "attrConverter")
public class AttributeConverter implements Converter {

@Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
    String type = s.substring(s.indexOf(":") + 2, s.indexOf(","));
    String name = s.substring(s.indexOf("name: ") + 6 , s.length());
    Attribute attribute = new Attribute(type, name);
    return attribute;
}

@Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object attr) {
    if(attr == null) {
        return null;
    }
    else{
        Attribute attribute = new Attribute();
        String s = "";
        Iterator iterator = ((LinkedTreeMap)attr).keySet().iterator();
        while(iterator.hasNext()){
            String key = (String) iterator.next();
            String value = (String) ((LinkedTreeMap)attr).get(key);
            if(key.equals("name")){
                attribute.setName(value);
            }
            else if(key.equals("type")){
                attribute.setType(value);
            }

        }
        return attribute.toString();
    }
}

但是,当我从下拉菜单中选择一个值时,出现以下异常

验证错误:值无效:验证错误:值无效

然后在我的屏幕右上角出现错误消息/弹出,知道我做错了什么吗?

PS:我见过很多例子,他们使用unique id 来通过getAsObject 方法中的DTO 检索对象,在我的例子中是uniqueness Attribute 对象是type &amp;&amp; value 成员变量的组合。

提前感谢您的帮助:)

【问题讨论】:

  • 所以你是说它适用于普通的 jsf h:selectOneMenu? (和转换器是 JSF 的东西,而不是 PrimeFaces 的东西。
  • getAsString 中,你的attr 对象是LinkedTreeMap,而getAsObject 返回Attribute...。这是不一致的,实际上是错误的。
  • 嗨@Kukeltje 感谢您的评论,事实上,在getAsString attr 对象是一个LinkedTreeMap 而getAsObject 返回一个Attribute 是一个不一致(和问题)。错误是我不小心使用gson 错误地序列化了一个json,而不是属性列表,而是将其转换为LinkedTreeMap。

标签: jsf primefaces selectonemenu converters


【解决方案1】:

我不知道你为什么将 attr 转换为 LinkedTreeMap,你需要将它转换为 Attribute 类。所以你的转换器类应该是:

@FacesConverter(forClass=Attribute.class,  value = "attrConverter")
public class AttributeConverter implements Converter {

 @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {

        if (value != null && value.trim().length() > 0 && !value.isEmpty()) {
         /*I take your bean as ViewScoped */
            CellBean cellBean = (CellBean) context.getViewRoot().getViewMap().get("cellBean");
            for(Attribute a : cellBean.getAllAttributes()){
                String combined = a.getType()+a.getValue();
                if(combined.equals(value)){
                    return a;
                }
            }
        }
        return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value)            {
        if (value != null) {
            Attribute a = (Attribute) value;
            return a.getType()+a.getValue();
        }
        return null;
    }
}

更新

面向提问者:

@Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
    String[] typeAndName = s.split("#");
    return new Attribute(typeAndName[0], typeAndName[1]);

}

@Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object attr) {
    if(attr == null) {
        return null;
    }
    else{
        /* I assume your type and name don't contain '#' charachter */
        return ((Attribute)attr).getType()+"#"+((Attribute)attr).getName();
    }
}

【讨论】:

  • 你是对的@mismanc,我不小心将属性列表错误地序列化为LinkedTreeMap,这是问题的根源,我将发布与你相似的最终答案...... +1: )
  • 我不知道你为什么在每次调用 getAsObject 函数时都创建新对象,但我会给你简单的方法来解码类型和名称。由您决定使用或不检查更新;).. @NickAth
  • 我喜欢你的解码方式,不幸的是,当我尝试提交selectOneMenu 现在所属的表单时,我遇到了一个新问题,(javascript 错误)我猜是因为转换器,因为当我从表单中删除 selectOneMenu 时,提交发生 VM2072:3 Uncaught SyntaxError: Unexpected identifier at new Function (&lt;anonymous&gt;) at Object.jsf.util.chain (jsf.js.xhtml?ln=javax.faces&amp;stage=Development:3192) 如果您愿意,我可以附上错误的屏幕截图:)
  • 对于新问题,您必须打开新问题@NickAth。
【解决方案2】:

问题的根源是我使用gson 的错误序列化,我将Attribute 对象转换为LinkedTreeMap,这也是cmets 部分中提到的不一致。当我正确进行序列化时,getAsObjectgetAsString 函数具有以下形式:

@Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
    String type = s.substring(s.indexOf("type=") + 5, s.indexOf(" "));
    String name = s.substring(s.indexOf("name=") + 5 , s.length());
    Attribute attribute = new Attribute(type, name);
    return attribute;

}

@Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object attr) {
    if(attr == null) {
        return null;
    }
    else{
        return "type="+((Attribute)attr).getType()+" name="+((Attribute)attr).getName();
    }
}

【讨论】:

  • 不,真正的原因不是错误的序列化,而是我的评论中的内容以及您有两种不同类型的另一个答案。 that 是由错误的序列化引起的,这有点无关紧要;-)
  • 你是对的,我在我发布的答案中重复了真正的原因是你提到的(类型不一致):)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-09
  • 2021-01-24
  • 1970-01-01
  • 2023-02-04
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多