p:orderList 转换器 getAsObject() 不调用 Object.toString()

p:orderList converter getAsObject() doesn't call Object.toString()

我写了一个自定义转换器如下:

@FacesConverter(value = "orderListConverter")
public class OrderListConverter implements Converter {

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

    Object ret = null;
    if (component instanceof OrderList) {
        Object list = ((OrderList) component).getValue();
        ArrayList<ExampleEntity> al = (ArrayList<ExampleEntity>) list;
        for (Object o : al) {
            String name = "" + ((ExampleEntity) o).getName();
            if (value.equals(name)) {
                ret = o;
                break;
            }
        }
    }
    return ret;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) 
{
    String str = "";
    if (value instanceof ExampleEntity) {
        str = "" + ((ExampleEntity) value).getNumber();
    }
    return str;
}
}

我的ExampleEntity实现如下:

public class ExampleEntity {

private String name;

private int number;

public ExampleEntity(String name, int number) {
    this.name = name;
    this.number = number;
}

@Override
public String toString() {
    return "toString(): [name=" + name + ", number=" + number + "]";
}

public String getName() {
    return this.name;
}

public void setName(String name) {
    this.name = name;
}

public int getNumber() {
    return number;
}

public void setNumber(int number) {
    this.number = number;
}

}

Primefaces 的 orderList-Component 看起来像这样:

<p:orderList value="#{orderListBean.exampleList}"
var="exampleEntity" itemValue="#{exampleEntity}"
converter="orderListConverter">

    <p:column style="width:25%">
        #{exampleEntity.number}
    </p:column>
    <p:column style="width:75%;">
        #{exampleEntity.name}
    </p:column>
</p:orderList>

bean 实现如下:

@SessionScoped
@ManagedBean(name = "orderListBean")
public class OrderListBean {

private List<ExampleEntity> exampleList;

@PostConstruct
public void init() {

    exampleList = new ArrayList<ExampleEntity>();

    exampleList.add(new ExampleEntity("nameOne", 1));
    exampleList.add(new ExampleEntity("nameTwo", 2));
    exampleList.add(new ExampleEntity("nameThree", 3));
    exampleList.add(new ExampleEntity("nameFour", 4));
    exampleList.add(new ExampleEntity("nameFive", 5));

}

public List<ExampleEntity> getExampleList() {
    return exampleList;
}

public void setExampleList(List<ExampleEntity> exampleList) {
    this.exampleList = exampleList;
}

}

1)调试时,getAsObject()value参数包含 ExampleEntitynumber,但我预料到了 toString() 方法 ExampleEntity 被调用!

2) itemValue 属性的正确内容是什么? 这是一种优于配置的约定吗?或者组件如何 'know',要使用整个对象,当将 exampleEntity 插入 itemValue

希望一切都清楚!非常感谢任何解释!

转换器主要用于在两个方向上转换值:

  1. 服务器到客户端,当值被呈现时。
  2. 客户端到服务器,提交值时。

在您的 getAsString 中,您建立了客户使用的字符串表示形式,即 exampleEntity 的号码。这就是作为价值呈现给客户的东西。稍后,当客户端提交其值时,该值是 number。要将其转换为对象(服务器)表示,使用 number 作为参数调用 getAsObject
服务器不可能用 exampleEntity.toString() 调用 getAsObject,因为此时它没有 exampleEntity 实例,只有提交的 number.

为了说明,这应该成立:

obj.equals(conv.getAsObject(ctx, comp, conv.getAsString(ctx, comp, obj)));

getAsObjectgetAsString 的输入和输出应该是可逆的。

回答你的第二个问题:这取决于你的需要。你可以说 itemValue="#{exampleEntity.number}",但只有当你对 exampleEntity 本身不感兴趣时​​,这才有意义,即在提交时你会从客户那里得到 number,这就是你所需要的用于您的服务器端逻辑。

@FacesConverter(value = "EntityConverter")
public class EntityConverter implements Converter, Serializable {

    private static final long serialVersionUID = 1L;

    public EntityConverter() {
        super();
    }

    @Override
    public Object getAsObject(final FacesContext context, final UIComponent component, final String value) {
        if (value == null) {
            return null;
        }
        return fromSelect(component, value);
    }

    /**
     * @param currentcomponent
     * @param objectString
     * @return the Object
     */
    private Object fromSelect(final UIComponent currentcomponent, final String objectString) {

        if (currentcomponent.getClass() == UISelectItem.class) {
            final UISelectItem item = (UISelectItem) currentcomponent;
            final Object value = item.getValue();
            if (objectString.equals(serialize(value))) {
                return value;
            }
        }

        if (currentcomponent.getClass() == UISelectItems.class) {
            final UISelectItems items = (UISelectItems) currentcomponent;
            final List<Object> elements = (List<Object>) items.getValue();
            for (final Object element : elements) {
                if (objectString.equals(serialize(element))) {
                    return element;
                }
            }
        }

        if (!currentcomponent.getChildren().isEmpty()) {
            for (final UIComponent component : currentcomponent.getChildren()) {
                final Object result = fromSelect(component, objectString);
                if (result != null) {
                    return result;
                }
            }
        }

        if (currentcomponent instanceof OrderList) {
            Object items = ((OrderList) currentcomponent).getValue();
            List<Object> elements = (List<Object>) items;
            for (final Object element : elements) {
                if (objectString.equals(serialize(element))) {
                    return element;
                }
            }
        }
        return null;
    }

    /**
     * @param object
     * @return the String
     */
    private String serialize(final Object object) {
        if (object == null) {
            return null;
        }
        return object.getClass() + "@" + object.hashCode();
    }

    @Override
    public String getAsString(final FacesContext arg0, final UIComponent arg1, final Object object) {
        return serialize(object);
    }
}