JSF自定义组件:支持自定义类型的参数,但属性设置器从未被调用

6

我根据众多教程(我使用PrimeFaces)创建了自定义的JSF组件,我添加了一个参数,并成功地将其传递给组件。

<c:custom command="command"/>

public void setCommand(String command) {
    log.debug("setCommand {}", command);
    this.command = command;
}

但我需要自定义类型的参数,并且我在教程中找不到相关内容,这些教程只处理最简单的情况。

<c:custom image="#{currentImageBean.image}"/>

public void setImage(Object image) {
    log.debug("setImage {}", image);
    this.image = (Image) image;
}

Bean返回的是Image类型的对象,但setter没有被调用。我本来以为这应该可以工作,因为一个好的教程应该会提到这种情况,但现在我陷入了更糟的错误中:什么也没有发生,日志中也没有任何提示为什么...那么,出了什么问题,我需要做出什么改变,从哪里寻找潜在的错误呢?

1个回答

6
这与自定义类型无关,而与使用字面(静态)值有关,例如attributename="attributevalue"attributename="#{attribute.value}"中的EL。这种行为是符合规范的。设置EL表达式(ValueExpression)的属性值是通过UIComponent#setValueExpression()实现的。它们通常只在请求时才会被真正地评估,通常在视图渲染时。它们不应该在烘焙UIComponent实例时直接评估,因为这会破坏动态值表达式的本质(考虑依赖于数据表当前迭代轮次)。
更好的方法是将可以容纳EL值表达式的属性的getter/setter委托给UIComponent#getStateHelper()而不是本地属性。最终,setValueExpression()也会最终进入StateHelperUIComponent#getAttributes()也会从StateHelper中解析值。
public Image getImage() {
   return (Image) getStateHelper().eval("image");
}

public void setImage(Image image) {
    getStateHelper().put("image", image);
}

请注意,没有本地属性。因此,当您需要属性的(计算)值时,只需调用getter。
为了实现您最初的功能要求,即设置属性的日志记录,您可能希望将日志记录语句添加到覆盖setValueExpression()的方法中,该方法委托给super。
@Override
public void setValueExpression(String name, ValueExpression binding) {
    log.debug(....);
    super.setValueExpression(name, binding);
}

谢谢,我已经在getAttributes.get("image")下找到了这个对象。 - Danubian Sailor
不客气。没错,它就像getAttributes()所回答的那样可用。但我强烈建议将getter/setter更改为这样,然后直接使用它们。这也是JSF实现和组件库构建其组件的方式。 - BalusC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接