反射抛出自定义异常问题

反射抛出自定义异常问题

作者: MysticalYcc

转载请注明出处:反射抛出自定义异常问题

问题描述

  1. 反射调用方法时,方法内部抛出了自定义异常,但是无法在反射调用点捕获到抛出的自定义异常。
  2. 反射调用方法时,方法再次调用反射抛出自定义异常,导致最底层异常消失。

调用逻辑代码

  1. @Slf4j
  2. public abstract class AbstractService implements BaseService<BaseDto> {
  3. protected String strategy = "ABS_BUS";
  4. /**
  5. * 注册表
  6. */
  7. protected static Map<String, BaseService<BaseDto>> strategyMap = new HashMap<>();
  8. /**
  9. * 强制要求实现类构造方法调用 super(strategy),注册实现类的自定义类型;
  10. * 如果实现类不覆盖属性 strategy {@link AbstractService#strategy},则注册为ABS_BUS方案。
  11. *
  12. * @param strategy
  13. */
  14. public AbstractService(String strategy) {
  15. this.addBean(strategy);
  16. }
  17. @Override
  18. public String dispose(BaseDto data) {
  19. String operation = data.getOperation();
  20. Object invoke = getObject(data, operation);
  21. return (String) invoke;
  22. }
  23. public String create(BaseDto baseDto) {
  24. String event = baseDto.getEvent();
  25. String data = baseDto.getData();
  26. //这里获取需要执行的创建事件。
  27. Object object = getObject(data, event);
  28. return (String) object;
  29. }
  30. protected <T> Object getObject(T data, String operation) {
  31. Object invoke;
  32. if (StringUtils.isEmpty(operation)) {
  33. throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), "无法找到对应的执行事件,请检查请求路劲和请求体参数");
  34. }
  35. try {
  36. Method method = this.getClass().getMethod(operation, data.getClass());
  37. invoke = method.invoke(this, data);
  38. System.out.println(invoke);
  39. } catch (ReflectiveOperationException e) {
  40. String format = String.format("未设置此方法:%s,请检查是否输错,或者联系管理员设置%s方法", operation, operation);
  41. log.error(format);
  42. e.printStackTrace();
  43. throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), format);
  44. }
  45. return invoke;
  46. }
  47. protected void addBean(String strategy) {
  48. strategyMap.putIfAbsent(strategy, this);
  49. }
  50. public static Optional<BaseService<BaseDto>> getOperation(String strategy) {
  51. return Optional.ofNullable(strategyMap.get(strategy));
  52. }
  53. }

执行方式如图:

反射抛出自定义异常问题

执行的gif:

反射抛出自定义异常问题

过程描述:

首先第一调用getObject`方法,执行了invoke方法,invoke方法执行了create方法,create方法调用了`getObject方法,这个时候判断为null,抛出自定义异常;

这个时候回到第一次调用invoke的地方异常了,这个时候按说不会被catch住,因为抛出的是自定义异常。结果catch住的是ReflectiveOperationException

猜想

invoke方法将抛出固定异常,其他的异常被处理;

参见JDK的API文档

可以发现,JDK的API文档中,关于method.invoke的注释说明

公共 对象 invoke(Object obj,
Object ... args)
抛出IllegalAccessException
IllegalArgumentException
InvocationTargetException
在Method 具有指定参数的指定对象上调用此对象表示的基础方法。各个参数将自动解包以匹配原始形式参数,并且原始参数和引用参数都必须根据需要进行方法调用转换。
如果基础方法是静态的,则obj 忽略指定的参数。它可以为空。

如果基础方法所需的形式参数的数量为0,则提供的args数组的长度可以为0或为null。

如果基础方法是实例方法,则使用《 Java语言规范,第二版》第15.12.4.4节中所述的动态方法查找来调用该方法。特别是,将发生基于目标对象的运行时类型的覆盖。

如果基础方法是静态的,则声明该方法的类将被初始化(如果尚未初始化)。

如果该方法正常完成,则将其返回的值返回给invoke的调用者;否则,返回false。如果该值具有原始类型,则首先将其适当包装在一个对象中。但是,如果该值具有原始类型的数组的类型,则该数组的元素不会包装在对象中;相反,换句话说,将返回原始类型的数组。如果基础方法的返回类型为void,则调用返回null。

参数:
obj -从其调用基础方法的对象
args -用于方法调用的参数
返回值:
obj用参数 分派此对象表示的方法的结果args
抛出:
IllegalAccessException-如果此Method对象正在强制执行Java语言访问控制,并且无法访问基础方法。
`IllegalArgumentException-如果该方法是实例方法,并且指定的对象参数不是声明基础方法(或其子类或实现者)的类或接口的实例;如果实际参数和形式参数的数量不同;如果原始参数的展开转换失败;或者在可能的解包之后,无法通过方法调用转换将参数值转换为相应的形式参数类型。
InvocationTargetException -如果基础方法引发异常。这里会处理基础方法引发的异常,猜想是这里处理了我们抛出的异常
NullPointerException-如果指定的对象为null,并且该方法是实例方法。
ExceptionInInitializerError-如果此方法引发的初始化失败。

InvocationTargetException

java.lang.reflect

类InvocationTargetException

目标发生的异常被封印在InvocationTargetException中, 我们从中获取即可。

修改代码

将反射的异常抛出,在最外层catch InvocationTargetException`,通过`getCause获取内部抛出的自定义异常。

  1. @Slf4j
  2. public abstract class AbstractService implements BaseService<BaseDto> {
  3. protected String strategy = "ABS_BUS";
  4. /**
  5. * 注册表
  6. */
  7. protected static Map<String, BaseService<BaseDto>> strategyMap = new HashMap<>();
  8. /**
  9. * 强制要求实现类构造方法调用 super(strategy),注册实现类的自定义类型;
  10. * 如果实现类不覆盖属性 strategy {@link AbstractService#strategy},则注册为ABS_BUS方案。
  11. *
  12. * @param strategy
  13. */
  14. public AbstractService(String strategy) {
  15. this.addBean(strategy);
  16. }
  17. @Override
  18. public String dispose(BaseDto data) {
  19. String operation = data.getOperation();
  20. Object invoke = null;
  21. try {
  22. invoke = getObject(data, operation);
  23. } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException e) {
  24. e.printStackTrace();
  25. String format = String.format("未设置此方法:%s,请检查是否输错,或者联系管理员设置%s方法", operation, operation);
  26. log.error(format);
  27. e.printStackTrace();
  28. throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), format);
  29. } catch (InvocationTargetException e) {
  30. e.printStackTrace();
  31. Throwable cause = e.getCause();
  32. //获取反射调用方法抛出的自定义异常
  33. if (cause instanceof EventBaseException) {
  34. EventBaseException ex = (EventBaseException) cause;
  35. throw new EventBaseException(ex.getErrorCode(), ex.getMessage());
  36. }
  37. }
  38. return (String) invoke;
  39. }
  40. /**
  41. * 公共创建事件方法
  42. *
  43. * @param baseDto {@link BaseDto}
  44. * @return result
  45. * @throws NoSuchMethodException NoSuchMethodException {@link NoSuchMethodException}
  46. * @throws IllegalAccessException IllegalAccessException{@link IllegalAccessException}
  47. * @throws InvocationTargetException InvocationTargetException {@link InvocationTargetException}
  48. */
  49. public String create(BaseDto baseDto) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
  50. String event = baseDto.getEvent();
  51. String data = baseDto.getData();
  52. Object object = null;
  53. //获取需要执行的创建事件。
  54. object = getObject(data, event);
  55. return (String) object;
  56. }
  57. /**
  58. * 获取具体的执行方案
  59. *
  60. * @param data
  61. * @param operation 方案
  62. * @param <T>
  63. * @return
  64. * @throws NoSuchMethodException NoSuchMethodException {@link NoSuchMethodException}
  65. * @throws IllegalAccessException IllegalAccessException{@link IllegalAccessException}
  66. * @throws InvocationTargetException InvocationTargetException {@link InvocationTargetException}
  67. */
  68. protected <T> Object getObject(T data, String operation) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
  69. Object invoke;
  70. if (StringUtils.isEmpty(operation)) {
  71. throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), "无法找到对应的执行事件,请检查请求路劲和请求体参数");
  72. }
  73. Method method = this.getClass().getMethod(operation, data.getClass());
  74. method.setAccessible(true);
  75. invoke = method.invoke(this, data);
  76. System.out.println(invoke);
  77. return invoke;
  78. }
  79. /**
  80. * 将实现类注册到注册表中,如果存在则忽略,即无法覆盖已有注册类。
  81. *
  82. * @param strategy {@link AbstractService#strategy}
  83. */
  84. protected void addBean(String strategy) {
  85. strategyMap.putIfAbsent(strategy, this);
  86. }
  87. /**
  88. * 获取方案
  89. *
  90. * @param strategy {@link AbstractService#strategy}
  91. * @return 方案具体实现类 extends AbstractService {@link AbstractService}
  92. */
  93. public static Optional<BaseService<BaseDto>> getOperation(String strategy) {
  94. return Optional.ofNullable(strategyMap.get(strategy));
  95. }
  96. }

这样修改后即可。


声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
报错记录

kafka无法启动,Cannot assign requested address.

2024-5-31 17:15:01

java报错记录

求解 springboot+mysql 随机出现的异常延迟

2024-9-14 10:03:45

0 条回复 A文章作者 M管理员
欢迎您,新朋友,感谢参与互动!
    暂无讨论,说说你的看法吧