Hello everyone. I wrote the following method to obtain the parameters in the constructor of a class:
/** Get the parameters in the constructor of a given scala class.
*
* Returns a list of tuples with the name as first and the type of the parameter as second.
*/
def getConstructorParams(target: Any): Seq[(String, String)] = {
import scala.reflect.runtime.universe._
import scala.reflect.api.{Mirror, TypeCreator, Universe}
val c = target.getClass
val mirror = runtimeMirror(c.getClassLoader) // obtain runtime mirror
val sym = mirror.staticClass(c.getName) // obtain class symbol for `c`
val tpe = sym.selfType // obtain type object for `c`
// create a type tag which contains above type object
val tt = TypeTag(
mirror,
new TypeCreator {
def apply[U <: Universe with Singleton](m: Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U#Type]
else
throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
}
)
// Collect all the parameters in the primary constructor
// 1. Get all the members of this type
// 2. Filter the method symbol that is the primary constructor
// 3. Get the list of params in this method
val l = tt.tpe.members.collect {
case m: MethodSymbol if m.isPrimaryConstructor =>
m.paramLists.flatten.map { a => (a.name.toString, a.info.toString) }
}.toList.flatten
// Remove the first element (the constructor itself)
l.tail
}
However, it “fails” on pretty print of the type when a parameter is of a class type:
it("should parameter of complex types of a class") {
class A(private val a: Int) { val c = 10 }
val a = new A(1)
getConstructorParams(a) should be(Seq(("a", "Int")))
class B(protected val aClass: A) { val c = 10 }
val b = new B(a)
getConstructorParams(b) should be(Seq(("aClass", "A")))
}
When applied to b
it returns List(("aClass", "ParametersAnnotationSpec.this.$A$7"))
instead of List(("aClass", "A"))
.
How can I solve this?