문제

Given lift-json 2.0 and the following Scala classes & sealed trait:

sealed trait Location

case class Coordinate(latitude: Double,
                      longitude: Double) extends Location

case class Address(...) extends Location

I'd like to be able to deserialize a Location object without determining the concrete implementation:

deserialize[Location](""" { "latitude":0.0, "longitude":0.0 } """)

should produce the equivalent of:

val location: Location = Coordinate(0.0, 0.0)

Any way of doing this?

도움이 되었습니까?

해결책

This may not be what you want, but with:

implicit val formats = net.liftweb.json.DefaultFormats
  .withHints(ShortTypeHints(List(classOf[Geo], classOf[Address])))

enables you to write

val loc: Location = read(write(Geo(0.0, 0.0)))

However your json then gets a TypeHint:

{"jsonClass":"Geo","latitude":0.0,"longitude":0.0}

This formats can be played with somewhat, here is a nice post about type hints.

다른 팁

Lift-Json won't automatically detect a subclass to deserialize to because there is no straight forward way to do that. You might have 2 subclasses of Location that accept latitude and longitude constructor parameters, or some other ambiguity.

Type hints are definitely one way to go. If you don't want to muddy up your JSON with scala specific info though, you can also deserialize the string representation to a JValue, then inspect the structure to determine which class to bind to.

def location(str: String): Location = {
  val jv = JsonParser.parse(string)
  jv match {
     case jo: JObject if jo.children.size == 2 => Extraction.extract[Coordninate](jo)
     case _ => Extraction.extract[Address](jv)
  }
}

If you can't choose your type based on arity, that would be more complicated, but you get the general idea.

@"Dave Whittaker" and @"Rin malavi" are right in general. Also, if you want a temporary solution, you may use:

str.extractOpt[Address] getOrElse str.extract[Coordinate]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top