使用ReactiveMongoRepository保存含泛型文档遇StackOverflowError求助
解决保存含泛型值的MongoDB文档时的StackOverflowError问题
为啥会出这个问题?
这个栈溢出本质是类型解析的循环依赖在搞事情:
- 你的
MyDocument里有个errors字段是List<SomeError>,而你实例化的ValidationError泛型参数刚好是MyDocument - Spring Data的
TypeDiscoverer在解析MyDocument的类型信息时,会一层层递归解析里面的字段类型,解析到ValidationError<MyDocument>时,又得回头解析MyDocument,这么来回递归下去,栈直接就爆了。
怎么解决?
给你几个可行的方案,按实用性排序:
1. 打破泛型循环引用(最推荐)
直接调整ValidationError的设计,别让它的泛型参数和包含它的MyDocument形成闭环。比如把KClass<T>换成字符串类型来存储对象类型:
data class ValidationError(val objectTypeName: String, val objectId: String) : SomeError
用的时候这么写:
myDocumentRepository.save(MyDocument( errors = listOf( ValidationError(objectTypeName = MyDocument::class.qualifiedName!!, objectId = "somedoc") ) ))
既保留了类型标识,又彻底切断了循环依赖,从根源上解决问题。
2. 自定义MongoDB类型转换器
如果一定要保留KClass<T>字段,可以给KClass写个类型转换器,让Spring Data直接把它转成字符串存,不用递归解析泛型:
先写两个转换器:
import org.springframework.core.convert.converter.Converter import org.springframework.data.convert.ReadingConverter import org.springframework.data.convert.WritingConverter @WritingConverter class KClassToStringConverter : Converter<KClass<*>, String> { override fun convert(source: KClass<*>): String = source.qualifiedName!! } @ReadingConverter class StringToKClassConverter : Converter<String, KClass<*>> { override fun convert(source: String): KClass<*> = Class.forName(source).kotlin }
然后在MongoDB配置类里注册:
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.data.mongodb.core.convert.MongoCustomConversions @Configuration class MongoConfig { @Bean fun customConversions(): MongoCustomConversions { return MongoCustomConversions(listOf( KClassToStringConverter(), StringToKClassConverter() )) } }
这样Spring Data处理KClass字段时,直接转成字符串存,不会再递归解析泛型参数,循环递归的问题就没了。
3. 用@Transient忽略字段(临时救急)
如果objectType字段不需要存到MongoDB里,可以加个@Transient注解让Spring Data忽略它:
data class ValidationError<T: Any>( @Transient val objectType: KClass<T>, val objectId: String ) : SomeError
但这个方案会导致objectType不会被持久化,只适合临时调试或者确实不需要保存这个字段的场景。
验证一下
选好方案后,跑一下保存操作,看看栈溢出是不是消失了,同时检查MongoDB里的文档结构是不是符合你的预期就行。
内容的提问来源于stack exchange,提问作者youngDev
相关产品推荐
相关产品推荐

