具有属性值的表达式语言的JSF 2自定义组件不会触发属性设置器

Rar*_*esI 8 jsf attributes custom-component jsf-2

我在JSF 2.0中构建了一个自定义组件

标签看起来像这样:

<x:myTag id="1" name="AAA" />
Run Code Online (Sandbox Code Playgroud)

对应的java类:

@FacesComponent("a.b.c.MyTag")
public class UIMyTag extends UIInput {

   private String name;
   private String id;

   public String getId() {
      return id;
   }

   public void setId(String id) {
       this.id = id;
   }


   public String getId() {
      return id;
   }

   public void setId(String id) {
       this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   @Override
   public void encodeBegin(FacesContext context) throws IOException {
       ResponseWriter writer = context.getResponseWriter();
       logger.debug(getName()); //prints null for name="#{dummyBean.name}" 
                                //   and AAA for name="AAA"
       logger.debug(getAttributes().get("name")); // always correct value
   ...
}
   ....

}
Run Code Online (Sandbox Code Playgroud)

如果我使用

<x:myTag id="1" name="AAA" />
Run Code Online (Sandbox Code Playgroud)

一切都按预期工作,但当我使用EL for myTag属性时,setName()方法永远不会被调用.因此对于,

<x:myTag id="#{dummyBean.id}" name="#{dummyBean.name}" />
Run Code Online (Sandbox Code Playgroud)

我总是nullname我的内财产encodeBegin法.经过调试后,我注意到该setName方法永远不会被调用.我认为关于EL的事情可能会让事情变得混乱(而且我仍然认为原因与此有关),但真正奇怪的是该id属性运作良好:setter被调用,并且当econding开始时值就像预期的那样.

我必须提一下,如果我getAttributes().get("name")encodeBegin方法调用,我得到正确的名称值,但我很感兴趣为什么它不适用于getter和setter.

任何想法我的组件缺少什么?

Bal*_*usC 12

此行为是预期的并且符合规范.作为值表达式的属性值由设置UIComponent#setValueExpression().它们应该仅在它们真正被使用时才被评估,通常在视图渲染时间期间.

id(和binding)属性具有特殊的待遇:它在视图生成时评估之前,它已经设定,因此,"规则"制定者将被调用,而不是setValueExpression()(因为视图的渲染时的本来崩溃id(或binding动态计算结果为)属性由于某种原因,视图构建时间内的值不同.

更好的方法是将getter/setter委托UIComponent#getStateHelper()给本地属性.该setValueExpression()最终也落得中StateHelper(注意,这不叫二传手在所有;只是调用的getter,如果你需要的数据),并且getAttributes()还从解析值StateHelper.

public String getName() {
   return (String) getStateHelper().eval("name");
}

public void setName(String name) {
    getStateHelper().put("name", name);
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可以安全地删除getId()setId()方法,因为他们在已经definied UIComponentBase您是从扩展超类.