我有一个代表城市的简单数据类
data class City(
val name: String,
val centroid: Coordinates
)
Run Code Online (Sandbox Code Playgroud)
出于外部兼容性的原因,该Coordinates类型被定义为typealias
typealias Coordinates = Pair<Double, Double>
val Coordinates.lat
get() = first
val Coordinates.lon
get() = second
Run Code Online (Sandbox Code Playgroud)
如何配置 Jackson,以便它能够将以下 JSON 反序列化为 的实例City?
{
"name": "Praha",
"centroid": {
"lat": 50.2141,
"lon": 14.42342
}
}
Run Code Online (Sandbox Code Playgroud)
如果您确实必须保持兼容性,您可以编写自己的序列化器和反序列化器,例如:
object CoordinatesConversions {
const val LATITUDE_FIELD_NAME = "lat"
const val LONGITUDE_FIELD_NAME = "lon"
object Serializer : JsonSerializer<Coordinates>() {
override fun serialize(value: Coordinates, gen: JsonGenerator, serializers: SerializerProvider) {
with(gen) {
writeStartObject()
writeNumberField(LATITUDE_FIELD_NAME, value.first)
writeNumberField(LONGITUDE_FIELD_NAME, value.second)
writeEndObject()
}
}
}
object Deserializer : JsonDeserializer<Coordinates>() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Coordinates {
val node = p.readValueAsTree<JsonNode>()
val lat = node.get(LATITUDE_FIELD_NAME).asDouble()
val lon = node.get(LONGITUDE_FIELD_NAME).asDouble()
return Coordinates(lat, lon)
}
}
}
Run Code Online (Sandbox Code Playgroud)
还指定您的城市模型应使用哪些序列化器
data class City(
val name: String,
@JsonSerialize(using = CoordinatesConversions.Serializer::class)
@JsonDeserialize(using = CoordinatesConversions.Deserializer::class)
val center: Coordinates
)
Run Code Online (Sandbox Code Playgroud)
一个完整的工作示例:
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
private typealias Coordinates = Pair<Double, Double>
object CoordinatesConversions {
const val LATITUDE_FIELD_NAME = "lat"
const val LONGITUDE_FIELD_NAME = "lon"
object Serializer : JsonSerializer<Coordinates>() {
override fun serialize(value: Coordinates, gen: JsonGenerator, serializers: SerializerProvider) {
with(gen) {
writeStartObject()
writeNumberField(LATITUDE_FIELD_NAME, value.first)
writeNumberField(LONGITUDE_FIELD_NAME, value.second)
writeEndObject()
}
}
}
object Deserializer : JsonDeserializer<Coordinates>() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Coordinates {
val node = p.readValueAsTree<JsonNode>()
val lat = node.get(LATITUDE_FIELD_NAME).asDouble()
val lon = node.get(LONGITUDE_FIELD_NAME).asDouble()
return Coordinates(lat, lon)
}
}
}
object StackOverflow {
private val objectMapper = jacksonObjectMapper().apply {
configure(SerializationFeature.INDENT_OUTPUT, true)
}
data class City(
val name: String,
@JsonSerialize(using = CoordinatesConversions.Serializer::class)
@JsonDeserialize(using = CoordinatesConversions.Deserializer::class)
val center: Coordinates
)
@JvmStatic
fun main(args: Array<String>) {
val city = City("Cair Paravel", 13.37 to 42.0)
val jsonOutput = objectMapper.writeValueAsString(city)
println(jsonOutput)
val deserializedCity = objectMapper.readValue<City>(jsonOutput)
println(deserializedCity)
}
}
Run Code Online (Sandbox Code Playgroud)
我仍然认为最好尝试摆脱使用 Pairs 来表示这种具体的数据结构,并且我认为这对您将来会有好处。
例如,在表示地理点时,并不总是清楚使用哪种标准,一些供应商使用(lat, lng),其他供应商使用(lng, lat)。即使您在别名之上定义了命名属性 getter,您也不需要经历定义自定义序列化器和反序列化器的麻烦,这总是很好的。
| 归档时间: |
|
| 查看次数: |
8761 次 |
| 最近记录: |