Polymerization of Liftinson Deserialization in a Complex Class

I am trying to automatically deserialize a json object to a scala class using Lift-Json with the coordinate class inside used to store GeoJson information.

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 

I want to deserialize a json string as follows:

 { name:"test", geometry:{ "type": "LineString", "coordinates": [ [100.0, 0.0], [101.0, 1.0] ] } } 

to the case class of the request with the correct LineString time class in the Geometry field. I think I should use TypeHint, but how ?. Is this the right approach or should I create three different requests (RequestPoint, RequestLineString and RequestPolygon)? This will be the scala code for deserialization:

 val json = parse(message) json.extract[Request] 
+6
source share
1 answer

Yes, you need to use type hints for sum types such as Geometry. Here is one example:

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

Not exactly what you wanted. Since you want to change the default serialization scheme for Points, you need to provide your own serializer for this type.

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

Better, but you need one more configuration if you need to change the default field named "jsonClass" to "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]] } } 
+6
source

Source: https://habr.com/ru/post/897884/


All Articles