具有 22 个字段但在 Scala 2.11.5 中播放 json 有问题的 Scala 案例
Scala case having 22 fields but having issue with play-json in scala 2.11.5
使用 Scala 2.11,我们可以在一个案例中拥有超过 22 个字段 class 对吗??
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]
上面是一个例子class,正好有22个字段是play-json格式,现在我编译的时候,我得到这个错误:
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]
而case class Phone和Foo,各有两个字段。
所以,为什么我实际上面临这个问题,它没有超过 22 个字段的限制,或者我做错了什么,我在 scala 2.11.5/2.11 中尝试过。 1 - 播放-json 2.3
更新:
基于 James 和 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)))
您可以拆分您的 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) }
"functional syntax" 对超过 22 个字段不起作用的原因是因为中间 classes 只定义了最多 22 个:FunctionalBuilder
完整的小例子看起来像:
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)
}
以及tryint验证的结果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())))))
如您所见,所有字段都已尝试。
或者您可以使用更多 CanBuildNN
class 来扩展游戏:https://github.com/playframework/playframework/blob/2.3.6/framework/src/play-functional/src/main/scala/play/api/libs/functional/Products.scala
但我建议您将 SomeResponse
class 中的字段分组,例如地址相关等。并手动编写 Reads
和 Writes
实例,如果 JSON 结构是扁平的且无法更改。
为了编译上面的例子,我必须明确类型:
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 }
}
使用 Scala 2.11,我们可以在一个案例中拥有超过 22 个字段 class 对吗??
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]
上面是一个例子class,正好有22个字段是play-json格式,现在我编译的时候,我得到这个错误:
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]
而case class Phone和Foo,各有两个字段。
所以,为什么我实际上面临这个问题,它没有超过 22 个字段的限制,或者我做错了什么,我在 scala 2.11.5/2.11 中尝试过。 1 - 播放-json 2.3
更新: 基于 James 和 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)))
您可以拆分您的 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) }
"functional syntax" 对超过 22 个字段不起作用的原因是因为中间 classes 只定义了最多 22 个:FunctionalBuilder
完整的小例子看起来像:
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)
}
以及tryint验证的结果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())))))
如您所见,所有字段都已尝试。
或者您可以使用更多 CanBuildNN
class 来扩展游戏:https://github.com/playframework/playframework/blob/2.3.6/framework/src/play-functional/src/main/scala/play/api/libs/functional/Products.scala
但我建议您将 SomeResponse
class 中的字段分组,例如地址相关等。并手动编写 Reads
和 Writes
实例,如果 JSON 结构是扁平的且无法更改。
为了编译上面的例子,我必须明确类型:
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 }
}