假设我从JSON服务器收到错误,该错误可以采用两种不同的结构:
var incidenceGroup = new L.GeoJSON.AJAX("http://127.0.0.1:8000/incidence_data/")
/* ...wait for it to load with whatever method... */
var incidenceLayers = incidenceGroup.getLayers(); // incidenceLayers will be an Array
for (var incidence of incidenceLayers) { /* do stuff */ }
// Or also a more classical for(;;) loop:
for (var i, l=incidenceLayers.length; i<l; i++) {
var incidence = incidenceLayers[i];
/* do stuff */
}
OR
{"errorMessage": "This action is unauthorized."}
如何反序列化这种json?
我尝试过的
我尝试使用抽象类“ Error”和两个孩子:
{"errorMessage":{"changePassword":"Old password is incorrect."}}
然后我尝试:
abstract class Error() {}
data class SingleError(val errorMessage: String) : Error()
data class MultiError(val errorMessage: Map<String, String>) : Error()
反序列化,但我有一个例外:
jacksonObjectMapper().readValue<Error>(response.body)
我也尝试了JsonDeserialize注释,但是如果我想解析为具体类型,似乎可以使用它:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.fifth_llc.siply.main.request.Forbidden$Error` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: (String)"{"errorMessage":{"changePassword":"Old password is incorrect."}}"; line: 1, column: 1]
有帮助吗?
答案 0 :(得分:1)
自定义解串器方法:
Immediate Windows
用法:
sealed class Error() {
data class SingleError(val errorMessage: String) : Error()
data class MultiError(val errorMessage: Map<String, String>) : Error()
}
...
class ErrorDeserializer : StdDeserializer<Error>(Error::class.java) {
companion object {
private val MAP_TYPE_REFERENCE = object : TypeReference<Map<String, String>>() {}
}
@Throws(IOException::class, JsonProcessingException::class)
override fun deserialize(jp: JsonParser, ctxt: DeserializationContext): Error {
val mapper = jp.codec as ObjectMapper
val node: JsonNode = mapper.readTree(jp)
val msgNode = node.get("errorMessage")
if (msgNode.isValueNode) {
val errorMsg = msgNode.asText()
return Error.SingleError(errorMsg)
} else {
val errorMsgs = mapper.readValue<Map<String, String>>(msgNode.toString(),
MAP_TYPE_REFERENCE)
return Error.MultiError(errorMsgs)
}
}
}
答案 1 :(得分:0)
据我所知,至少我有经验,不能将抽象类型分配给readValue方法,必须在readValue parameterizedType及其属性中指定它的具体类型。
jacksonObjectMapper().readValue<Error>(response.body)
在上面的行中,您必须将Error替换为所需的子类型之一,然后在其中必须将Map
替换为HashedMap
data class MultiError(val errorMessage: Map<String, String>) : Error()
另一种方法是使用@JsonTypeInfo进入json对象,以通知JackSon将确切的对象类型作为元数据包括到json流中。此解决方案在服务器和客户端应用程序中都需要代码更正。请参阅以下链接:
答案 2 :(得分:0)
问题在于,杰克逊需要一个JsonCreator或一个空的构造函数。
数据类没有空的构造函数。如果仍然想要一个空的构造函数,则可以使用Kotlin No-Args plugin.
等级:
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion"
...
}
...
apply plugin: "kotlin-noarg"
...
noArg {
annotation("com.your.package.NoArgs")
}
现在,创建自定义注释:
package com.your.package
annotation class NoArgs
现在,最简单的 * 方法是使用通用类型作为错误消息并使用自定义注释:
@NoArgs
data class Error<out T>(val errorMessage: T)
val x = ObjectMapper().readValue<Error<*>>(json1)
val y = ObjectMapper().readValue<Error<*>>(json2)
when(y.errorMessage) {
is String -> println("I'm a String!")
is Map<*,*> -> println("I'm a Map")
else -> println("I'm something else!")
}
如果事先知道,您还可以在readValue
上明确定义类型:readValue<Error<String>>
您还可以在Error
内的when
内为该逻辑创建一个方法
* 可能有更优雅或更有用的解决方案,具体取决于您的具体情况。