Java 为什么我的bean验证消息没有被接收?

Java 为什么我的bean验证消息没有被接收?,java,jsf,bean-validation,hibernate-validator,Java,Jsf,Bean Validation,Hibernate Validator,我正在为以后的i18n定义一些bean验证消息。 此消息应验证输入是否为number/BigDecimal类型: class Payment { @Digits(message = "test error msg", fraction = 2, integer = 13) private BigDecimal amount; } <p:inputText value="#{payment.amount}" /> @FacesConverter("MyBigDeci

我正在为以后的i18n定义一些bean验证消息。 此消息应验证输入是否为number/BigDecimal类型:

class Payment {
    @Digits(message = "test error msg", fraction = 2, integer = 13)
    private BigDecimal amount;
}

<p:inputText value="#{payment.amount}" />
@FacesConverter("MyBigDecimalConverter")
public class MyBigDecimalConverter extends NumberConverter {
@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
    try {
        HtmlInputText it = (HtmlInputText) arg1;
        ValueExpression ve = it.getValueExpression("value");
        String expression = ve.getExpressionString();
        String field = expression.replaceAll("#\\{.*\\.", "");
        field = field.replace("}", "");
        String parent = expression.replace("." + field, "");
        ExpressionFactory expressionFactory = arg0.getApplication().getExpressionFactory();
        ValueExpression exp = expressionFactory.createValueExpression(arg0.getELContext(), parent, Object.class);
        Object obj = exp.getValue(arg0.getELContext());

        Digits d = null;    
        Field f = obj.getClass().getDeclaredField(field);
        d = f.getAnnotation(Digits.class);
        return super.getAsObject(arg0, arg1, arg2);
    } catch (ConverterException e) {
        FacesMessage msg = new FacesMessage(d.message());
        msg.setSeverity(FacesMessage.SEVERITY_ERROR);
        throw new ConverterException(msg);
    } catch (Exception e) {
        return super.getAsObject(arg0, arg1, arg2);
    }
}

@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
    return super.getAsString(arg0, arg1, arg2);
}

}
有人能解释一下原因吗?或者更确切地说,如何强制输入字段始终使用@Digits进行验证?

您应该使用它将验证委托给Bean验证API(JSR 303)


在JSF中,验证发生在转换之后。如果在映射到支持bean中的BigDecimal的文本字段中输入的不是数字的内容,JSF将尝试将其转换为BigDecimal,当然,它将失败。所以Hibernate验证器实际上没有机会启动。您需要本地化JSF转换消息,以实现所需的功能

我不熟悉@Digits注释。但是,似乎表明它验证了该数字是否使用了预期的整数和小数位数。因此,与其在文本字段中输入文本,不如尝试输入一个与验证器接受的格式不同的值(在您的例子中,分数=2,整数=13)。所以试着输入123.123120的值,看看你是否得到了预期的消息

这里有一个技巧,可以一直深入到实体中,并在转换器中获取注释。首先,需要为数字(在本例中为BigDecimal)创建自定义转换器:

您需要在页面中使用该转换器:

    <h:outputText value="#{someBean.someEntity.nome}" />
    <h:form>
        <p:inputText value="#{someBean.someEntity.someBigDecimal}" id="test">
            <f:converter converterId="MyBigDecimalConverter" />
        </p:inputText>
        <h:message for="test"></h:message>
        <p:commandButton value="teste" process="@form" update="@form"></p:commandButton>
    </h:form>

我在这里使用primeFaces组件,但您并不真正需要它们


转换器到底在做什么?它获取bean中的对象,该对象包含inputText引用的值和字段名。然后,它找到该字段的@Digits注释并读取其消息。它要求NumericConverter将字符串转换为数字。如果失败,它将使用@Digits注释中的消息作为错误消息。

不确定此
标记,但在vanilla JSF中,您可以:

<h:inputText id="price"
    value="#{movieController.movie.price}" redisplay="true"
    converterMessage="Please input a decimal">
    <f:ajax event="blur" render="numberOfCopiesMessage" />
</h:inputText>

请注意
converterMessage
属性


虽然这看起来像是违反了DRY(因为实体中已经有一条消息),但事实并非如此。您的模型与用户以整数形式提交
'asd'
无关-这实际上是一个视图问题

是的,当我输入通过jsf时,我会得到相应的hib验证器消息。我想这就回答了您的问题了?我很高兴能帮上忙。不是真的。我仍然试图强制验证休眠,并跳过jsf验证。正如下面所评论的,f:validateBean对我不起作用,即使我完全删除了标记。默认情况下,JSF似乎会验证到支持BigDecimal的映射。但我仍然没有找到任何东西来禁用这个特定的功能。问题是我们现在并没有真正讨论验证。我们讨论的是转换,这就是JSF处理事情的方式。你不能跳过这个。正如您所说,如果您输入可以转换为BigDecimal的内容,那么将调用Hibernate验证器。否则,它就不会;这是没有办法的。更改您收到的消息的简单方法是更改资源包中的特定字符串。你需要帮助吗?我刚刚编辑了答案。这是一个巨大的黑客;你可能需要在这里和那里稍微调整一下,但你明白了。这很奇怪。我试过这个标签,但不起作用。即使我完全删除了验证标签,仍然会进行JSF验证。
    <h:outputText value="#{someBean.someEntity.nome}" />
    <h:form>
        <p:inputText value="#{someBean.someEntity.someBigDecimal}" id="test">
            <f:converter converterId="MyBigDecimalConverter" />
        </p:inputText>
        <h:message for="test"></h:message>
        <p:commandButton value="teste" process="@form" update="@form"></p:commandButton>
    </h:form>
<h:inputText id="price"
    value="#{movieController.movie.price}" redisplay="true"
    converterMessage="Please input a decimal">
    <f:ajax event="blur" render="numberOfCopiesMessage" />
</h:inputText>