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

时间:2011-10-04 20:33:09

标签: jsf primefaces jsf-2 label converters

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

5 个答案:

答案 0 :(得分:12)

您不应该使用List<SelectItem>来提供它。你应该用List<Pessoa>喂它。你也不应该专注于转换SelectItem。您应该专注于转换项目值PessoaSelectItem是旧JSF 1.x年代的遗留物。在JSF 2.x中,由于视图中的varitemValueitemLabel属性,这不再是必需的。这样可以使bean保持清洁,不会出现特定于视图的混乱。

只有在您使用ConverteritemValue="#{pessoa}"引用#{modeloPopupBuscaPessoa.itemSelecionado}属性时才需要Pessoa。然后,您应该getAsString()Pessoa转换为其唯一的String表示形式(以便以HTML格式打印),并getAsObject()String转换为{ {1}}(以便可以在bean属性中设置)。

但是,如果Pessoa#{pessoa.value}String也是#{modeloPopupBuscaPessoa.itemSelecionado},那么您应该使用String并删除itemValue="#{pessoa.value}"完全。

另见:

答案 1 :(得分: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;
    }

}

答案 2 :(得分:1)

实现这一目标的另一种最简单方法:
覆盖Pessoa Pojo类中的 toString()方法。 此toString()应仅返回您要显示的标签 如果您使用此方法,那么 NO NEED for converter

例如:

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}"/>

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

答案 3 :(得分: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.groupIdString,而itemLabel用来对{{1} }设置为String groupId,而value="#{collaborator.groupId}"产生的CollaboratorGroupList生成。

可能的解决方案

  1. 如果不破坏设计,可以通过将completeMethod="#{bean.completeGroup}"中的成员Model更改为groupId来调整CollaboratorGroup。在这种情况下,尤其是Collaborator具有成员CollaboratorGroup的情况。
  2. 您可以只用Collaborator piUserId填充p:autoComplete,但是在这种情况下,您必须为List<String> groupIdList找到不同的解决方案。

  3. 一种非常快速的解决方案是使用Primefaces autocomplete with POJO and String value中提到的itemtip

    • 问题
      • 您必须关心itemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}"
      • 您用逻辑填充NullPointerExceptions
      • 这不是一个非常灵活或动态的设计。
  4. 实现3.在bean方法View中,您可以完全控制逻辑。这就是我所做的。

    itemLabel="#{bean.printGroupId(group)}"

    (不是最好的,只是给您一个主意。)

答案 4 :(得分:-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;
     }
 }