Search code examples
jsonscalaserializationscala-pickling

remove tpe from json after serialization via scala-pickling


Is there an easy way to serialize to json without "tpe" field inside an object? I need to serialize case classes to json structures and then, send them over the wire (They won't been deserialized in future). I have a specific api, so.. I don't need additional fields.

For class Person illustrated below:

case class Person(Name: String, Age: int, CandyLover: Boolean)

I'd like to see following:

{
  "Name": "Paul",
  "Age": 23,
  "CandyLover": true
}

Solution

  • Probably the simplest way to do it is to pass somehow the Hint into JSONPickleBuilder. Quick way to do it is to override builders in JSONPickleFormat by calling hintStaticallyElidedType() method from PickleTools.

    Here is kind of code snippet to demonstrate it:

    import org.specs2.matcher.JsonMatchers
    import org.specs2.mutable.Specification
    import org.specs2.specification.Scope
    
    import scala.pickling.Defaults._
    import scala.pickling.json.{JSONPickleBuilder, JSONPickleFormat, JsonFormats}
    import scala.pickling.{Output, PBuilder, PickleTools, StringOutput}
    
    class PersonJsonFormatsTest extends Specification with JsonMatchers {
      trait Context extends Scope with PersonJsonFormats
    
      trait PersonJsonFormats extends JsonFormats {
        override implicit val pickleFormat: JSONPickleFormat = new PersonJSONPickleFormat
      }
    
      class PersonJSONPickleFormat extends JSONPickleFormat {
        override def createBuilder() = new JSONPickleBuilder(this, new StringOutput) with PickleTools {
          hintStaticallyElidedType()
        }
        override def createBuilder(out: Output[String]): PBuilder = new JSONPickleBuilder(this, out) with PickleTools {
          hintStaticallyElidedType()
        }
      }
    
      "Pickle" should {
        "Serialize Person without $type field in resulting JSON" in new Context {
          case class Person(Name: String, Age: Int, CandyLover: Boolean)
    
          val pickledPersonObject = Person("Paul", 23, CandyLover = true).pickle
          println(pickledPersonObject.value)
          pickledPersonObject.value must not */("$type" → ".*".r)
        }
      }
    }
    

    The output of println(pickledPersonObject.value) will be as you need:

    {
      "Name": "Paul",
      "Age": 23,
      "CandyLover": true
    }
    

    This way you will stay aligned with further pickle updates.

    P.S. If someone knows more elegant and convenient way to reach the same behaviour - please let us know :-)