Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
378 views
in Technique[技术] by (71.8m points)

playframework - Scala case having 22 fields but having issue with play-json in scala 2.11.5

With Scala 2.11, we are allowed to have more then 22 fields in a case class right??

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]

Well the above is a case class which has exactly 22 fields with the play-json format, now when I compile, I get this 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]

And the case class Phone and Foo, each have two fields each.

So, why am I actually facing the issue, it doesn't cross the 22 fields limit or is there something else I did wrong, and I tried it in scala 2.11.5/2.11.1 - play-json 2.3

Update: Based on answers by James and 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)))
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can split your Reads definition:

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

The reason why "functional syntax" doesn't work for more than 22 fields is because there are intermediate classes defined only up to 22: FunctionalBuilder


Fully written out for small example it would look like:

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

And the result of tryint to validate 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())))))

As you can see, all fields are tried.


Or you could extend play with even more CanBuildNN classes: https://github.com/playframework/playframework/blob/2.3.6/framework/src/play-functional/src/main/scala/play/api/libs/functional/Products.scala


Yet I'd advice you to group fields in the SomeResponse class, for example address related etc. And write Reads and Writes instances by hand, if the JSON structure is flat and cannot be changed.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...