p:autoComplete itemLabel 抛出“类“java.lang.String”;没有属性“标签”。
我正在从 IceFaces 更改为 PrimeFaces(我真的很想更改为 RichFaces,但会在新版本中导致错误,我不会),并且我在正确实现 primefaces 自动完成方面遇到了一些困难。根据他的手册,我只需要实现一个返回对象列表的方法,在这种情况下需要一个转换器。
我返回的列表是 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 没有默认转换器吗?有没有更简单的方法来实现这个转换器?
I'm changing from IceFaces to PrimeFaces (I really wanted to change to RichFaces but cause a bug in new version, I won't) and I'm havinng some dificults to implement correctly primefaces autoComplete. According to his manual I just need to implement a method that returns a list of objects, and in this case a converter is required.
The list I'm returning is a list of javax.faces.model.SelectItem, I really can't understand why I need to create a converter to this, but lets continue. I've created a simple converter just to test, but primefaces don't recognizes my converter and returns this error in browser:
/resources/components/popups/popupBuscaPessoa.xhtml @35,41 itemLabel="#{pessoa.label}": The class 'java.lang.String' does not have the property 'label'.
This is my conversor class (just to test):
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();
}
}
This is where I try use p:autocomplete:
<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
var="pessoa" itemLabel="#{pessoa.label}" itemValue="#{pessoa.value}"
converter="#{conversorSelectItem}"/>
Did I do something wrong? Isn't there a default converter for SelectItem? Is there a easier way to implement this converter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(5)
一个通用转换器,可用于 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;
}
}
我遇到了同样的问题以及作者的评论 Primefaces autocomplete with POJO and String value< /a> 给了我在我的案例中找到问题根源的提示。
概述
问题在于 value=#{objectValue}
的类型为 String
,但 completeMethod
中引用的方法返回一个 List
对象>
。
设计
我有以下 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,这是不需要的。
问题的根源
我将 List
提供给 p:autoComplete
,而 Collaborator.groupId
是一个 String
和 itemLabel
用于“格式化”两者,String groupId
设置为 value="#{collaborator.groupId}"
和来自 List
的 CollaboratorGroup
,由 completeMethod="#{bean.completeGroup}"
生成。
可能的解决方案
- 如果不会破坏您的模型,您可以通过将
Collaborator
中的成员groupId
更改为CollaboratorGroup
来调整Model
。设计。在这种情况下,特别是当CollaboratorGroup
具有成员Collaborator piUserId
时。 您只需用
List
但在这种情况下,您必须为填充 p:autoComplete
即可。 groupIdListitemtip
找到不同的解决方案。一个非常快速的解决方案是使用
itemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}"
如 Primefaces 使用 POJO 和字符串值自动完成。- 问题
- 您必须关心
NullPointerExceptions
。 - 您用逻辑填充您的
View
。 - 这不是一个非常灵活或动态的设计。
- 您必须关心
- 问题
在 bean 方法
itemLabel="#{bean.printGroupId(group)}"
中实现 3.,您可以完全控制逻辑。这就是我所做的。public String printGroupId(对象组) { if (group == null) 返回 null; 返回(字符串的组实例)? (字符串)组:(CollaboratorGroup 的组实例)? ((CollaboratorGroup) 组).getGroupId() : null; }
(不是最好的,只是为了给您一个想法。)
实现这一目标的另一种最简单的方法是:
重写 Pessoa Pojo 类中的 toString() 方法。
这个 toString() 应该只返回您想要显示的标签。
如果您使用此方法,则无需转换器。
例如:
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}"/>
这是我目前正在使用并且运行良好的方式。
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;
}
}
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
您不应该使用
List
为其提供数据。您应该使用List
为其提供数据。您也不应该专注于转换SelectItem
。您应该集中精力转换项目值,即Pessoa
。SelectItem
是旧 JSF 1.x 时代的遗留物。在 JSF 2.x 中,由于视图中的var
、itemValue
和itemLabel
属性,这不再是强制性的。这可以让您的 Bean 免受特定于视图的混乱的影响。仅当您使用
itemValue="#{pessoa}"
且#{modeloPopupBuscaPessoa.itemSelecionado}
引用时,才需要
Converter
佩索阿属性。然后,您应该在getAsString()
中将Pessoa
转换为其唯一的String
表示形式(以便可以以 HTML 格式打印)并在getAsObject()
从String
转换为Pessoa
(以便可以在 bean 属性中设置)。但是,如果
#{pessoa.value}
是String
并且#{modeloPopupBuscaPessoa.itemSelecionado}
也是String
>,那么您应该只使用itemValue="#{pessoa.value}"
并完全删除Converter
。另请参阅:
以及POJOYou shouldn't feed it with
List<SelectItem>
. You should feed it withList<Pessoa>
. You should also not concentrate on convertingSelectItem
. You should concentrate on converting the item value, which isPessoa
. TheSelectItem
is a leftover from the old JSF 1.x ages. In JSF 2.x this is not mandatory anymore, thanks to thevar
,itemValue
anditemLabel
attributes in the view. This keeps your bean clean from view-specific clutter.The
Converter
is only necessary whenever you useitemValue="#{pessoa}"
and the#{modeloPopupBuscaPessoa.itemSelecionado}
refers aPessoa
property. You should then ingetAsString()
convertPessoa
to its uniqueString
representation (so that it can be printed in HTML) and ingetAsObject()
convert fromString
toPessoa
(so that it can be set in bean property).However, if
#{pessoa.value}
is aString
and#{modeloPopupBuscaPessoa.itemSelecionado}
is also aString
, then you should just useitemValue="#{pessoa.value}"
and remove theConverter
altogether.See also:
<p:autoComplete>
with POJO