通过“ mixins”进行验证

时间:2018-12-10 22:21:58

标签: java spring spring-boot bean-validation hibernate-validator

我正在Spring Boot 2+中开发RESTful API,对此我需要执行一些验证。没什么特别的,只是典型的@NotNull@NotEmpty@Max@Min@Email@Regex@Future等东西...

除了我有必须使用但不能修改的API中的bean。这意味着我无法注释那些DTO中的字段和方法。

如果我可以创建与我必须在API中使用的真实DTO相同结构的 mixin-like 类或接口,那将是一件很棒的事,我将在其中愉快地放置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 bean),我很乐意按照以下方式进行操作:

ValidationMixinsSetup.addMixinFor(Person.class, PersonMixin.class);
ValidationMixinsSetup.addMixinFor(Address.class, AddressMixin.class);

除了ValidationMixinsSetup.addMixinFor是纯粹的幻想外,即它不存在。

我知道there exists a similar construct for Jackson关于JSON序列化/反序列化。我发现它非常有用。

现在,我一直在查看Spring和Hibernate Validator的源代码。但这不是小菜一碟...我已经研究了ValidatorFactoryLocalValidatorFactoryBeanTraversableResolver的实现,但是我什至无法启动概念验证。任何人都可以对此有所了解吗?即不是如何实现整个功能,而是如何以及从哪里开始。我想知道了哪些是扩展和/或实现的基本类或接口,哪些是重写的方法等。


编辑1:也许这种方法不是最佳方法。如果您认为有更好的方法,请告诉我。


编辑2:对于这种方法过于复杂,过于复杂, Rube Goldberg 等,我很欣赏并尊重这些观点,但我并不赞成询问通过mixins进行的验证是好是坏,方便还是不方便,都没有为什么这样。通过mixins进行验证有其自身的优点,我认为这对于某些有效的用例而言可能是一个不错的方法,即使用声明性验证而不是脚本验证或程序验证,同时也将验证与模型分开,让基础框架进行实际验证工作而我只指定约束条件,等等。

1 个答案:

答案 0 :(得分:2)

在使用Person的情况下,使用programmatic API(如注释中所述),您可以为约束应用下一个映射:

    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时-您需要在其中一个定义验证程序bean的sping配置文件中执行该操作。