通过“mixins”进行验证

Fed*_*ner 5 java spring hibernate-validator bean-validation spring-boot

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

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

如果我可以创建与我必须在 API 中使用的真实 DTO 具有相同结构的类似 mixin 的类或接口,那就太好了,我很乐意在其上放置 bean-validation 的注释。

例如,如果我有以下无法修改的 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
}
Run Code Online (Sandbox Code Playgroud)

我将创建以下两个接口来模仿它们的结构并根据需要对它们进行注释:

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
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,接口中方法的名称与 bean 类的属性名称相匹配。这只是一种可能的约定......

然后,理想情况下,在应用程序加载时(通常是一些@Configurationbean),我很乐意做以下事情:

ValidationMixinsSetup.addMixinFor(Person.class, PersonMixin.class);
ValidationMixinsSetup.addMixinFor(Address.class, AddressMixin.class);
Run Code Online (Sandbox Code Playgroud)

但这ValidationMixinsSetup.addMixinFor纯粹是幻想,即它不存在。

我知道Jackson 在 JSON 序列化/反序列化方面存在类似的构造。我多次发现它非常有用。

现在,我一直在查看 Spring 和 Hibernate Validator 的源代码。但这不是小菜一碟......我已经深入研究了,,,ValidatorFactory实现,但我什至无法开始概念验证。有人能解释一下吗?即不是如何实现整个功能,而是如何以及从哪里开始。我正在寻找一些关于哪些是要扩展和/或实现的基本类或接口、要重写哪些方法等的提示。LocalValidatorFactoryBeanTraversableResolver


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


编辑2:至于这种方法过于复杂,过于复杂,Rube Goldberg等,我欣赏并尊重这些观点,但我并不是问通过mixin进行验证是好是坏,方便还是不方便,也不是问为什么可能是这样的。通过 mixins 进行验证本身就有优点,我认为对于某些有效用例来说,这可能是一种很好的方法,即使用声明性验证而不是脚本化或编程验证,同时还将验证与模型分开,让底层框架完成实际的验证工作而我只指定约束等。

小智 4

在 Person 的情况下使用编程 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();
Run Code Online (Sandbox Code Playgroud)

当您使用 Spring 时,您需要在定义验证器 bean 的 sping 配置文件之一中执行此操作。