I am trying to get the reflected runtime method in an instance but it is not shown in the decls
result:
val foo: AnyRef = new Object {
def bar = 1
}
typeOf[foo.type].decls //Does not contain bar method
I tried to use Java reflection class and it works:
foo.getClass.getDeclaredMethods //It contains bar method
But I prefer to work with MethodSymbols and Scala Type than Java Class and Method reflection. How can I get the reflected MethodSymbol?
I want an method to look up an object passed as AnyRef for a method bar and call it. Something like below:
def getBarMethodFromObj(obj: AnyRef): MethodSymbol = {
//typeOf(obj).decl(TermName("bar")) this doesn't work
}
I cannot use trait because bar can have different argument and return types and numbers. As Scala does not support varadic generic arguments, I plan to use reflection to find the method and call, but this cannot be done in Scala as well. I am currently use Java solution:
val bar = foo.getClass.getDeclaredMethods.find(_.getName == "bar")
bar.invoke(foo, params: _*)
However Java reflection does not retain generic types as it creates problem for List and Map, etc. So I want to know if I can implement this in Scala, or is there any coming solution
I don't know what you're trying to do, but removing the AnyRef
annotation makes your code work:
val foo = new { def bar = 1 }
typeOf[foo.type].decls // Contains bar method
If you need a type annotation (for example, in a method signature), you can use the same structural type that the compiler infers:
val foo: { def bar: Int } = new { def bar = 1 }
If you want to get the full list of methods from another method without knowing the exact type except via generics, you may be interested in TypeTag
:
import scala.reflect.runtime.universe.{ TypeTag, typeTag }
val foo = new { def bar = 1 }
def getMethods[T: TypeTag](t: T) = typeTag[T].tpe.decls
getMethods(foo) // Contains bar
If you can't use TypeTag
(maybe because you can't make API changes), then you're probably best off using the Java reflection API. The Scala reflection API is generally designed to use type information, so it may not work for you if you only know the type is AnyRef
.
In response to your edit:
I cannot use trait because bar can have different argument and return types and numbers.
Sure you can:
trait Foo[A, B] {
def bar(a: A): B
}
If you need multiple arguments, just have bar
take a tuple instead. If you need to do some list manipulation that tuples don't support, you might consider learning about HLists and shapeless.
However Java reflection does not retain generic types...
Well, no runtime-only reflection API will help you there. There is simply no way to find out what generic parameters an AnyRef
has at runtime, as that information doesn't exist on the JVM. Use TypeTags, or use a trait
in the manner described above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With