Your browser may have trouble rendering this page. See supported browsers for more information.

This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Inherited Method Annotations

Description

<n>This article was originally published on the <a href="http://blogs.encodo.ch/news/view_article.php?id=6"><b>Encodo Blogs</b></a>. Browse on over to see more!</n> <hr> <n>See <a href="{app}view_article.php?id=1423">Finding Conforming Methods</a> for part one of this two-part article.</n> The problem we're working on is as follows: <ol> Given an object, a method name and a list of parameters, execute the matching method on the given object. Determine from the object's class whether the given method can be executed from the given context (web, command-line, etc.) </ol> We will use annotations to mark up methods as <i>callable</i> or not. Given the <c>Method</c> we obtained in part one, it shouldn't be too hard to find its annotations. Simply pass the class of the desired annotation to <c>getAnnotation()</c>; if the annotation was specified for that method, we check its contents to determine whether the method can be called or not. <h>These are not the Annotations you're Looking For</h> In part one, calling <c>getConformingMethod( "giveCommandTo", {new Assistant()}, Manager.getClass())</c> returns the overridden method from the <c>Manager</c> class. Unfortunately, a call to <c>getAnnotations()</c> on this method returns an empty list. Why? The Java reflection API makes a distinction between annotations that appear directly on an element and <i>all</i> annotations for an element, including ancestors. These two lists can be retrieved from any <c>AnnotatedElement</c> using the following methods: <code> Annotation[] getAnnotations(); Annotation[] getDeclaredAnnotations(); </code> The documentation states that <c>getDeclaredAnnotations()</c> returns <iq>all annotations that are directly present on this element</iq>, whereas <c>getAnnotations()</c> returns <iq>all annotations present on this element</iq>. The key word here is <i>directly</i>, which is to be interpreted as stated above ... for <i>classes</i>. For methods, there is no notion of inheritance per se in the reflection API. That is, if a method in a base class has an annotation and that method is overridden in a descendent, the signature for the method in the descendent returns empty lists for both <c>getDeclaredAnnotations()</c> and <c>getAnnotations()</c>. This doesn't make any sense and directly contradicts the documentation. It seems that the all vs. declared distinction only holds for classes, even though it is defined for all elements. A quick look into the Java source shows that <c>Method</c> inherits from <c>AccessibleObject</c>, which implements the <c>AnnotatedElement</c> interface. <c>AccessibleObject</c> implements <c>getAnnotations()</c> with the following code: <code> public Annotation[] getAnnotations() { return getDeclaredAnnotations(); } </code> Alrighty then! <c>Method</c> itself does not override this method, so it's relatively clear that inherited annotations are not available from a method. In effect, the <c>@inherited</c> keyword only has an effect for classes, which is a shame. A quick check of the documentation for <i>that</i> keyword verifies this claim: <bq>Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class.</bq> So, once again, we're on our own and must build the functionality in a custom function. The code below shows how to search a method and its inherited implementations for the <c>Callable</c> interface: <code> private Callable getCallable(Method m, Object[] actualParameters) { result = null; if (m != null) { Callable result = m.getAnnotation(Callable.class); if (result == null) { Class parent = m.getDeclaringClass().getSuperclass(); if (parent != null) { Method superMethod = getConformingMethod(m.getName(), actualParameters, parent); result = getCallable(superMethod, actualParameters); } } } return result; } </code> It's not rocket science, but it involves a lot of digging around in the guts of Java reflection that shouldn't be necessary. <hr> <n>Using Java 1.5</n>