p:autoComplete itemLabel抛出“类'java.lang.String'没有属性'label'。”
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了p:autoComplete itemLabel抛出“类'java.lang.String'没有属性'label'。”相关的知识,希望对你有一定的参考价值。
我正在从IceFaces变为PrimeFaces(我真的想改为RichFaces,但是在新版本中会导致错误,我不会)并且我正在努力实现正确的primefaces autoComplete。根据他的手册,我只需要实现一个返回对象列表的方法,在这种情况下需要一个转换器。
我正在返回的列表是javax.faces.model.SelectItem的列表,我真的不明白为什么我需要为此创建一个转换器,但让我们继续。我创建了一个简单的转换器来测试,但是primefaces无法识别我的转换器并在浏览器中返回此错误:
/resources/components/popups/popupBuscaPessoa.xhtml @ 35,41 itemLabel =“#{pessoa.label}”:类'java.lang.String'没有属性'label'。
这是我的转换课程(只是为了测试):
public class ConversorSelectItem implements Converter {
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value!=null && value.isEmpty())
return null;
SelectItem selectItem=new SelectItem();
selectItem.setLabel(value);
return selectItem;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
return ((SelectItem)object).getLabel();
}
}
这是我尝试使用p:autocomplete的地方:
<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
var="pessoa" itemLabel="#{pessoa.label}" itemValue="#{pessoa.value}"
converter="#{conversorSelectItem}"/>
我做错什么了吗?是否有SelectItem的默认转换器?有没有更简单的方法来实现这个转换器?
你不应该用List<SelectItem>
喂它。你应该用List<Pessoa>
喂它。你也不应该专注于转换SelectItem
。您应该专注于转换项目值,即Pessoa
。 SelectItem
是旧JSF 1.x时代的遗留物。在JSF 2.x中,由于视图中的var
,itemValue
和itemLabel
属性,这不再是强制性的。这样可以使bean保持清洁,避免特定于视图的混乱。
Converter
只在你使用itemValue="#{pessoa}"
时才有必要,而#{modeloPopupBuscaPessoa.itemSelecionado}
指的是Pessoa
属性。然后你应该在getAsString()
将Pessoa
转换为其独特的String
表示(以便它可以用HTML打印)和getAsObject()
从String
转换为Pessoa
(这样它可以在bean属性中设置)。
但是,如果#{pessoa.value}
是String
而#{modeloPopupBuscaPessoa.itemSelecionado}
也是String
,那么你应该只使用itemValue="#{pessoa.value}"
并完全删除Converter
。
See also:
- PrimeFaces showcase:
<p:autoComplete>
with POJO - Can I use omnifaces generic converter in primefaces autocomplete component?
- Conversion Error setting value for 'null Converter'
可用于Primefaces自动完成的通用转换器以及所有其他用途:
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.WeakHashMap;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
@FacesConverter(value = "entityConverter")
public class EntityConverter implements Converter {
private static Map<Object, String> entities = new WeakHashMap<Object, String>();
@Override
public String getAsString(FacesContext context, UIComponent component, Object entity) {
synchronized (entities) {
if (!entities.containsKey(entity)) {
String uuid = UUID.randomUUID().toString();
entities.put(entity, uuid);
return uuid;
} else {
return entities.get(entity);
}
}
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String uuid) {
for (Entry<Object, String> entry : entities.entrySet()) {
if (entry.getValue().equals(uuid)) {
return entry.getKey();
}
}
return null;
}
}
通过以下方式实现此目的的最简单方法之一: 覆盖Pessoa Pojo类中的toString()方法。此toString()应仅返回要显示的Label。 如果您使用此方法,则转换器无需任何操作。
例如:
public class Pessoa implements Serializable{
private String value;
private String label;
//Setter and getters
@Override
public void toString(){
return label;
}
}
然后你可以使用:
<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
var="pessoa" itemLabel="#{pessoa}" itemValue="#{pessoa.value}"/>
这是我目前使用和运作良好的方式。
我遇到了同样的问题,作者在Primefaces autocomplete with POJO and String value的评论给了我一些提示,以便在我的案例中找到问题的根源。
概观
问题是value=#{objectValue}
是String
类型,但completeMethod
引用的方法返回List<Object>
。
该设计
我有以下POJO(简化):
public class CollaboratorGroup {
private String groupId;
private String groupName;
private Collaborator piUserId;
...
}
和
public class Collaborator {
private String userId;
private String fullName;
private String groupId;
...
}
这是否是一个有用的设计并不重要。我只是想解决这个问题。
以下p:autoComplete
(简化):
<p:autoComplete var="group"
itemLabel="#{group.groupId}"
itemValue="#{group.groupId}"
completeMethod="#{bean.completeGroup}"
value="#{collaborator.groupId}">
<f:facet name="itemtip">
<p:panelGrid columns="2">
<f:facet name="header">
<h:outputText value="#{group.groupId}" />
</f:facet>
<h:outputText value="Name:" />
<h:outputText value="#{group.groupName}" />
<h:outputText value="PI" />
<h:outputText value="#{group.piUserId.fullName}" />
</p:panelGrid>
</f:facet>
</p:autoComplete>
将扔The class 'java.lang.String' does not have the property 'groupId'
。当我改为itemLabel=#{group}
时,我将在输入字段中看到groupId CG00255
,但在下拉列表中会看到许多org.coadd.sharedresources.model.CollaboratorGroup@...
。如果我选择其中一个,则将此toString()
值设置为Collaborator.groupId,这是不需要的。
问题的来源
我用p:autoComplete
喂List<CollaboratorGroup>
,而Collaborator.groupId
是String
,itemLabel
用于“格式化”两者,String groupId
设置为value="#{collaborator.groupId}"
,而CollaboratorGroup
来自List
,由completeMethod="#{bean.completeGroup}"
生成。
可能的解决方案
- 你可以通过在
Model
中将成员groupId
更改为CollaboratorGroup
来调整Collaborator
,如果它不会破坏你的设计。在这种情况下,特别是因为CollaboratorGroup
有成员Collaborator piUserId
。 - 你可以用
p:autoComplete
填充List<String> groupIdList
,但在这种情况下你必须为itemtip
找到一个不同的解决方案。 - 一个非常快速的解决方案是使用
itemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}"
提到的Primefaces autocomplete with POJO and String value。 问题 你必须关心NullPointerExceptions
。 你用逻辑填满你的View
。 它不是一个非常灵活或动态的设计。 - 在bean方法
itemLabel="#{bean.printGroupId(group)}"
中实现3.您可以完全控制逻辑。这就是我做的。public String printGroupId(Object group) { if (group == null) return null; return (group instanceof String) ? (String) group : (group instanceof CollaboratorGroup) ? ((CollaboratorGroup) group).getGroupId() : null; }
(不是最好的,只是为了给你一个主意。)
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
ItemBean itemBean = (ItemBean) elContext.getELResolver().getValue(elContext, null, "itemBean");
for(Item item : itemBean.getItems()){
if(item.getId().getItemCode().equals(value)){
return item;
}
}
以上是关于p:autoComplete itemLabel抛出“类'java.lang.String'没有属性'label'。”的主要内容,如果未能解决你的问题,请参考以下文章
将参数传递给 p:autoComplete 的 completeMethod
捕获 primefaces <p:autoComplete> 更改事件(检测清空)