我有一个用Scala编写的自定义Jackson解串器。结构如下。
override def deserialize(jp: JsonParser, ctx: DeserializationContext): Item = {
val node: JsonNode = jp.getCodec.readTree(jp)
// few double fields
val usageHours = node.get("usageHours").asDouble()
val usageUnits = node.get("usageUnits").asDouble()
// few string fields
val accountId = node.get("accountId").asText()
val accountName = node.get("accountName").asText()
// few long fields
val cardinality = node.get("cardinality").asLong()
// few date fields
val endDateTime = customDeserializer.convert(node.get("startDateTime").asText())
// few optionals with default values
val engine = Option(node.get("engine")).map(value => value.asText()).getOrElse(Constants.Unknown)
// case class object
Item(usageHours,
usageUnits,
accountId,
accountName,
cardinality,
endDateTime,
engine)
}
问题是要解析的字段太多,显然为每个字段调用node.get()或Option(node.get)都是不好的。我正在尝试编写一个通用方法getValueForJsonKey()可以
这就是我想出的
// Basically trying to identify the return type from the default value passed by the user
// This will not work if the user doesn’t pass a default value.
private def parseValueForJsonKey [A] (node: JsonNode, key: String, defaultValue: A): A = {
val parsedValue = Option(node.get(key)).map(value => {
defaultValue match {
case _: String => value.asText()
case _: Double => value.asDouble()
case _: Long => value.asLong()
case _: ZonedDateTime => customDateDeserializer.convert(value)
case _ => throw new RuntimeException(s"Unsupported type. Cannot parse ${key} to other than supported types")
}
})
parsedValue match{
case Some(value) => value.asInstanceOf[A]
case None => defaultValue
}
}
这显然是行不通的,而且不是正确的方法。我相信有更好的方法可以做到这一点。感谢您的帮助。
修订版2
def parseValueForJsonKeyWithReturnType[A: TypeTag](
node: JsonNode,
key: String,
defaultValue: Any = None
): A = {
val parsedValue = Option(node.get(key)).map(value => {
typeOf[A] match {
case t if t =:= typeOf[String] =>
value.asText()
case t if t =:= typeOf[Double] =>
value.asDouble()
case t if t =:= typeOf[Long] =>
value.asLong()
case t if t =:= typeOf[ZonedDateTime] =>
zonedDateTimeDeserializer.convert(value.asText())
case _ => throw new RuntimeException(s"Parsing to ${typeOf[A]} isn't supported by custom deserializer")
}
})
parsedValue.getOrElse(defaultValue).asInstanceOf[A]
}
答案 0 :(得分:1)
您的代码实际上非常接近。您需要:
修正范围(您似乎尝试在方法之外使用局部变量parsedValue
)
删除.get
个电话(value
和defaultValue
都不是Option
个电话)
从.getClass
案例中删除asInstanceOf
(A
需要类型参数,并且Some(value)
已经是类型),然后从{{ 1}}。
但是更好的书写方式是
None
请注意,由于类型擦除,如果类型不正确,val parsedValue = /* what you have */
parsedValue.getOrElse(defaultValue).asInstanceOf[A]
本身不会引发异常,但是您的代码已经处理了该部分。
答案 1 :(得分:0)
尝试jsoniter-scala。它具有用于案例类字段的build in support of default values,因此在这种情况下,它不需要编写自定义编解码器。
另一方面,它允许writing of custom codecs,而无需冗余的中间AST或/和字符串表示形式。