Search code examples
scalaspray-json

Parsing more than 22 fields with Spray Json without nesting case classes


I am trying to use Spray-JSON to marshall an incoming JSON with more than 22 fields. Since there is no JsonFormat23() method, I am having to nest my case classes to get around the limitation. However, the incoming JSON does not know of the nested structure.

Is there a way to avoid using nested structure in Spray Json?

EDIT

Here is my solution so that others do not have the same pain. One of my issues was that all my fields were optional, which added another layer of complexity. You can put as many fields as you want in this solution

    implicit object myFormat extends RootJsonFormat[myFormat] {
        override def write(js : myFormat):JsValue =
          JsObject(
            List(
              Some("language" -> js.language.toJson),
              Some("author" -> js.author.toJson),
                ....
            ).flatten: _*
          )

        override def read(json: JsValue):myFormat= {
          val fieldNames = Array("language", ... , "author")

          val jsObject = json.asJsObject
          jsObject.getFields(fieldNames:_*)

          // code to transform fields to case class

          // Initializes class with list of parameters
          myFormat.getClass.getMethods.find(x => x.getName == "apply" && x.isBridge)
            .get.invoke(myFormat, mylist map (_.asInstanceOf[AnyRef]): _*).asInstanceOf[myFormat]

        }
    }

Solution

  • You can implement RootJsonFormat as described here to work around Tupple22 and Function22 limitations. There is no limit of 22 parameters in case classes anymore (with caveats) so you can keep your class structure flat. You don't even have to use case class as target deserialization type when implementing RootJsonFormat, it could be a regular class instead.

    Note that even though you can get your JSON get parsed into a case class, there might be other limitations of 22 you could face in your code. See this for explanation. For example, you get your case class and now want to save it to DB and your DB framework can't work around 22 parameters limitation without custom serializer. In that case converting to nested case classes might be simpler.

    In Dotty the limit of 22 will be completely gone, but that will take some time:

    The limit of 22 for the maximal number of parameters of function types has been dropped. Functions can now have an arbitrary number of parameters. Functions beyond Function22 are represented with a new trait scala.FunctionXXL.

    The limit of 22 for the size of tuples is about to be dropped. Tuples will in the future be represented by an HList-like structure which can be arbitrarily large.