7

GeoJson情報を格納するために内部に座標クラスを使用して、Lift-Jsonを使用してjsonオブジェクトをscalaクラスに自動的に逆シリアル化しようとしています。

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 ケース クラスに変換します。TypeHint を使用する必要があると思いますが、どうすればよいでしょうか。これは正しいアプローチですか、それとも 3 つの異なるリクエスト (RequestPoint、RequestLineString、RequestPolygon) を作成する必要がありますか? これは逆シリアル化する Scala コードです。

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

1 に答える 1

7

はい、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}}]}
}

あなたが望んでいたものではありません。ポイントのデフォルトのシリアライゼーション スキームを変更したいので、そのタイプのカスタム シリアライザーを提供する必要があります。

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」に変更する必要がある場合は、もう 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]]
  }
}
于 2011-09-23T08:55:17.177 に答える