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

如何处理Tmap Route Api中Retrofit返回的Geometry多类型响应

处理Tmap Route API中Geometry多类型coordinates的映射问题

Tmap Route API返回的Geometry字段里,coordinates存在两种格式:Point类型对应单层List<String>,LineString类型对应嵌套List<List<String>>,直接用默认序列化器会因为类型不匹配报错,需要自定义类型转换器来处理。

方案1:Gson自定义TypeAdapter

1. 定义密封类封装坐标类型

sealed class Coordinates {
    data class Point(val latLng: List<String>) : Coordinates()
    data class LineString(val points: List<List<String>>) : Coordinates()
}

2. 实现TypeAdapter处理序列化/反序列化

class CoordinatesTypeAdapter : TypeAdapter<Coordinates>() {
    override fun write(out: JsonWriter, value: Coordinates?) {
        when (value) {
            is Coordinates.Point -> out.jsonArray {
                value.latLng.forEach { value(it) }
            }
            is Coordinates.LineString -> out.jsonArray {
                value.points.forEach { point ->
                    jsonArray {
                        point.forEach { value(it) }
                    }
                }
            }
            null -> out.nullValue()
        }
    }

    override fun read(`in`: JsonReader): Coordinates {
        return when (`in`.peek()) {
            JsonToken.BEGIN_ARRAY -> {
                `in`.beginArray()
                return if (`in`.peek() == JsonToken.STRING) {
                    // 解析Point类型的单层数组
                    val pointList = mutableListOf<String>()
                    while (`in`.hasNext()) pointList.add(`in`.nextString())
                    `in`.endArray()
                    Coordinates.Point(pointList)
                } else {
                    // 解析LineString类型的嵌套数组
                    val lineList = mutableListOf<List<String>>()
                    while (`in`.hasNext()) {
                        `in`.beginArray()
                        val point = mutableListOf<String>()
                        while (`in`.hasNext()) point.add(`in`.nextString())
                        `in`.endArray()
                        lineList.add(point)
                    }
                    `in`.endArray()
                    Coordinates.LineString(lineList)
                }
            }
            else -> throw JsonParseException("Coordinates格式错误")
        }
    }
}

3. 关联到Geometry数据类

在coordinates字段上添加注解,指定使用自定义Adapter:

data class Geometry(
    val type: String,
    @JsonAdapter(CoordinatesTypeAdapter::class)
    val coordinates: Coordinates
)

方案2:Moshi自定义JsonAdapter

1. 定义密封类(同Gson方案)

sealed class Coordinates {
    data class Point(val latLng: List<String>) : Coordinates()
    data class LineString(val points: List<List<String>>) : Coordinates()
}

2. 实现JsonAdapter

class CoordinatesAdapter {
    @FromJson
    fun fromJson(reader: JsonReader): Coordinates {
        return when (reader.peek()) {
            JsonReader.Token.BEGIN_ARRAY -> {
                reader.beginArray()
                return if (reader.peek() == JsonReader.Token.STRING) {
                    val point = mutableListOf<String>()
                    while (reader.hasNext()) point.add(reader.nextString())
                    reader.endArray()
                    Coordinates.Point(point)
                } else {
                    val line = mutableListOf<List<String>>()
                    while (reader.hasNext()) {
                        reader.beginArray()
                        val innerPoint = mutableListOf<String>()
                        while (reader.hasNext()) innerPoint.add(reader.nextString())
                        reader.endArray()
                        line.add(innerPoint)
                    }
                    reader.endArray()
                    Coordinates.LineString(line)
                }
            }
            else -> throw JsonDataException("Coordinates格式错误")
        }
    }

    @ToJson
    fun toJson(writer: JsonWriter, value: Coordinates?) {
        when (value) {
            is Coordinates.Point -> {
                writer.beginArray()
                value.latLng.forEach { writer.value(it) }
                writer.endArray()
            }
            is Coordinates.LineString -> {
                writer.beginArray()
                value.points.forEach { point ->
                    writer.beginArray()
                    point.forEach { writer.value(it) }
                    writer.endArray()
                }
                writer.endArray()
            }
            null -> writer.nullValue()
        }
    }
}

3. 注册Adapter或关联到数据类

注册到Moshi实例:

val moshi = Moshi.Builder()
    .add(CoordinatesAdapter())
    .build()

或者直接在Geometry字段上加注解:

data class Geometry(
    val type: String,
    @JsonAdapter(CoordinatesAdapter::class)
    val coordinates: Coordinates
)

在Repository中使用

拿到Geometry对象后,根据type字段判断坐标类型并处理:

when (geometry.type) {
    "Point" -> {
        val pointCoords = (geometry.coordinates as Coordinates.Point).latLng
        // 处理Point坐标逻辑
    }
    "LineString" -> {
        val lineCoords = (geometry.coordinates as Coordinates.LineString).points
        // 处理LineString坐标逻辑
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:01:11