p:autoComplete itemLabel抛出“类'java.lang.String'没有属性'label'。”

问题描述 投票:6回答:5

我正在从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的默认转换器?有没有更简单的方法来实现这个转换器?

jsf primefaces jsf-2 label converters
5个回答
12
投票

你不应该用List<SelectItem>喂它。你应该用List<Pessoa>喂它。你也不应该专注于转换SelectItem。您应该专注于转换项目值,即PessoaSelectItem是旧JSF 1.x时代的遗留物。在JSF 2.x中,由于视图中的varitemValueitemLabel属性,这不再是强制性的。这样可以使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:


6
投票

可用于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;
    }

}

1
投票

通过以下方式实现此目的的最简单方法之一: 覆盖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}"/>

这是我目前使用和运作良好的方式。


0
投票

我遇到了同样的问题,作者在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:autoCompleteList<CollaboratorGroup>,而Collaborator.groupIdStringitemLabel用于“格式化”两者,String groupId设置为value="#{collaborator.groupId}",而CollaboratorGroup来自List,由completeMethod="#{bean.completeGroup}"生成。

可能的解决方案

  1. 你可以通过在Model中将成员groupId更改为CollaboratorGroup来调整Collaborator,如果它不会破坏你的设计。在这种情况下,特别是因为CollaboratorGroup有成员Collaborator piUserId
  2. 你可以用p:autoComplete填充List<String> groupIdList,但在这种情况下你必须为itemtip找到一个不同的解决方案。
  3. 一个非常快速的解决方案是使用itemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}"提到的Primefaces autocomplete with POJO and String value。 问题 你必须关心NullPointerExceptions。 你用逻辑填满你的View。 它不是一个非常灵活或动态的设计。
  4. 在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; } (不是最好的,只是为了给你一个主意。)

-1
投票
 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;
     }
 }
© www.soinside.com 2019 - 2024. All rights reserved.