Dariusz Mydlarz
Dariusz Mydlarz

Reputation: 3002

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.

Upvotes: 1

Views: 1736

Answers (3)

KARTHIKEYAN.A
KARTHIKEYAN.A

Reputation: 20088

json_conversion.scala file we created the trait SimpleMongoDbJsonConversion and we use this in MyScalatraServlet.scala file, see the example below.

json_conversion.scala

package com.example.app

import org.scalatra._
import com.mongodb.casbah.Imports._

trait SimpleMongoDbJsonConversion extends ScalatraBase with ApiFormats {

  def renderMongo = {
    case dbo: DBObject =>
      contentType = formats("json")
      dbo.toString

    case xs: TraversableOnce[_] =>
      contentType = formats("json")
      val l = xs map (x => x.toString) mkString(",")
      "[" + l + "]"

  }: RenderPipeline

  override protected def renderPipeline = renderMongo orElse super.renderPipeline

}

MyScalatraServlet.scala

package com.example.app

import org.scalatra._
import com.mongodb.casbah.Imports._

class MyScalatraMongoServlet(mongoColl: MongoCollection) extends MyScalatraWebAppStack with SimpleMongoDbJsonConversion {

  get("/") {
    <html>
      <body>
        <h1>Hello, world!</h1>
        Say <a href="hello-scalate">hello to Scalate</a>.
      </body>
    </html>
  }

  post("/insert") {
    val key = params("key")
    val value = params("value")
    val newObj = MongoDBObject(key->value)
    mongoColl += newObj
  }

  get("/users") {
    mongoColl.find()
    for { x <- mongoColl } yield x
  }

}

Upvotes: 0

Stefan Ollinger
Stefan Ollinger

Reputation: 1587

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

  }

}

Upvotes: 1

Dmitry  Meshkov
Dmitry Meshkov

Reputation: 931

I think, that the easiest way is to update your case classes like

case class Adding(value: Int, operation: String = "Adding") 
case class Removing (value: Int, operation: String = "Removing") 

Another way is to update your jsonFormats with custom serializer, I found example of jsons custom serialization here

Upvotes: 1

Related Questions