scala playframework playframework-2.3

Caso Scala tiene 22 campos pero tiene problemas con play-json en scala 2.11.5



playframework playframework-2.3 (2)

Con Scala 2.11, podemos tener más de 22 campos en una clase de caso, ¿no?

case class SomeResponse( var compositeKey: String, var id1: String, var id2: String, var firstName: String, var lastName: String, var email: String, var email2: String, var birth: Long, var gender: String, var phone: Phone, var city: String, var zip: String, var carriage: Boolean, var carriage2: Boolean, var fooLong: Long, var fooLong2: Long, var suspended: Boolean, var foo: Foo, var address: String, var suite: String, var state: String, var instructions: String) implicit val formatSomeResponse = Json.format[SomeResponse]

Bueno, lo anterior es una clase de caso que tiene exactamente 22 campos con el formato play-json, ahora cuando compilo, recibo este error:

SomeFile.scala:126: value apply is not a member of play.api.libs.functional.FunctionalBuilder[play.api.libs.json.OFormat]#CanBuild22[String,String,String,String,String,String,String,Long,String,com.Phone,String,String,Boolean,Boolean,Long,Long,Boolean,com.Foo,String,String,String,String]

Y la clase de casos Phone y Foo, cada uno tiene dos campos cada uno.

Entonces, ¿por qué me enfrento al problema? No cruza el límite de 22 campos o hay algo más que hice mal, y lo intenté en la Scala 2.11.5 / 2.11.1 - play-json 2.3

Actualización: Basado en las respuestas de James y Phadej

val someResponseFirstFormat: OFormat[(String, String, String, String, String, String, String, Long, String, Phone, String)] = ((__ / "compositeKey").format[String] and (__ / "id1").format[String] and (__ / "id2").format[String] and (__ / "firstName").format[String] and (__ / "lastName").format[String] and (__ / "email").format[String] and (__ / "email2").format[String] and (__ / "birth").format[Long] and (__ / "gender").format[String] and (__ / "phone").format[Phone] and (__ / "city").format[String]).tupled val someResponseSecondFormat: OFormat[(String, Boolean, Boolean, Long, Long, Boolean, Foo, String, String, String, String)] = ((__ / "zip").format[String] and (__ / "carriage").format[Boolean] and (__ / "carriage2").format[Boolean] and (__ / "fooLong").format[Long] and (__ / "fooLong2").format[Long] and (__ / "suspended").format[Boolean] and (__ / "foo").format[Foo] and (__ / "address").format[String] and (__ / "suite").format[String] and (__ / "country").format[String] and (__ / "instructions").format[String]).tupled implicit val formatSome: Format[SomeResponse] = ( someResponseFirstFormat and someResponseSecondFormat ).apply({ case ((compositeKey, id1, id2, firstName, lastName, email, email2, birth, gender, phone, city), (zip, carriage, carriage2, created, updated, suspended, foo, address, suite, country, instructions)) => SomeResponse(compositeKey, id1, id2, firstName, lastName, email, email2, birth, gender, phone, city, zip, carriage, carriage2, created, updated, suspended, location, address, suite, country, instructions) }, huge => ((huge.compositeKey, huge.id1, huge.id2, huge.firstName, huge.lastName, huge.email, huge.email2, huge.birth, huge.gender, huge.phone, huge.city), (huge.zip, huge.carriage, huge.carriage2, huge.created, huge.updated, huge.suspended, huge.foo, huge.address, huge.suite, huge.country, huge.instructions)))


Para hacer el ejemplo anterior compilar, tuve que hacer el tipo explícito:

import play.api.libs.json._ import play.api.libs.functional.syntax._ // Let''s pretend this is huge: case class Huge(a: Int, b: String, c: Boolean, d: List[Int]) object Huge { val fields1to2: Reads[(Int, String)] = ( (__ / "a").read[Int] and (__ / "b").read[String] ).tupled val fields3to4: Reads[(Boolean, List[Int])] = ( (__ / "c").read[Boolean] and (__ / "d").read[List[Int]] ).tupled val f: ((Int, String), (Boolean, List[Int])) => Huge = { case ((a, b), (c, d)) => Huge(a, b, c, d) } implicit val hugeCaseClassReads: Reads[Huge] = ( fields1to2 and fields3to4 ) { f } }


Puedes dividir la definición de tus Reads :

val fields1to10: Reads[(A,B,C,D,E,F,G,H,I,J)] = ??? val fields11to20 = ??? val fields21to30 = ??? implicit val hugeCaseClassReads: Reads[HugeCaseClass] = ( fields1to10 and fields11to20 and fields21to30 ) { a, b, c => createHugeCaseClassFromThreeTuples(a, b, c) }

La razón por la que la "sintaxis funcional" no funciona para más de 22 campos es porque hay clases intermedias definidas solo hasta 22: FunctionalBuilder

Completamente escrito para un pequeño ejemplo, se vería así:

import play.api.libs.json._ import play.api.libs.functional.syntax._ // Let''s pretend this is huge: case class Huge(a: Int, b: String, c: Boolean, d: List[Int]) val fields1to2: Reads[(Int, String)] = ( (__ / "a").read[Int] and (__ / "b").read[String] ).tupled val fields3to4: Reads[(Boolean, List[Int])] = ( (__ / "c").read[Boolean] and (__ / "d").read[List[Int]] ).tupled implicit val hugeCaseClassReads: Reads[Huge] = ( fields1to2 and fields3to4 ) { case ((a, b), (c, d)) => Huge(a, b, c, d) }

Y el resultado de tryint para validar null :

scala> JsNull.validate[Huge] res6: play.api.libs.json.JsResult[Huge] = JsError( List( (/b,List(ValidationError(error.path.missing,WrappedArray()))), (/d,List(ValidationError(error.path.missing,WrappedArray()))), (/c,List(ValidationError(error.path.missing,WrappedArray()))), (/a,List(ValidationError(error.path.missing,WrappedArray())))))

Como se puede ver, todos los campos son probados.

O podría extender el juego con más clases de CanBuildNN : https://github.com/playframework/playframework/blob/2.3.6/framework/src/play-functional/src/main/scala/play/api/libs/functional/Products.scala

Sin embargo, le aconsejo que SomeResponse los campos en la clase SomeResponse , por ejemplo, relacionados con la dirección, etc. Y escriba las instancias de Reads y Writes mano, si la estructura JSON es plana y no se puede cambiar.