2

I have a JSON like this:

{
  "switch": "foo",
  "items": [
    {"type": "one"},
    {"type": "two"}
  ]
}

I want to load it into a structure of classes like that:

case class MyFile(
  @JsonProperty("switch") _switch: String,
  @JsonProperty("items") _items: JList[Item],
) {
  val items: List[Item] = _items.toList
}

case class Item(t: String)
object Item {
  @JsonCreator
  def create(@JsonProperty("type") _type: String): Item = {
    Item(t) // <= conversion
  }
}

The trick is that I want to do a conversion of incoming "type" string with some sort of function that will depend on the value of "switch". The simplest example would be something like

def create(@JsonProperty("type") _type: String): Item = {
  Item(t + "_" + switchValue)
}

However, I don't seem to find a way to access about parts of JSON tree while inside a parsing (i.e. in constructors or in @JsonCreator static method).

The only thing I've came with so far is basically a global variable like:

case class MyFile(
  @JsonProperty("switch") _switch: String,
  @JsonProperty("items") _items: JList[Item],
) {
  MyFile.globalSwitch = _switch
  val items: List[Item] = _items.toList
}

object MyFile {
  var globalSwitch = ""
}

case class Item(t: String)
object Item {
  @JsonCreator
  def create(@JsonProperty("type") _type: String): Item = {
    Item(t + "_" + MyFile.globalSwitch) // <= conversion
  }
}

It works, but it's obviously fairly ugly: you can't, for example, parse 2 files with different switch values in parallel, etc. Is there a better solution? For example, maybe I can access some sort of per-ObjectMapper or per-parsing context, where I can store this setting?

GreyCat
  • 16,622
  • 18
  • 74
  • 112

1 Answers1

1

I think it will help to you : https://github.com/spray/spray-json

import spray.json._
case class NamedList[A](name: String, items: List[A])
case class Item(t: String)

object MyJsonProtocol extends DefaultJsonProtocol {
  implicit def namedListFormat[A :JsonFormat] = jsonFormat2(NamedList.apply[A])
implicit val ItemDTO = jsonFormat1(Item.apply)
}
import MyJsonProtocol._
val list = NamedList[Item](name = "Alex", items = Item("Moran")::Item("Sem")::Nil)
val res = list.toJson.toString()
val parse = res.parseJson.convertTo[NamedList[Item]]

res:

   res: String = 
{
    "name":"Alex",
    "items":
    [
      {"t":"Moran"},
      {"t":"Sem"}
    ]
}

parse :

parse: NamedList[Item] = NamedList(Alex, List(Item(Moran), Item(Sem)))

Switcher can be like ~~

 implicit class Switcher[A <: Item](data: NamedList[A]){
      def getEr = data.name match{
        case "Jone" => ("It`s Jone", data)
        case "Alex" => ("It`s Alex", data)
      }
     def getErFunc[T](func : (NamedList[A], String) => T) = 
         data.name match{
           case "Jone" => ("It`s Jone", func(data , "Param"))
           case "Alex" => ("It`s Alex", func(data, "Not Param"))
  }
}

val res2 = parse.getEr
val res3 = parse.getErFunc((f, s) => (f.items.size, s.toUpperCase))

res:

res2: (String, NamedList[Item]) = 
  (It`s Alex,NamedList(Alex,List(Item(Moran), Item(Sem))))

res3: (String, (Int, String)) = (It`s Alex,(2,NOT PARAM))
  • Well, it probably won't, as actually I need Jackson to parse YAML/XML/JSON representations of the same data model. But anyway, I don't quite see a way to create custom conversion of `items` based on `switch` judging from your example. I don't see any examples like this on Github either. Could you point me in the right direction? – GreyCat Mar 10 '16 at 18:20
  • I am edited my answer. You can also see Spray Doc [link](http://spray.io/) and Scala Future [link](http://docs.scala-lang.org/overviews/core/futures.html) it's more than enough – Александр Третьяк Mar 10 '16 at 21:41
  • So, basically, you suggest to just convert whole tree *after* parsing? If so, then it doesn't really matter which parsing engine one uses — it's definitely possible, but I think in practice it would be a lot more complicated than "ugly" solution with global variable (and I won't even dare to think of stuff like nice error messages and such UX here). – GreyCat Mar 10 '16 at 22:08