I am trying to map a list of objects
into a <p:selectOneMenu
(code shown below):
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 code
<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>
Attribute converter (attrConverter) code
@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();
}
}
However, when I am selecting a value from the dropdown menu I am getting the following exception
Validation Error: Value is not valid : Validation Error: Value is not valid
followed by an error message / pop on the top right of my screen, any idea what I am doing wrong?
PS: I have seen lots of examples that they use a unique id
in order to retrieve the object through a DTO in the getAsObject
method, in my example the uniqueness
of the the Attribute
object is the combination of type && value
member variables.
Thanks in advance for any help :)
I don't know why you cast attr to LinkedTreeMap
, you need to cast it to Attribute
class. So your converter class should be:
@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;
}
}
UPDATE
Asker oriented:
@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();
}
}