2011-09-23 53 views
6

我试图使用Lift-Json和内部用于存储GeoJson信息的坐标类自动将json对象反序列化为scala类。组合类中的多态lift-json反序列化

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] ] 
    } 
} 

与在几何场右侧线段形式运行时类请求的情况下类。我想我应该使用TypeHint,但是如何?这是正确的方法,还是应该创建三个不同的请求(RequestPoint,RequestLineString和RequestPolygon)? 这将是Scala代码反序列化:

val json = parse(message) 
json.extract[Request] 

回答

6

是的,你需要使用类型的提示和类型,如几何。这里有一个例子:

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”到“型”的缺省领域:

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]] 
    } 
}