【问题标题】:p:autoComplete itemLabel throws "The class 'java.lang.String' does not have the property 'label'."p:autoComplete itemLabel 抛出“类 'java.lang.String' 没有属性 'label'。”
【发布时间】:2011-12-01 00:11:08
【问题描述】:

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

【问题讨论】:

    标签: jsf primefaces jsf-2 label converters


    【解决方案1】:

    你不应该用List&lt;SelectItem&gt; 喂它。你应该用List&lt;Pessoa&gt; 喂它。您也不应该专注于转换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

    另见:

    【讨论】:

    • 我认为您的最后一句话不起作用,因为由于某种原因,当您重新加载/提交小部件时,显示的标签希望从 itemValue 构建,这打破了将字符串放入的想法value 属性中的 itemValue 等。你可以有不同的字符串作为值和标签,这在转换器上工作得很好,但是在你使用 var 属性的那一刻,它会顺流而下。如果你不需要 var 这行得通,但如果你需要 var 用列“美化”你的标签和我的想法结束的东西,没有让它运行。
    • 参见第二个“另见”链接如何做到这一点。
    【解决方案2】:

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

    【讨论】:

    • 嗨 Makky 感谢您提供通用转换器代码,这是一个好主意,非常有用。如果我愿意,我也可以将 Map 实体更改为 List 吗??
    • erm,实体地图会随着时间的推移而填满吗?什么时候清理? (=内存猪)
    • @Bernhard 你有什么建议可以避免这个问题?
    【解决方案3】:

    我遇到了同样的问题,作者在Primefaces autocomplete with POJO and String value 的评论给了我在我的案例中找到问题根源的提示。

    概述

    问题在于value=#{objectValue} 的类型为String,但completeMethod 中引用的方法返回List&lt;Object&gt;

    设计

    我有以下 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&lt;CollaboratorGroup&gt;p:autoCompleteCollaborator.groupIdStringitemLabel 用于“格式化”两者,String groupId 设置为value="#{collaborator.groupId}"CollaboratorGroup来自List,由completeMethod="#{bean.completeGroup}"生成。

    可能的解决方案

    1. 如果不破坏您的设计,您可以通过将Collaborator 中的成员groupId 更改为CollaboratorGroup 来调整Model。在这种情况下,尤其是 CollaboratorGroup 有成员 Collaborator piUserId
    2. 您可以只用List&lt;String&gt; groupIdList 填充p:autoComplete,但在这种情况下,您必须为itemtip 找到不同的解决方案。

    3. 一个非常快速的解决方案是使用itemLabel="#{group.class.simpleName eq 'String' ? group : group.groupId}",如Primefaces autocomplete with POJO and String value 所述。

      • 问题
        • 你要关心NullPointerExceptions
        • 你用逻辑填写你的View
        • 这不是一个非常灵活或动态的设计。
    4. 实现 3. 在 bean 方法 itemLabel="#{bean.printGroupId(group)}" 中,您可以完全控制逻辑。这就是我所做的。

      public String printGroupId(Object group) {
          if (group == null) return null;
          return (group instanceof String) ? (String) group : (group instanceof CollaboratorGroup) ? ((CollaboratorGroup) group).getGroupId() : null;
      }
      

      (不是最好的,只是给你一个想法。)

    【讨论】:

      【解决方案4】:

      实现这一目标的更简单方法是:
      覆盖 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}"/>
      

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

      【讨论】:

      • 推荐使用转换器。
      • @Makky :转换器会将对象转换为字符串,对吗?默认情况下,在 java 中,如果需要显示对象,则 JVM 将调用 toString() 方法。这就是我在 toString() 中所做的。两种方法只产生相同的结果。坦克,我肯定会使用 Converter 作为推荐
      • 我发布了一个适用于任何对象的通用转换器。
      【解决方案5】:
       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;
           }
       }
      

      【讨论】:

      • in Conver Class ,Public Object getAsObject(FacesContext context, UIComponent component, String value) { 在这个方法中写下上面的逻辑,并从bean中获取item的列表,definatley你会得到它跨度>
      • 请将此添加到您的答案中,您可以对其进行编辑。并且请添加更多解释为什么这有效并且是比已经发布的更好的答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 2018-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      相关资源
      最近更新 更多