我有以下案例: 我想序列化扩展父类的Scala案例类,其类型为java.util.UUID。 此案例类的序列化应该在没有任何配置的情况下发生 - 没有自定义格式的注释和定义。任何序列化提示都可能位于父类中。
我尝试过sjson,但基于反射的序列化无法序列化UUID类型,基于类型的序列化迫使我为每个案例类定义格式。 哪个json序列化库最适合这种情况?
答案 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)
答案 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)
}
}