You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Mock对象更新MongoDB中List字段时出现StackOverflowError

嘿,这个问题我之前在维护老项目时刚好遇到过类似的情况,咱们来拆解一下背后的原因和可行的解决办法:

问题根源分析

你遇到的StackOverflowError本质是Spring Data MongoDB 1.9.1版本对动态代理对象(比如Mockito生成的Mock实例)的序列化逻辑不完善导致的无限递归。

Mockito生成的Mock对象是基于Java动态代理创建的子类,当Spring Data MongoDB的转换器尝试将这些Mock对象转换为MongoDB能识别的文档格式时,会通过反射不断去遍历对象的类结构、父类信息、代理相关的属性,而这个过程在旧版本的转换器里没有做边界处理,最终触发了栈溢出。

反观真实的Foo实例,它是普通的POJO类,转换器可以正常遍历属性完成序列化,所以不会出问题。

可行的解决方案

1. 测试场景替换为真实Foo实例(最推荐)

测试DAO的更新逻辑时,没必要用Mock对象来模拟实体——毕竟你要验证的是DAO能不能正确把数据写入MongoDB,用真实的Foo实例才更贴合实际场景。比如把测试代码改成:

@Test 
public void givenPersistedBar_whenUpdateFoos_thenUpdatesThem() { 
    // 创建真实的Foo实例,哪怕只填充必要属性
    List<Foo> foos = Collections.nCopies(10, new Foo()); 
    barDao.updateFoos(ID, foos); 
}

这个方法最简单,也符合单元测试的设计初衷,完全可以规避代理对象的序列化问题。

2. 自定义Mongo序列化转换器(特殊场景适用)

如果因为某些特殊需求必须在测试中使用Mock对象,可以自定义一个Converter来处理Foo类型的转换,手动拦截Mock对象并提取需要持久化的属性:

public class FooMockConverter implements Converter<Foo, DBObject> {
    @Override
    public DBObject convert(Foo source) {
        DBObject dbObject = new BasicDBObject();
        
        // 判断是否是Mockito代理对象
        if (source instanceof MockitoProxy) {
            // 用反射提取内部属性(需要依赖Mockito的Whitebox工具)
            dbObject.put("id", Whitebox.getInternalState(source, "id"));
            // 按需添加其他需要持久化的属性
        } else {
            // 正常处理真实Foo实例
            dbObject.put("id", source.getId());
            // ...其他属性映射
        }
        
        return dbObject;
    }
}

然后把这个转换器注册到你的MongoTemplate中:

// 假设你已经有mongoDbFactory和mappingContext实例
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory, mappingContext);
converter.setCustomConversions(new CustomConversions(Arrays.asList(new FooMockConverter())));
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter);

不过这个方法比较繁琐,而且测试场景用Mock对象更新数据库本身就不太合理,只建议在极端情况下使用。

3. 升级Spring Data MongoDB版本(长期解决方案)

你当前使用的spring-data-mongodb:1.9.1是2016年的旧版本,后续的1.10.x及更高版本(比如2.x系列)对动态代理对象的序列化逻辑做了优化,能避免这种无限递归的问题。

不过要注意版本兼容性:

  • Spring 4.5.2可以兼容spring-data-mongodb:1.10.x(最高到1.10.19.RELEASE)
  • 如果要升级到2.x系列,需要把Spring版本升级到5.x及以上

升级依赖能从根源上解决这类老版本的兼容性问题,同时还能获得更多新特性和Bug修复。


内容的提问来源于stack exchange,提问作者Jeep87c

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:56:02