Let's say that I have this class
case class Test (id: Long, name: String)
and an instance of this class :
Test :
id -> 1
name -> toto
I would like to create a Map[String, String] as follow :
Map( "id" -> "1", "name" -> "toto")
My question is : Is there a way to turn this instance of Test into Map[String, String] ? I want to avoid to use a method as this one :
def createMap(instance: Test): Map[String, String] = {
val map = new Map[String, String]
map.put("id", instance.id.toString)
map.put("name", instance.name)
map
}
If there is no method to do so in Scala, is there a way to iterate over class properties ? Maybe I can create a generic function to do so :
def createMap(instance: T): Map[String, String] = {
val map = new Map[String, String]
//pseudocode
for ((name, value) <- instance.getClassProperties.getValues) {
case value.isInstanceOf[String] : map.push(name, value)
case _ : map.push(name, value.toString)
}
map
}
Is that possible ? If you have good examples/links, I'm interested.
Starting
Scala 2.13
,case classes
(as implementations ofProduct
) are provided with aproductElementNames
method which returns an iterator over their field's names.By zipping field names with field values obtained with
productIterator
we can generically obtain the associatedMap[String, Any]
and by mapping values withtoString
the associatedMap[String, String]
:The topic you are dealing with is becoming incredibly recurring on StackOverFlow and the problem is not trivial if you want to have a typesafe implementation.
One way to solve the problem is using reflection (as suggested) but I personally prefer using the type system and implicits.
There is a well-known library, developed by an extremely smart guy, who let you perform advanced operations such as turn any case class into a typesafe heterogeneous list, or create heteregeneous maps, which can be used to implement "extensible records". The library is called Shapeless, and here one example:
Book behaves like a typesafe map which can indexed using objects as keys. If you are interested in knowing more, a good entry point might be this post:
Are HLists nothing more than a convoluted way of writing tuples?
Yes it's possible. Since Scala 2.10 you can use reflection.
Assuming you have:
The following will get you what you want:
To simply iterate over field values of case class use
.productIterator
on its instance.