【问题标题】:JSF 2.2 ViewDeclarationLanguage createComponent passes attributes as String?JSF 2.2 ViewDeclarationLanguage createComponent 将属性作为字符串传递?
【发布时间】:2015-06-09 10:02:13
【问题描述】:

我正在尝试编写一个动态选择创建和呈现现有复合组件的JSF 自定义组件。到目前为止,除了将属性传递给组合之外,一切都运行良好。

这是我的自定义组件类(为了更好地阅读而删除了错误处理等):

@FacesComponent(createTag = true)
public class ChooseEZComp extends UIComponentBase {

  @Override
  public void encodeBegin(FacesContext context) throws IOException {
    Object value = getAttributes().get("value");

    String ezCompName = value.getClass().getSimpleName().toLowerCase();
    // ezCompName is something like "freelink" or "treenode"

    Map<String, Object> params = new HashMap<>();
    params.put("node", value);
    // log.debug(params.get("node").getClass().getName()) -> yields correct class name

    ViewDeclarationLanguage viewDeclarationLanguage = context
      .getApplication()
      .getViewHandler()
      .getViewDeclarationLanguage(context, context.getViewRoot().getViewId());

    UIComponent component = viewDeclarationLanguage
      .createComponent(context,
        "http://xmlns.jcp.org/jsf/composite/ezcomp",
        ezCompName,
        params);

    component.encodeAll(context);
  }
}

由此类选择和呈现的复合组件(我有几个):

  <cc:interface>
    <cc:attribute name="node" required="true"/>
  </cc:interface>

  <cc:implementation>
    <h:outputText value="The class of node is: #{cc.attrs.node.class.name}"/>
  </cc:implementation>

这就是我在 JSF 页面中使用标签的方式:

<test:chooseEZComp value="#{treeView.selectedNode.data}"/>

所以“价值”总是保证 not 类型为 java.lang.String(它是一些 JPA @Entity)。

但是JSF页面中的结果输出总是:

节点的类是:java.lang.String

我哪里错了?难道不能将字符串以外的东西作为参数传递给组合吗?

我正在使用 Java EE 7(和 Primefaces 5,但此处未使用)运行 wildfly-8.2.0-final

欢迎任何提示!


编辑:当然我也尝试在 cc:interface 中强制属性的类型

<cc:interface>
  <cc:attribute name="node" required="true" type="some.package.type"/>
</cc:interface>

但这因此导致了 IllegalArgument 异常:

IllegalArgumentException: 无法将 java.lang.String 类型的 ... 转换为类

【问题讨论】:

    标签: jsf-2.2 custom-component wildfly-8 java-ee-7


    【解决方案1】:

    原来我误解了 API ...签名中的 Map 让我觉得我可以传递一个对象。但 Javadoc 对此更准确:

    属性 - 任何名称=值对,否则会在标记上给出,这会导致创建此组件 [..]

    因此,您不会将值传递给 createComponent,而是传递用于计算指定属性或属性名称的值的表达式

      Map<String, Object> attributes = new HashMap<>();
      ValueExpression valueExpression = getValueExpression("value");
      attributes.put("node", valueExpression.getExpressionString());
    

    有趣的一面阅读: 为了找到解决方案,我通过 jsf-imp-2.2.8-jbossorg 进行了调试,偶然发现了创建组件的代码。基本上它的作用是:

    • 在 temp 文件夹中创建一个 JSF xhtml 文件并使用 OutputStreamWriter#append 编写一个 JSF 页面,其中只有一个标签(您要创建的标签)
    • 循环遍历所有属性并将它们作为属性写入标签
    • 保存文件并将其提供给 DefaultFaceletFactory#createFacelet
    • 创建一个命名容器并使其成为生成的 facelet 的父级(应用)
    • 在命名容器上使用 findComponent 来获取生成的标签并返回它

    至少在找到这一点之后,就清楚了为什么需要传入值表达式而不是值本身。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 2013-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      相关资源
      最近更新 更多