Git Product home page Git Product logo

play-json-extensions's Introduction

Play-Json extensions

installation

Add this to your build.sbt:

libraryDependencies += "ai.x" %% "play-json-extensions" % "0.42.0"

latest versions

Play-json Scala group id latest version
2.8.x 2.12, 2.13 ai.x 0.42.0
2.7.x 2.11, 2.12, 2.13 ai.x 0.40.2
2.5.x 2.11 ai.x 0.9.0
2.4.x 2.11 org.cvogt 0.6.1
2.3.x 2.11 org.cvogt 0.2

all versions and scaladoc

0.40 - latest

0.9 - 0.30

0.1 - 0.8

De-/Serialize case classes of arbitrary size (23+ fields allowed)

    case class Foo(
      _1:Int,_2:Int,_3:Int,_4:Int,_5:Int,
      _21:Int,_22:Int,_23:Int,_24:Int,_25:Int,
      _31:Int,_32:Int,_33:Int,_34:Int,_35:Int,
      _41:Int,_42:Int,_43:Int,_44:Int,_45:Int,
      _51:Int,_52:Int,_53:Int,_54:Int,_55:Int
    )

    val foo = Foo(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5)

Create explicit formatter

    import ai.x.play.json.Jsonx
    implicit lazy val jsonFormat = Jsonx.formatCaseClass[Foo]

    // if your case class uses Option make sure you import
    // one of the below implicit Option Reads to avoid
    // "could not find implicit value for parameter helper: ai.x.play.json.OptionValidationDispatcher"

    // note: formatCaseClass catches IllegalArgumentException and turns them into JsError enclosing the stack trace as the message
    // this allows using require(...) in class constructors and still get JsErrors out of serialization

Then use ordinary play-json

    val json = Json.toJson( foo )
    assert(foo == json.as[Foo])

deserialization uses default values

    case class Bar(s: String, i: Int = 6)
    implicit lazy val format = Jsonx.formatCaseClassUseDefaults[Bar]
    assert(Bar("asd",6) == Json.parse("""{"s":"asd"}""").validate[Bar].get)

De-/Serialize tuples

    import ai.x.play.json.tuples._
    val json = Json.parse("""[1,1.0,"Test"]""")
    val res = Json.fromJson[(Int,Double,String)](json)
    assert(JsSuccess((1,1.0,"Test")) === res)

De-/Serialize single value classes

    case class Foo(i: Int)
    val json = Json.parse("1")
    val res = Json.fromJson[Foo](json)
    assert(JsSuccess(Foo(1)) === res)

Option for play-json 2.4

implicit Option Reads

    import ai.x.play.json.implicits.optionWithNull // play 2.4 suggested behavior
    // or
    import ai.x.play.json.implicits.optionNoError // play 2.3 behavior

automatic option validation: validateAuto

    val json = (Json.parse("""{}""") \ "s")
    json.validateAuto[Option[String]] == JsResult(None) // works as expected correctly

    // play-json built-ins
    json.validate[Option[String]] // JsError: "'s' is undefined on object: {}"
    json.validateOpt[String] == JsResult(None) // manual alternative (provided here, built-into play-json >= 2.4.2)

automatic formatting of sealed traits, delegating to formatters of the subclasses

formatSealed uses orElse of subclass Reads in random order, careful in case of ambiguities of field-class correspondances

    sealed trait SomeAdt
    case object A extends SomeAdt
    final case class X(i: Int, s: String) extends SomeAdt
    object X{
      implicit lazy val jsonFormat: Format[X] = Jsonx.formatCaseClass[X]
    }
    object SomeAdt{
      import ai.x.play.json.SingletonEncoder.simpleName  // required for formatSingleton
      import ai.x.play.json.implicits.formatSingleton    // required if trait has object children
      implicit lazy val jsonFormat: Format[SomeAdt] = Jsonx.formatSealed[SomeAdt]
    }

    Json.parse("""A""").as[SomeAdt] == A
    Json.parse("""{"i": 5, "s":"foo", "type": "X"}""").as[SomeAdt] == X(5,"foo")

formatSealedWithFallback[A,B <: A] is like formatSealed but provides a fallback for unknown cases.

It makes sure the class B is tried last, which allows it to be permissive enough for a fallback.

This allows graceful schema evolution without breaking old readers. Example:

    sealed trait SomeAdt
    final case class X(i: Int, s: String) extends SomeAdt
    final case class Unknown(json: JsValue) extends SomeAdt
    object SomeAdt{
      implicit lazy val jsonFormat: Format[SomeAdt] = {
        implicit lazy val XFormat: Format[X] = Jsonx.formatCaseClass[X]
        implicit lazy val UnknownFormat: Format[Unknown] = Jsonx.formatInline[Unknown]
        Jsonx.formatSealedWithFallback[SomeAdt]
      }
    }

    Json.parse("""{"i": 5, "s":"foo", "type": "X"}""").as[SomeAdt] == X(5,"foo")
    val unknownJson = Json.parse("""{"x":"y"}""")
    unknownJson.as[Unknown] == Unknown(unknownJson)

formatSealedWithFallback[A,B <: A] is like formatSealed but provides a fallback for unknown cases.

It makes sure the class B is tried last, which allows it to be permissive enough for a fallback.

This allows graceful schema evolution without breaking old readers. Example:

    sealed trait SomeAdt
    final case class X(i: Int, s: String) extends SomeAdt
    final case class Unknown(json: JsValue) extends SomeAdt
    object SomeAdt{
      implicit lazy val jsonFormat: Format[SomeAdt] = {
        implicit lazy val XFormat: Format[X] = Jsonx.formatCaseClass[X]
        implicit lazy val UnknownFormat: Format[Unknown] = Jsonx.formatInline[Unknown]
        Jsonx.formatSealedWithFallback[SomeAdt]
      }
    }

    Json.parse("""{"i": 5, "s":"foo", "type": "X"}""").as[SomeAdt] == X(5,"foo")
    val unknownJson = Json.parse("""{"x":"y"}""")
    unknownJson.as[Unknown] == Unknown(unknownJson)

experimental features (will change)

Serialization nirvana - formatAuto FULLY automatic de-serializer (note: needs more optimized internal implementation)

    sealed trait SomeAdt
    case object A extends SomeAdt
    final case class X(i: Int, s: String) extends SomeAdt
    object Baz
    case class Bar(a: Int, b:Float, foo: Baz.type, o: Option[Int])
    case class Foo(_1:Bar,_11:SomeAdt, _2:String,_3:Int,_4:Int,_5:Int,_21:Int,_22:Int,_23:Int,_24:Int,_25:Int,_31:Int,_32:Int,_33:Int,_34:Int,_35:Int,_41:Int,_42:Int,_43:Int,_44:Int,_45:Int,_51:Int,_52:Int,_53:Int,_54:Int,_55:Int)
    val foo = Foo(Bar(5,1.0f, Baz, Some(4): Option[Int]),A,"sdf",3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5)
    val foo2 = Foo(Bar(5,1.0f, Baz, None: Option[Int]),X(5,"x"),"sdf",3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5)
    
    import ai.x.play.json.implicits.optionWithNull
    val fmt2: Format[Foo] = Jsonx.formatAuto[Foo] // not implicit to avoid infinite recursion

    {
      implicit lazy val fmt3: Format[Foo] = fmt2    
      val json = Json.toJson( foo )
      assert(foo === json.as[Foo])
      val json2 = Json.toJson( foo2 )
      assert(foo2 === json2.as[Foo])
    }

play-json-extensions's People

Contributors

cvogt avatar caente avatar jtjeferreira avatar xuwei-k avatar sullis avatar clamothe avatar rcoh avatar joprice avatar mtsokol avatar pedrofurla avatar rogach avatar ntbrock avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.