【问题标题】:How do you write a json4s CustomSerializer that handles collections怎么写一个处理集合的json4s CustomSerializer
【发布时间】:2016-02-10 10:25:54
【问题描述】:

我有一个类,我正在尝试使用 json4s CustomSerializer 功能反序列化。由于inability of json4s to deserialize mutable collections,我需要这样做。

这是我要反序列化的类的基本结构(不用担心为什么类是这样的结构):

case class FeatureValue(timestamp:Double)

object FeatureValue{
  implicit def ordering[F <: FeatureValue] = new Ordering[F] {
    override def compare(a: F, b: F): Int = {
      a.timestamp.compareTo(b.timestamp)
    }
  }
}

class Point {
  val features = new HashMap[String, SortedSet[FeatureValue]]

  def add(name:String, value:FeatureValue):Unit = {
    val oldValue:SortedSet[FeatureValue] = features.getOrElseUpdate(name, SortedSet[FeatureValue]())
    oldValue += value
  }
}

Json4s 序列化这个就好了。一个序列化的实例可能如下所示:

{"features":
  {
   "CODE0":[{"timestamp":4.8828914447482E8}],
   "CODE1":[{"timestamp":4.8828914541333E8}],
   "CODE2":[{"timestamp":4.8828915127325E8},{"timestamp":4.8828910097466E8}]
  }
}

我尝试编写自定义反序列化程序,但我不知道如何处理列表尾部。在普通匹配器中,您可以递归调用自己的函数,但在这种情况下,该函数是匿名的,并且通过 json4s API 调用。我找不到任何处理这个问题的例子,我也想不通。

目前我只能匹配一个哈希键和一个 FeatureValue 实例的值。这是 CustomSerializer 的现状:

import org.json4s.{FieldSerializer, DefaultFormats, Extraction, CustomSerializer}
import org.json4s.JsonAST._

class PointSerializer extends CustomSerializer[Point](format => (
  {
    case JObject(JField("features", JObject(Nil)) :: Nil) => new Point
    case JObject(List(("features", JObject(List(
      (feature:String, JArray(List(JObject(List(("timestamp",JDouble(ts)))))))))
    ))) => {
      val point = new Point
      point.add(feature, FeatureValue(ts))
      point
    }
  },
  {
    // don't need to customize this, it works fine
    case x: Point => Extraction.decompose(x)(DefaultFormats + FieldSerializer[Point]())
  }
  ))

如果我尝试更改为使用 :: 分隔的列表格式,到目前为止我得到了编译器错误。即使我没有遇到编译器错误,我也不确定我会如何处理它们。

【问题讨论】:

    标签: scala functional-programming deserialization json4s


    【解决方案1】:

    您可以获取模式匹配中的 json 特征列表,然后映射此列表以获取 Features 及其代码。

    class PointSerializer extends CustomSerializer[Point](format => (
      {
        case JObject(List(("features", JObject(featuresJson)))) => 
          val features = featuresJson.flatMap { 
            case (code:String, JArray(timestamps)) =>
              timestamps.map { case JObject(List(("timestamp",JDouble(ts)))) =>
                code -> FeatureValue(ts)
              }
          }
    
          val point = new Point
          features.foreach((point.add _).tupled)
          point
      }, {
        case x: Point => Extraction.decompose(x)(DefaultFormats + FieldSerializer[Point]())
      }
    ))
    

    将您的 json 反序列化如下:

    import org.json4s.native.Serialization.{read, write}
    implicit val formats = Serialization.formats(NoTypeHints) + new PointSerializer
    
    val json = """
    {"features":
      {
       "CODE0":[{"timestamp":4.8828914447482E8}],
       "CODE1":[{"timestamp":4.8828914541333E8}],
       "CODE2":[{"timestamp":4.8828915127325E8},{"timestamp":4.8828910097466E8}]
      }
    }
    """
    
    val point0 = read[Point]("""{"features": {}}""")
    val point1 = read[Point](json)
    
    point0.features // Map()
    point1.features 
    // Map(
    //   CODE0 -> TreeSet(FeatureValue(4.8828914447482E8)), 
    //   CODE2 -> TreeSet(FeatureValue(4.8828910097466E8), FeatureValue(4.8828915127325E8)), 
    //   CODE1 -> TreeSet(FeatureValue(4.8828914541333E8))
    // )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多