如何处理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
相关产品推荐
相关产品推荐

