score:25
here is a manual implementation of the foo
companion object:
implicit val barfmt = json.format[bar]
implicit val bazfmt = json.format[baz]
object foo {
def unapply(foo: foo): option[(string, jsvalue)] = {
val (prod: product, sub) = foo match {
case b: bar => (b, json.tojson(b)(barfmt))
case b: baz => (b, json.tojson(b)(bazfmt))
}
some(prod.productprefix -> sub)
}
def apply(`class`: string, data: jsvalue): foo = {
(`class` match {
case "bar" => json.fromjson[bar](data)(barfmt)
case "baz" => json.fromjson[baz](data)(bazfmt)
}).get
}
}
sealed trait foo
case class bar(i: int ) extends foo
case class baz(f: float) extends foo
implicit val foofmt = json.format[foo] // ça marche!
verification:
val in: foo = bar(33)
val js = json.tojson(in)
println(json.prettyprint(js))
val out = json.fromjson[foo](js).getorelse(sys.error("oh no!"))
assert(in == out)
alternatively the direct format definition:
implicit val foofmt: format[foo] = new format[foo] {
def reads(json: jsvalue): jsresult[foo] = json match {
case jsobject(seq(("class", jsstring(name)), ("data", data))) =>
name match {
case "bar" => json.fromjson[bar](data)(barfmt)
case "baz" => json.fromjson[baz](data)(bazfmt)
case _ => jserror(s"unknown class '$name'")
}
case _ => jserror(s"unexpected json value $json")
}
def writes(foo: foo): jsvalue = {
val (prod: product, sub) = foo match {
case b: bar => (b, json.tojson(b)(barfmt))
case b: baz => (b, json.tojson(b)(bazfmt))
}
jsobject(seq("class" -> jsstring(prod.productprefix), "data" -> sub))
}
}
now ideally i would like to automatically generate the apply
and unapply
methods. it seems i will need to use either reflection or dive into macros.
score:4
a small fix for the previous answer by 0__ regarding the direct format definition - the reads method didn't work, and here is my refactor to it, to also become more idiomatic -
def reads(json: jsvalue): jsresult[foo] = {
def from(name: string, data: jsobject): jsresult[foo] = name match {
case "bar" => json.fromjson[bar](data)(barfmt)
case "baz" => json.fromjson[baz](data)(bazfmt)
case _ => jserror(s"unknown class '$name'")
}
for {
name <- (json \ "class").validate[string]
data <- (json \ "data").validate[jsobject]
result <- from(name, data)
} yield result
}
score:6
play 2.7
sealed traits
are supported in play-json
.
object foo{
implicit val format = json.format[foo]
}
play 2.6
this can be done now elegantly with play-json-derived-codecs
just add this:
object foo{
implicit val jsonformat: oformat[foo] = derived.oformat[foo]()
}
see here for the whole example: scalafiddle
score:26
amended 2015-09-22
the library play-json-extra includes the play-json-variants strategy, but also the [play-json-extensions] strategy (flat string for case objects mixed with objects for case classes no extra $variant or $type unless needed). it also provides serializers and deserializers for macramé based enums.
previous answer there is now a library called play-json-variants which allows you to write :
implicit val format: format[foo] = variants.format[foo]
this will generate the corresponding formats automatically, it will also handle disambiguation of the following case by adding a $variant attribute (the equivalent of 0__ 's class
attribute)
sealed trait foo
case class bar(x: int) extends foo
case class baz(s: string) extends foo
case class bah(s: string) extends foo
would generate
val bahjson = json.obj("s" -> "hello", "$variant" -> "bah") // this is a `bah`
val bazjson = json.obj("s" -> "bye", "$variant" -> "baz") // this is a `baz`
val barjson = json.obj("x" -> "42", "$variant" -> "bar") // and this is a `bar`
Source: stackoverflow.com
Related Query
- Noise free JSON format for sealed traits with Play 2.2 library
- Json Serialization for Trait with Multiple Case Classes (Sum Types) in Scala's Play
- How do I write a JSON Format for an object in the Java library that doesn't have an apply method?
- Play Scala No Json deserializer found for type (String, String). Try to implement an implicit Reads or Format for this type
- How to write a Play JSON writes converter for a case class with a single nullable member
- Play Framework JSON Format for Case Objects
- Play / Scala JSON Format for Either
- Play json merge formats for case class with more than 22 fields
- Providing implicit value for singletons in Play Json library
- Format nullable Seq or List of objects with Play Json and Salat
- Scala Play Json Format for Map[Locale, String]
- Scala Play - How to format Generics for JSON conversion
- How to define a JSON format for an object with nested generic types?
- Scala Play Framework 2.6 sealed trait format to Json
- How to write a symmetric Play Json formatter for a case class with one field in scala?
- Play JSON with sealed trait / case classes: infinite recursion
- JSON format for Generics in Play 2.x
- Play JSON formatter for case class with generic type classes
- Building a Json Format for a Case Class with Abstract Members
- Serialisation/deserialisation for sealed traits with Upickle
- Writes for JSON views with more than 21 fields in Play 2.3
- custom format in JSON for DateTimeField with mongorecord
- Deserialize multi JSON string with Play JSON library
- Json format with Play 2.4 / Scala
- Looking for a clean solution to validate the input in json with play framework
- Play 2.1 Scala - JSON - Symmetric Format object with nested data structure not serializing correctly
- Compile error with Tagged Type and Play Json Format typeclass derivation
- getting serealizing case class with play json library
- How do I create a JSON format for Map[Int, Int] using Play Framework JSON libs?
- scala read/write format for json with Type
More Query from same tag
- Webservice call in Play2 Scala
- Spark 1.3.1 install failed in MLlib when I run make-distribution.sh in Ubuntu 14.04
- Calling method based on json object parameter in Spark scala?
- Problem with Actors and Networking
- Scala Map merge and sum the value when the key is same
- Space between elements inside BoxPanel in scala Swing
- Multiple ResultSets were returned by the query Exception
- how to write a method correctly that returns a given array
- How to do Groupby and map in one go in python just like we do in scala
- How does PartialFunction deal with undefined values in Scala?
- How to decode HTML entities in Spark-scala?
- Spray: factor out onSuccess directive
- Why the scala actor message queue have no bound(size)
- RDD[Array[String]] to Dataframe
- How to return prevent entity escapes from returning in Play?
- How to compute a value to pass into a primary constructor from an auxiliary constructor?
- Scala: Using the App trait
- How to obfuscate fat Scala Jar with Proguard and SBT
- C# dotnet "Require" and Assertions
- Upper Triangular Matrix in Scala
- Spark jdbc read performance tuning with no primary key column
- The <<= operator in SBT Explained
- Dependency Injection in Scala Guice - Passing Parameters
- Unable to create nested object from three level mappings in Scala
- Input array in scala
- Why type equality check with implicitly fails?
- Can't run Play in dev mode under Ubuntu
- Reading Nested data from ElasticSearch via Spark Scala
- String passed to Class appear null
- Spark, keeping state information through CollectionAccumulator[int]