I want to generate a method which will convert an Object
into a Map[String, _]
, and later back from Map[String, _]
to Object
.
I generate the initial object as follows:
case class Name (firstName : String, lastName : String)
case class Documents (idx: String, name: Name, code: String)
val mName1 = Name("Roger", "Rabbit")
val myDoc = Documents("12", mName1, "ABCD")
Then following method converts a given Map[String, _]
into an Object:
def fromMap[T : TypeTag: ClassTag ](m: Map[String,_]) = {
val rm = runtimeMirror(classTag[T].runtimeClass.getClassLoader)
val classTest = typeOf[T].typeSymbol.asClass
val classMirror = rm.reflectClass(classTest)
val constructor = typeOf[T].decl(termNames.CONSTRUCTOR).asMethod
val constructorMirror = classMirror.reflectConstructor(constructor)
val constructorArgs = constructor.paramLists.flatten.map( (param: Symbol) => {
val paramName = param.name.toString
if(param.typeSignature <:< typeOf[Option[Any]])
m.get(paramName)
else
m.get(paramName).getOrElse(throw new IllegalArgumentException("Map is missing required parameter named " + paramName))
})
constructorMirror(constructorArgs:_*).asInstanceOf[T]
}
And inside this method I convert the initial Object
into a Map[String, _]
, and back to Object
(by invoking the method above):
def fromMapToObject(input: Any) : Unit= {
println("input: "+input)
//Converting an Object into a Map
val r = currentMirror.reflect(input)
val docAsMapValues = r.symbol.typeSignature.members.toStream
.collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)}
.map(r => r.symbol.name.toString.trim -> r.get)
.toMap
println("intermediate: "+docAsMapValues)
val obj = fromMap[Documents](docAsMapValues)
println("output: "+obj)
}
So if I call:
fromMapToObject(myDoc)
Input and output will match.
Problem, trying to get a step further, I want now to do the same with the field name
, which is of type Name
. But I want this step to be generic, in the sense that without knowing what is the type of the field name
, I could convert it into a Map[String, _]
, and from Map[String, _]
back to Object
.
So what I will do now in fromMapToObject is:
- Extract from the input a Map[String, _]
- Extract from the input a Map[String, Types]
- Convert the value of the field
name
fromName
into a Map[String, _] - Revert the 3rd step to get back an Object of type
Name
This is how I am trying to approach this new scenario:
def fromMapToObject[T: TypeTag: ClassTag](input: Any) : Unit = {
println("input: "+input)
//Converting an Object into a Map
val r = currentMirror.reflect(input)
val docAsMapValues = r.symbol.typeSignature.members.toStream
.collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)}
.map(r => r.symbol.name.toString.trim -> r.get)
.toMap
val docAsMapTypes = r.symbol.typeSignature.members.toStream
.collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)}
.map(r => r.symbol.name.toString.trim -> r.symbol.typeSignature)
.toMap
// Here I extract from the map the value and type of the attribute name
val nameType = docAsMapValues("name")
val nameValue = docAsMapValues("name")
// Converting Name into a map
val r2 = currentMirror.reflect(nameValue)
val nameAsMapValues = r2.symbol.typeSignature.members.toStream
.collect{case s : TermSymbol if !s.isMethod => r2.reflectField(s)}
.map(r2 => r2.symbol.name.toString.trim -> r2.get)
.toMap
type nameT = nameType.type
val obj = fromMap[nameT](nameAsMapValues)
}
But I am getting the following error when compiling in Intellij:
Error:(111, 29) No TypeTag available for nameT
val obj = fromMap[nameT](nameAsMapValues)
I would like to know how could I convert that runtime.universe.Type
which is returned from r.symbol.typeSignature
into a TypeTag : ClassTag
Aucun commentaire:
Enregistrer un commentaire