scala - 使用 json4s 反序列化嵌套多态 json 字段

标签 scala json-deserialization json4s

我有一个常见问题,但仍然无法理解我正在阅读的内容。

在 scalatra 应用程序中,我收到以下 json:

{
_type: "hello",
timestamp: 123,
data: [
{table: "stuffJ",_id: 24},
{table: "preferences",_id: 34,word: "john"}
]}

字段“数据”中的元素数量未知。字段表将始终存在以区分类类型。我试图将其解析为 RestAPIMessage 类。这是我到目前为止所拥有的:

    implicit val jsonFormats = new DefaultFormats { outer =>
        override val typeHintFieldName = "table"
        override val typeHints = ShortTypeHints(List(classOf[Preferences], classOf[StuffJ]))
      }

    sealed trait DataJson 
    case class Preferences(table: String, _id: Long, word : String) extends DataJson
    case class StuffJ(table: String, _id: Long) extends DataJson
    case class RestAPIMessage(_type: String, timestamp: Long, data: List[DataJson])

    // if sent as Json, returns a json with two "table" fields
    val message = new RestAPIMessage("hello", 123, List(new StuffJ("StuffJ", 24), new Preferences("preferences", 34, "john"))) 

    // if received as Json, fails with a "no usable value for outer" 
    val djson = """{"_type":"hello","timestamp":123,"data":[{"table":"StuffJ","_id":24},{"table":"table":"preferences","_id":34,"word":"john"}]}"""

感谢您的帮助!

最佳答案

好吧,我想我明白了。 最后,我似乎无法“开箱即用”地获得我需要的东西,并且不得不编写一个自定义序列化器。我找不到简单的“多态”示例,因此我在下面放置了一个最小的 foobar 示例:

import org.json4s.{DefaultFormats, Formats}
import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.native.Serialization.{read, write}
import org.json4s.native.Serialization


sealed trait Bar 

case class Bar1(name : String, value: Int) extends Bar
case class Bar2(name : String, stuff: Int) extends Bar
case class Foo(timestamp:Long, bar: List[Bar])
var testFoo : Foo = new Foo(123, List(Bar1("bar1",1), Bar2("bar2",2)))

object BarSerializer extends CustomSerializer[Bar](format => (
  {
    case x: JObject =>
      val name = (x \ "name").extract[String]
      name match {
        case "bar1" =>
          val value = (x \ "value").extract[Int]
          Bar1(name,value)
        case "bar2" =>
          val value = (x \ "stuff").extract[Int]
          Bar2(name,value)
        case x => throw new MappingException("Can't convert bar with name " + x + " to Bar")
      }
  },
  {
    case x: Bar =>
      //if you need only the deserializing part above, I think you could replace the below with write(x)
      x match {
        case Bar1(a,b) => 
          ("name" -> a) ~ ("value" -> b)
        case Bar2(a,b) =>
          ("name" -> a) ~ ("stuff" -> b)
      }
  }
))

implicit val jsonFormats: Formats = Serialization.formats(NoTypeHints) + BarSerializer

val a = write(testFoo)
//returns : String = {"timestamp":123,"bar":[{"name":"bar1","value":1},{"name":"bar2","value":2}]}
read[Foo](a)
//returns : Foo = Foo(123,List(Bar1(bar1,1), Bar2(bar2,2)))

关于scala - 使用 json4s 反序列化嵌套多态 json 字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33413144/

相关文章:

scala - Play 异常: '{' expected but 'import' found

c# - 反射——从类型到类(不是类的实例)

c# - 使用自定义格式作为引用时,如何使用 Json.NET 通过引用反序列化对象?

c# - 使用 Json.NET 使用新的部分 JSON 数据修改现有对象

json - 将键值字符串转换为 Scala Map 的方法

json - 如何使用Json4s将Map转Json

json - 使用json4s将json中的字符串解析为java.time.LocalTime

scala - 使用scalaz的promise时调用函数

java - Scala 代码片段 - Java 8 的等效项是什么?

scala - 延迟评估和死锁