p: autoComplete itemLabel бросает «У класса 'java.lang.String' нет свойства 'label'." - PullRequest
6 голосов
/ 05 октября 2011

Я перехожу с IceFaces на PrimeFaces (я действительно хотел перейти на RichFaces, но я не буду вызывать ошибку в новой версии), и у меня есть некоторые сложности для правильной реализации autoComplete простых лиц. Согласно его руководству, мне просто нужно реализовать метод, который возвращает список объектов, и в этом случае требуется конвертер.

Список, который я возвращаю, является списком javax.faces.model.SelectItem, я действительно не могу понять, почему мне нужно создать конвертер для этого, но давайте продолжим. Я создал простой конвертер просто для тестирования, но простые лица не распознают мой конвертер и возвращают эту ошибку в браузере:

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

12 голосов
/ 05 октября 2011

Вы не должны кормить его List<SelectItem>.Вы должны кормить его List<Pessoa>.Вы также не должны концентрироваться на конвертации SelectItem.Вы должны сконцентрироваться на конвертации значения предмета, которое составляет Pessoa.SelectItem - это пережиток старого возраста JSF 1.x.В JSF 2.x это больше не является обязательным, благодаря атрибутам var, itemValue и itemLabel в представлении.Это сохраняет ваш бин чистым от беспорядка, зависящего от вида.

Converter необходим только всякий раз, когда вы используете itemValue="#{pessoa}", а #{modeloPopupBuscaPessoa.itemSelecionado} ссылается на свойство Pessoa.Затем в getAsString() необходимо преобразовать Pessoa в его уникальное представление String (чтобы его можно было печатать в HTML), а в getAsObject() преобразовать из String в Pessoa (чтобы его можно было установить всвойство bean).

Однако, если #{pessoa.value} - это String, а #{modeloPopupBuscaPessoa.itemSelecionado} - также String, вам следует просто использовать itemValue="#{pessoa.value}" и удалить Converter в целом.

См. Также:

6 голосов
/ 13 июня 2013

Универсальный конвертер, который вы можете использовать для автозаполнения 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 голос
/ 13 июня 2013

Еще один самый простой способ достичь этого:
переопределение метода toString () в классе Pessoa Pojo.Эта функция toString () должна возвращать только метку , которую вы хотите отобразить.
Если вы используете этот метод, то для преобразователя .

, например, NO NEED:

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 голосов
/ 27 июля 2018

Я столкнулся с той же проблемой, и комментарий автора на Автозаполнение Primefaces с POJO и значением String подсказало мне найти источник проблемы в моем случае.

Обзор

Проблема в том, что 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:autoComplete List<CollaboratorGroup>, в то время как Collaborator.groupId является String, а itemLabel используется для «форматирования» обоих: 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, автозаполнение с POJO и значением String .

    • Проблемы
      • Вы должны заботиться о 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;
    }
    

    (Не самый лучший, просто чтобы дать вам представление.)

0 голосов
/ 22 февраля 2016
 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;
     }
 }
...