【问题标题】:Illegal Syntax for Set Operation: How to tell JSF I don't "want" a setter集合操作的非法语法:如何告诉 JSF 我不“想要”一个 setter
【发布时间】:2014-08-13 18:49:59
【问题描述】:

这个问题可能更多的是“概念性”或“我不懂 JSF”。

我的场景: 我有一个 JSF 页面 (index.xhtml),我在其中使用 p:accordionPanel(但我认为它是什么组件并不重要)。我要做的是设置它的activeIndexes

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever')}">
// bla bla...
</p:accordionPanel>

以及backing bean中的(简化的)方法:

public String getActiveIndexesForSections(String holderName){
    String activeSections = "";
    for(Section s : sectionMap.get(holderName)){
        if (s.isActive())
        //add to the string
    }
    return activeSections;
}

现在这在正常页面加载时工作得很好。

但是如果我点击p:commandButton(带有ajax=false)(或者我猜想其他任何将数据“发送”回服务器的东西) - 我会得到以下异常:

/WEB-INF/tags/normalTextSection.xhtml @8,112 activeIndex="#{myController.getActiveIndexesForSections(name)}": Illegal Syntax for Set Operation
// bla..
Caused by: javax.el.PropertyNotWritableException: Illegal Syntax for Set Operation

在谷歌搜索/阅读错误消息后,我发现我需要setter

首先:我不想要一个 setter - 我真的需要一个 setter 还是有办法告诉 JSF 我不想要这种“行为”。

其次,我意识到提供 setter 并不是那么“容易”,因为我的方法有一个参数(所以 public void setActiveIndexesForSections(String name, String activeIndexes)public void setActiveIndexesForSections(String name) 不起作用)。 我最后想到的是:

创建一个(通用)“伪属性类”:

// just a dummy class since the class is recreated at every request
public class Property<T> implements Serializable {

    private T val;

    public Property(T val) {
        this.val= val;
    }

    public T getVal() {
        return val;
    }

            //no need to do anyhting
    public void setVal(T val) {
    }
}

改变bean方法:

public Property<String> getActiveIndexesForSections(String holderName){
    String activeSections = "";
    for(Section s : sectionMap.get(holderName)){
        if (s.isActive())
        //add to the string
    }
    return new Property<String>(activeSections);
}

并从index.xhtml 调用它:

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever').val}">
// bla bla...
</p:accordionPanel>

这可行,但显然是一个丑陋的黑客/解决方法。

处理这种情况的正确方法是什么?还是我做的完全错了?

【问题讨论】:

    标签: jsf jsf-2 primefaces el jsf-2.2


    【解决方案1】:

    setter 需要记住表单提交时的活动索引。基本上,您需要将其绑定为值表达式(带有属性),而不是方法表达式(如操作方法),也不是不可修改的集合(如activeIndex="#{param.tab}")。与输入值完全一样。从技术上讲,您确实“完全错误”;)

    不过,要求是可以理解的。鉴于您真的对更改的活动索引不感兴趣,因此希望在每次提交表单时将它们重置为默认值,那么您可以通过在&lt;c:set&gt; 的帮助下将结果存储为请求属性来绕过它。这样你就可以欺骗 EL 在请求属性映射中设置它,而不是在意图的 bean 属性中设置它。

    <c:set var="activeIndex" value="#{myController.getActiveIndexesForSections('whatever')}" scope="request" />
    <p:accordionPanel multiple="true" activeIndex="#{activeIndex}">
        <!-- bla bla... -->
    </p:accordionPanel>
    

    在幕后,它基本上会将externalContext.getRequestMap().put("activeIndex", value)作为setter操作,这显然可以工作。


    更新:在检查source code of AccordionPanel component 时,我看到了另一种解决方法,因为当rendered 属性评估false 时不会设置activeIndex。因此,只需更改 rendered 属性使其行为完全一致:在更新模型值阶段(第 4 阶段)评估 false

    <p:accordionPanel multiple="true" 
        activeIndex="#{myController.getActiveIndexesForSections('whatever')}"
        rendered="#{facesContext.currentPhaseId.ordinal ne 4}">
        <!-- bla bla... -->
    </p:accordionPanel>
    

    【讨论】:

    • 感谢您怜悯我;)您会推荐另一种方法吗?因为它“完全”错了? (我不敢相信,这个用例是如此罕见,以至于没有人(除了我)想要这样做——所以我确实想知道我是否误解了大局……)——也是我的accordionPanel s 在标签中生成,其中“whatever”作为参数传入 - 我什至可以将该参数用作c:setvar,然后用作accordionPanelactiveIndex?如果有怎么办?
    • 在这种特定情况下,正确的方法是返回一个自定义的 Map 实现。不,你不能在var 属性中使用EL,所以标签文件会很讨厌。无论如何,在检查了&lt;p:accordionPanel&gt; 的源代码之后,我看到了另一种更适合在标记文件中重用的解决方法。查看答案更新。
    • 谢谢。明天将尝试这个以及“自定义”map。如果它有效,请接受+“赏金”你:)
    • 不客气。我无法详细说明自定义 Map 实现的答案,因为该问题不包含有关 Section 事物的所有必要信息。但是到了这一点,您应该能够以activeIndex="#{myController.activeIndexesForSections[whateverVariable]}" 的形式使用它,其中getActiveIndexForSections() 返回一个Map&lt;String, String&gt;,因此whateverVariable 是代表键的变量。在 get 和 set 操作中分别调用 Map#get()Map#put()。您需要重写这些方法以返回并设置所需的值。
    • 好吧,如果你愿意,我可以给你信息——甚至是我的代码,然后你查看它;-) 无论如何:你提供的两种解决方案,确实有效——所以再次感谢你。我尝试了地图 (gist.github.com/anonymous/ea9a9afd46a11ecdbf95) - 我不确定我是否满意 - 我真的不想将我的逻辑从地图类中的 cookieController 移动,因为 set-cookie 方法(发生在tabChange-Event 上)仍然发生在 cookie 控制器内部。我倾向于使用您在更新中提到的rendered 方法...
    猜你喜欢
    • 2013-08-20
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    相关资源
    最近更新 更多