我正在尝试使用Lift-Json自动将json对象反序列化为scala类,其中一个坐标类用于存储GeoJson信息。
case class Request(name:String, geometry:Geometry)
sealed abstract class Geometry
case class Point(coordinates:(Double,Double)) extends Geometry
case class LineString(coordinates:List[Point]) extends Geometry
case class Polygon(coordinates:List[LineString]) extends Geometry
我想反序列化一个像这样的json字符串:
{
name:"test",
geometry:{
"type": "LineString",
"coordinates": [ [100.0, 0.0], [101.0, 1.0] ]
}
}
在Geometry字段中使用正确的LineString运行时类进入Request case类。我想我应该使用TypeHint但是怎么样?这是正确的方法还是应该创建三个不同的Request(RequestPoint,RequestLineString和RequestPolygon)? 这将是反序列化的Scala代码:
val json = parse(message)
json.extract[Request]
答案 0 :(得分:6)
是的,您需要对像Geometry这样的和类型使用类型提示。这是一个例子:
implicit val formats = DefaultFormats.withHints(ShortTypeHints(List(classOf[Point], classOf[LineString], classOf[Polygon])))
val r = Request("test", LineString(List(Point(100.0, 0.0), Point(101.0, 1.0))))
Serialization.write(r)
{
"name":"test",
"geometry":{
"jsonClass":"LineString",
"coordinates":[{"jsonClass":"Point","coordinates":{"_1$mcD$sp":100.0,"_2$mcD$sp":0.0}},{"jsonClass":"Point","coordinates":{"_1$mcD$sp":101.0,"_2$mcD$sp":1.0}}]}
}
不完全是你想要的。由于您要更改Points的默认序列化方案,因此需要为该类型提供自定义序列化程序。
class PointSerializer extends Serializer[Point] {
private val Class = classOf[Point]
def deserialize(implicit format: Formats) = {
case (TypeInfo(Class, _), json) => json match {
case JArray(JDouble(x) :: JDouble(y) :: Nil) => Point(x, y)
case x => throw new MappingException("Can't convert " + x + " to Point")
}
}
def serialize(implicit format: Formats) = {
case p: Point => JArray(JDouble(p.coordinates._1) :: JDouble(p.coordinates._2) :: Nil)
}
}
// Configure it
implicit val formats = DefaultFormats.withHints(ShortTypeHints(List(classOf[Point], classOf[LineString], classOf[Polygon]))) + new PointSerializer
Serialization.write(r)
{
"name":"test",
"geometry":{
"jsonClass":"LineString",
"coordinates":[[100.0,0.0],[101.0,1.0]]
}
}
更好,但如果您需要将名为'jsonClass'的默认字段更改为'type',则还需要一个配置:
implicit val formats = new DefaultFormats {
override val typeHintFieldName = "type"
override val typeHints = ShortTypeHints(List(classOf[Point], classOf[LineString], classOf[Polygon]))
} + new PointSerializer
Serialization.write(r)
{
"name":"test",
"geometry":{
"type":"LineString",
"coordinates":[[100.0,0.0],[101.0,1.0]]
}
}