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

2022-01-13 00:00:00 attributes custom-component java jsf jsf-2

我根据许多教程之一创建了我的自定义 JSF 组件(我正在使用 PrimeFaces),我添加了一个已成功传递给组件.

I've created my custom JSF component according to one of many tutorials (I'm using PrimeFaces), I've added an argument which was successfully passed to component.

<c:custom command="command"/>

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

但我需要自定义类型的参数,这是我在教程中找不到的东西,教程只处理最琐碎的情况.

But I need the argument of custom type, and that's something that I couldn't find in tutorials, which are handling only the most trivial cases.

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

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

bean 正在返回 Image 类型的对象,但未调用 setter.我预计这会起作用,因为否则一个好的教程应该提到这种情况,但现在我被更糟糕的错误所困扰:没有任何反应,日志中没有任何内容表明原因......所以,出了什么问题,我需要改变什么,在哪里寻找潜在的错误?

The bean is returning the object of type Image, but the setter is not called. I've expected that this will work, because otherwise a good tutorial should mention that case, but now I'm stuck with the worse of the errors: nothing happens, and there's nothing in logs suggesting why... So, what is wrong, what I need to change, where to look for potential error?

推荐答案

这与自定义类型无关.这与使用文字(静态)值与 EL 有关,如 attributename="attributevalue"attributename="#{attribute.value}".

This has nothing to do with custom types. This has to do with using literal (static) values versus EL as in attributename="attributevalue" versus attributename="#{attribute.value}".

这种行为是预期的,并且符合规范.EL 表达式的属性值(ValueExpressions) 由 UIComponent#setValueExpression().它们应该只在真正被请求时才被评估,通常是在视图渲染期间.在烘焙 UIComponent 实例期间不应直接评估它们,因为这会破坏动态值表达式的性质(考虑取决于数据表的当前迭代轮次).

This behavior is expected and by specification. Attribute values which are EL expressions (ValueExpressions) are been set by UIComponent#setValueExpression(). They are namely supposed to be evaluated only when they are really been requested, usually during view render time. They shouldn't be evaluated directly during baking the UIComponent instance as that would defeat the nature of dynamic value expressions (think of depending on the current iteration round of data table).

更好的方法是将可以保存 EL 值表达式的属性的 getter/setter 委托给 UIComponent#getStateHelper() 而不是本地属性.setValueExpression() 最终也会在 StateHelper 中结束.UIComponent#getAttributes() 还解析来自 StateHelper.

Better is to delegate the getters/setters of attributes which can hold an EL value expression to UIComponent#getStateHelper() instead of to local properties. The setValueExpression() will namely ultimately also end up in the StateHelper. The UIComponent#getAttributes() also resolves the values from the StateHelper.

public Image getImage() {
   return (Image) getStateHelper().eval("image");
}

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

请注意,没有本地属性.因此,当您需要属性的(评估)值时,只需调用 getter.

Note that there's no local property. So when you need the (evaluated) value of the attribute, then just call the getter.

为了实现您的初始功能需求,即设置属性的日志记录,您可能希望将日志记录语句添加到委托给 super<的 setValueExpression() 覆盖/代码>.

In order to achieve your initial functional requirement, which is the logging of the set attribute, you might want to add the logging statement to the setValueExpression() override which delegates to super.

@Override
public void setValueExpression(String name, ValueExpression binding) {
    log.debug(....);
    super.setValueExpression(name, binding);
}

相关文章