2011-09-23 54 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]] 
    } 
}