メソッドのパラメータと戻り値のためのさまざまな検証グループ

Mブッシュ:

私は、メソッドのパラメータや戻り値に対して異なる検証グループを使用したいと思います。私はこれを達成するためにSpringの@Validated注釈にしようとしています。例えば:

public interface UserOperations {

    @Validated({ResponseGroup.class})
    @Valid 
    User createUser(@Validated({RequestGroup.class}) @Valid User user);

}

戻り値が実際に照らして検証なっていることが表示されますResponseGroupがメソッドの引数は、user両方に対して検証なっているResponseGroupRequestGroup私が見たときにこれが起こっている理由を参照してください。org.springframework.validation.beanvalidation.MethodValidationInterceptor#invoke

戻り値にメソッドの引数と異なる検証グループに1検証グループを適用するためのエレガントな方法はありますか?

Mブッシュ:

問題は方法があるということMethodValidationInterceptor.invokeで定義された検証グループを探し@Validated個々のパラメータに各メソッドに注釈、またはクラスではなく。指定された検証グループは、パラメータ並びに戻り値に適用されます。

別の検証グループは、パラメータと戻り値に適用されます持っているために、私はそれぞれの引数の戻り値と検証グループの検証グループを指定するために使用される2つのアノテーションを作成しました:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateReturnValue {
    Class<?>[] value();

}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateArguments {
    Class<?>[] value();
}

今、検証グループの1セットは、戻り値を検証するために指定することができ、検証グループの異なるセットは、すべてのメソッドの引数に指定することができます。

@Validated
public interface MyClassWithMethodsToValidate {

    @ValidateReturnValue({FooResponseGroup.class})
    @ValidateArguments({FooRequestGroup.class})
    FooResource createFoo(Foo foo);
}

処理すべきこれらの注釈のために、私は拡張するクラス作成MethodValidationInterceptorのとオーバーライドinvoke(コードの多くは、オーバーライドされたメソッドと同じである)の方法を

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.validation.beanvalidation.MethodValidationInterceptor;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.Method;
import java.util.Set;

class MyMethodValidationInterceptor extends MethodValidationInterceptor {
    private final Validator validator;

    public MyMethodValidationInterceptor() {
        this(Validation.buildDefaultValidatorFactory().getValidator());
    }
    public MyMethodValidationInterceptor(Validator validator) {
        super(validator);
        this.validator = validator;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
            return invocation.proceed();
        }

        Method methodToValidate = invocation.getMethod();
        Class<?>[] parameterGroups = getArgumentsGroups(methodToValidate);
        if(parameterGroups == null){
            parameterGroups = super.determineValidationGroups(invocation);
        }

        Set<ConstraintViolation<Object>> violations;
        try {
            violations = validator.forExecutables().validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), parameterGroups);
        }
        catch (IllegalArgumentException ex) {
            methodToValidate = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
            violations = validator.forExecutables().validateParameters(invocation.getThis(), methodToValidate, invocation.getArguments(), parameterGroups);
        }
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }

        Object returnValue = invocation.proceed();

        Class<?>[] returnValueGroups = getReturnValueGroups(methodToValidate);
        if(returnValueGroups == null){
            returnValueGroups = super.determineValidationGroups(invocation);
        }

        violations = validator.forExecutables().validateReturnValue(invocation.getThis(), methodToValidate, returnValue, returnValueGroups);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }

        return returnValue;
    }

    private Class<?>[] getReturnValueGroups(Method methodToValidate){
        ValidateReturnValue annotation =  AnnotationUtils.findAnnotation(methodToValidate, ValidateReturnValue.class);
        if(annotation != null){
            return annotation.value();
        }else {
            return null;
        }
    }

    private Class<?>[] getArgumentsGroups(Method methodToValidate){
        ValidateArguments annotation =  AnnotationUtils.findAnnotation(methodToValidate, ValidateArguments.class);
        if(annotation != null){
            return annotation.value();
        }else {
            return null;
        }
    }

    private boolean isFactoryBeanMetadataMethod(Method method) {
        Class<?> clazz = method.getDeclaringClass();

        if (clazz.isInterface()) {
            return ((clazz == FactoryBean.class || clazz == SmartFactoryBean.class) &&
                    !method.getName().equals("getObject"));
        }

        Class<?> factoryBeanType = null;
        if (SmartFactoryBean.class.isAssignableFrom(clazz)) {
            factoryBeanType = SmartFactoryBean.class;
        }
        else if (FactoryBean.class.isAssignableFrom(clazz)) {
            factoryBeanType = FactoryBean.class;
        }
        return (factoryBeanType != null && !method.getName().equals("getObject") &&
                ClassUtils.hasMethod(factoryBeanType, method));
    }
}

それから私は、拡張するクラスを作成MethodValidationPostProcessorし、その上書きされますcreateMethodValidationAdvice新しい使用する方法MyMethodValidationInterceptorクラス:

class MyMethodValidationPostProcessor extends MethodValidationPostProcessor {

    @Override
    protected Advice createMethodValidationAdvice(Validator validator) {
        return (validator != null ? new MyMethodValidationInterceptor(validator) : new MyMethodValidationInterceptor());
    }
}

最後に、のBeanを構成します MyMethodValidationPostProcessor

@Configuration
public class MethodValidationConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MyMethodValidationPostProcessor();
    }
}

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=17411&siteId=1