0

メソッド呼び出しが自動的に検証されるように、既存のオブジェクトを装飾したいと考えています。Hibernate バリデーターを呼び出すインターセプターにメソッド呼び出しを委譲することができましたが、これまでのところ正常に動作しています。

public class HibernateBeanValidator implements BeanValidator{

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

    @Override
    public <T> T addMethodValidation(T object) {
        ExecutableValidator executableValidator = factory.getValidator().forExecutables();

        Class<? extends T> dynamicType = (Class<? extends T>)new ByteBuddy()
                .subclass(object.getClass())
                .method(isPublic()).intercept(MethodDelegation.to(new ValidationInterceptor(object, executableValidator)).andThen(SuperMethodCall.INSTANCE))
                .make()
                .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();

        try {
            T validatedObject = dynamicType.newInstance();
            return  validatedObject;
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public static class ValidationInterceptor {

        private final Object validatedObject;
        private final ExecutableValidator executableValidator;

        public <T> ValidationInterceptor(T object, ExecutableValidator executableValidator) {
            this.validatedObject = object;
            this.executableValidator = executableValidator;
        }

        public void validate(@Origin Method method, @AllArguments Object[] arguments)
                throws Exception {
            Set<ConstraintViolation<Object>> constraintViolations = executableValidator.validateParameters(validatedObject, method, arguments);
            if(! constraintViolations.isEmpty()) {
                throw new ValidationException(constraintViolations);
            }
        }
    }
}

私が改善したいのは、メソッド呼び出しを、次のような制約注釈で注釈が付けられたパラメーターを少なくとも 1 つ持つメソッドにのみバインドすることです。

class Echo {
    public String repeat(@NotNull String word) { /* should bind validation here */
        return word;
    }

    public String notAnnotated(String word) { /* should not bind validation */
        return word;
    }
}

Byte Buddy で ElementMatcher を指定して、@NotNull (javax.validation.constraints から取得) などの @Constraint で注釈が付けられたパラメーターを持つメソッドにのみバインドするようにするにはどうすればよいですか?

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {

    String message() default "{javax.validation.constraints.NotNull.message}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    /**
     * Defines several {@link NotNull} annotations on the same element.
     *
     * @see javax.validation.constraints.NotNull
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @interface List {

        NotNull[] value();
    }
}
4

2 に答える 2

0

実際には、名前空間からアノテーションをチェックするだけでなくjavax.validation.constraints、Bean Validation メタデータ API を使用する方がよいでしょう。制約はこの名前空間から取得する必要はありませんが、Hibernate Validator ( org.hibernate.validator.constraints) から取得したり、カスタム制約にすることもできます。ElementMatcherメタデータ API を使用する可能な実装は、次のようになります。

public static class BeanValidationMatcher は ElementMatcher を実装します {

private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

@Override
public boolean matches(Object target) {
    // handle different descriptors and potentially use generic MethodDescription
    if ( !( target instanceof MethodDescription.ForLoadedMethod ) ) {
        return false;
    }
    MethodDescription.ForLoadedMethod methodDescription = (MethodDescription.ForLoadedMethod) target;
    Method method = methodDescription.getLoadedMethod();

    boolean isGetter = ReflectionHelper.isGetterMethod( method );

    boolean needsValidation;
    BeanDescriptor beanDescriptor = validator.getConstraintsForClass( method.getDeclaringClass() );
    if ( isGetter ) {
        needsValidation = isGetterConstrained( method, beanDescriptor );
    }
    else {
        needsValidation = isNonGetterConstrained( method, beanDescriptor );
    }

    return needsValidation;
}

private boolean isNonGetterConstrained(Method method, BeanDescriptor beanDescriptor) {
    return beanDescriptor.getConstraintsForMethod( method.getName(), method.getParameterTypes() ) != null;
}

private boolean isGetterConstrained(Method method, BeanDescriptor beanDescriptor) {
    String propertyName = ReflectionHelper.getPropertyName( method );
    PropertyDescriptor propertyDescriptor = beanDescriptor.getConstraintsForProperty( propertyName );
    return propertyDescriptor != null && propertyDescriptor.findConstraints()
            .declaredOn( ElementType.METHOD )
            .hasConstraints();
}

}

于 2015-06-08T18:55:01.610 に答える