2011-09-23 8 views
6

GeoJson情報を格納するために使用される座標クラスを持つLift-Jsonを使用してjsonオブジェクトをスカラークラスに自動的に逆シリアル化しようとしています。複合クラス内の多態リフト・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を使うべきだと思いますが、どうですか?これは正しいアプローチですか、3つの異なるRequest(RequestPoint、RequestLineString、RequestPolygon)を作成する必要がありますか? これはScalaのコードをデシリアライズするために次のようになります。

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

答えて

6

はい、あなたはジオメトリのような和型の型ヒントを使用する必要があります。ここに1つの例があります:

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

Pointのデフォルトのシリアル化スキームを変更したいので、そのタイプのカスタムシリアライザを用意する必要があります。

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」と名付けデフォルトのフィールドを変更する必要がある場合は、1より多くの設定が必要になります。

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]] 
    } 
} 
関連する問題