You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PrimeFaces p:autoComplete结合OmniFaces ListConverter报错求助

问题:PrimeFaces AutoComplete 触发 PropertyNotFoundException 错误

开发TCG卡牌搜索表单时,使用PrimeFaces AutoComplete组件实现带自动补全且保持下拉展开的功能,但更新搜索框时出现以下错误:

GRAVE:
Error Rendering View[/login.xhtml]
javax.el.PropertyNotFoundException: /login.xhtml @46,42 itemLabel="#{card.name}": Propiedad [name] no hallada en el tipo [java.lang.String].

已尝试使用OmniFaces ListConverter,但问题未解决。相关代码如下:

相关代码

XHTML代码

<p:panel header="Card Search" id="searchField">
        <p:autoComplete id="cardSearch"
                        value="#{imageGridView.query}"
                        completeMethod="#{imageGridView.completeCards}"
                        var="card"
                        itemLabel="#{card.name}"
                        itemValue="#{card.id}"
                        forceSelection="true"
                        minQueryLength="3"
                        scrollHeight="200"
                        emptyMessage="Cards not found"
                        dropdown="true"
                        queryDelay="500">
                        <o:converter converterId="omnifaces.ListConverter" list="#{imageGridView.cardsAvailable}" />
            
            <p:column>
                <h:outputText value="#{card.name}" />
            </p:column>
            
            <p:ajax event="itemSelect"
                    listener="#{imageGridView.onCardSelect}"
                    update="messages imageGrid searchField"
                    process="@this"
                    oncomplete="keepAutoCompleteOpen()"
                    />
                    
        </p:autoComplete>
    </p:panel>

JavaScript代码

<h:outputScript>
function keepAutoCompleteOpen() {
    var input = PF('cardSearch').input;
    var query = input.val();
    if (query.length >= 3) { 
        PF('cardSearch').search(query);
    }
}</h:outputScript>

Java代码(imageGridView.java)

public List<YGOCard> completeCards(String query) {
        cardsAvailable=new LinkedList<YGOCard>();
        String queryLowerCase = query.toLowerCase();
        Controller db=new Controller();
        cardsAvailable=db.getYGOCardsByName(queryLowerCase);
        return cardsAvailable;
    }
    
    public void onCardSelect(SelectEvent<?> event) {
        if (event.getObject() != null) {
            imageNames.add(event.getObject().toString());
            updateDecklist();
            FacesMessage message = new FacesMessage("Success",
                    "Card Added: " + event.getObject().toString());
            FacesContext.getCurrentInstance().addMessage(null, message);
        }
    }

错误原因分析

这个错误的核心是:组件尝试对java.lang.String类型的对象调用name属性,但String类并没有name方法。出现该问题的关键原因有两点:

  1. value与itemValue类型不匹配:autoComplete的value="#{imageGridView.query}"如果是String类型,而itemValue绑定的是card.id(字符串/数值类型),组件渲染下拉选项时会把value的字符串值当成var="card"的实例,导致调用card.name时出错。
  2. ListConverter使用场景错误:OmniFaces ListConverter适用于itemValue绑定实体对象本身的场景,但这里itemValue是实体ID而非实体对象,Converter无法将ID正确转换回YGOCard实例,最终card变量变成了ID字符串。

解决方案

1. 统一value与itemValue的类型为实体对象

将autoComplete的value绑定到实体对象,同时修改itemValue为实体本身,确保Converter能正确识别:

  • 修改XHTML中的autoComplete配置:
<p:autoComplete id="cardSearch"
                value="#{imageGridView.selectedCard}" <!-- 绑定实体对象 -->
                completeMethod="#{imageGridView.completeCards}"
                var="card"
                itemLabel="#{card.name}"
                itemValue="#{card}" <!-- 绑定实体对象而非ID -->
                forceSelection="true"
                minQueryLength="3"
                scrollHeight="200"
                emptyMessage="Cards not found"
                dropdown="true"
                queryDelay="500">
        <o:converter converterId="omnifaces.ListConverter" list="#{imageGridView.cardsAvailable}" />
        <!-- 其余代码不变 -->
</p:autoComplete>
  • 在imageGridView.java中添加selectedCard属性及getter/setter:
private YGOCard selectedCard;

public YGOCard getSelectedCard() {
    return selectedCard;
}

public void setSelectedCard(YGOCard selectedCard) {
    this.selectedCard = selectedCard;
}

2. 调整onCardSelect方法逻辑

现在event.getObject()返回的是YGOCard实体,修改方法以获取正确的卡牌信息:

public void onCardSelect(SelectEvent<?> event) {
    if (event.getObject() != null) {
        YGOCard selectedCard = (YGOCard) event.getObject();
        imageNames.add(selectedCard.getId().toString()); // 存储卡牌ID
        updateDecklist();
        FacesMessage message = new FacesMessage("Success",
                "Card Added: " + selectedCard.getName()); // 显示卡牌名称
        FacesContext.getCurrentInstance().addMessage(null, message);
    }
}

3. 优化下拉展开的JavaScript逻辑

原JS中重复调用search(query)会触发不必要的后端请求,改为直接展开下拉面板:

<h:outputScript>
function keepAutoCompleteOpen() {
    var autoComplete = PF('cardSearch');
    var inputValue = autoComplete.jq.val();
    if (inputValue.length >= 3 && !autoComplete.panel.is(':visible')) {
        autoComplete.show(); // 直接展开面板,无需重新查询
    }
}
</h:outputScript>

4. 确保cardsAvailable的作用域正确

在completeCards方法中,不要每次都重新实例化cardsAvailable,直接赋值即可,保证ListConverter能获取到正确的列表:

private List<YGOCard> cardsAvailable; // 实例变量

public List<YGOCard> completeCards(String query) {
    String queryLowerCase = query.toLowerCase();
    Controller db = new Controller();
    cardsAvailable = db.getYGOCardsByName(queryLowerCase); // 直接赋值
    return cardsAvailable;
}

// 添加getter方法供Converter调用
public List<YGOCard> getCardsAvailable() {
    return cardsAvailable;
}

内容的提问来源于stack exchange,提问作者Phaleg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 05:55:02