哪个JSON序列化库适合以下情况?

时间:2011-01-26 13:03:10

标签: json scala

我有以下案例: 我想序列化扩展父类的Scala案例类,其类型为java.util.UUID。 此案例类的序列化应该在没有任何配置的情况下发生 - 没有自定义格式的注释和定义。任何序列化提示都可能位于父类中。

我尝试过sjson,但基于反射的序列化无法序列化UUID类型,基于类型的序列化迫使我为每个案例类定义格式。 哪个json序列化库最适合这种情况?

4 个答案:

答案 0 :(得分:4)

以下是Lift JSON的一个解决方案。

import java.util.UUID
import net.liftweb.json._
import net.liftweb.json.JsonAST._
import net.liftweb.json.JsonDSL._
import net.liftweb.json.Serialization._

sealed abstract class Parent {
  def uuid: UUID
}
case class Foo(uuid: UUID, name: String) extends Parent

object UUIDTest extends Application {
  implicit val formats =  Serialization.formats(NoTypeHints) + new UUIDSerializer

  val f = Foo(UUID.randomUUID, "foo")
  val ser = write(f)
  println(ser)
  val f2 = read[Foo](ser)
  assert(f == f2)

  // Special serializer for UUID type
  class UUIDSerializer extends Serializer[UUID] {
    private val Class = classOf[UUID]

    def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), UUID] = {
      case (TypeInfo(Class, _), json) => json match {
        case JObject(JField("mostSig", JInt(m)) :: JField("leastSig", JInt(l)) :: Nil) =>
          new UUID(m.longValue, l.longValue)
        case x => throw new MappingException("Can't convert " + x + " to UUID")
      }
    }

    def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case x: UUID =>
        ("mostSig" -> x.getMostSignificantBits) ~ ("leastSig" -> x.getLeastSignificantBits)
    }
  }
}

打印:

{"uuid":{"mostSig":-8054689529719995935,"leastSig":-5722404370736228056},"name":"foo"}'

另一种使用父类型的自定义序列化程序的解决方案。

sealed abstract class Parent {
  var uuid: UUID = UUID.randomUUID
}
case class Foo(name: String) extends Parent

object UUIDTest extends Application {
  implicit val formats = 
    Serialization.formats(NoTypeHints) + new ParentSerializer

  val f = Foo("foo")
  val ser = write(f)
  println(ser)
  val f2 = read[Foo](ser)
  assert(f == f2)

  // Special serializer for Parent type
  class ParentSerializer extends Serializer[Parent] {
    def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Parent] = {
      case (t@TypeInfo(cl, _), json) if (classOf[Parent].isAssignableFrom(cl)) => 
        val x = Extraction.extract(json, t)(DefaultFormats).asInstanceOf[Parent]
        x.uuid = (for { 
          JField("mostSig", JInt(m))  <- json
          JField("leastSig", JInt(l)) <- json 
        } yield new UUID(m.longValue, l.longValue)).head
        x
    }

    def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
      case x: Parent =>
        Extraction.decompose(x)(DefaultFormats) ++ 
        JField("mostSig", x.uuid.getMostSignificantBits) ++ 
        JField("leastSig", x.uuid.getLeastSignificantBits)
    }
  }
}

答案 1 :(得分:2)

如果类型很重要,你应该看看YAML。

http://www.google.fr/search?q=java+yaml

它是json的一个子集,具有改进的东西,比如变量输入。

答案 2 :(得分:2)

尝试包含JSON支持的XStream库。我在一些项目中成功使用了它。它有许多默认转换器,包括java.util.UUID的转换器。完整的默认转换列表位于:http://x-stream.github.io/converters.html

有关使用XStream进行JSON读写的简要教程,请访问:http://x-stream.github.io/json-tutorial.html。教程代码是为Java编写的,但由于反射在幕后使用,它对Scala应该是一样的。

请记住,使用此库并不总是可以序列化然后反序列化对象的任意图形。特别是,无法处理数据中的循环,即您的数据必须是纯粹的分层树。考虑到JSON格式的意图,这是一个合理的限制。

参考链接:
XStream JSON教程:http://x-stream.github.io/json-tutorial.html
XStream默认转换器:http://x-stream.github.io/converters.html

答案 3 :(得分:2)

您可以尝试jerkson:https://github.com/codahale/jerkson

它适合我的使用,但主要是列表/地图结构。如果它支持你的需求会不会感到惊讶..

编辑:尝试使用以下示例(受另一个答案中的提升示例的启发)。似乎工作正常。

import java.util.UUID
import com.codahale.jerkson.Json
import org.scalatest.FunSuite

sealed abstract class Parent {
   def uuid: UUID
}

case class Foo(uuid: UUID, name: String) extends Parent

class TmpJsonTest extends FunSuite {
   test("Json case class serialize") {
      val f = Foo(UUID.randomUUID, "foo")
      val ser = Json.generate(f)
      println(ser)
      val f2 = Json.parse[Foo](ser)
      assert(f === f2)
   }
}