JSF 2.2 ViewDeclarationLanguage createComponent将属性传递为String?

时间:2015-06-09 10:02:13

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

我正在尝试编写一个动态选择创建和呈现现有复合组件的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}"/>

所以&#34;价值&#34;始终保证不是 类型 java.lang.String (它是一些JPA @Entity)。

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

  

节点类是:java.lang.String

我哪里错了?是不是可以将除String之外的东西作为参数传递给复合材料?

我使用Java EE 7运行wildfly-8.2.0-final(和Primefaces 5,但这里没有使用)

欢迎任何提示!

编辑:当然我也试图强制cc:interface

中的属性类型
<cc:interface>
  <cc:attribute name="node" required="true" type="some.package.type"/>
</cc:interface>

但是这导致了IllegalArgument异常:

  

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

1 个答案:

答案 0 :(得分:0)

原来我误解了API ... Map&lt; String,Object&gt;在签名让我觉得我可以通过一个对象。但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 #creinFacelet
  • 创建一个命名容器并使其成为生成的facelet(应用)的父级
  • 在命名容器上使用findComponent来获取生成的标记并将其返回

至少在找到它之后,很明显为什么你需要传递值表达式而不是值本身。