如何将JSON字段值映射到Kotlin数据类并精简输出
解决JSON到Kotlin数据类的映射与精简问题
你现在遇到的核心问题是JSON键名与Kotlin数据类属性名不匹配、嵌套结构/数组处理逻辑混乱,再加上原清理函数的错误逻辑导致无法生成期望的精简JSON。下面一步步帮你解决:
1. 修正Kotlin数据类定义
首先你的数据类存在几个关键问题:
- 属性名和JSON键的命名风格不匹配(比如
accuracyRadius对应JSON的accuracy_radius) subdivision应该是列表类型(对应JSON的subdivisions数组)- 部分字段类型不合理(比如
latitude/longitude是数字,没必要定义成String;geonameId用Long比String更贴合原始数据) - 缺少JSON键名映射的注解(这里用Jackson的
@JsonProperty处理下划线到驼峰的转换)
修正后的数据类:
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.registerKotlinModule data class LocationData( @JsonProperty("accuracy_radius") val accuracyRadius: Int = 0, @JsonProperty("time_zone") val timeZone: String = "", val latitude: Double = 0.0, val longitude: Double = 0.0, val postalCode: String = "", // 对应原JSON的postal.code val continent: Continent, val country: Country, val city: City, val subdivisions: List<Subdivision> ) data class Continent( val code: String = "", val name: String = "", // 对应原JSON的names.en @JsonProperty("geonameId") val geonameId: Long = 0 ) data class Country( @JsonProperty("isEU") val isEU: Boolean = false, val name: String = "", // 对应原JSON的names.en @JsonProperty("isoCode") val isoCode: String = "", @JsonProperty("geonameId") val geonameId: Long = 0 ) data class City( val name: String = "", // 对应原JSON的names.en @JsonProperty("geonameId") val geonameId: Long = 0 ) data class Subdivision( val name: String = "", // 对应原JSON的names.en @JsonProperty("isoCode") val isoCode: String = "", @JsonProperty("geonameId") val geonameId: Long = 0 )
2. 编写正确的JSON解析与精简逻辑
原cleanData函数因为过早return导致后续逻辑完全不执行,而且没有处理嵌套结构。我们需要手动从原JsonNode提取字段,构建数据类实例后再序列化为精简JSON:
private val objectMapper = ObjectMapper().registerKotlinModule() private fun cleanData(data: JsonNode): String { // 提取location模块的核心字段 val locationNode = data.get("location") val accuracyRadius = locationNode.get("accuracy_radius").asInt() val timeZone = locationNode.get("time_zone").asText() val latitude = locationNode.get("latitude").asDouble() val longitude = locationNode.get("longitude").asDouble() // 提取邮政编码 val postalCode = data.get("postal").get("code").asText() // 构建Continent对象(提取names.en作为name) val continentNode = data.get("continent") val continent = Continent( code = continentNode.get("code").asText(), name = continentNode.get("names").get("en").asText(), geonameId = continentNode.get("geoname_id").asLong() ) // 构建Country对象 val countryNode = data.get("country") val country = Country( isEU = countryNode.get("is_in_european_union").asBoolean(), name = countryNode.get("names").get("en").asText(), isoCode = countryNode.get("iso_code").asText(), geonameId = countryNode.get("geoname_id").asLong() ) // 构建City对象 val cityNode = data.get("city") val city = City( name = cityNode.get("names").get("en").asText(), geonameId = cityNode.get("geoname_id").asLong() ) // 处理subdivisions数组 val subdivisions = mutableListOf<Subdivision>() val subdivisionsNode = data.get("subdivisions") subdivisionsNode.forEach { subNode -> val subdivision = Subdivision( name = subNode.get("names").get("en").asText(), isoCode = subNode.get("iso_code").asText(), geonameId = subNode.get("geoname_id").asLong() ) subdivisions.add(subdivision) } // 组装最终数据类并序列化为JSON val locationData = LocationData( accuracyRadius = accuracyRadius, timeZone = timeZone, latitude = latitude, longitude = longitude, postalCode = postalCode, continent = continent, country = country, city = city, subdivisions = subdivisions ) return objectMapper.writeValueAsString(locationData) }
3. 验证输出
调用该函数后,你会得到和期望完全一致的精简JSON:
{ "accuracy_radius":10, "time_zone":"Europe/Paris", "latitude":50.3714, "longitude":3.5561, "postalCode":"59880", "continent":{ "code":"EU", "name":"Europe", "geonameId":6255148 }, "country":{ "isEU":true, "name":"France", "isoCode":"FR", "geonameId":3017382 }, "city":{ "name":"Saint-Saulve", "geonameId":2977058 }, "subdivisions":[ { "name":"Hauts-de-France", "isoCode":"HDF", "geonameId":11071624 }, { "name":"North", "isoCode":"59", "geonameId":2990129 } ] }
关键注意点
- 确保项目引入Jackson Kotlin模块依赖(比如Gradle中添加
com.fasterxml.jackson.module:jackson-module-kotlin) - 原函数中过早的
return语句是导致逻辑失效的核心原因,要避免在循环或分支中提前返回中断后续处理
内容的提问来源于stack exchange,提问作者Jmh2013
相关产品推荐
相关产品推荐

