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

如何将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 17:08:12