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

Android开发:如何将动态结构JSON转为Kotlin Data Class?

处理动态键的JSON转Kotlin Data Class方案

问题背景

作为Android开发新手,我正在用Retrofit+Coroutines做开发,需要把秘鲁、德国的国家信息JSON转换成Kotlin Data Class,但遇到了属性键随国家变化的问题:

  • languages、currencies、nativeName的键是动态的(比如秘鲁货币键是PEN,德国是EUR;秘鲁有3种语言,德国仅1种)
  • 部分字段仅部分国家存在(比如德国有flag和maps字段,秘鲁没有)

秘鲁JSON示例

{
        "name": {
            "common": "Peru",
            "official": "Republic of Peru",
            "nativeName": {
                "aym": {
                    "official": "Piruw Suyu",
                    "common": "Piruw"
                },
                "que": {
                    "official": "Piruw Ripuwlika",
                    "common": "Piruw"
                },
                "spa": {
                    "official": "República del Perú",
                    "common": "Perú"
                }
            }
        },
        "tld": [".pe"],
        "cca2": "PE",
        "ccn3": "604",
        "cca3": "PER",
        "cioc": "PER",
        "independent": true,
        "status": "officially-assigned",
        "unMember": true,
        "currencies": {
            "PEN": {
                "name": "Peruvian sol",
                "symbol": "S/ "
            }
        },
        "idd": {
            "root": "+5",
            "suffixes": ["1"]
        },
        "capital": ["Lima"],
        "altSpellings": ["PE", "Republic of Peru", "República del Perú"],
        "region": "Americas",
        "subregion": "South America",
        "languages": {
            "aym": "Aymara",
            "que": "Quechua",
            "spa": "Spanish"
        },
        "latlng": [-10.0, -76.0],
        "landlocked": false,
        "borders": ["BOL", "BRA", "CHL", "COL", "ECU"],
        "area": 1285216.0,
        "demonyms": {
            "eng": {"f": "Peruvian", "m": "Peruvian"},
            "fra": {"f": "Péruvienne", "m": "Péruvien"}
        },
        "population": 32971846,
        "timezones": ["UTC-05:00"],
        "continents": ["South America"],
        "flags": {
            "png": "https://flagcdn.com/w320/pe.png",
            "svg": "https://flagcdn.com/pe.svg"
        },
        "capitalInfo": {"latlng": [-12.05, -77.05]}
    }

德国JSON示例

{
        "name": {
            "common": "Germany",
            "official": "Federal Republic of Germany",
            "nativeName": {
                "deu": {
                    "official": "Bundesrepublik Deutschland",
                    "common": "Deutschland"
                }
            }
        },
        "tld": [".de"],
        "cca2": "DE",
        "ccn3": "276",
        "cca3": "DEU",
        "cioc": "GER",
        "independent": true,
        "status": "officially-assigned",
        "unMember": true,
        "currencies": {
            "EUR": {"name": "Euro", "symbol": "€"}
        },
        "idd": {"root": "+4", "suffixes": ["9"]},
        "capital": ["Berlin"],
        "altSpellings": ["DE", "Federal Republic of Germany", "Bundesrepublik Deutschland"],
        "region": "Europe",
        "subregion": "Western Europe",
       "languages": {"deu": "German"},
        "latlng": [51.0, 9.0],
        "landlocked": false,
        "borders": ["AUT", "BEL", "CZE", "DNK", "FRA", "LUX", "NLD", "POL", "CHE"],
        "area": 357114.0,
        "demonyms": {
            "eng": {"f": "German", "m": "German"},
            "fra": {"f": "Allemande", "m": "Allemand"}
        },
        "flag": "🇩🇪",
        "maps": {
            "googleMaps": "https://goo.gl/maps/mD9FBMq1nvXUBrkv6",
            "openStreetMaps": "https://www.openstreetmap.org/relation/51477"
        },
        "population": 83240525,
        "timezones": ["UTC+01:00"],
        "continents": ["Europe"],
        "flags": {
            "png": "https://flagcdn.com/w320/de.png",
            "svg": "https://flagcdn.com/de.svg"
        },
        "capitalInfo": {"latlng": [52.52, 13.4]}
    }

解决方法

1. 用Map处理动态键字段

对于键不固定的字段,直接用Map<String, T>定义,适配任意数量的动态键值对:

// 嵌套数据类定义
data class Name(
    val common: String,
    val official: String,
    // nativeName的键为语言代码,值为对应名称对象
    val nativeName: Map<String, NativeName>
)

data class NativeName(
    val official: String,
    val common: String
)

data class Currency(
    val name: String,
    val symbol: String? // 部分货币无symbol,设为可空
)

data class Demonym(
    val f: String,
    val m: String
)

data class Flags(
    val png: String,
    val svg: String
)

data class CapitalInfo(
    val latlng: List<Double>
)

data class Maps(
    val googleMaps: String,
    val openStreetMaps: String
)

data class Idd(
    val root: String,
    val suffixes: List<String>
)

2. 定义顶层Country数据类

包含所有可能的字段,仅部分国家存在的字段标记为可空:

data class Country(
    val name: Name,
    val tld: List<String>,
    val cca2: String,
    val ccn3: String,
    val cca3: String,
    val cioc: String,
    val independent: Boolean,
    val status: String,
    val unMember: Boolean,
    // currencies的键为货币代码,值为Currency对象
    val currencies: Map<String, Currency>,
    val idd: Idd,
    val capital: List<String>,
    val altSpellings: List<String>,
    val region: String,
    val subregion: String,
    // languages的键为语言代码,值为语言名称
    val languages: Map<String, String>,
    val latlng: List<Double>,
    val landlocked: Boolean,
    val borders: List<String>?, // 内陆国可能无边界,设为可空
    val area: Double,
    val demonyms: Map<String, Demonym>,
    val population: Long,
    val timezones: List<String>,
    val continents: List<String>,
    val flags: Flags,
    val capitalInfo: CapitalInfo,
    // 可选字段,部分国家才有
    val flag: String?,
    val maps: Maps?
)

3. Retrofit序列化适配

无论用Gson还是Moshi,都能自动解析Map类型:

  • Gson:Retrofit默认集成,直接使用GsonConverterFactory.create()即可
  • Moshi:添加Kotlin支持依赖后,无需额外配置就能解析Map结构

4. 访问动态键数据

解析后通过Map的方法获取目标数据:

// 获取秘鲁货币名称
val peruCurrencyName = country.currencies["PEN"]?.name
// 获取德国语言名称
val germanLanguage = country.languages["deu"]
// 遍历所有语言
country.languages.forEach { (code, name) ->
    println("语言代码:$code,名称:$name")
}

5. 处理可选字段

对仅部分国家存在的字段,访问时需判空:

country.flag?.let { emojiFlag ->
    println("国旗emoji:$emojiFlag")
} ?: run {
    println("使用PNG国旗链接:${country.flags.png}")
}

内容的提问来源于stack exchange,提问作者OFFICIAL_SEB15

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:25:18