Re: how can i reflect the instantiated return type of a generic type's method?

Daniel Armak <[email protected]> Sat, 12 Mar 2016 18:47:12 +0200
Newsgroups gmane.comp.lang.scala
Message-ID <CADtYB+=KqOBshojyFYdUtX76kPpxDfR=on7Qr-MbQ2NBf6tAdA@mail.gmail.com>
You need to use Symbol.typeSignatureIn(Type):

scala> case class Person[T](name: T)
defined class Person

scala> val tpe = typeOf[Person[String]]
tpe: reflect.runtime.universe.Type = Person[String]

scala> val method = tpe.members.find(_.name.toString == "name").get.asMethod
method: reflect.runtime.universe.MethodSymbol = value name

scala> val methodType = method.typeSignatureIn(tpe)
methodType: reflect.runtime.universe.Type = => String

scala> methodType.resultType
res24: reflect.runtime.universe.Type = String

​

Daniel Armak

On Mon, Mar 7, 2016 at 11:09 AM, Leon <[email protected]> wrote:

> Hi,
>
> I have just write a method to reflect the methods of case class, but meet
> some problem, the code is:
>
>
>     case class Name(first: String, last: String)
>     case class Person[T](name: T, age: Int)
>     case class America(val name: Name, val age: Int)
>
>     val m = runtimeMirror(getClass.getClassLoader)
>
>     def getFlattenFields(tag: Type, prefix: String = ""): Map[String,
> Method] = {
>         val cls = m.runtimeClass(tag)
>         tag.members.filter(sym =>
>             sym.isMethod && sym.asMethod.isGetter && sym.asMethod.isPublic
>         ).flatMap { sym =>
>             val methodSym = sym.asMethod
>             val returnType = methodSym.returnType
> *            // When reflect generic types, the returnType will be
> something like 'T' but not the*
> *            // instantiated return type, how can i get the real return
> type instead of the generic*
> *            // type ?*
>             Map[String, Method](prefix + methodSym.name.toString ->
>                 cls.getDeclaredMethod(methodSym.name.toString)) ++
>                 (if (returnType.typeSymbol.isClass &&
> returnType.typeSymbol.asClass.isCaseClass) {
>                     getFlattenFields(returnType, prefix +
> methodSym.name.toString + ".")
>                 } else {
>                     Map.empty[String, Method]
>                 })
>         } toMap
>     }
>
>     println(getFlattenFields(typeOf[Person[Name]]))
>     println(getFlattenFields(typeOf[America]))
>
>
> the result of above is:
>
> Map(age -> public int test.Reflect$Person.age(), name -> public
> java.lang.Object test.Reflect$Person.name())
> Map(age -> public int test.Reflect$America.age(), name -> public
> test.Reflect$Name test.Reflect$America.name(), name.last -> public
> java.lang.String test.Reflect$Name.last(), name.first -> public
> java.lang.String test.Reflect$Name.first())
>
> the first line of the result is not my expectation, how can i get the
> second line, but using "println(getFlattenFields(typeOf[Person[Name]]))"?
>
>
> Thanks very much
>
> --
> You received this message because you are subscribed to the Google Groups
> "scala-language" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.