Kotlin反射创建@Serializable类实例遇序列化构造标记问题求解
带@Serializable注解类的反射主构造器实例化解决方案
当Kotlin类添加@Serializable注解后,序列化编译器插件会自动生成一个带有SerializationConstructorMarker参数的合成构造器,你当前代码中constructors.first()拿到的正是这个合成构造器,而非你定义的主构造器,这就是报错的原因。以下两种方案可以解决问题:
方案1:直接获取用户定义的主构造器
利用Kotlin反射的primaryConstructor属性直接获取类的主构造器,这是最可靠的方式:
internal fun <T : ParentThingy> KClass<in T>.random(): T { val primaryConstructor = primaryConstructor ?: error("Class ${this.simpleName} has no primary constructor") val args = primaryConstructor.parameters.associateWith { param -> when (param.type) { Int::class.starProjectedType -> gen.primitive().int() // 保留其他类型的处理逻辑 else -> error("$param not supported, it's type ${param.type}") } } @Suppress("UNCHECKED_CAST") return primaryConstructor.callBy(args) as T }
方案2:兼容处理合成构造器的标记参数
如果必须使用当前获取到的构造器(比如类没有显式主构造器),可以为SerializationConstructorMarker类型的参数传入null——这个标记是序列化框架内部使用的,实例化时传null不影响类的正常功能:
internal fun <T : ParentThingy> KClass<in T>.random(): T { val createViaConstructor = constructors.first() val args = createViaConstructor.parameters.associateWith { param -> when { param.type == Int::class.starProjectedType -> gen.primitive().int() // 匹配序列化标记参数,传入null param.name == "serializationConstructorMarker" -> null // 保留其他类型的处理逻辑 else -> error("$param not supported, it's type ${param.type}") } } @Suppress("UNCHECKED_CAST") return createViaConstructor.callBy(args) as T }
额外提示
primaryConstructor是Kotlin反射专门提供的获取主构造器的入口,比遍历构造器列表更精准,能避开注解生成的合成构造器。- 不建议直接依赖
SerializationConstructorMarker的类引用(避免序列化库版本更新导致的兼容性问题),通过参数名称判断是更稳妥的方式。
内容的提问来源于stack exchange,提问作者Alexander Vasiljev
相关产品推荐
相关产品推荐

