如何在Kotlinx Serialization泛型数据类中使用@JsonNames解析多JSON字段名?
在Kotlinx Serialization泛型数据类中使用@JsonNames注解
结论
可以在泛型数据类中使用@JsonNames注解,你遇到的编译错误是kotlinx.serialization编译器插件的已知bug,通过升级依赖版本即可解决。
问题复现
普通数据类中正常使用@JsonNames的示例
@OptIn(ExperimentalSerializationApi::class) @Serializable data class Project(@JsonNames("title") val name: String) fun main() { val project = Json.decodeFromString<Project>("""{"name":"kotlinx.serialization"}""") println(project) val oldProject = Json.decodeFromString<Project>("""{"title":"kotlinx.coroutines"}""") println(oldProject) }
输出:
Project(name=kotlinx.serialization) Project(name=kotlinx.coroutines)
泛型数据类中的错误场景
泛型数据类代码:
@OptIn(ExperimentalSerializationApi::class) @Serializable data class GoogleBaseApiResponse<T> ( var status : String = "", var error_message : String? = null, @JsonNames("results", "predictions", "result") var responseData : T? = null )
编译时抛出错误:
Exception in thread "main" java.lang.IllegalStateException: Problem with constructing exception message at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializerClassLowering.lower(SerializationLoweringExtension.kt:184) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitClass(SerializationLoweringExtension.kt:46) at org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid$DefaultImpls.visitClass(IrElementVisitorVoid.kt:111) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitClass(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitClass(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlin.ir.declarations.IrClass.accept(IrClass.kt:64) at org.jetbrains.kotlin.ir.declarations.IrClass.acceptChildren(IrClass.kt:68) at org.jetbrains.kotlin.ir.visitors.IrVisitorsKt.acceptChildrenVoid(IrVisitors.kt:15) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitClass(SerializationLoweringExtension.kt:47) at org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid$DefaultImpls.visitClass(IrElementVisitorVoid.kt:111) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitClass(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitClass(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlin.ir.declarations.IrClass.accept(IrClass.kt:64) at org.jetbrains.kotlin.ir.declarations.IrFile.acceptChildren(IrFile.kt:36) at org.jetbrains.kotlin.ir.visitors.IrVisitorsKt.acceptChildrenVoid(IrVisitors.kt:15) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitElement(SerializationLoweringExtension.kt:42) at org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid$DefaultImpls.visitPackageFragment(IrElementVisitorVoid.kt:190) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitPackageFragment(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid$DefaultImpls.visitFile(IrElementVisitorVoid.kt:200) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitFile(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid$DefaultImpls.visitFile(IrElementVisitorVoid.kt:198) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitFile(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt$runOnFileInOrder$1.visitFile(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlin.ir.declarations.IrFile.accept(IrFile.kt:30) at org.jetbrains.kotlin.ir.visitors.IrVisitorsKt.acceptVoid(IrVisitors.kt:11) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtensionKt.runOnFileInOrder(SerializationLoweringExtension.kt:40) at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationLoweringExtension.generate(SerializationLoweringExtension.kt:149) at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.convertToIr$lambda$1(JvmIrCodegenFactory.kt:186) at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment(Psi2IrTranslator.kt:104) at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.convertToIr(JvmIrCodegenFactory.kt:218) at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.convertToIr(JvmIrCodegenFactory.kt:55) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.convertToIr(KotlinToJVMBytecodeCompiler.kt:225) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:102) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:47) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:167) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:53) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:101) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:47) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:79) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:43) at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit(CLITool.kt:179) at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit$default(CLITool.kt:177) at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMain(CLITool.kt:166) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler$Companion.main(K2JVMCompiler.kt:250) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.main(K2JVMCompiler.kt)
解决方案
- 升级kotlinx.serialization版本:该bug在
1.5.0及以上版本中已被修复,建议同步升级依赖和插件版本。示例Gradle配置:implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") kotlin("plugin.serialization") version "1.9.0" - 临时替代方案(无法升级时):可自定义序列化器处理多字段名,或结合
@SerialName与JsonBuilder.ignoreUnknownKeys实现解析,但这种方式繁琐,优先推荐版本升级。
修复后验证示例
升级版本后,泛型数据类可正常编译并解析不同字段名的JSON:
@OptIn(ExperimentalSerializationApi::class) @Serializable data class GoogleBaseApiResponse<T> ( var status : String = "", var error_message : String? = null, @JsonNames("results", "predictions", "result") var responseData : T? = null ) fun main() { val json1 = """{"status":"OK","results":[{"name":"test"}]}""" val response1 = Json.decodeFromString<GoogleBaseApiResponse<List<Map<String, String>>>>(json1) println(response1) val json2 = """{"status":"OK","predictions":[{"description":"test"}]}""" val response2 = Json.decodeFromString<GoogleBaseApiResponse<List<Map<String, String>>>>(json2) println(response2) val json3 = """{"status":"OK","result":{"id":1}}""" val response3 = Json.decodeFromString<GoogleBaseApiResponse<Map<String, Int>>>(json3) println(response3) }
内容的提问来源于stack exchange,提问作者Suman Radhakrishnan
相关产品推荐
相关产品推荐

