关于<f:viewParam>的jsf:Validation // conversion错误不会本地化为<f:view语言环境>,而是默认语言环境

Validation/conversion errors of <f:viewParam> do not localize to <f:view locale>, but to default locale

我在JSF页面上有一个<f:viewParam>标记,该标记在转换和验证后将GET参数设置为相应的托管bean。

如果发生转换或验证错误,那么将从资源束中获取适当的错误消息并显示在<p:messages>(也可能是<p:growl><h:messages>)上。

该应用程序是多语言的。因此,当选择了不同的语言,应根据默认区域en(对于英文)被显示在该语言的消息,但它总是显示该消息。

Test.xhtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="#{localeBean.language}"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

    <f:view locale="#{localeBean.locale}">
        <f:metadata>
            <f:viewParam name="id" converter="#{myConverter}" />
        </f:metadata>
        <h:head>
            Test
        </h:head>
        <h:body>
            <h:messages />
        </h:body>
    </f:view>
</html>

转换器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@FacesConverter("myConverter")
public final class MyConverter implements Converter
{
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value)
    {
        ResourceBundle bundle = context.getApplication()
            .evaluateExpressionGet(context,"#{messages}", ResourceBundle.class);
        String message = bundle.getString("id.conversion.error");
        throw new ConverterException(
            new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value)
    {
        throw new UnsupportedOperationException(); // Not relevant in this problem.
    }
}

除了来自<f:viewParam>的消息,没有问题。所有其他类型的消息均以用户选择的语言显示。

<f:viewParam>有什么特别之处吗?


我可以重现您的问题。 Mojarra 2.1.25和MyFaces 2.1.12都存在相同的问题。因此,我不确定这是JSF暗示中的错误还是JSF规范中的疏忽。到目前为止,事实证明,在进入渲染响应阶段之前,尚未为GET请求设置viewroot语言环境。该转换器在验证阶段运行,远远早于渲染响应,这解释了为什么它使用默认语言环境。我必须稍后进行调查,如有必要,请向Mojarra报告问题。

同时,解决此问题的最佳选择是按如下方式获取捆绑包,而不是EL评估<resource-bundle><var>

1
2
3
4
String basename ="com.example.i18n.message"; // Exactly the same as <resource-bundle><base-name>
Locale locale = context.getApplication().evaluateExpressionGet(context,"#{localeBean.locale}", Locale.class);
ResourceBundle bundle = ResourceBundle.getBundle(basename, locale);
// ...

更新:我已经根据此问题报告了3021问题。此时,我仍然无法确定规范的含义,但是我发现该实现的行为是不直观的。

更新2:Mojarra和MyFaces成员对此表示同意。对于Mojarra,已根据2.2.5进行了修复(尚无2.1.x反向端口?),对于MyFaces,已根据2.0.19、2.1.13和2.2.0进行了修复。