在" beforeSave"之前的实体验证RepositoryEventHandler被解雇了

时间:2017-02-28 00:04:04

标签: spring validation spring-data-rest

Spring Data REST docs描述了 RepositoryEventHandler被解雇后验证实体的方法:

  

您只需要在其中注册验证器的实例   bean的工作是在正确的事件之后调用验证器

有没有办法在实体之前应用[声​​明式] JSR-303验证,然后将它们传递给" beforeSave" RepositoryEventHandler S'

从目前为止我看到的调试情况来看,情况并非如此,并且" beforeSave"在进行任何验证之前,RepositoryEventHandler会被解雇。

我可以直接在处理程序中编写验证调用,但这与"之后"验证得到处理。

顺便说一下。事件处理程序调用的序列似乎在Spring Boot 1.3.8和1.5.1之间发生了变化。过去,验证在 @HandleBeforeSave处理程序之前发生。在 ValidatingRepositoryEventListener处理程序之后的1.5.1 @HandleBeforeSave解雇中。

更新

正如评论中所提到的,Spring Data REST中似乎有一个ticket Jira对此持开放态度。

2 个答案:

答案 0 :(得分:2)

作为解决方法:

  1. 创建扩展X的{​​{1}}并使用PreflightValidatingRepositoryEventListener对其进行注释。

    ValidatingRepositoryEventListener
  2. 添加与@Order(Ordered.HIGHEST_PRECEDENCE)

    相同的验证器
    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class PreflightValidatingRepositoryEventListener extends ValidatingRepositoryEventListener {
        public PreflightValidatingRepositoryEventListener(ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
            super(persistentEntitiesFactory);
        }
    }
    
  3.   

    注意:验证将运行两次

答案 1 :(得分:2)

作为替代解决方法,这里有一个完全基于this示例的验证方面(稍作修改)。不要忘记添加@EnableAspectJAutoProxy来激活方面并将其放入扫描Spring配置的包中。

@Aspect
@Component
public class RestRepositoryValidationAspect {

    @Autowired
    private Validator validator;

    @Pointcut("@annotation(org.springframework.data.rest.core.annotation.HandleBeforeCreate)")
    private void beforeCreateInvocation() {
    }

    @Pointcut("@annotation(org.springframework.data.rest.core.annotation.HandleBeforeSave)")
    private void beforeSaveInvocation() {
    }


    @Around("beforeCreateInvocation() || beforeSaveInvocation()")
    public Object validateBeforeRepostioryEventHandler(ProceedingJoinPoint joinPoint) throws Throwable {

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Annotation[][] argAnnotations = method.getParameterAnnotations();
        String[] argNames = methodSignature.getParameterNames();
        Object[] args = joinPoint.getArgs();

        for (int i = 0; i < args.length; i++) {
          if (hasValidAnnotations(argAnnotations[i])) {
            validateArg(args[i], argNames[i]);
          }
        }

        return joinPoint.proceed(args);

    }

    private boolean hasValidAnnotations(Annotation[] annotations) {
        if (annotations.length < 1) {
            return false;
        }

        for (Annotation annotation : annotations) {
            if (Valid.class.isInstance(annotation)) {
                return true;
            }
        }
        return false;
    }

    private void validateArg(Object arg, String argName) {
        BindingResult result = getBindingResult(arg, argName);
        validator.validate(arg, result);
        if (result.hasErrors()) {
            throw new RepositoryConstraintViolationException(result);
        }
    }

    private BindingResult getBindingResult(Object target, String targetName) {
        return new BeanPropertyBindingResult(target, targetName);
    }

}

需要验证的存储库事件处理程序参数必须标有@Valid注释,例如

@HandleBeforeSave
public void handleSave(@Valid MyEntity myEntity) {
    ...
}