P: autoComplete itemLabel throws "Class" java.lang.String "does not have the property" label "."

I am switching from IceFaces to PrimeFaces (I really wanted to switch to RichFaces, but I will not cause an error in the new version), and I have some difficulties for the correct implementation of autoComplete ordinary people. According to his guide, I just need to implement a method that returns a list of objects, in which case a converter is required.

The list I am returning is a list of javax.faces.model.SelectItem, I really can't understand why I need to create a converter for this, but let's continue. I created a simple converter just for testing, but simple faces do not recognize my converter and return this error in the 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 interlocutor class (for verification only):

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(); } } 

Here I am trying to 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 an easier way to implement this converter?

+6
source share
5 answers

You should not feed it List<SelectItem> . You must submit it using List<Pessoa> . You should also not concentrate on transforming SelectItem . You should concentrate on converting the value of the element that Pessoa . SelectItem is the remainder of the old JSF 1.x. In JSF 2.x, this is no longer necessary, thanks to the var , itemValue and itemLabel in the view. This will prevent your bean from getting messy.

Converter is only required when using itemValue="#{pessoa}" , and #{modeloPopupBuscaPessoa.itemSelecionado} means the Pessoa property. Then you need to convert Pessoa into getAsString() into your unique String representation (so that it can be printed in HTML) and from getAsObject() convert from String to Pessoa (so that it can be set to a bean).

However, if #{pessoa.value} is String and #{modeloPopupBuscaPessoa.itemSelecionado} also String , you should simply use itemValue="#{pessoa.value}" and generally remove Converter .

See also:

+12
source

A generic converter that you can use to automatically terminate Primefaces and all other purposes:

 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; } } 
+6
source

Another easy way to achieve this:
overriding the toString () method in the Pessoa Pojo class. This toString () should only return the shortcut you want to display.
If you use this method, there is NO NEED for the converter .

For instance:

 public class Pessoa implements Serializable{ private String value; private String label; //Setter and getters @Override public void toString(){ return label; } } 

Then you can use:

 <p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}" completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}" var="pessoa" itemLabel="#{pessoa}" itemValue="#{pessoa.value}"/> 

I use and work well.

+1
source

I ran into the same problem, and the author’s comment on Primefaces autofill with POJO and String value gave me a hint to find the source of the problem in my case.

overview

The problem is that value=#{objectValue} is of type String but the method referenced by completeMethod returns a List<Object> .

Design

I have the following POJOs (simplified):

 public class CollaboratorGroup { private String groupId; private String groupName; private Collaborator piUserId; ... } 

and

 public class Collaborator { private String userId; private String fullName; private String groupId; ... } 

It doesn't matter if this is a useful design. I just want to solve the problem.

Next p:autoComplete (simplified):

 <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> 

Will The class 'java.lang.String' does not have the property 'groupId' . The class 'java.lang.String' does not have the property 'groupId' . When I change to itemLabel=#{group} , I see groupId CG00255 in the input field, but many of org.coadd.sharedresources.model.CollaboratorGroup@... in the drop-down list. If I select one of them, this toString() value will be set to Collaborator.groupId, which is undesirable.

Source of problem

I p:autoComplete using List<CollaboratorGroup> while Collaborator.groupId is String and itemLabel used to “format” both, String groupId is set to value="#{collaborator.groupId}" String groupId value="#{collaborator.groupId}" and the CollaboratorGroup obtained from the List generated by completeMethod="#{bean.completeGroup}" .

Possible solutions

  1. You can customize the Model by changing the groupId element to CollaboratorGroup in Collaborator if this does not destroy your design. In this case, especially since the CollaboratorGroup has a Collaborator piUserId membership.
  2. You can simply populate p:autoComplete List<String> groupIdList but in this case you need to find another solution for itemtip .

  3. A very quick solution is to use itemLabel="#{group.class.simpleName eq 'String'? group: group.groupId}" as mentioned in PrimeCom autocomplete with POJO and String value .

    • Problems
      • You must take care of NullPointerExceptions .
      • You fill your View logic.
      • This is not a very flexible or dynamic design.
  4. itemLabel="#{bean.printGroupId(group)}" 3. in the bean method itemLabel="#{bean.printGroupId(group)}" where you have full control over the logic. This is what I did.

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

    (Not the best, just to give you an idea.)

0
source
  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; } } 
-1
source

Source: https://habr.com/ru/post/898627/


All Articles