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

如何用Retrofit+GSON+Room将API返回的子对象解析为字符串字段?

解决方案

方案1:自定义GSON TypeAdapter,在Retrofit解析时直接映射

这种方式能让Retrofit把API返回的JSON直接解析成你需要的Department实体,跳过手动映射的中间类。

步骤1:定义Room实体类

@Entity(tableName = "departments")
data class Department(
    @PrimaryKey val id: Int,
    val name: String,
    val region: String // 直接存储region的nom值
    // 其他字段...
)

步骤2:编写GSON TypeAdapter

创建自定义TypeAdapter处理Department的反序列化,手动提取region.nom字段:

class DepartmentTypeAdapter : TypeAdapter<Department>() {
    override fun write(out: JsonWriter, value: Department) {
        // 若需序列化(如上传数据)可按需实现,此处省略
        out.beginObject()
        out.name("id").value(value.id)
        out.name("name").value(value.name)
        out.name("region").value(value.region)
        out.endObject()
    }

    override fun read(`in`: JsonReader): Department {
        var id = 0
        var name = ""
        var regionNom = ""

        `in`.beginObject()
        while (`in`.hasNext()) {
            when (`in`.nextName()) {
                "id" -> id = `in`.nextInt()
                "name" -> name = `in`.nextString()
                "region" -> {
                    // 解析嵌套的region对象,提取nom字段
                    `in`.beginObject()
                    while (`in`.hasNext()) {
                        if (`in`.nextName() == "nom") {
                            regionNom = `in`.nextString()
                        } else {
                            `in`.skipValue() // 跳过不需要的code字段
                        }
                    }
                    `in`.endObject()
                }
                else -> `in`.skipValue() // 跳过其他无关字段
            }
        }
        `in`.endObject()

        return Department(id, name, regionNom)
    }
}

步骤3:配置Retrofit使用TypeAdapter

在构建Retrofit实例时,将自定义TypeAdapter加入GSON配置:

val gson = GsonBuilder()
    .registerTypeAdapter(Department::class.java, DepartmentTypeAdapter())
    .create()

val retrofit = Retrofit.Builder()
    .baseUrl("你的API地址")
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build()

之后Retrofit请求返回的直接是Department实体,可直接插入Room数据库,无需手动映射。


方案2:用@JsonAdapter注解简化配置

若不想手动构建Gson实例,可直接在实体类上标注@JsonAdapter指定TypeAdapter:

@Entity(tableName = "departments")
@JsonAdapter(DepartmentTypeAdapter::class)
data class Department(
    @PrimaryKey val id: Int,
    val name: String,
    val region: String
)

这样Retrofit的默认GsonConverterFactory会自动识别并使用该TypeAdapter,省去手动配置Gson的步骤。


额外说明:Room TypeConverter的适用场景

如果你的需求是在数据库中存储完整的Region对象,但查询时仅需nom字段,Room TypeConverter才适用:

  1. 定义Region数据类:
data class Region(val code: String, val nom: String)
  1. 修改Department实体的region字段为Region类型:
@Entity(tableName = "departments")
data class Department(
    @PrimaryKey val id: Int,
    val name: String,
    val region: Region
)
  1. 编写Room TypeConverter,实现Region与JSON字符串的互转:
class Converters {
    private val gson = Gson()

    @TypeConverter
    fun fromRegionToString(region: Region): String {
        return gson.toJson(region)
    }

    @TypeConverter
    fun fromStringToRegion(regionString: String): Region {
        return gson.fromJson(regionString, Region::class.java)
    }
}
  1. 在RoomDatabase类上添加@TypeConverters注解:
@Database(entities = [Department::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun departmentDao(): DepartmentDao
}

但此场景与你当前需求(实体类region为String类型)不符,因此更推荐前面的TypeAdapter方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 09:41:12