反射抛出自定义异常问题
作者: MysticalYcc
转载请注明出处:反射抛出自定义异常问题
问题描述
- 反射调用方法时,方法内部抛出了自定义异常,但是无法在反射调用点捕获到抛出的自定义异常。
- 反射调用方法时,方法再次调用反射抛出自定义异常,导致最底层异常消失。
调用逻辑代码
@Slf4j
public abstract class AbstractService implements BaseService<BaseDto> {
protected String strategy = "ABS_BUS";
/**
* 注册表
*/
protected static Map<String, BaseService<BaseDto>> strategyMap = new HashMap<>();
/**
* 强制要求实现类构造方法调用 super(strategy),注册实现类的自定义类型;
* 如果实现类不覆盖属性 strategy {@link AbstractService#strategy},则注册为ABS_BUS方案。
*
* @param strategy
*/
public AbstractService(String strategy) {
this.addBean(strategy);
}
@Override
public String dispose(BaseDto data) {
String operation = data.getOperation();
Object invoke = getObject(data, operation);
return (String) invoke;
}
public String create(BaseDto baseDto) {
String event = baseDto.getEvent();
String data = baseDto.getData();
//这里获取需要执行的创建事件。
Object object = getObject(data, event);
return (String) object;
}
protected <T> Object getObject(T data, String operation) {
Object invoke;
if (StringUtils.isEmpty(operation)) {
throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), "无法找到对应的执行事件,请检查请求路劲和请求体参数");
}
try {
Method method = this.getClass().getMethod(operation, data.getClass());
invoke = method.invoke(this, data);
System.out.println(invoke);
} catch (ReflectiveOperationException e) {
String format = String.format("未设置此方法:%s,请检查是否输错,或者联系管理员设置%s方法", operation, operation);
log.error(format);
e.printStackTrace();
throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), format);
}
return invoke;
}
protected void addBean(String strategy) {
strategyMap.putIfAbsent(strategy, this);
}
public static Optional<BaseService<BaseDto>> getOperation(String strategy) {
return Optional.ofNullable(strategyMap.get(strategy));
}
}
执行方式如图:
执行的gif:
过程描述:
首先第一调用
方法,这个时候判断为null,抛出自定义异常;getObject
`方法,执行了invoke方法,invoke方法执行了create方法,create方法调用了
`getObject
这个时候回到第一次调用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
抛出:
-如果此Method对象正在强制执行Java语言访问控制,并且无法访问基础方法。
IllegalAccessException
`
-如果该方法是实例方法,并且指定的对象参数不是声明基础方法(或其子类或实现者)的类或接口的实例;如果实际参数和形式参数的数量不同;如果原始参数的展开转换失败;或者在可能的解包之后,无法通过方法调用转换将参数值转换为相应的形式参数类型。IllegalArgumentException
InvocationTargetException -如果基础方法引发异常。(这里会处理基础方法引发的异常,猜想是这里处理了我们抛出的异常)
-如果指定的对象为null,并且该方法是实例方法。
NullPointerException
-如果此方法引发的初始化失败。
ExceptionInInitializerError
InvocationTargetException
java.lang.reflect
类InvocationTargetException
- java.lang.Throwable
- java.lang.ReflectiveOperationException
- java.lang.reflect.InvocationTargetException
- 所有已实现的接口:
公共类InvocationTargetException 扩展了ReflectiveOperationException
`
InvocationTargetException
“是一个已检查的异常,该异常包装了被调用的方法或构造函数引发的异常。从版本1.4开始,已对该异常进行了改进以符合通用异常链机制。现在将在构建时提供并通过该[
getTargetException()
](https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/InvocationTargetException.html#getTargetException())方法访问的“目标异常” 称为原因,并且可以通过该[Throwable.getCause()
](https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getCause())方法以及上述“旧式方法”进行访问。方法细节
getTargetException
公共 Throwable getTargetException()
获取引发的目标异常。
此方法早于通用异常链接工具。[
Throwable.getCause()
](https://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getCause())现在,该方法是获取此信息的首选方法。
返回值:
引发的目标异常(此异常的原因)。
getCause
公共 Throwable getCause()
返回此异常的原因(引发的目标异常,可能是
null
)。
覆写:
getCause
在班上Throwable
返回值:
此异常的原因。
自从:
1.4
目标发生的异常被封印在
中, 我们从中获取即可。InvocationTargetException
修改代码
将反射的异常抛出,在最外层
获取内部抛出的自定义异常。catch InvocationTargetException
`,通过
`getCause
@Slf4j
public abstract class AbstractService implements BaseService<BaseDto> {
protected String strategy = "ABS_BUS";
/**
* 注册表
*/
protected static Map<String, BaseService<BaseDto>> strategyMap = new HashMap<>();
/**
* 强制要求实现类构造方法调用 super(strategy),注册实现类的自定义类型;
* 如果实现类不覆盖属性 strategy {@link AbstractService#strategy},则注册为ABS_BUS方案。
*
* @param strategy
*/
public AbstractService(String strategy) {
this.addBean(strategy);
}
@Override
public String dispose(BaseDto data) {
String operation = data.getOperation();
Object invoke = null;
try {
invoke = getObject(data, operation);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException e) {
e.printStackTrace();
String format = String.format("未设置此方法:%s,请检查是否输错,或者联系管理员设置%s方法", operation, operation);
log.error(format);
e.printStackTrace();
throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), format);
} catch (InvocationTargetException e) {
e.printStackTrace();
Throwable cause = e.getCause();
//获取反射调用方法抛出的自定义异常
if (cause instanceof EventBaseException) {
EventBaseException ex = (EventBaseException) cause;
throw new EventBaseException(ex.getErrorCode(), ex.getMessage());
}
}
return (String) invoke;
}
/**
* 公共创建事件方法
*
* @param baseDto {@link BaseDto}
* @return result
* @throws NoSuchMethodException NoSuchMethodException {@link NoSuchMethodException}
* @throws IllegalAccessException IllegalAccessException{@link IllegalAccessException}
* @throws InvocationTargetException InvocationTargetException {@link InvocationTargetException}
*/
public String create(BaseDto baseDto) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
String event = baseDto.getEvent();
String data = baseDto.getData();
Object object = null;
//获取需要执行的创建事件。
object = getObject(data, event);
return (String) object;
}
/**
* 获取具体的执行方案
*
* @param data
* @param operation 方案
* @param <T>
* @return
* @throws NoSuchMethodException NoSuchMethodException {@link NoSuchMethodException}
* @throws IllegalAccessException IllegalAccessException{@link IllegalAccessException}
* @throws InvocationTargetException InvocationTargetException {@link InvocationTargetException}
*/
protected <T> Object getObject(T data, String operation) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object invoke;
if (StringUtils.isEmpty(operation)) {
throw new EventBaseException(CommonEnum.METHOD_LOST.getResultCode(), "无法找到对应的执行事件,请检查请求路劲和请求体参数");
}
Method method = this.getClass().getMethod(operation, data.getClass());
method.setAccessible(true);
invoke = method.invoke(this, data);
System.out.println(invoke);
return invoke;
}
/**
* 将实现类注册到注册表中,如果存在则忽略,即无法覆盖已有注册类。
*
* @param strategy {@link AbstractService#strategy}
*/
protected void addBean(String strategy) {
strategyMap.putIfAbsent(strategy, this);
}
/**
* 获取方案
*
* @param strategy {@link AbstractService#strategy}
* @return 方案具体实现类 extends AbstractService {@link AbstractService}
*/
public static Optional<BaseService<BaseDto>> getOperation(String strategy) {
return Optional.ofNullable(strategyMap.get(strategy));
}
}
这样修改后即可。