Добавить сообщение об ошибке проверки уровня типа в определенное поле

У меня есть простой класс, который проверяется с использованием метода boolean isValid(), который работает, и, конечно же, сообщение об ошибке находится на уровне класса/типа.

Вот мой простой класс:

public class NewPasswordDTO {
    @NotNull
    public String password;

    @NotNull
    public String confirmation;

    @AssertTrue(message="Passwords must match.")
    protected boolean isValid() {
        return password.equals(confirmation);
    }
}

Но то, что я действительно хочу, это что-то вроде этого:

public class NewPasswordDTO {
    @NotNull
    @Equals("confirmation", message="...")
    public String password;

    @NotNull
    public String confirmation;
}

Таким образом, сообщение об ошибке будет установлено на уровне поля, а не на уровне класса/типа.

Это возможно как-то? Может быть, использовать собственный валидатор для этого класса?

Заранее спасибо!

РЕШЕНИЕ:

Спасибо Гуннару! Я только что придумал отличное универсальное решение :-). Я просто использовал (имеется в виду копирование и вставка) код из Hibernates @ScriptAssert и ScriptAssertValidator и немного изменил его:

@ScriptAssert:

  • Добавьте новый String field(). (здесь добавляется сообщение об ошибке)

ScriptAssertValidator:

  • Внутри метода initialize не забудьте также сохранить свойства fieldName и message, потому что нам нужно получить к ним доступ на следующем шаге.

  • Добавьте этот фрагмент внизу метода isValid:

    context.buildConstraintViolationWithTemplate(errorMessage) .addPropertyNode(fieldName).addConstraintViolation();

  • Также добавьте context.disableDefaultConstraintViolation(); где-нибудь внутри метода isValid, чтобы не генерировать сообщение об ошибке по умолчанию, которое в противном случае было бы добавлено на уровне класса.

И это все. Теперь я могу использовать его так:

@FieldScriptAssert(lang="javascript", script="_this.password.equals(_this.confirmation)", field="password", message="...")
public class NewPasswordDTO { ... }

person Benjamin M    schedule 19.01.2014    source источник


Ответы (3)


Простой ответ: это не так (если вы его не реализуете): http://docs.oracle.com/javaee/6/api/javax/validation/constraints/package-summary.html показывает все ограничения аннотаций. Конечно, вы можете внедрить свою строку в качестве ресурса в свой класс с помощью @producer и т. д. (который недавно обсуждается для удаления в jdk8), но вы не можете использовать это значение для своего утверждения.
В ответ на комментарий:
Это предполагало, что природа представляет собой константную строку, которую вы хотели бы использовать в качестве строкового ресурса. И тогда, конечно, можно написать свой собственный класс на основе java. lang.string с @Producer, который затем поддерживает @Inject. Хотя это, конечно, не тот способ, которым я лично занимался бы постоянными строками.

person Peter    schedule 19.01.2014
comment
Спасибо. Я знаю все эти аннотации, вопрос был больше похож на: Могу ли я написать свою собственную аннотацию/валидатор, которая справится с этим? ... И я действительно не понимаю, что вы имеете в виду. Конечно, вы можете ввести свою строку в качестве ресурса в свой класс с помощью @producer и так далее. У вас есть пример? - person Benjamin M; 20.01.2014
comment
Вау, это звучит как халявный хак :-D. Неужели нельзя как-то использовать @ScriptAssert(...) для моей задачи? ... (тоже грязно, но) может есть возможность сделать что-то подобное: @ScriptAssert(lang="javascript", script="if(!_this.password.equals(_this.confirmation)) password=''; return true;"). Тогда у меня будет некоторая @NotEmpty проверка в password, которая поймает эту новую спровоцированную ошибку... - person Benjamin M; 20.01.2014
comment
Я добавил свое собственное решение вверху. Вместо жесткой пользовательской аннотации я решил использовать логику @ScriptAssert. Довольно круто!! - person Benjamin M; 20.01.2014

Вы можете либо использовать ограничение @ScriptAssert для класса (обратите внимание, что ограничение всегда должно быть свободным от побочных эффектов, поэтому не рекомендуется изменять состояние проверенного bean-компонента; вместо этого вы должны просто проверить, совпадают ли два поля) или вы реализуете пользовательское ограничение на уровне класса.

Последний также позволяет, чтобы указать путь к пользовательскому свойству для нарушения ограничения, что позволяет пометить свойство «подтверждение» как ошибочное, а не полный класс.

person Gunnar    schedule 20.01.2014
comment
Это хорошие новости! Я проверю это. Кстати. Я пытался изменить состояние с помощью @ScriptAssert, что бесполезно. Журнал отладки всегда выглядел так: some field constraint checked, some other field constraint checked, ..., class constraint checked. Так что нет шансов вызвать какое-то ограничение на уровне поля. - person Benjamin M; 20.01.2014

Если вы используете Spring Framework, то в качестве альтернативы @ScriptAssert используйте JSR 223, вы можете использовать @SpELAssert, использующий язык выражений Spring. (СпЭл). Преимущество заключается в том, что ему не нужен механизм сценариев, совместимый с JSR 223, который может быть недоступен в некоторых средах. См. этот ответ для получения дополнительной информации.

person Jakub Jirutka    schedule 23.01.2014
comment
Спасибо. Это тоже звучит красиво. Предоставленный вами код действительно мал, и, глядя на тестовые примеры, кажется, что используемые выражения очень похожи на эти выражения javascript. ... Можете ли вы сказать мне, какая среда не поддерживает JSR 223? Я думал, что это часть Java с версии 6? - person Benjamin M; 23.01.2014