具有 2 个成员变量的元组作为唯一 ID 的对象列表的转换器

Converter for list of objects that have as unique id a tuple of 2 member variables

我正在尝试将 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();
    }
}

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

Validation Error: Value is not valid : Validation Error: Value is not valid

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

PS: 我见过很多例子,他们使用 unique id 来通过 [=16 中的 DTO 检索对象=] 方法,在我的示例中 Attribute 对象的 uniquenesstype && value 成员变量的组合。

在此先感谢您的帮助:)

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

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

问题的根源是我使用 gson 进行了错误的序列化,我将 Attribute 对象转换为 LinkedTreeMap,这也是评论部分中提到的不一致。当我正确地进行序列化时,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();
    }
}