You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Scala 2.12.4+Play2.6.3如何映射超22个键的JSON到样例类?

Hey there! The issue you're hitting is because Scala's default case classes have a 22-parameter limit (tied to the maximum arity of tuples, which Play JSON's macro uses under the hood). For your Person case class with 23 fields, here are three solid solutions tailored to Play 2.6.3 and Scala 2.12.4:

The cleanest approach is to group related fields into smaller case classes to stay under the 22-parameter limit. For your example, all those name* fields can live in a dedicated class:

case class Hobby(id: Int, name: String)
case class NameGroup(
  name: String,
  name1: String,
  name2: String,
  name3: String,
  name4: String,
  name5: String,
  name6: String,
  name7: String,
  name8: String,
  name9: String,
  name10: String,
  name11: String,
  name12: String,
  name13: String,
  name14: String,
  name15: String,
  name16: String,
  name17: String,
  name18: String,
  name19: String,
  name20: String
)
case class Person(
  names: NameGroup,
  nickname: Boolean,
  hobbies: Seq[Hobby]
)

Then generate the Play JSON formatters as usual—since each case class now has ≤22 parameters, the standard Json.format macro works perfectly:

import play.api.libs.json._

implicit val hobbyFormat: OFormat[Hobby] = Json.format[Hobby]
implicit val nameGroupFormat: OFormat[NameGroup] = Json.format[NameGroup]
implicit val personFormat: OFormat[Person] = Json.format[Person]

This keeps your code organized and avoids any workarounds or external dependencies.

2. Manually Implement the JSON Formatter

If you don't want to restructure your case class, you can write a custom OFormat without relying on the macro. This is more verbose but avoids the parameter limit:

import play.api.libs.json._
import play.api.libs.functional.syntax._

case class Hobby(id: Int, name: String)
case class Person(
  name: String, name1: String, name2: String, name3: String, name4: String,
  name5: String, name6: String, name7: String, name8: String, name9: String,
  name10: String, name11: String, name12: String, name13: String, name14: String,
  name15: String, name16: String, name17: String, name18: String, name19: String,
  name20: String, nickname: Boolean, hobbies: Seq[Hobby]
)

implicit val hobbyFormat: OFormat[Hobby] = Json.format[Hobby]

implicit val personFormat: OFormat[Person] = (
  (__ \ "name").format[String] and
  (__ \ "name1").format[String] and
  (__ \ "name2").format[String] and
  (__ \ "name3").format[String] and
  (__ \ "name4").format[String] and
  (__ \ "name5").format[String] and
  (__ \ "name6").format[String] and
  (__ \ "name7").format[String] and
  (__ \ "name8").format[String] and
  (__ \ "name9").format[String] and
  (__ \ "name10").format[String] and
  (__ \ "name11").format[String] and
  (__ \ "name12").format[String] and
  (__ \ "name13").format[String] and
  (__ \ "name14").format[String] and
  (__ \ "name15").format[String] and
  (__ \ "name16").format[String] and
  (__ \ "name17").format[String] and
  (__ \ "name18").format[String] and
  (__ \ "name19").format[String] and
  (__ \ "name20").format[String] and
  (__ \ "nickname").format[Boolean] and
  (__ \ "hobbies").format[Seq[Hobby]]
)(Person.apply, unlift(Person.unapply))

Using Play's functional syntax makes this a bit cleaner than writing full reads/writes methods from scratch, but it's still tedious if you ever need to add/remove fields.

3. Use a Third-Party Library for Extended Macro Support

If you want to keep your original case class structure and avoid manual code, you can use a library that extends Play JSON's macro capabilities to handle >22 parameters. For Play 2.6.x, play-json-derived-codecs is a popular choice:

First, add the dependency to your build.sbt (version 3.0.0 is compatible with Play 2.6.3 and Scala 2.12.4):

libraryDependencies += "org.julienrf" %% "play-json-derived-codecs" % "3.0.0"

Then import the library's macro and generate the formatter:

import play.api.libs.json._
import julienrf.json.derived._

case class Hobby(id: Int, name: String)
case class Person(/* your original 23 fields */)

implicit val hobbyFormat: OFormat[Hobby] = Json.format[Hobby]
implicit val personFormat: OFormat[Person] = deriveOFormat[Person]

This keeps your code concise, but you'll need to manage an external dependency and ensure version compatibility.

内容的提问来源于stack exchange,提问作者Robert Gabriel

火山引擎 最新活动