OmniFaces @Param 无法使用转换器设置基元 属性

OmniFaces @Param fails to use converter to set a primitive property

@Inject @Param(converter = "#{pageConverter}") // or "pageConverter"
private int page;

@Named
@ApplicationScoped
public class PageConverter implements Converter

page 上使用 OmniFaces @Param 时出现异常

java.lang.IllegalArgumentException: Can not set int field com.example.Bean.page to null value
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeIntegerFieldAccessorImpl.set(UnsafeIntegerFieldAccessorImpl.java:80)
    at java.lang.reflect.Field.set(Field.java:758)
    at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:94)
    ...

我的转换器应该会处理这个问题,但 getAsObject 从未被调用过。

这个有效:

<f:metadata>
    <f:viewParam name="page" value="#{bean.page}">
        <f:converter binding="#{pageConverter}"/>
    </f:viewParam>
</f:metadata>

这个问题分为三个方面:

  1. CDI 本身不支持注入原始默认值(需要自定义生产者)。
  2. @Param 从一开始就从未支持原语(因为实践不佳)。
  3. 当请求参数完全不存在时,永远不会调用 JSF 转换器。

为了解决 1 和 2,我创建了 issue 266,我会在 2.4 最终版之前完成它。

现在,只需使用 Integer 而不是 int。不使用基元作为模型属性也被认为是更好的做法,因为您可以使用 null 来区分 "value is never submitted" 和 "value is submitted, but is empty".

此外,JSF 转换器从未像 "default value providers" 那样打算。当请求参数完全不存在时, <f:viewParam> 案例也永远不会触发转换器。所以说 "works" 实际上是不正确的。设置 0 的效果只是 EL 强制转换的结果,不涉及转换器。当您将转换器从您的外壳中完全移除时,会出现完全相同的问题。