Is there a nice way I can convert a Scala case class
instance, e.g.
case class MyClass(param1: String, param2: String) val x = MyClass("hello", "world")
into a mapping of some kind, e.g.
getCCParams(x) returns "param1" -> "hello", "param2" -> "world"
Which works for any case class, not just predefined ones. I've found you can pull the case class name out by writing a method that interrogates the underlying Product class, e.g.
def getCCName(caseobj: Product) = caseobj.productPrefix getCCName(x) returns "MyClass"
So I'm looking for a similar solution but for the case class fields. I'd imagine a solution might have to use Java reflection, but I'd hate to write something that might break in a future release of Scala if the underlying implementation of case classes changes.
Currently I'm working on a Scala server and defining the protocol and all its messages and exceptions using case classes, as they are such a beautiful, concise construct for this. But I then need to translate them into a Java map to send over the messaging layer for any client implementation to use. My current implementation just defines a translation for each case class separately, but it would be nice to find a generalised solution.
This should work:
def getCCParams(cc: AnyRef) = cc.getClass.getDeclaredFields.foldLeft(Map.empty[String, Any]) { (a, f) => f.setAccessible(true) a + (f.getName -> f.get(cc)) }
Because case classes extend Product one can simply use .productIterator
to get field values:
def getCCParams(cc: Product) = cc.getClass.getDeclaredFields.map( _.getName ) // all field names .zip( cc.productIterator.to ).toMap // zipped with all values
Or alternatively:
def getCCParams(cc: Product) = { val values = cc.productIterator cc.getClass.getDeclaredFields.map( _.getName -> values.next ).toMap }
One advantage of Product is that you don't need to call setAccessible
on the field to read its value. Another is that productIterator doesn't use reflection.
Note that this example works with simple case classes that don't extend other classes and don't declare fields outside the constructor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With