1

I've written a custom converter as follows:

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

My ExampleEntity is implemented as follows:

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

}

the orderList-Component from Primefaces looks like that:

<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>

and the bean is implemented as follows:

@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) when debugging, the value Parameter of getAsObject() contains the number of the ExampleEntity, but I had expected the toString() method of ExampleEntity to be called!

2) What is the correct content for itemValue attribute? Is it a kind of convention over configuration? Or how does the component 'know', to use the whole object, when inserting exampleEntity into itemValue

Hope everything is clear! Tanks a lot for any explanation!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
bauz
  • 125
  • 1
  • 12

2 Answers2

2

Converters basically serve to transform values in 2 directions:

  1. Server to client, when the value is rendered.
  2. Client to server, when the value is submitted.

In your getAsString you established, that the string representation, the one which client uses, is exampleEntity's number. So that's what gets rendered to client as a value. And later, when the client submits its value, that value is number. To convert it to the object (server) representation, the getAsObject called with the number as a parameter.
The server can't possibly call getAsObject with exampleEntity.toString(), because it doesn't have the exampleEntity instance at that point, only the submitted number.

To illustrate, this should hold:

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

getAsObject and getAsString should be inversive in their input and output.

To answer your 2nd question: that depends on your needs. You could say itemValue="#{exampleEntity.number}", but that would make sense only if you're not interested in the exampleEntity itself, i.e. on submit you would get the number from the client and that's all you need for your server-side logic.

Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65
  • Question 2: I understand, that `exampleEntity` will return the whole Object. But there is no Annotation or anything else (like for the Bean `(name = "beanName")` so how do I know how to write the correct name. Is it always the class-name with lowercase beginning? It was more or less a guess to write `exampleEntity` – bauz Jun 01 '15 at 08:52
  • 2
    @bauz_69, in your `p:orderList` you define `value` to say "iterate collection `#{orderListBean.exampleList}`" with `var="exampleEntity"` as the name of the loop variable. You could've just as well made it `var="whatever"` and `itemValue="#{wharever}"`. – Vsevolod Golovanov Jun 01 '15 at 13:50
-1
@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);
    }
}
help-ukraine-now
  • 3,850
  • 4
  • 19
  • 36