Spring @Validated in service layer

后端 未结 5 467
天命终不由人
天命终不由人 2020-12-01 05:26

Hej,

I want to use the @Validated(group=Foo.class) annotation to validate an argument before executing a method like following:

public v         


        
5条回答
  •  孤独总比滥情好
    2020-12-01 05:56

    As stated above to specify validation groups is possible only through @Validated annotation at class level. However, it is not very convenient since sometimes you have a class containing several methods with the same entity as a parameter but each of which requiring different subset of properties to validate. It was also my case and below you can find several steps to take to solve it.

    1) Implement custom annotation that enables to specify validation groups at method level in addition to groups specified through @Validated at class level.

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ValidatedGroups {
    
        Class[] value() default {};
    }
    

    2) Extend MethodValidationInterceptor and override determineValidationGroups method as follows.

    @Override
    protected Class[] determineValidationGroups(MethodInvocation invocation) {
        final Class[] classLevelGroups = super.determineValidationGroups(invocation);
    
        final ValidatedGroups validatedGroups = AnnotationUtils.findAnnotation(
                invocation.getMethod(), ValidatedGroups.class);
    
        final Class[] methodLevelGroups = validatedGroups != null ? validatedGroups.value() : new Class[0];
        if (methodLevelGroups.length == 0) {
            return classLevelGroups;
        }
    
        final int newLength = classLevelGroups.length + methodLevelGroups.length;
        final Class[] mergedGroups = Arrays.copyOf(classLevelGroups, newLength);
        System.arraycopy(methodLevelGroups, 0, mergedGroups, classLevelGroups.length, methodLevelGroups.length);
    
        return mergedGroups;
    }
    

    3) Implement your own MethodValidationPostProcessor (just copy the Spring one) and in the method afterPropertiesSet use validation interceptor implemented in step 2.

    @Override
    public void afterPropertiesSet() throws Exception {
        Pointcut pointcut = new AnnotationMatchingPointcut(Validated.class, true);
        Advice advice = (this.validator != null ? new ValidatedGroupsAwareMethodValidationInterceptor(this.validator) :
                new ValidatedGroupsAwareMethodValidationInterceptor());
        this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
    }
    

    4) Register your validation post processor instead of Spring one.

     
    

    That's it. Now you can use it as follows.

    @Validated(groups = Group1.class)   
    public class MyClass {
    
        @ValidatedGroups(Group2.class)
        public myMethod1(Foo foo) { ... }
    
        public myMethod2(Foo foo) { ... }
    
        ...
    }
    

提交回复
热议问题