Я хочу сгенерировать метод, который преобразует Object
в Map[String, _]
, а затем обратно из Map[String, _]
в Object
.
Я создаю исходный объект следующим образом:
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")
Затем следующий метод преобразует данный Map[String, _]
в 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]
}
И внутри следующего метода я конвертирую начальный Object
в Map[String, _]
, ивернуться к Object
(вызывая метод выше):
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)
}
Так что если я позвоню:
fromMapToObject(myDoc)
Вход и выход будут совпадать.
Задача , пытаясь пойти дальше, я хочу сделать то же самое с полем name
, которое имеет тип Name
.Но я хочу, чтобы этот шаг был общим, в том смысле, что, не зная, какой тип поля name
, я мог бы преобразовать его в Map[String, _]
и из Map[String, _]
обратно в Object
.
Итак, что я сейчас сделаю в fromMapToObject:
- Извлечение из ввода a
Map[String, _]
- Извлечение из ввода a
Map[String, Types]
- Преобразовать значение поля
name
из Name
в Map[String, _]
- Вернуть 3-й шаг, чтобы вернуть Объект типа
Name
Вот какЯ пытаюсь приблизиться к этому новому сценарию:
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)
}
Но я получаю следующую ошибку при компиляции в Intellij:
Error:(111, 29) No TypeTag available for nameT
val obj = fromMap[nameT](nameAsMapValues)
Я хотел бы знать, как я могу преобразовать это runtime.universe.Type
, который возвращается из r.symbol.typeSignature
в TypeTag : ClassTag