Проверка через «миксины»

Я разрабатываю 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: Может быть, это не лучший подход. Если вы думаете, что есть лучший подход, дайте мне знать.


Обновлено еще раз: Что касается того, что этот подход слишком сложен, слишком запутан, Руби Голдберг и т. д., Я ценю и уважаю эти точки зрения, но я не спрашиваю, хороша ли проверка с помощью миксинов, удобна или неудобна, и почему это может быть так. У валидации с помощью миксинов есть свои плюсы, и я думаю, что это может быть хорошим подходом для некоторых допустимых вариантов использования, то есть декларативной валидации вместо скриптовой или программной валидации, а также отделения валидации от модели, позволяя базовой структуре выполнять фактическую работу валидации. пока я только указываю ограничения и т. д.

Похоже на то, что у Руба Голдберга много, когда вы могли бы просто написать базовый код проверки или скопировать DTO, которым вы не можете управлять, в экземпляр класса, который вы можете.

Robert Harvey 10.12.2018 23:24

@RobertHarvey Спасибо за ваш комментарий. Что касается копирования DTO, я мог бы это сделать, но мой новый DTO скоро устареет. Я могу справиться с отсутствующими проверками, но не с отсутствующими полями. Теперь у меня есть проверка вручную :) Я надеялся, что есть альтернатива получше.

fps 10.12.2018 23:35

Так, может быть, размышления могут помочь? Если DTO может измениться, довольно сложно «добавить» в него какой-либо код или полагаться на его структуру. Что-то должно быть определено, чтобы не измениться, иначе сделать что-то хорошо очень сложно. Отражение можно использовать для чтения произвольных классов и применения валидаторов, возможно, через какую-то внешнюю конфигурацию. Хотя для меня это тоже звучит как Руби Голдберг.

markspace 10.12.2018 23:45

@markspace Ой, извините, я думал, что это было ясно в вопросе, но, похоже, это ясно только в моей голове: должно быть какое-то соглашение, т.е. аннотированные методы интерфейса должны иметь то же имя, что и атрибут bean.

fps 10.12.2018 23:47

Почему бы просто не определить ограничения через xml или с помощью программного API? Я бы предпочел последний. Таким образом, вам не понадобятся дополнительные классы / интерфейсы и т. д. И вы также сможете контролировать все свои ограничения.

mark_o 11.12.2018 11:37

@mark_o не могли бы вы показать такой подход?

fps 11.12.2018 11:39

пожалуйста, взгляните на эту часть документа - docs.jboss.org/hibernate/stable/validator/reference/en-US/…, и если есть другие вопросы - я буду рад помочь

mark_o 11.12.2018 11:40

@fps, что ты в итоге делал? У меня тоже есть подобная потребность.

s7vr 28.10.2021 17:26

Привет @ s7vr! В итоге я проверил все в коде

fps 28.10.2021 17:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
9
785
1

Ответы 1

Используя программный 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-компонент валидатора.

Другие вопросы по теме