我希望有一个带有公式和下拉菜单的facelet页面。使用下拉菜单,用户可以选择Lieferant类型的POJO:
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;
}
}
这是我写的facelet代码:
<h:selectOneMenu>
标签。此标记应显示Lieferant类型的POJO(非bean)列表。这是facelet代码:
<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>
这是refenrenced托管支持bean
@ManagedBean
@RequestScoped
public class LieferantenBackingBean extends AbstractWarenwirtschaftsBackingBean {
private List<Lieferant> lieferanten;
public List<Lieferant> getLieferanten() {
if (lieferanten == null) {
lieferanten = getApplication().getLieferanten();
}
return lieferanten;
}
}
据我所知,我需要一个自定义转换器来交换POJO和Lieferant对象的String表示之间的交换。这是转换器的样子:
@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();
}
}
页面加载时没有任何错误。当我填写公式并提交时,页面上会显示一条错误消息:
Bestellung:lieferantenBestellungForm:lieferant: Validierungsfehler: Wert ist keine gültige Auswahl
translated: validation error: value is not a valid selection
不幸的是,它没有说出它所谈论的价值。转换器似乎正常工作。
我发现了similar question from stackoverflow这个 article about selectOneMenu and converters,但我无法在代码中找到问题。为什么
List<SelectItem>
在第二个链接的示例中使用。给我同样的错误。
任何帮助将不胜感激。提前谢谢。
答案 0 :(得分:2)
验证错误:值不是有效选择
此错误表示所选项目与列表中的任何选项都不匹配。在您的情况下,这可能有两个原因:Object#equals()
被错误地实现,或者<f:selectItems>
后面的getter不会在后续请求中(在提交表单期间)返回相同的列表。初始请求(在提交表单之前,在选择值时)。
要排除其中一个:您可以使用“普通的vanilla”测试用例轻松测试Object#equals()
,并且可以通过将bean放在会话范围内来测试列表的一致性。
要清楚,您的转换器看起来很好并且似乎工作正常(否则您将无法获得此类错误消息;因此转换步骤已成功完成)。
答案 1 :(得分:0)
我真的很确定转换器工作正常,但最后的错误是在转换器中。也许这在调试的几个小时内发生了。这是转换器的固定getAsString方法。 Ñ
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value != null && value instanceof Lieferant) {
Lieferant lieferant = (Lieferant) value;
return "" + lieferant.getPrimaryKey();
}
return "";
}
现在它返回primaryKey,它被用作selectOneMenu列表的值。另外,我从selectItems标签中更改了此属性:
itemValue="#{lieferant}"
现在,如果最后一次改变是必要的,我并不感到害羞。但现在谎言被正确转换了。