I want to have a facelet page with a formular and a dropdown menu. With the dropdown menu the user shoul select a POJO of the type Lieferant:
public class Lieferant extends AbstractPersistentWarenwirtschaftsObject {
private String firma;
public Lieferant(WarenwirtschaftDatabaseLayer database, String firma) {
this(database, null, firma);
}
public Lieferant(WarenwirtschaftDatabaseLayer database, Long primaryKey, String firma) {
super(database, primaryKey);
this.firma = firma;
}
public String getFirma() {
return firma;
}
@Override
public String toString() {
return getFirma();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firma == null) ? 0 : firma.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Lieferant other = (Lieferant) obj;
if (firma == null) {
if (other.firma != null)
return false;
} else if (!firma.equals(other.firma))
return false;
return true;
}
}
Here is the facelet code that I wrote:
<h:selectOneMenu>
tag. This tag should display a list of POJOs (not beans) of the type Lieferant. Here is the facelet code:
<h:selectOneMenu id="lieferant" value="#{lieferantenBestellungBackingBean.lieferant}">
<f:selectItems var="lieferant" value="#{lieferantenBackingBean.lieferanten}" itemLabel="#{lieferant.firma}" itemValue="#{lieferant.primaryKey}" />
<f:converter converterId="LieferantConverter" />
</h:selectOneMenu>
Here is the refenrenced managed backing bean
@ManagedBean
@RequestScoped
public class LieferantenBackingBean extends AbstractWarenwirtschaftsBackingBean {
private List<Lieferant> lieferanten;
public List<Lieferant> getLieferanten() {
if (lieferanten == null) {
lieferanten = getApplication().getLieferanten();
}
return lieferanten;
}
}
As far as I know, I need a custom converter, to swap beetween POJO and String representations of the Lieferant objects. Here is what the converter looks like:
@FacesConverter(value="LieferantConverter")
public class LieferantConverter implements Converter {
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
long primaryKey = Long.parseLong(value);
WarenwirtschaftApplicationLayer application = WarenwirtschaftApplication.getInstance();
Lieferant lieferant = application.getLieferant(primaryKey);
return lieferant;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
The page loads without any error. When I fill out the formular and submit it, there is an error message displayed on the page:
Bestellung:lieferantenBestellungForm:lieferant: Validierungsfehler: Wert ist keine gültige Auswahl
translated: validation error: value is not a valid selection
Unfortunaltely it does not say which value it is talking about. The converter seems to work correctly.
I found this similar question from stackoverflow and this article about selectOneMenu and converters, but I was not able to find the problem in my code. Why is
List<SelectItem>
used in the example from the second link. Gives the same error for me.
Any help would be appreciated. Thanks in advance.
This error means that the selected item does not match any of the select items in the list. In your case this can have two causes: either
Object#equals()
is wrongly implemented, or the getter behind<f:selectItems>
doesn't return the same list in the subsequent request (during submitting the form) as it did during the initial request (before submitting the form, during selecting the value).To exclude the one or other: you can easily test
Object#equals()
with a "plain vanilla" testcase and you can test the consistency of the list by putting the bean in session scope.To be clear, your converter looks fine and seems to work fine (else you wouldn't be able to get this kind of error message; the conversion step was thus completed successfully).
I was realy shure that the converter was working correctly, but the final error was in the converter. Maybe this happened someway during hours of debugging. Here is the fixed getAsString method of the converter. N
Now it returns the primaryKey which is used as the value of the selectOneMenu list. Additionally I changed this attribute from the selectItems tag:
Right now I am not shure if this last change was neccessary. But now the lieferants are converted correctly.