Search code examples
jsonscalascalatrajson4s

How to serialize object type to JSON in Scalatra?


I am a newbie in Scalatra. I have a servlet with JacksonJsonSupport which serves REST endpoint with list of objects.

class OperationsController extends MyappStack with JacksonJsonSupport {

  before() {
    contentType = formats("json")
  }

  get("/") {
    Data.operations
  }
}

The Operation is implemented by either Adding or Removing case classes. How do I add to the GET / response the specific class to the value? I would like to get as a response:

[
  {
     "operation": "Adding",
     "value": 100
  }
]

Instead of

[
  {
     "value": 100
  }
]

Where Adding is a class that extends Operation.


Solution

  • For polymorphic values json4s can add the concrete type as an additional field. This is called a "type hint":

    [{
        "jsonClass": "Adding",
        "value": 10
    }, {
        "jsonClass": "Adding",
        "value": 20
    }, {
        "jsonClass": "Removing",
        "value": 20
    }]
    

    This is for example using the ShortTypeHints:

    import org.json4s.{ShortTypeHints, DefaultFormats}
    import org.scalatra.ScalatraServlet
    import org.scalatra.json.JacksonJsonSupport
    import org.scalatra.test.specs2.MutableScalatraSpec
    
    sealed trait Operation
    case class Adding(value: Int) extends Operation
    case class Removing(value: Int) extends Operation
    
    class json1 extends MutableScalatraSpec {
    
      mount(new ScalatraServlet with JacksonJsonSupport {
    
        def typeHints = new ShortTypeHints(List(
          classOf[Adding], classOf[Removing]
        ))
    
        implicit lazy val jsonFormats = DefaultFormats + typeHints
    
        before() {
          contentType = formats("json")
        }
    
        get("/") {
          List(
            Adding(10),
            Adding(20),
            Removing(20)
          )
        }
    
      }, "/*")
    
      "Should return a list of operations" in {
    
        get("/", headers = Seq("Content-type" -> "application/json")) {
          println(body)
          status should beEqualTo(200)
        }
    
      }
    
    }