lucidsoftware / xtract

A library to make it easy to deserialize XML to user types in scala
Apache License 2.0
60 stars 20 forks source link

Parsing case classes with more than 22 fields #21

Closed dhhuynh2 closed 5 years ago

dhhuynh2 commented 5 years ago

Hello,

I've been successfully using the library to parse a complex XML file, but ran into an instance where my case class has more than 22 fields. Assuming it was all just strings, you would do something like this according to examples:

object Foo {
  implicit val reader: XmlReader[Foo] = (
    attribute[String]("A"),
    attribute[String]("B"),
    attribute[String]("C"),
    attribute[String]("D"),
    attribute[String]("E"),
    attribute[String]("F"),
    attribute[String]("G"),
...
    attribute[String]("Z"),
  ) mapN(apply _)
}

This won't work due to Scala's limit on 22 tuples. Is there anyway to parse the case class in Xtract without simply breaking down the class? I see that in play-json, this case can be solved with two separate readers. Is something like that possible with Xtract?

tmccombs commented 5 years ago

I see that in play-json, this case can be solved with two separate readers. Is something like that possible with Xtract?

Probably, do you have a link or code snippet to how that is done with play-json?

dhhuynh2 commented 5 years ago

Sure, not a problem. Here's a link I found describing the issue:

https://stackoverflow.com/questions/28167971/scala-case-having-22-fields-but-having-issue-with-play-json-in-scala-2-11-5

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

Another code snippet I found handling it in a similar way: https://gist.github.com/EdgeCaseBerg/e2b366644802eec1263ddbf130f9df4f

tmccombs commented 5 years ago

Sorry, it took so long to respond. I think you should be able to do something pretty similar with xtract. Something like:

import com.lucidchart.open.xtract._
import cats.syntax.all._

case class Huge(a: Int, b: String, c: Boolean, d: List[Int])

val fields1to2: XmlReader[(Int, String)] = (
  (__ \ "a").read[Int],
  (__ \ "b").read[String]
).tupled

val fields3to4: XmlReader[(Boolean, List[Int])] = (
  (__ \ "c").read[Boolean],
  (__ \ "d").read[List[Int]]
).tupled

implicit val hugeCaseClassReads: XmlReader[Huge] = (
  fields1to2, fields3to4
).mapN { case ((a, b), (c, d)) =>  
    Huge(a, b, c, d)
}