All Projects → bizzabo → play-json-extensions

bizzabo / play-json-extensions

Licence: other
+22 field case class formatter and more for play-json

Programming Languages

scala
5932 projects
shell
77523 projects

Projects that are alternatives of or similar to play-json-extensions

diff
Visually compare Scala data structures with out of the box support for arbitrary case classes.
Stars: ✭ 179 (-7.25%)
Mutual labels:  backend, rnd, xdotai
typeless
running wild with shapeless
Stars: ✭ 16 (-91.71%)
Mutual labels:  backend, rnd, xdotai
deno-pokemon
a simple api to create and explore pokemons - made with oak deno framework
Stars: ✭ 20 (-89.64%)
Mutual labels:  backend
Car-Rental-Project
A car rental project developed with ASP.Net Core & Angular.
Stars: ✭ 90 (-53.37%)
Mutual labels:  backend
testnet.backend
Backend for a ViaBTC exchange server (trading engine)
Stars: ✭ 18 (-90.67%)
Mutual labels:  backend
awesome-backend
Curadoria de conteúdos relacionados à backend.
Stars: ✭ 158 (-18.13%)
Mutual labels:  backend
ex syslogger
ExSyslogger is an Elixir Logger custom backend to syslog.
Stars: ✭ 13 (-93.26%)
Mutual labels:  backend
Trybe-School
All activities while studying at Trybe fullstack software development school. Contains: projects, exercises, course summaries. Brazil, 2020-2021.
Stars: ✭ 73 (-62.18%)
Mutual labels:  backend
backend-best-practices
Backend uygulamaları geliştirirken dikkate alınabilecek örnek yöntemlerin derlendiği güncellenen bir kaynak.
Stars: ✭ 80 (-58.55%)
Mutual labels:  backend
pinterest-backend
Pinterest Clone Backend in Phoenix Framework
Stars: ✭ 19 (-90.16%)
Mutual labels:  backend
simplQ-backend
SimplQ backend, written in Java for AWS
Stars: ✭ 17 (-91.19%)
Mutual labels:  backend
fotongo
Simple boilerplate for building Backend services like ExpressJS with GOFIBER ⚡️
Stars: ✭ 29 (-84.97%)
Mutual labels:  backend
smartsla-backend
Backend module for SmartSLA
Stars: ✭ 22 (-88.6%)
Mutual labels:  backend
kwang
High Performance Kotlin Native Web Framework based on Lwan
Stars: ✭ 59 (-69.43%)
Mutual labels:  backend
parse-react
[EXPERIMENTAL] React, React Native, and React with SSR (e.g. Next.js) packages to interact with Parse Server backend
Stars: ✭ 58 (-69.95%)
Mutual labels:  backend
minecraftrs
A rusty Minecraft backend. Aims to split core structures from vanilla definitions, allowing you to define your own set of blocks, biomes or entities instead of vanilla ones.
Stars: ✭ 16 (-91.71%)
Mutual labels:  backend
content defender
Define allowed or denied content element types in your backend layouts
Stars: ✭ 63 (-67.36%)
Mutual labels:  backend
juice
Java后端开发库,涵盖:常用工具类、SPI扩展、分布式锁、限流、分布式链路追踪等。
Stars: ✭ 32 (-83.42%)
Mutual labels:  backend
Proxy
The type-safe REST library for .NET Standard 2.0 (NetCoreStack Flying Proxy)
Stars: ✭ 40 (-79.27%)
Mutual labels:  backend
Magento2 NewsletterSubscribeAtCheckout
This Magento 2 module allows you to enable a newsletter subscription checkbox on the checkout page.
Stars: ✭ 13 (-93.26%)
Mutual labels:  backend

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])
    }
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].