java - 将 JSR 303 Java Bean Validation 异常转换为自定义异常

标签 java aspectj bean-validation custom-exceptions

我已经在我的 Web 应用程序的服务层中实现了 JSR303 JavaBean 验证(根据 this article)。现在我想将所有验证异常(例如 javax.validation.ConstraintViolationException)转换为我的自定义异常。

我创建了一个切面,只要在服务层中抛出异常就会调用它:

@Aspect
public class ExceptionConversionAspect {

    @AfterThrowing(pointcut="execution(* com.myexample.service.*.*(..))", throwing="e")
    public void convertServiceException(Exception e) {

        if (e instanceof ConstraintViolationException) {
             // this is my custom exception
            throw new InvalidServiceInputException("The service inputs failed validation", e);
        }
    }
}

但是当我的服务使用 ConstraintViolationException 验证失败时,不会触发我的异常转换方面。我怀疑这是因为验证异常本身是由 Aspect 触发的:
@Aspect
public class ValidateAspect {

    @Autowired
    private Validator validator;

    // Match any public methods in a class annotated with @AutoValidating
    @Around("execution(public * *(..)) && @within(com.myexample.validator.annotation.Validate)")
    public Object validateMethodInvocation(ProceedingJoinPoint pjp) throws Throwable {

    // some code here
    ....
}

如何以正确的顺序链接我的方面?先ValidateAspect,然后是ExceptionConversionAspect?

最佳答案

Raul Bertone 几乎是对的,但并不完全正确。逻辑必须颠倒,ExceptionConversionAspect必须是第一个优先。

Java SE 的完整工作示例(我只是模拟 Java EE 异常):

助手类:

package javax.validation;

public class ConstraintViolationException extends RuntimeException {
    private static final long serialVersionUID = -8041265519275356912L;

    public ConstraintViolationException(String arg0) {
        super(arg0);
    }
}

package com.myexample.validator.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {}

package com.myexample.service;

public class InvalidServiceInputException extends RuntimeException {
    public InvalidServiceInputException(String arg0, Throwable arg1) {
        super(arg0, arg1);
    }
}

示例驱动程序应用程序:

驱动程序应用由 @Validate 注释。并模拟服务 - 请参阅包名称。它循环执行 10 个方法调用,捕获异常并将它们打印到标准输出,以表明它们确实按照需要进行了转换。

package com.myexample.service;

import com.myexample.validator.annotation.Validate;

@Validate
public class Application {
    public void doSomething(int i) {
        System.out.printf("Doing something #%d%n", i);
    }

    public static void main(String[] args) {
        Application application = new Application();
        for (int i = 0; i < 10; i++) {
            try {
                application.doSomething(i + 1);
            }
            catch (Exception e) {
                System.out.println(e);
                System.out.println("  cause: " + e.getCause());
            }
        }
    }
}

方面:

验证方面随机抛出 ConstraintViolationException用于演示目的。

package com.myexample.aspect;

import java.util.Random;
import javax.validation.ConstraintViolationException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class ValidateAspect {
    private static final Random RANDOM = new Random();

    @Around("execution(public !static * *(..)) && @within(com.myexample.validator.annotation.Validate)")
    public Object validateMethodInvocation(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        Object result = thisJoinPoint.proceed();
        if (RANDOM.nextBoolean())
            throw new ConstraintViolationException("uh-oh");
        return result;
    }
}

异常转换方面有一个额外的 @DeclarePrecedence现在注释。

package com.myexample.aspect;

import javax.validation.ConstraintViolationException;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclarePrecedence;
import com.myexample.service.InvalidServiceInputException;

@Aspect
@DeclarePrecedence("ExceptionConversionAspect, *")
public class ExceptionConversionAspect {
    @AfterThrowing(pointcut = "execution(* com.myexample.service..*(..))", throwing = "e")
    public void convertServiceException(Exception e) {
        if (e instanceof ConstraintViolationException) {
            throw new InvalidServiceInputException("The service inputs failed validation", e);
        }
    }
}

控制台输出:

Doing something #1
Doing something #2
com.myexample.service.InvalidServiceInputException: The service inputs failed validation
  cause: javax.validation.ConstraintViolationException: uh-oh
Doing something #3
com.myexample.service.InvalidServiceInputException: The service inputs failed validation
  cause: javax.validation.ConstraintViolationException: uh-oh
Doing something #4
Doing something #5
Doing something #6
com.myexample.service.InvalidServiceInputException: The service inputs failed validation
  cause: javax.validation.ConstraintViolationException: uh-oh
Doing something #7
Doing something #8
Doing something #9
Doing something #10

关于java - 将 JSR 303 Java Bean Validation 异常转换为自定义异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10197678/

相关文章:

java - 类、方法、实例创建和 Main 相当于 Python 中的 Java

java - Firebase 电话身份验证替换了 userimage 和 Displayname

java - 如何将文件从表单复制到我的根 Web 应用程序 Java EE

java - 如何将数组元素从子类传递到主类

Java自定义注解在调用被注解的方法之前调用其他一些方法

java - Spring 3.2.12 正在寻找 Spring 4.0 类吗?

java - 跨字段 Java Bean 验证不验证来自 JSF 的字段

java - 参数化注释 AspectJ 的表达式

jsf - 使用 JSF bean 验证在一个字段上使用多个验证器

Kotlin 和 javax.validation.constraints.NotNull