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

1 Answer 1

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]()

}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.