JDK17中Spy ByteArrayOutputStream致对象上下文丢失引发空指针问题
问题:JDK11升级至17+Mockito版本升级后,Spy ByteArrayOutputStream触发空指针异常
问题背景
我们将JDK从11升级到17,同时把Mockito从3.3.3版本升级至4.11.0后,原有正常运行的测试用例失效。该测试通过Spy ByteArrayOutputStream 对象来验证其未被关闭,执行时触发空指针异常。
测试代码
@Test void encryptionDoesNotCloseOutputStream() throws Throwable { byte[] key = new byte[32]; RANDOM.nextBytes(key); byte[] data = new byte[101]; RANDOM.nextBytes(data); ByteArrayInputStream in = spy(new ByteArrayInputStream(data)); ByteArrayOutputStream out = spy(new ByteArrayOutputStream()); ... // Write the IV at the beginning of the file (first 12 Bytes) out.write(buffers.iv); ... verify(in, never()).close(); verify(out, never()).close(); }
报错信息
[ERROR] Errors:
[ERROR] CryptoUtilsTest.encryptionDoesNotCloseOutputStream:47 » NullPointer Cannot read the array length because "this.buf" is null
已尝试的排查动作
- 替换Mockito依赖为
mockito-inline,问题未解决 - 单独升级JDK至17不改动Mockito时,问题依然出现;暂未验证仅升级Mockito在JDK11环境下是否触发该问题
解决方案
方案1:自定义跟踪类替代Spy
避免直接Spy ByteArrayOutputStream,改用自定义子类跟踪关闭状态:
class TrackedByteArrayOutputStream extends ByteArrayOutputStream { private boolean closed = false; @Override public void close() throws IOException { closed = true; super.close(); } public boolean isClosed() { return closed; } }
测试代码调整为:
@Test void encryptionDoesNotCloseOutputStream() throws Throwable { // ...其他初始化逻辑 TrackedByteArrayOutputStream out = new TrackedByteArrayOutputStream(); // ...执行测试逻辑 // 验证未关闭 assertFalse(out.isClosed()); verify(in, never()).close(); }
方案2:使用Mockito委托模式替代Spy
如果依赖Mockito的验证逻辑,可以通过delegatesTo委托实际实现,避免Spy具体类:
@Test void encryptionDoesNotCloseOutputStream() throws Throwable { // ...其他初始化逻辑 ByteArrayOutputStream delegateOut = new ByteArrayOutputStream(); OutputStream out = mock(OutputStream.class, AdditionalAnswers.delegatesTo(delegateOut)); // ...执行测试逻辑,out的方法调用会委托给delegateOut verify(in, never()).close(); verify(out, never()).close(); }
原因分析
JDK17对ByteArrayOutputStream的内部实现(如buf字段的访问逻辑、生命周期管理)做了调整,Mockito的Spy机制在代理该类时,无法正确维护内部字段的状态,导致后续调用write等方法时触发空指针异常。单独升级JDK17就出现问题,说明核心诱因是JDK版本升级带来的类内部变化,Mockito的版本升级进一步叠加了该问题。
内容的提问来源于stack exchange,提问作者Lars van roy
相关产品推荐
相关产品推荐

