Я разрабатываю RESTful API в Spring Boot 2+, для которого мне нужно выполнить несколько проверок. Ничего особенного, только типичные @NotNull, @NotEmpty, @Max, @Min, @Email, @Regex, @Future и т.д.
За исключением того, что у меня есть beans от API, который я должен использовать, но не может изменять. Это означает, что я не могу аннотировать поля и методы в этих DTO.
Было бы здорово, если бы я мог создавать классы или интерфейсы подобный миксину с той же структурой, что и реальные DTO, которые я должен использовать в API, на которые я бы с радостью разместил аннотации для проверки bean-компонентов.
Например, если бы у меня были следующие DTO, которые я не мог изменить:
public class Person {
private String name;
private String dateOfBirth;
private Address address;
// constructors, getters and setters ommited
}
public class Address {
private String street;
private String number;
private String zipCode;
// constructors, getters and setters ommited
}
Я бы создал следующие 2 интерфейса, которые имитируют их структуру и аннотируют их по мере необходимости:
public interface PersonMixin {
@NotBlank String name();
@Past String dateOfBirth();
@Valid @NotNull Address address();
}
public interface AddressMixin {
@NotBlank String street();
@Positive int number();
@NotBlank String zipCode(); // Or maybe a custom validator
}
Как видите, названия методов в интерфейсах совпадают с названиями свойств классов bean-компонентов. Это всего лишь одно возможное соглашение ...
Тогда, в идеале, где-нибудь, пока приложение загружается (обычно какой-то компонент @Configuration), я был бы очень рад сделать что-то вроде:
ValidationMixinsSetup.addMixinFor(Person.class, PersonMixin.class);
ValidationMixinsSetup.addMixinFor(Address.class, AddressMixin.class);
Вот только ValidationMixinsSetup.addMixinFor - чистая фантастика, т.е. его не существует.
Я знаю, что существует аналогичная конструкция для Джексона относительно сериализации / десериализации JSON. Я много раз находил это чрезвычайно полезным.
Теперь я изучал исходный код Spring и Hibernate Validator. Но это не пустяк ... Я покопался в реализациях ValidatorFactory, LocalValidatorFactoryBean, TraversableResolver, но не смог даже приступить к проверке концепции. Может ли кто-нибудь пролить свет на это? Т.е. не как реализовать всю функциональность, а только как и с чего начать. Мне нужны подсказки относительно того, какие классы или интерфейсы необходимо расширить и / или реализовать, какие методы следует переопределить и т. д.
РЕДАКТИРОВАТЬ 1: Может быть, это не лучший подход. Если вы думаете, что есть лучший подход, дайте мне знать.
Обновлено еще раз: Что касается того, что этот подход слишком сложен, слишком запутан, Руби Голдберг и т. д., Я ценю и уважаю эти точки зрения, но я не спрашиваю, хороша ли проверка с помощью миксинов, удобна или неудобна, и почему это может быть так. У валидации с помощью миксинов есть свои плюсы, и я думаю, что это может быть хорошим подходом для некоторых допустимых вариантов использования, то есть декларативной валидации вместо скриптовой или программной валидации, а также отделения валидации от модели, позволяя базовой структуре выполнять фактическую работу валидации. пока я только указываю ограничения и т. д.
@RobertHarvey Спасибо за ваш комментарий. Что касается копирования DTO, я мог бы это сделать, но мой новый DTO скоро устареет. Я могу справиться с отсутствующими проверками, но не с отсутствующими полями. Теперь у меня есть проверка вручную :) Я надеялся, что есть альтернатива получше.
Так, может быть, размышления могут помочь? Если DTO может измениться, довольно сложно «добавить» в него какой-либо код или полагаться на его структуру. Что-то должно быть определено, чтобы не измениться, иначе сделать что-то хорошо очень сложно. Отражение можно использовать для чтения произвольных классов и применения валидаторов, возможно, через какую-то внешнюю конфигурацию. Хотя для меня это тоже звучит как Руби Голдберг.
@markspace Ой, извините, я думал, что это было ясно в вопросе, но, похоже, это ясно только в моей голове: должно быть какое-то соглашение, т.е. аннотированные методы интерфейса должны иметь то же имя, что и атрибут bean.
Почему бы просто не определить ограничения через xml или с помощью программного API? Я бы предпочел последний. Таким образом, вам не понадобятся дополнительные классы / интерфейсы и т. д. И вы также сможете контролировать все свои ограничения.
@mark_o не могли бы вы показать такой подход?
пожалуйста, взгляните на эту часть документа - docs.jboss.org/hibernate/stable/validator/reference/en-US/…, и если есть другие вопросы - я буду рад помочь
@fps, что ты в итоге делал? У меня тоже есть подобная потребность.
Привет @ s7vr! В итоге я проверил все в коде




Используя программный API (как указано в комментарии) в случае Person, вы можете применить следующие сопоставления для ваших ограничений:
HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();
ConstraintMapping mapping = config.createConstraintMapping();
mapping.type( Person.class )
.field( "name" )
.constraint( new NotNullDef() )
.field( "number" )
.constraint( new PositiveDef() )
.field( "address" )
.constraint( new NotNullDef() )
.valid();
Validator validator = config.addMapping( mapping )
.buildValidatorFactory()
.getValidator();
И поскольку вы используете Spring, вам нужно будет сделать это в одном из ваших файлов конфигурации sping, где вы определяете bean-компонент валидатора.
Похоже на то, что у Руба Голдберга много, когда вы могли бы просто написать базовый код проверки или скопировать DTO, которым вы не можете управлять, в экземпляр класса, который вы можете.