使用Mockito.mock结合Json.toJson时出现无限递归(StackOverflowError)问题
解决Mockito Mock对象JSON序列化时的无限递归问题
我之前碰到过完全一样的问题!这种情况的根源在于Mockito生成的Mock对象是动态代理子类,它内部包含了Mockito的代理逻辑(比如InvocationHandler相关的引用),而JSON序列化库在遍历对象字段时,会把这些内部的代理字段也纳入序列化范围,这些内部类之间往往存在循环引用,最终触发栈溢出错误。而直接new Details()创建的是原始类实例,没有这些额外的代理结构,所以不会出现问题。
下面是几个可行的解决方案:
1. 使用Spy代替Mock(适合无需完全Mock的场景)
如果你的测试不需要完全Mock Details类的所有方法,只是需要Mock部分逻辑,可以用Mockito.spy()包装一个真实的Details实例:
details = Mockito.spy(new Details()); // 基于真实对象创建Spy代理
Spy对象会复用真实实例的属性,序列化时只会处理Details类本身的字段,不会包含Mockito的代理结构,从根源上避免循环引用。
2. 配置JSON序列化库忽略代理类的额外字段
如果必须使用Mock对象,可以配置你的JSON序列化库(不管是Jackson、Gson还是其他),只序列化Details类本身声明的字段,忽略动态代理类的额外字段。
以Jackson为例,可通过以下方式配置:
ObjectMapper mapper = new ObjectMapper(); // 只序列化目标类及其父类的声明字段,忽略代理子类的额外字段 mapper.configure(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, true); // 或者用Mixin标记忽略Mockito内部类型的字段 mapper.addMixIn(InvocationHandler.class, IgnoreMockitoFieldsMixin.class); // 定义Mixin类 abstract class IgnoreMockitoFieldsMixin { @JsonIgnore abstract Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
如果是Gson,可自定义TypeAdapter手动控制序列化字段:
Gson gson = new GsonBuilder() .registerTypeAdapter(Details.class, new TypeAdapter<Details>() { @Override public void write(JsonWriter out, Details value) throws IOException { out.beginObject(); // 手动序列化Details的每个业务字段 out.name("id").value(value.getId()); out.name("name").value(value.getName()); // ... 其他业务字段 out.endObject(); } @Override public Details read(JsonReader in) throws IOException { // 按需实现反序列化逻辑 return null; } }) .create();
3. Mock序列化相关的Getter方法(适合字段较少的场景)
如果你的JSON序列化依赖对象的Getter方法,可以直接Mock所有Getter返回预期值,这样序列化时只会获取到你指定的字段值,不会触发代理内部的循环引用:
// Mock所有业务字段的Getter when(details.getId()).thenReturn(1001); when(details.getName()).thenReturn("testDetail"); // ... 其他字段的Getter
内容的提问来源于stack exchange,提问作者innek
相关产品推荐
相关产品推荐

