Почему мое сообщение проверки бина не получено? - PullRequest
3 голосов
/ 28 февраля 2012

Я определяю некоторые сообщения проверки bean-компонентов для более поздней версии i18n.Это сообщение должно подтвердить, что вход имеет тип номер / BigDecimal:

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

<p:inputText value="#{payment.amount}" />

К сожалению, если я пытаюсь ввести текст, я не получаю определенное сообщение, но:

'asd' must be a signed decimal number

Может кто-нибудь объяснить, почему?Или, скорее, как заставить мое поле ввода всегда проверять с помощью @Digits?

Ответы [ 3 ]

5 голосов
/ 28 февраля 2012

В JSF проверка происходит после преобразования.Если вы введете что-то, не являющееся числом, в текстовое поле, которое сопоставлено с BigDecimal в компоненте поддержки, JSF попытается преобразовать это в BigDecimal, и это, конечно, не удастся.Таким образом, Hibernate Validator на самом деле не получит шанса. Вам нужно будет локализовать конверсионные сообщения JSF, чтобы достичь желаемого.

Я не знаком с аннотацией @Digits.Но документы Hibernate Validator , кажется, указывают, что он проверяет, использует ли число ожидаемое количество целых и дробных цифр.Поэтому вместо ввода текста в текстовое поле попробуйте ввести значение, которое не соответствует формату, принятому валидатором (в вашем случае дробная = 2, целое = 13).Поэтому попробуйте ввести значение 123.123120 и посмотреть, получите ли вы ожидаемое сообщение.

Вот хак, чтобы пройти весь путь до сущностей и получить аннотации в конвертере.Сначала вам нужно создать собственный конвертер для числа (в данном случае, BigDecimal):

@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);
}

}

И вам нужно использовать этот конвертер на своей странице:

    <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, но они вам на самом деле не нужны.

Что именно делает конвертер?Он выбирает объект в вашем бине, который содержит значение, на которое ссылается inputText, и имя поля.Затем он находит аннотацию @Digits для этого поля и читает его сообщение.Он просит NumericConverter преобразовать строку в число.Если это не удается, он использует сообщение в аннотации @Digits для сообщения об ошибке.

0 голосов
/ 10 февраля 2014

Не уверен насчет этого тега <p:inputText>, но в ванильном 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' как целое число - это действительно представление значение

0 голосов
/ 28 февраля 2012

Вы должны использовать <f:validateBean /> для делегирования валидации в API Bean Validation (JSR 303)

<p:inputText value="#{payment.amount}" >
    <f:validateBean />
</p:inputText>
...