【问题标题】:JSF 2.2: Passing bean attribute as ValueExpression to compositeJSF 2.2:将 bean 属性作为 ValueExpression 传递给组合
【发布时间】:2016-01-22 12:19:09
【问题描述】:

我想将非托管(非字符串)对象作为属性传递给动态添加的复合组件,并让它在会话中存活。

JSF 2.2 ViewDeclarationLanguage#createComponent 处理复合组件的动态非字符串属性值与旧的 Mojarra 相关代码 (Application#createComponent) 不同。我找不到完全适用于 JSF 2.2 技术的方法,但可能是我。

[我正在尝试通过转换为 MyFaces 来删除 Mojarra 依赖项(并且还解决了一些其他 Mojarra 问题)。我正在使用 JSF 2.2、CDI Weld 2.2.16、Tomcat v8.0]

我正在以编程方式实例化不同的复合组件(注意 bean 属性):

<cc:interface>
    <cc:attribute name="bean" required="true" type="com.aadhoc.cvc.spikes.extensionsapproach.ExtensionBeanInterface"/>
</cc:interface>

<cc:implementation>
    <h:panelGrid columns="2">
        <h:outputText value="Title:"/>
        <h:inputText value="#{cc.attrs.bean.title}"/>
    </h:panelGrid>
</cc:implementation>

在较旧的 Mojarra 依赖方法中,我实例化了非托管 bean 对象,并将其作为属性直接添加到复合组件中,它工作得很好(我正在使用来自 OmniFaces 的 @BalusC 很棒但依赖于 Mojarra 的示例代码@ 987654324@):

ExtensionBeanInterface bean = Class.forName(className).newInstance();
attributes = new HashMap<String, Object>();
attributes.put("bean", bean); // Using bean object itself

[..]
UIComponent composite = application.createComponent(context, resource);
composite.getAttributes().putAll(attributes);
[..]

在 JSF 2.2 中,我发现我必须直接传递一个字符串 ValueExpression 而不是我的 bean 对象。我目前正在使用这种技术,但不能完全正确:

FacesContext context = FacesContext.getCurrentInstance();
ELContext elContext = context.getELContext();

ValueExpression beanValExp = context.getApplication().getExpressionFactory()
            .createValueExpression(elContext, "#{customBeanVE}", ExtensionBeanInterface.class);
beanValExp.setValue(elContext, bean);
String beanValExpStr = beanValExp.getExpressionString();

attributes = new HashMap<String, Object>();
attributes.put("bean", beanValExpStr); // Using VE instead of bean object

UIComponent composite = context.getApplication().getViewHandler()
                .getViewDeclarationLanguage(context, context.getViewRoot().getViewId())
                .createComponent(context, taglibURI, tagName, attributes);
[..]

这在第一次“添加复合”时效果很好,但在任何以下表单提交中,我得到:

/resources/com/aadhoc/cvc/spikes/extensionsapproach/components/House.xhtml @16,49 value="#{cc.attrs.bean.title}": 目标不可达,'bean' 返回null

我已经验证了组合的 required 和 type 属性工作正常,并且 #{cc.attrs.bean.title} 最初显示了 bean 的标题。我使用刷新的复合组件的静态使用进行了验证。

这是怎么回事,我如何切换 bean 对象,以便它在整个会话中与组合一起存在?

【问题讨论】:

  • 我假设我的新 ValueExpression EL 映射仅在请求期间存在。我猜我必须创建一个到实际会话值的“真实映射”......所以映射将继续跨请求工作。例如,如果我使用唯一键将值放入 sessionMap,我可以在 EL 中使用该键,它将在会话中继续工作。我还可以使用一个会话 bean,我已经必须保存具有唯一 ID 的对象。旧方法效果很好,我没有意识到我被锁定在 Mojarra 中:-(
  • 顺便说一句,使用旧的 Mojarra 依赖方法,当我切换到 MyFaces 时,我在添加复合材料时得到了这个:java.lang.NullPointerException - java.lang.NullPointerException at org.apache.myfaces.view.facelets.impl.FaceletCompositionContextImpl.generateUniqueId(FaceletCompositionContextImpl.java:1048)

标签: jsf jsf-2.2 composite-component


【解决方案1】:

我在 Mojarra 做得很好。我可以将 bean 对象放入属性值中,一切都很棒。尝试 MyFaces,我需要更改/更新我的方法,现在我需要使用 EL 字符串而不是直接对象引用。

由于只是将 bean 对象放入属性 Map 中,我想要一个神奇而优雅的地方来放置 bean 对象并让它们存活。我本可以将它们放入“全局”会话映射中(例如:How to save an object into JSF Session),但它不够干净。然后我将它们放入我的一个主会话状态 bean (modelerBean),它是正确的。这就是我保存 bean 的方式,以及我用 EL 字符串指向它的方式。无需创建 ValueExpression 或 MethodExpression 对象或注册特殊映射。这种与 JSF 2.2 兼容的方法在 Mojarra 和 MyFaces 中都适用于我。

public void onAdd(ActionEvent ev) {
    [..]
    ChosenBean chosenBean = new ChosenBean();
    chosenBean.setComponentId(id);
    chosenBean.setBean(bean);
    modelerBean.addChosen(chosenBean);
    [..]
    String el = "#{modelerBean.getChosen('"+id+"').bean}"
    attributes.put(MODELER_EXTENSION_BEAN_ATTRIBUTE_NAME, el);
    [..]

我在阅读@BalusC 的帖子后决定这样做:How do I get and set an object in session scope in JSF?

注意,我对@BalusC 的两种“动态添加复合”方法 (How to programmatically or dynamically create a composite component in JSF 2) 的经验是,如果可以的话,您绝对应该使用 JSF 2.2 方法。如果您不在 JSF 2.2 中,旧的 Mojarra 方法确实有效。一旦我修改了我的代码以使 JSF 2.2 方法工作,旧的 Mojarra 方法就会以奇怪的方式中断。

【讨论】:

    猜你喜欢
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 2017-02-07
    相关资源
    最近更新 更多