JSF CompositeComponent:实现选择

时间:2013-01-27 17:00:00

标签: java jsf-2 composite-component

您好我想实现类似的CC,它实现选择属性。这类似于Primefaces instant row selection <p:dataTable selection="#{bean.user}" .../>

这是复合材料中的相关定义:

<composite:interface componentType="my.CcSelection">
  <composite:attribute name="actionListener" required="true"
          method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)"/>
  <composite:attribute name="selection"/>
</composite:interface>

<composite:implementation>
  ...
  <ui:repeat var="item" value="#{cc.attrs.data}">
    <p:commandLink actionListener="#{cc.actionListener(item)}"/>
  </ui:repeat>
  ...
</composite:implementation>

支持bean中的actionListener - 方法如下:

public void actionListener(MyObject object)
{
  logger.info("ActionListener "+object); //Always the correct object
  FacesContext context = FacesContext.getCurrentInstance();

  Iterator<String> it = this.getAttributes().keySet().iterator();
  while(it.hasNext()) {   //Only for debugging ...
    logger.debug(it.next());
  }

  // I want the set the value here
  ValueExpression veSelection = (ValueExpression)getAttributes().get("selection");
  veSelection.setValue(context.getELContext(), object);

  // And then call a method in a `@ManagedBean` (this works fine)  
  MethodExpression al = (MethodExpression) getAttributes().get("actionListener");
  al.invoke(context.getELContext(), new Object[] {});
}

如果我使用带有选择的值表达式的CC(例如selection="#{testBean.user}"veSelectionnull(并且选择没有在调试迭代中打印出来,我得到一个NPE。如果我传递一个字符串(例如selection="test"),属性选择在调试迭代中可用,但是(当然)我得到ClassCastException

java.lang.String cannot be cast to javax.el.ValueExpression

如何为组件提供 actionListener 选择属性,并在第一步中设置所选值,然后调用 actionListener

1 个答案:

答案 0 :(得分:2)

对于调试迭代,您不会在UIComponent#getAttributes()的键集或入口集中看到值表达式。 javadoc中也明确提到了这一点。换句话说,该映射仅包含具有静态值的条目。只有在地图上显式调用get()并且底层属性是值表达式时,它才会实际调用它并返回评估值。

要获得值表达式,请改用UIComponent#getValueExpression()

ValueExpression selection = getValueExpression("selection");

关于方法表达式,嗯,如果你的复合从UICommand扩展,这是最简单的,但这在你的特殊情况下是简单的笨拙。只需将侦听器方法的目标设置为命令链接,并使用<f:setPropertyActionListener>在bean中设置所需的属性。这样就不需要支持组件了。

<composite:interface>
  <composite:attribute name="actionListener" required="true" targets="link"
          method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)"/>
  <composite:attribute name="selection"/>
</composite:interface>

<composite:implementation>
  ...
  <ui:repeat var="item" value="#{cc.attrs.data}">
    <p:commandLink id="link">
      <f:setPropertyActionListener target="#{cc.attrs.selection}" value="#{item}" />
    </p:commandLink>
  </ui:repeat>
  ...
</composite:implementation>