Right now it's easy to run into IllegalAccessException with Velocity
although the called method is (or at least, seems to be) public since it has
no dynamic casting.

Consider for example enumerating entries of a HashMap:

#foreach ($entry in $hashmap.entrySet())
  $entry.key = $entry.value
#end

While this seems innocent, it in fact does not work - it dies with an
IllegalAccessException. Why, you might ask?
Each entry of a HashMap is an instance of HashMap.Entry, which is a
*private* class in HashMap. When you try to call the getKey() method on an
entry, you're doing the dynamic equivalent of the following Java expression:

  ((HashMap.Entry)entry).getKey()

which clearly wouldn't even compile, let alone run as you are not allowed to
cast an object into HashMap's private inner class.
What you would like to do were this static code is probably

  ((Map.Entry)entry).getKey()

as Map.Entry is a public interface, therefore legal to cast to and use.

However, for this you need the Method object returned from
Map.Entry.class.getMethod("getKey", null) instead of the one returned from
HashMap.Entry.class.getMethod("getKey", null).

Therefore, before a public(ly looking) method can be used, it must be
checked whether it's declaring class is itself public. If it isn't, you must
first find a legal "cast" dinamically, that is do a lookup for a public
method with same signature in the declaring class' public superclasses and
implemented interfaces. If you find one -- that's the right one to use. If
you don't find any -- it's legal, altough quite a semantic nonsense you
shouldn't encounter in a well designed class (namely, it's a public method
of a non-public class that isn't publicly declared in any public superclass
or interface -- so it does not make sense for it to be public at all, since
it's not accessible outside the package).

I've added a "Method getPublicMethod(Method)" method (try reading this
sentence aloud :-)) to org.apache.velocity.util.introspection.Introspector
that does the job. Also made ClassMap, ASTReference, and PropertyExecutor
use it. The diff -u patches are attached.

BTW, is there any particular reason you folks aren't using
java.beans.Introspector under covers of Velocity's own Introspector?

Cheers,
  Attila.

dynamic-cast.zip

Reply via email to