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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:40:29