首页 > 解决方案 > 抛出自定义异常时如何动态确定方法签名?

问题描述

我遵循的标准要求我记录引发异常的 class#method,以便从我们的 UI 中轻松调试。在不提取日志的情况下,我知道是什么方法引发了异常,并且(通常)可以轻松找到根本原因。

但是,我想要一种确定方法签名的动态方式,因为我目前在抛出异常的任何地方都对其进行硬编码。有没有更好的办法。

 @Service
 public class UserService {

     @Autowired
     private UserRepository userRepository;

     public User findUser(Long id){

          if(id == null || id < 1){
               throw new BadRequestException("UserService#findUser", String.format(
                                             "Invalid Id: %d", id));
          }

          User user = userRepository.findOne(id);

          if(user == null){
               throw new DataNotFoundException("UserService#findUser", String.format(
                                               "Can't Find User for Id: %d", id));
          }
          return user;
     }
 }

--

目标是我可以创建任何自定义异常,并且在该构造函数中,我可以通过创建异常的位置推断方法签名。

 public BadRequestException(String issue){
      super(String.format("%s | Bad Request | %s", <<signature>>, issue);
 }

--

 UserService class --> findUser method --> BadRequest("UserService#findUser")
 UserService class --> createUser method --> BadRequest("UserService#createUser")

标签: javareflectionexception-handling

解决方案


您可以引入一个辅助方法,从当前线程中检索方法和类名:

private static MethodAndClassName retrieveMethodAndClassName() {
       StackTraceElement[] allStackTraces = Thread.currentThread().getStackTrace();
       StackTraceElement currentMethod = allStackTraces[2]; 
       return new MethodAndClassName(currentMethod.getMethodName(), currentMethod.getClassName());      
}

请注意,方法调用是堆叠的。我得到倒数第三个嵌套调用 ( allStackTraces[2]),因为最后一个调用 ( allStackTraces[0]) 是Thread.getStackTrace(),前一个调用 ( allStackTraces[1]) 是retrieveMethodAndClassName(),前一个前调用 ( allStackTraces[2]) 是您要查找的:调用的方法retrieveMethodAndClassName()

MethodAndClassName是一个自定义类,它定义了跟踪所需的信息:

public class MethodAndClassName {

    private String method;
    private String clazz;

    public MethodAndClassName(String method, String clazz) {
        this.method = method;
        this.clazz = clazz;
    }

    public String getMethodName() {
        return method;
    }

    public String getClassName() {
        return clazz;
    }
}

并在您的客户端代码中使用它,例如:

 public User findUser(Long id){

      if(id == null || id < 1){             
           throw new BadRequestException(ReflectionHelper.retrieveMethodAndClassName(), String.format(
                                         "Invalid Id: %d", id));
      }

      User user = userRepository.findOne(id);

      if(user == null){
           throw new DataNotFoundException(ReflectionHelper.retrieveMethodAndClassName(), String.format(
                                           "Can't Find User for Id: %d", id));
      }
      return user;
 }

推荐阅读