切换至mockito-inline导致logback-classic抛出空指针异常求助
问题原因及修复方案
核心原因
Mockito-inline 4.11.0通过字节码生成创建的Mock异常实例,没有初始化Throwable类中的suppressed数组(JVM默认会将该数组初始化为空数组,但Mockito-inline的mock逻辑跳过了这一步)。而Logback 1.2.11的ThrowableProxy构造方法中直接访问这个数组的length属性,未做null校验,因此抛出NPE。
可行修复方案
- 升级Logback版本(最优解):Logback在1.2.12版本中修复了这个NPE问题,直接将
logback-classic和logback-core升级至1.2.12或更高版本,无需修改业务代码,既能保留堆栈信息,又能正常使用Mockito-inline的特性。 - 包装Mock异常(临时兼容方案):如果暂时无法升级Logback,在日志打印前把mock的异常包装成普通RuntimeException,确保
suppressed数组正常初始化,示例代码:
catch (Throwable oe) { // 用普通异常包装mock异常,保留原信息和堆栈 Throwable safeThrowable = new RuntimeException(oe.getMessage(), oe); LOG.warn( "{} while registering RIC {}, will retry once: {}", oe.getClass().getSimpleName(), ric, safeThrowable.getMessage(), safeThrowable); }
- 切换Mockito Mock实现(妥协方案):如果不需要Mockito-inline的特性(比如mock final类、静态方法),可以改回传统的CGLIB代理。在测试类上添加注解:
@MockSettings(mockMaker = MockMakerType.CGLIB)
或者在src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker文件中写入:
mock-maker-class=org.mockito.internal.creation.cglib.CglibMockMaker
此方案会放弃inline mock的能力,但能避免NPE问题。
为什么之前的参数调整无效
不管是直接传oe还是重复传oe,只要Logback需要处理这个mock的Throwable实例,就会触发ThrowableProxy的构造逻辑,而mock异常的suppressed数组为null,必然抛出NPE;仅传oe.toString()是因为没有让Logback处理Throwable实例,所以不会触发异常,但丢失了堆栈信息。
内容的提问来源于stack exchange,提问作者dlipofsky
相关产品推荐
相关产品推荐

