2

I inherited a legacy Scalatra application which offers a REST API. The serialisation of the returned object works perfectly if the returned object is a case class build on other case classes. But if return a object created from a Java or Scala class it is not serialised by Scalatra. I will get only the result of Object.toString(). So what do I need to do serialise also non case classes properly?

Here is my class

class Snafu(sna: String, foo: String) {
}

and this is my servlet:

class HealthServlet(implicit inj: Injector)
 extends ScalatraServlet with SLF4JLogging
 with JacksonJsonSupport
 with Injectable with InternalViaLocalhostOnlySupport {
 protected implicit val jsonFormats: Formats = DefaultFormats

 val healthStateCheck = inject[HealthStateCheck]

  before("/") {
  }

  get("/") {
    Ok(new Snafu("4", "2"))
  }
}
DeRauk
  • 373
  • 1
  • 8
Oliver
  • 3,815
  • 8
  • 35
  • 63

1 Answers1

1

Non case class serialization isn't supported by default in json4s. You'll need to add a CustomSerializer for your classes.

class IntervalSerializer extends CustomSerializer[Interval](format => (
  {
    // Deserialize
    case JObject(JField("start", JInt(s)) :: JField("end", JInt(e)) :: Nil) =>
      new Interval(s.longValue, e.longValue)
  },
  {
    // Serialize
    case x: Interval =>
      JObject(JField("start", JInt(BigInt(x.startTime))) ::
        JField("end",   JInt(BigInt(x.endTime))) :: Nil)
  }
  ))

You'll also need to add those serializers to the jsonFormats being used.

  protected implicit lazy val jsonFormats: Formats = DefaultFormats + FieldSerializer[Interval]()

Here's the example from the json4s documentation modified to show a working servlet returning serialized json from a regular class.

import org.json4s._
import org.json4s.JsonAST.{JInt, JField, JObject}
import org.scalatra.json.JacksonJsonSupport

class Interval(start: Long, end: Long) {
  val startTime = start
  val endTime = end
}

class IntervalSerializer extends CustomSerializer[Interval](format => (
  {
    // Deserialize
    case JObject(JField("start", JInt(s)) :: JField("end", JInt(e)) :: Nil) =>
      new Interval(s.longValue, e.longValue)
  },
  {
    // Serialize
    case x: Interval =>
      JObject(JField("start", JInt(BigInt(x.startTime))) ::
        JField("end",   JInt(BigInt(x.endTime))) :: Nil)
  }
  ))

class IntervalServlet extends ScalatraServlet with ScalateSupport with JacksonJsonSupport {

  get("/intervalsample") {
    contentType = "application/json"

    val interval = new Interval(1, 2)

    Extraction.decompose(interval)
  }

  protected implicit lazy val jsonFormats: Formats = DefaultFormats + FieldSerializer[Interval]()

}
DeRauk
  • 373
  • 1
  • 8