Question

I'm trying to write a generic method to iterate over a case class's fields :

case class PriceMove(price: Double, delta: Double)

def log(pm : PriceMove) { info("price -> " + price + " delta -> " + delta)}

I need to make log able to handle any case class. What needs to be the argument type for log to handle case classes only and the actual generic field iteration code?

Was it helpful?

Solution

Okay, considering the two questions I attached to the question, here is what I'd use:

object Implicits {
  implicit class CaseClassToString(c: AnyRef) {
    def toStringWithFields: String = {
      val fields = (Map[String, Any]() /: c.getClass.getDeclaredFields) { (a, f) =>
        f.setAccessible(true)
        a + (f.getName -> f.get(c))
      }

      s"${c.getClass.getName}(${fields.mkString(", ")})"
    }
  }
}

case class PriceMove(price: Double, delta: Double)

object Test extends App {
  import Implicits._
  println(PriceMove(1.23, 2.56).toStringWithFields)
}

This produces:

PriceMove(price -> 1.23, delta -> 2.56)

OTHER TIPS

I'm afraid there is no easy way to achieve what you're after, as you can't easily get the field names from the case class as discussed here: Reflection on a Scala case class and Generic customisation of case class ToString.

You can try using reflection (though you can guarantee the order of the fields) or tools.nsc.interpreter.ProductCompletion, but both solutions are significantly more complex then you'd really expect.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top