2014-11-05 27 views
2

我正在构建一个包含primefaces p:autoComplete组件的JSF表单。 以下是我的xhtml页面的摘录,显示了有关autoComplete组件的相关信息。Primefaces p:POJO中字符串字段的autcomplete问题

<p:autoComplete 
    value="#{curAttribute.value}" 
    completeMethod="#{newBacking.lookupActivated}" 
    var="curEntry" 
    itemLabel="#{curEntry.classname}" 
    itemValue="#{curEntry.id}" 
    emptyMessage="Start typing..."/> 

请注意curAttributeCosmoAttribute类的一个实例,并且该CosmoAttribute.value是一个String(当然,CosmoAttribute拥有所有的getter和setter方法的字段)。

方法newBacking.lookupActivated()返回List<CosmoCard>

CosmoCard.classnameCosmoCard.id都是字符串。

我知道我在用POJO编程,但是因为我的所有值都是POJO的字符串字段,我不认为我需要一个转换器。无论如何,我的自动完成野外工作正常,但是当我选择一个项目,我得到以下异常:

SEVERE: Error Rendering View[/test.xhtml] 
javax.el.PropertyNotFoundException: /test.xhtml @98,68 itemLabel="#{curEntry.id}": The class 'java.lang.String' does not have the property 'id'. 
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111) 
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194) 
    at org.primefaces.component.autocomplete.AutoComplete.getItemLabel(AutoComplete.java:148) 
    . 
    . 

Caused by: javax.el.PropertyNotFoundException: The class 'java.lang.String' does not have the property 'id'. 
    at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:730) 
    at javax.el.BeanELResolver.getValue(BeanELResolver.java:351) 
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176) 
    . 
    . 

有没有人的什么我做错了线索?你可以找到一个very similar question here,但不幸的是它没有回答。我愿意提供更多关于我的代码的细节。

UPDATE:

其实,一切工作正常:我看到在P的下拉列表中正确的值:自动完成。当我选择一个值时,支持bean(newBacking)中的数据会相应地更新。我无法摆脱这个异常,但是这对我的页面执行没有任何影响。

我在尊重标签的约束条件,即value属性和itemValue属于同一类型(两个字符串)。唯一不正确的是系统试图转换列表中的列表,我不知道为什么,或者什么时候,但是转换失败(以及后面的异常)对这个列表没有任何影响我的页面的行为。

UPDATE:

这里是链接到一个very simplified version of the project(netbeans的)。该项目的相关文件也在下面列出。

test.xhtml

<h:body> 
    <h:form id="form"> 
     <p:dataTable var="curAttribute" value="#{newBacking.card.attributes}"> 
      <p:column > 
       THE CURSED FIELD <br /><br /> 

       <p:autoComplete 
        value="#{curAttribute.value}" 
        completeMethod="#{newBacking.lookupActivated}" 
        var="curEntry" 
        itemLabel="#{curEntry.code}" 
        itemValue="#{curEntry.id}"> 
       </p:autoComplete> 
      </p:column> 
     </p:dataTable> 
    </h:form>  

newBacking.java

@Named() 
@SessionScoped 
public class NewBacking implements Serializable { 

    private CosmoCard card; 

    private String currentCardClassname = ""; 

    @PostConstruct 
    public void init() { 

     Random randomGenerator = new Random(); 
     card = new CosmoCard(); 
     card.setId("ID" + randomGenerator.nextInt(1000)); 

     CosmoAttribute myLA = new CosmoAttribute(); 
     myLA.setLabel("LookupAttributeLabel"); 
     myLA.setValue("LookupAttributeValue"); 
     card.getAttributes().add(myLA); 
    } 

    public CosmoCard getCard() { 
     return card; 
    } 

    public String getCurrentCardClassname() { 
     return currentCardClassname; 
    } 

    public void setCurrentCardClassname(String currentCardClassname) { 
     this.currentCardClassname = currentCardClassname; 
    } 

    public List<CosmoCard> lookupActivated(String tgtQuery) { 

     Logger.getLogger(NewBacking.class.getName()).info("[NewBacking.lookupActivated()] Query: " + tgtQuery); 
     return CosmoCardList.generateCardList(10).getCards(); 
    } 

} 
+0

@Pumpkin看来,我不能使用,原因如下的POJO方法: 1)POJO(CosmoAttribute ),它应该是p:autocomplete标记的值与完整方法(CosmoCard)返回的类型不同。2)完整的方法返回列表,除非我使用转换器。 3)即使我使用转换器,系统也会在分配值时尝试将CosmoCard放入CosmoAttribute位置。我开始认为我将使用列表作为完整方法的返回类型。也许用分隔符来区分标签的价值。 – INElutTabile 2014-11-05 14:02:31

+1

在我看来,你应该明显地回报你使用的东西。所以这个问题是由于你的第一个推理导致2和3的原因,比如使用分隔符和处理返回的字符串不是好的做法。 – Pumpkin 2014-11-05 14:23:48

+0

我的想法(关于分隔符的东西)。那么,似乎我被迫在p:autocomplete的值和完整方法的返回类型中使用相同类型的POJO,对吧?所以我没有任何问题使用转换器。我没有看到任何其他解决方案。 – INElutTabile 2014-11-05 14:27:21

回答

3

你完整的方法返回一个复杂的类的实例,从而你需要一个转换器。如果没有转换器的存在,你的组件会认为它使用了一个字符串,并试图在获取值和标签属性时提供参考。尝试使用这个,看看它的工作原理,但我强烈建议创建自己的转换器根据您的需求:

@FacesConverter("anySelectConverter") 
public class AnySelectConverter implements Converter{ 


    private static Map<Object, String> entities = new ConcurrentHashMap<Object, String>(); 

     @Override 
     public String getAsString(FacesContext context, UIComponent component, Object entity) { 

      // TODO : Fix 
      if(entity == null) 
       return ""; 

      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

将尝试使用转换器,我实际上正在寻找一种方法来避免使用转换器。 primefaces只接受“简单”类作为完整方法的输出吗? – INElutTabile 2014-11-05 13:19:27

+0

仅接受字符串,因此转换器的使用变为强制性的,替代方法要求您手动执行所有这些操作。我建议为相对更重要的组件创建基本的,很少使用的组件和自定义转换器的anySelectConverter。 – Pumpkin 2014-11-05 13:27:24

+0

在问题的评论区域回答。 – INElutTabile 2014-11-05 14:02:55