Invoke a method via Scala-reflection

983 views
Skip to first unread message

Andreas Joseph Krogh

unread,
Jul 6, 2013, 4:50:53 PM7/6/13
to scala-user
Hi.
 
I have a method where I want to call the compiler-generated getter (ie. created() for field created) if such a method exists (which is; Having the same name and return-type of the field) for a given java.lang.reflect.Field fof a given instance:

def getField(field: java.lang.reflect.Field, value: Any): AnyRef = {
        val c = field.getDeclaringClass
        val classMirror = mirror.classSymbol(c)
        val method = classMirror.toType.members.collect{case m: MethodSymbol => m}.
                find(s => s.name.decoded == field.getName && s.returnType.typeSymbol.asClass.fullName == field.getType.getName)
        method.map{m =>
                println(m.name)
                println(m.returnType)
                // m.invoke(value) ???
        }.getOrElse(field.get(value))
}
This doesn't work, of course.
What is the best way to do this?
 
Thanks
 
--
Andreas Joseph Krogh <and...@officenet.no>      mob: +47 909 56 963
Senior Software Developer / CTO - OfficeNet AS - http://www.officenet.no
Public key: http://home.officenet.no/~andreak/public_key.asc

Andreas Joseph Krogh

unread,
Jul 6, 2013, 5:17:22 PM7/6/13
to scala...@googlegroups.com
På lørdag 06. juli 2013 kl. 22:50:53, skrev Andreas Joseph Krogh <and...@officenet.no>:
Hi.
 
I have a method where I want to call the compiler-generated getter (ie. created() for field created) if such a method exists (which is; Having the same name and return-type of the field) for a given java.lang.reflect.Field fof a given instance:

def getField(field: java.lang.reflect.Field, value: Any): AnyRef = {
        val c = field.getDeclaringClass
        val classMirror = mirror.classSymbol(c)
        val method = classMirror.toType.members.collect{case m: MethodSymbol => m}.
                find(s => s.name.decoded == field.getName && s.returnType.typeSymbol.asClass.fullName == field.getType.getName)
        method.map{m =>
                println(m.name)
                println(m.returnType)
                // m.invoke(value) ???
        }.getOrElse(field.get(value))
}
This doesn't work, of course.
What is the best way to do this?
 
Thanks
 
I came up with this:
def getField(field: java.lang.reflect.Field, value: Any): AnyRef = {
        val c = field.getDeclaringClass
        val classMirror = mirror.classSymbol(c)
        val im = mirror.reflect(value)
        val method = classMirror.toType.members.collect{case m: MethodSymbol => m}.
                find(s => s.name.decoded == field.getName && s.returnType.typeSymbol.asClass.fullName == field.getType.getName)
        method.map{m =>
                val mm = im.reflectMethod(m)
                mm.apply().asInstanceOf[AnyRef]
        }.getOrElse(field.get(value))
}
Is there a way to optimize this (efficiency matters in my case).
 
Thanks.

Eugene Burmako

unread,
Jul 6, 2013, 7:16:25 PM7/6/13
to Andreas Joseph Krogh, scala-user
Sorry for not having time to come up with an end-to-end example, but here's what might help:

1) I'd look through { case m: TermSymbol if !m.isMethod && m.isVal }, and then use the getter method on the result.

2) Repeated lookups of symbols and creations of mirrors are quite slow. However, in 2.11.0-M3 there's some remedy for that in the form of FieldMirror.bind and MethodMirror.bind that you can use to swiftly product mirrors for the same underlying symbols, but for different targets. People have reported significant performance boosts coming from bind. Unfortunately we can't add new APIs in 2.10.x because of binary compatibility constraints, so this will have to wait for 2.11 (or you can probably cast your way around even in 2.10).


 

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Andreas Joseph Krogh

unread,
Jul 7, 2013, 5:14:27 AM7/7/13
to scala...@googlegroups.com
På søndag 07. juli 2013 kl. 01:16:25, skrev Eugene Burmako <eugene....@epfl.ch>:
Sorry for not having time to come up with an end-to-end example, but here's what might help:
 
1) I'd look through { case m: TermSymbol if !m.isMethod && m.isVal }, and then use the getter method on the result.
 
2) Repeated lookups of symbols and creations of mirrors are quite slow. However, in 2.11.0-M3 there's some remedy for that in the form of FieldMirror.bind and MethodMirror.bind that you can use to swiftly product mirrors for the same underlying symbols, but for different targets. People have reported significant performance boosts coming from bind. Unfortunately we can't add new APIs in 2.10.x because of binary compatibility constraints, so this will have to wait for 2.11 (or you can probably cast your way around even in 2.10).
 
Ok, thanks.
 
This is what I have so far (you're right that it's the getter-method of a Field I'm after):
def getField(field: java.lang.reflect.Field, value: Any): AnyRef = {
        val c = field.getDeclaringClass
        val classMirror = mirror.classSymbol(c)
        val im = mirror.reflect(value)
        classMirror.toType.declarations.find(_ match {
                case m: TermSymbol if m.name.decoded == (field.getName + " ") && !m.isMethod && m.isVar => true
                case _ => false
        }).collect{case m: TermSymbol => m}.map{m =>
                val getter = m.getter
                val mm = im.reflectMethod(getter.asInstanceOf[MethodSymbol])
                mm.apply().asInstanceOf[AnyRef]
        }.getOrElse(field.get(value))
}
The strange thing (to me at least) is that the field in Scala is called <fieldName> + SPC (ie. "createdBy" + " ").
 
Some questions:
1. Why doesn't m.getter return a MethodSymbol, instead of Symbol so I don't have to cast? Can it be anything else than a MethodSymbol, begin a getter?
2. Is there a less hacky way to match m.name.decoded with field.getName than to append a white-space to make it match?
3. Is this really the optimal way to get an instance of java.lang.reflect.Field's corresponding Scala-field (Symbol)?

Eugene Burmako

unread,
Jul 10, 2013, 7:18:53 AM7/10/13
to Andreas Joseph Krogh, scala-user
1) That's because it can also return NoSymbol, which is not a MethodSymbol. The current situation is by far not ideal though, so we're thinking of addressing the need to cast somehow.
2) You can use nme.LOCAL_SUFFIX_STRING (https://github.com/scalamacros/kepler/blob/54cb6af7dbcf630a4f57e98f0099d77dd3b36693/src/reflect/scala/reflect/api/StandardNames.scala#L92), but there's nothing better at the moment.
3) Maybe it might be better to look up a corresponding getter method (isGetter == true) and then check whether there's a corresponding field (meth.accessed != NoSymbol).


 

--
Reply all
Reply to author
Forward
0 new messages