How Do Annotations Work?

Recently, I was giving an overview of Java to a bunch of C/C++ developers to help them bridge the gap. Mostly I ended up assuring them that they knew what they were doing and filled in very few gaps. I did enlighten them on some of the fun things like Collections and some confusing things like Date. We covered lots of ground in those few hours of presentation and banter, but one question I couldn’t answer was about annotations.

I had put a few code samples in my presentation that I’d pulled from a recent project. Stuff I knew worked, so I wouldn’t be surprised with any hastily thrown together code with style, format, or syntax errors. One of the classes was an annotated Spring class, with some code not too much unlike this snippet:

@Autowire private SomeBean someBean;

We went down a path of queries related to how to create new ones, which is a simple @interface declaration like the following.

public @interface Foo{ }

They queried how to put them in the code, and I pointed back to the example. I also showed them some other examples related to using them on class definitions, methods, and on parameter values, as defined by the @Target annotation and ElementType enum. We looked at examples of commonly encountered annotations such as @Deprecated and @SuppressWarning among others. We even looked at the different uses of @Retention and discussed the RetentionPolicy enum; how SOURCE is used to provide hints for the compilers (and IDEs) but aren’t retained in the compiled code, how CLASS is retained in the code but not necessarily available at runtime, and how RUNTIME is certain to be available at runtime.

Then they wanted to know how to use them. Not how to implement them, but how to access the @Retention(RetentionPolicy.RUNTIME) declared annotations.

I hated to admit that I didn’t really know. I knew there weren’t any frequently used utility classes for grabbing annotations, but that there were annotation-related methods on the reflection classes. I knew in practice that they were used, but not directly how, so I set out to learn so I could completely satisfy their questions.

To be sure, I use annotations all day long. I probably @Deprecate a method every day, sometimes permanently, sometimes just to quickly find uses as Eclipse is faster at adding them to problems than it is at searching. Any class that extends or implements another is surely fraught with @Override annotations. I probably write twice as many @Test annotated methods than anything else. I have @Autowire in nearly every function-full class of a Spring application, and every Hibernate project is filled with the @Column and all the other JPA annotations.

What I hadn’t had to do, though, was write any code to find and use annotations. I can’t even recall passing an annotation to a method to try to identify them. After much digging, I ascertained that indeed there aren’t any utility classes that aid in finding or using annotations. There’s got to be some heavy work behind the classpath scanning in frameworks like Spring and Hibernate to find annotated classes and methods. I’m not quite prepared to dive into that, but let’s look at some simple cases of using annotations.

First, a simple set of annotations should be built for our various uses. Let’s take one for each kind of element: class, method, and property.

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME)
public @interface TypeAnnotation { }

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation { }

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME)
public @interface MethodAnnotation { }

@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME)
public @interface ParameterAnnotation { }

There are actually eight different ElementTypes that can be used, but these are surely the most common, and are certainly enough to provide a thorough example. I’ll expand on the simple examples here, but I wanted to first discuss the annotations on our annotations.

The @Target annotation lets the compiler know where the annotation may be used. Compilers and IDEs will warn if the annotation is used on the wrong type of element. If the @Target is left off, the annotation may be applied anywhere without warning. The ElementType must be defined, and allows multiple, but not duplicate entries. Multiple ElementType allow the annotation to be used in any of those instances.

The @Retention annotation lets the compiler know how long to maintain the annotation. As mentioned, there are three RetentionPolicy values that are allowed, SOURCE, CLASS, and RUNTIME. If the @Retention annotation is used, a RetentionPolicy must be declared. If the @Retention annotation is not used, the default is CLASS, which will keep the annotation in the compiled class, but it may not be available to the runtime.

The @interface is used to define the annotation. The name of the interface is then used when putting the annotation in source later. Other than that modification to the naming, the annotation is declared much like any other interface, in that you can declare member variables and methods. It is important to note these aren’t intended for use as regular interfaces, so there are some other restrictions. Member variables must be public, static, or final, but may be of any valid type. Only public and abstract modifiers are allowed on methods. And only a small set of return types are allowed for methods; strictly, primitives, Strings, enumerations, other annotations are allowed, or 1-dimensional arrays of those types.

One more bit, if you want to make an annotation that takes a value without a name, you must declare a member variable named “value.” That is, like @SuppressWarnings(“unchecked”). It can be a single value or array, depending on your needs. If you define it as an array you can provide several values by wrapping them in squiggly-braces like @SuppressWarnings({“unchecked”,”unused”}) would do. If you do not wish to use “value,” the variable must be explicitly declared (and, truly, value is optional) such as @SuppressWarnings(value=”unchecked”).

Other differences will become apparent as the article continues, and as you play with annotations of your own. In trying to keep the article short, and not delve too much into every possible use case, I’ll show some simple uses, point out some of these other nuances of @interface definitions, and leave it to the reader to expand on that.

We’ve got some trivial annotations set up, so let’s apply them to a simple class.

@TypeAnnotation class Foo {
  @FieldAnnotation public Object object;

  @MethodAnnotation public Object setObject(@ParameterAnnotation final Object object){
    this.object = object;
  }
}

If you’ve used annotations in your code, you’ve probably used some or all of these kinds of annotations. Certainly, the annotations used before have actually done something. Before we get into doing something, let’s try to find the annotations at runtime.

I mentioned previously that Spring and Hibernate and other frameworks have functionality to scan classes in the classpath for annotations. If you’ve taken a look at how they do it (they’re both open-source projects, so dig in…) or hit a search engine looking for the answer, you probably have seen or correctly surmised that interrogating a classpath is not as easy as it seems. As such, I’m not going to try to lay that out here (sorry to whet your appetite), but instead will use the annotations in a more explicit manner.

First, a simple method to see if the annotation exists, just as an example of accessing them.

public boolean isAliased(final Class type) {
    final TypeAnnotation typeAnnotation = type.getAnnotation(TypeAnnotation.class);
    return (typeAnnotation != null);
}

The trivial example interrogates the provided class using the Class.getAnnotation() method. There’s a similar Class.getAnnotations() that will return an array (zero-length if empty) of the annotations if you want to check for more than one. This would be used very simply by something like the following snippets, the first returning true, and the other false.

isAliased(Foo.class);
isAliased("yes, a literal".getClass());

It isn’t a terribly useful example, so let’s make a method that does a little more. First, let’s expand one of our annotations to give us some runtime differences from source.

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation { String value(); }

Here we’ve changed our FieldAnnotation to require we provide some additional information in the form of a String property. It’s been named “value” for convenience, so we can use it without forcing the use of the name. Note that it looks like a method declaration, but we’ll be treating it as both a variable and a function.

If we applied the same annotation to the same class as before, we’d run into an error as we’re missing a required property. Let’s update our class a little and give this value some functionality.

@TypeAnnotation class Foo {
    @FieldAnnotation("here") public Object object;

    @FieldAnnotation("there") public Object other;

    @MethodAnnotation public Object setObject(@ParameterAnnotation final Object object){
      this.object = object;
    }
}

Again, the class isn’t terribly useful, but we now have two annotated member variables with different names. Let’s make a quick method to set those values by their annotation name, ignoring their object name.

void setPropertyByAnnotationName(final Object object, final String name, final Object value) {
    final Field[] fields = object.getClass().getDeclaredFields();
    for (final Field field : fields) {
        final FieldAnnotation fieldAnnotation = field.getAnnotation(FieldAnnotation.class);
        if(fieldAnnotation!=null && name.equals(fieldAnnotation.value()){
            field.set(object, value);
        }
    }
}

Lots of spots for error there, as there’s no null checking, it assumes the field is accessible, and the object is of the right type…but it matches our simple Foo class, so we’ll let it go for now. As with the Class, there is a Field.getAnnotations() in case you’d like to investigate more than one annotation. What we have is a method that interrogates our object (first one) to look for fields (member variables) annotated with our FieldAnnotation. When it finds one, it checks to see if the name matches the value (note it looks like a function here) in the annotation. When there’s a match, it sets the value as provided by our value parameter. This would be used simply as thus:

Foo foo = new Foo();
setPropertyByAnnotationName(foo, "here", "this is set!");
setPropertyByAnnotationName(foo, "there", Calendar.getInstance());

With this, we should end up with a Foo.object that contains the String “this is set!” and Foo.other that contains a Calendar with the current time in it.

One might desire to ask what good is that? We surely have access to Foo.object and Foo.other directly in this class, but it will certainly be the case that we might not have such access in other classes. Additionally, with the annotation, we don’t even really need to care that it’s a Foo object. We could very easily declare another class with similar annotated members and have their fields accessed with the same method we just created. This is roughly how Spring’s @Autowire works. They, of course, do a bit more in terms of recognizing names and types and whatnot without explicit definition, but this is the crux of it.

Accessing methods is done pretty much the same way. Let’s use the @MethodAnnotation to use the setter we’ve got. Note that calling methods is a lot trickier because the annotation itself has no way to ensure that the parameter list is correct. It is up to the method using reflection to determine if the prototype of the method is something it can work with. For brevity, I’ll leave this using the original annotation, which means every annotated method will be called and its value set to the same thing; the same modifications on the @FieldAnnotation can be done here for similar functionality.

void callMethodByAnnotation(final Object object, final Object value) {
    final Method[] methods = object.getClass().getDeclaredMethods();
    for (final Method method : methods) {
        final MethodAnnotation methodAnnotation = method.getAnnotation(MethodAnnotation.class);
        if(fieldAnnotation!=null){
            method.invoke(object, value);
        }
    }
}

Again, a slew of opportunities for errors with missing null-checks, accessibility, and the mentioned parameter list validation. Also, there is a similar Method.getAnnotations() method that will return an array of annotations in case you want to check for more than one. This method simply checks the class for all methods with the right annotation, and if found, tries to invoke the method with the provided object as the parameter. Again, with this functionality you can find methods in classes without caring about their real names. This, again with more guts, is how Spring handles its @RequestMapping methods in @Controller classes. As before, this can be implemented with this simple

Foo foo = new Foo();
callMethodByAnnotation(foo, ""this is set!");

In the end, we end up with Foo.other set to a String saying “this is set!” using the annotation instead of calling the method directly.

Trickier is handling the ElementTypePARAMETER annotations. This is because there’s no direct reflection access to the parameter list. There are a few arrays that can be gathered to help identify the parameters, but the parameters are actually only realized when you use the Method.invoke(), so to use these, you need to handle all of the parameters by annotation, name, or type. A typical use would be some form of IOC or other runtime association of parameters to other values available to the application.

Why this is tricky is that there is no opportunity, except perhaps inside an invoked method, to access the parameter annotations when calling the methods directly. With that understanding, we can see that these are best paired with annotated classes or methods, where the functions are going to be called indirectly, and therefore there is time to interrogate the Method for annotations before calling Method.invoke. That said, let’s modify our other method-calling method to take a map of values to tie to our parameters.

Before we do, though, this brings about another sticky bit. Unlike classes, member variables, and methods, parameters don’t always keep their names. When classes are compiled, the parameters are reduced essentially to a type and order. The variable name associated with it is not kept with the method unless the class is compiled with debugging symbols. As such, like we did for the fields, we’ll add a required value to represent the name of the parameter. This way, the annotation will maintain the value that we’ll use to pull values from our map, and it won’t matter if debug is enabled or not; our annotation will continue to work.

@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME)
public @interface ParameterAnnotation { String value(); }

And since it’s required with no default, we’ll have to change our class appropriately.

@TypeAnnotation class Foo {
    @FieldAnnotation("here") public Object object;

    @FieldAnnotation("there") public Object other;

    @MethodAnnotation public Object setObject(@ParameterAnnotation("inside") final Object object){
        this.object = object;
    }
}

And we’ll modify the method to take advantage of that annotation.

public void callMethodByAnnotation(final Object object, final Map map) {
    final Method[] methods = object.getClass().getDeclaredMethods();
    for (final Method method : methods) {
        final MethodAnnotation methodAnnotation = method.getAnnotation(MethodAnnotation.class);
        if (methodAnnotation != null) {

            final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            final Object[] parameters = new Object[parameterAnnotations.length];
            for (int i = 0; i < parameterAnnotations.length; i++) {
                parameters[i] = null;

                final Annotation[] annotations = parameterAnnotations[i];
                for (final Annotation annotation : annotations) {
                    if (annotation instanceof ParameterAnnotation) {
                        parameters[i] = map.get(((ParameterAnnotation) annotation).value());
                    }
                }
            }
            method.invoke(object, parameters);
        }
    }
}

Note the busy work necessary to grab the annotation. The annotations come from an array of arrays. The first dimension is one for each parameter, and the second dimension is the array of annotations for the parameter at that first dimension. If there are no parameters, the first dimension array is zero-length. For each parameter, if there are no annotations, that second dimension array is zero length. There is a related Method.getParameterTypes() that could be used to be certain that the type in the map was compatible with the type in the parameter, but ours is an Object, so we can be a little sloppy.

The new method can be used very much like the other, except we'll pass the parameters in a Map. We could, of course, use any mechanism for keeping track of the things that could be put in the parameter list. If you've used Spring to annotate a @Controller with @RequestMethod methods, you'll notice that you can just toss in a whole slew of parameters such as ModelMap or HttpServletRequest and it will figure them out by type.

Map map = new Map();
map.put("inside", "this is set!");
Foo foo = new Foo();
callMethodByAnnotation(foo,map);

Same caveats as before regarding shortcuts taken for brevity... Now when we call our method, it will check our map for the value. If it doesn't find an element in the map that matches our annotation name, it puts null in the parameter list. As before, our Foo.other will have a String with the value "this is set!" when we're done.

That seems like a lot of busy work to make sense of annotations. Really it's a lot of fluff code around it to make it understandable. Really, the magic lies in the getAnnotations() or getAnnotation() methods on the Class and the reflection classes Field and Method, and the Method.getParameterAnnotations() method. And, of course, our trivial examples don't carry much insight into any kind of usefulness, so let's expand on this and make a one-class annotated XML parser. A very simple one, mind you.

Parsing XML is a pain that way too many of us go through. There are plenty of tools to help us do this, so this isn't intended as a replacement or any kind of competition for them. It's just familiar territory, and one I think I can squeak in a small pair of classes for a solid example of annotation use.

Consider this fairly trivial XML, where we have a Foo element with a single attribute, id, and a nested element also named Foo.

<Foo id="alpha">
    <Foo/>
</Foo>

The astute among us can quickly envision a likewise trivial POJO that would do the same. I'm making public members for brevity; for real, we'd use getters and setters, right?

class Foo {
    public String id;
    public Foo foo;
}

With this class in mind, we can see we'll need a couple annotations to handle identifying the class and our members.

@Target({ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME)
@interface XMLElement { String value() default ""; }

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME)
@interface XMLAttibute { String value() default ""; }

A quick word about the two noticeable differences from the previous examples. First, we'll note that the XMLElement has been annotated with two ElementType targets. This allows the same attribute to be used to identify types and members, as XML elements are often neatly identified with POJOs. Also, I've added a default to each. This is both to show what it looks like and allow us to optionally rename the item in question. A small annoyance with the defaults is that there is no null value. When the value is an array, you can declare an empty list as the default, but that's not really null either.

@interface ArrayExampleAnnotation { String[] value() default {}; }

This allows us to alter our class to add the annotations as follows:

@XMLElement class Foo {
    @XMLAttribute public String id;
    @XMLElement public Foo foo;
}

We could be more explicit and annotate it thusly:

@XMLElement("Foo") class Foo {
    @XMLAttribute("id") public String id;
    @XMLElement("Foo") public Foo foo;
}

Or even make the POJO and XML a little less tightly coupled by changing the POJO names from the expected XML names (this is where the value makes more sense!):

@XMLElement("Foo") class FiddleStix {
    @XMLAttribute("id") public String identifyingAttribute;
    @XMLElement("Foo") public FiddleStix next;
}

Now we just need a function to digest our XML string and populate our POJO. To be short and sweet, and not emphasize the XML processing too much, I'm just going to use the typical W3C DOM classes that come with the Java runtime. Easy, short-ish.

public static  POJO turnXMLStringIntoPOJO(final String string, final Class type) {
    final POJO pojo = type.newInstance();
    final XMLElement topXmlElement = type.getAnnotation(XMLElement.class);
    final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
            .parse(new ByteArrayInputStream(string.getBytes()));
    if (document.getNodeName().equals(topXmlElement.value())) {
        final NamedNodeMap namedNodeMap = document.getAttributes();
        for (int i = 0; i < namedNodeMap.getLength(); i++) {
            final Node node = namedNodeMap.item(i);
            String name = node.getNodeName();
            final Field[] fields = type.getDeclaredFields();
            for (final Field field : fields) {
                final XMLAttribute xmlAttribute = field.getAnnotation(XMLAttribute.class);
                if (xmlAttribute != null) {
                    if (("".equals(xmlAttribute.value()) && field.getName().equals(name))
                            || xmlAttribute.value().equals(name)) {
                        field.set(pojo, node.getNodeValue());
                    }
                }
            }
        }
        final NodeList nodeList = document.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            final Node node = nodeList.item(i);
            final String name = node.getNodeName();
            final Field[] fields = type.getDeclaredFields();
            for (final Field field : fields) {
                final XMLElement xmlElement = field.getAnnotation(XMLElement.class);
                if (xmlElement != null) {
                    if (("".equals(xmlElement.value()) && field.getName().equals(name))
                            || xmlElement.value().equals(name)) {
                        final Object object = field.getType().newInstance();
                        field.set(pojo, object);
                    }
                }
            }
        }
    }

    return pojo;
}

With a little recursion or other care, this simple method could be used to handle nesting our XML so that Foo could have Foo wtih Foo containing Foo... But for our purposes, this meets our needs. Again, much with the caveats of missing care exchanged for brevity. Notice it's a generic class, giving us flexibility to just send it any old class. With our caveats, it makes assumptions that the class is annotated (or null pointer exceptions will occur). The string is quickly (since it's small) into a DOM tree, and we make two passes through it, once for the attributes and once for the elements. We compare the names of the nodes to the names (value) of our annotations, if they're defined, or to the name of the field, if the value is empty. If a match is found for the annotation, we set the value to whatever the XML contained. If a match is contained for the element, we simply instantiate the right type and add it to our object. We could explore the DOM deeper and set its values, but that's a little larger example.

This class could take all three of our example classes (careful, as two of the classes will conflict) and parse the same XML and get the expected results.

String xmlString = "<Foo id="alpha"><Foo /></Foo>";
Foo foo = turnXMLStringIntoPOJO(xmlString, Foo.class);
FiddleStix fiddleStix = turnXMLStringIntoPOJO(xmlString, FiddleStix.class);

What should result is that our objects would have an id String of "alpha" and their same-type member populated with an empty, but instantiated item. Both classes, from the same XML just because of the annotations.

And that, my friends, is how you use annotations. Well, one way...

One thought on “How Do Annotations Work?

  1. Todd Meadows says:

    Good article Jeff – and I hadn’t heard that deprecate trick before.

  2. diana says:

    Annotations are, sadly, underrated. But lack of annotations is a form of job security. Presumably. 😉

    d

  3. landrain says:

    Best article on annotations I’ve read so far (and I’ve read quite a few).

    Thanks.

  4. arlo says:

    I predict annotations will in the future be seen as an antipattern. Any time I rely on annotations, precompilers and “black box” libraries to implement my business requirements I am introducing variables that merely serve to decouple cause (the code I write) and effect (the resultant behaviour I see when it runs).

    On a more practical level it binds my solution to a framework or library vendor in ways that in the long run will prove unpredictable.

    As an added irritation I learned this week that the framework I have been using does not implement annotations for all metadata, so now I have annotations AND xml. So whats the point.

  5. Jeff Warren says:

    It’s a bummer you see it that way, Arlo. I didn’t write the article in an attempt to advocate or evangelize annotations in any way, and I hope this response doesn’t do that either.

    I think your prediction is wrong, and that annotations will continue replace unnecessarily bulky configuration files.

    You probably use annotations already, like the occasional SuppressWarnings or Deprecated through your Java code. These have value that doesn’t leave the compiler, mostly to help manage IDE messages or build-time output. Using annotations like in my example above, the IOC in Spring, or the configuration replacements in Servlet 3 all offer different uses of the same reductive mechanism.

    Other annotations can provide a mechanism for decoupling your code, but this is a good thing. As with any IOC it should be completely within your control what gets coupled at run time as you deploy your app. When your class “requesting” an object with a name (or type or whatever the annotation demands) looks to its container or annotation handler (note my example is rather explicit, but Serlvet 3.0 is done on load) for a matching value, your packaging and deployment is responsible for making that match; it won’t happen randomly unless you are careless in your deployment (and depending on how the container handles collisions–are they immutable or does the last defined “win”?).

    Annotations don’t bind your software to any framework any more than using any framework classes directly. This is why POJOs annotated with JPA annotations work as Hibernate objects, or EJBs, or with other frameworks, even when the annotations specific to that framework aren’t used; of course, there may be framework-specific annotations that provide additional features or configuration reduction. If you choose to use a framework’s annotation, then you are committing to continuing to use that framework; no different than if you import a package from that framework to use its provided objects.

    And let’s be realistic; how often do you start writing software with one framework and switch to another, and even more, if that happens, how often does it happen without refactoring? Annotations can actually ease this pain, although it doesn’t always, and it completely depends on how they’re used.

    It is irritating to learn that your framework has not completely implemented annotations. This should be considered a growing pain and not a deal breaker. I don’t know what framework you are referencing, but all of the frameworks I use continue to improve their annotations, and reduce their dependence on XML or other configuration files and methods, as they continue to improve the software in general. So the point to using what annotations are offered is to iteratively improve your software as your framework improves theirs.

    Of course, all of this comes with all of the caveats of “your mileage may vary.” It’s hard to infer what annotations you’re trying to use. Are you replacing a web.xml servlet mappings with WebServlet annotations? Then it isn’t a framework issue, but does add a requirement that you need to deploy to a Servlet 3 container. Are you replacing Spring bean definitions with Autowire annotations, or even XML configured controllers with Controller annotations? Either way you’re tied to Spring for those. If you use annotations to overcome some polymorphism shortcomings of Java, as my example shows, then you are tied to at least having the annotation classes (or removing them from your code); if you implemented an object mapping like the example and later removed the annotations, you also need to refactor the get and set object building that it replaced.

    These are all decisions of the individual or group creating and maintaining the software. I for one find annotations very powerful, very helpful, and generally prefer them to other coupling and configuration mechanisms available.

  6. Giga says:

    I have a annotation. for example
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Equals {

    }

    I also have a class

    public class myClass {

    @Equals
    public String myField;
    }
    I have a method in other class

    public void method (myClass param) {
    // here I want to access annotated field’s value (myField’s value)
    // I know that I have to use reflection , I have accessed field’s name (myField)
    // can anyone help me and tell how to access value of that field (param’s field)
    }

    please answer me : giga.chalauri@gmail.com

  7. Jeff Warren says:

    The article kind of skips over some of the possibilities of annotation use, but here’s a simple getter method in the same vein as the setter in the article, that would meet your requirements.

    Object getValueByEqualsAnnotation(final myClass /* should really be MyClass */ instance)
    throws IllegalArgumentException,IllegalAccessException {
    final Field[] fields = myClass.getClass().getDeclaredFields();
    for (final Field field : fields) {
    final FieldAnnotation fieldAnnotation = field.getAnnotation(Equals.class);
    if (fieldAnnotation != null) {
    field.setAccessible(true);
    return field.get(myClass);
    }
    }
    return null;
    }

    Again, the reflection will retreive the fields defined in your object. Then read the annotations by each field. Then upon finding one (and in this simple example, only the first one) that matches the expected annotation type, it returns the value of that field. Failure to find any annotated methods returns null.

    You would use this in your method thus:

    public void method(myClass object){
    String equalsValue = (String)getValueByEqualsAnnotation(object);
    }

  8. Chris Marx says:

    What would happen if the same annotation were applied on the interface as well as the implementation? I like the idea of the annotation on the interface, but I also like seeing the rules near the actual code as well-

  9. Jeff Warren says:

    You didn’t specify the use case for your annotations, but the mechanisms outlined here for using annotations to find and call methods abstractly wouldn’t work.

    This simple (sorry for the format loss) test class shows that for an interface with an annotated method that a concrete class doesn’t expose annotations when declared on its interfaces, but a class that also has the annotation on the method does find it.

    public class TestInterface {

    public static void main(String[] args) throws Exception {

    for (java.lang.annotation.Annotation annotation :
    Concrete.class.getMethod(“foo”).getAnnotations())
    if (annotation.annotationType() == MyAnnotation.class)
    System.out.println(“found our annotation on Concrete”);

    for (java.lang.annotation.Annotation annotation :
    AnnotatedConcrete.class.getMethod(“foo”).getAnnotations())
    if (annotation.annotationType() == MyAnnotation.class)
    System.out.println(“found our annotation on AnnotatedConcrete”);
    }

    @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
    public @interface MyAnnotation {}

    public interface Interface {
    @MyAnnotation void foo();
    }

    public class Concrete implements Interface {
    public void foo() {}
    }

    public class AnnotatedConcrete implements Interface {
    @MyAnnotation public void foo() {}
    }
    }

    I hope this helps (and is accurate)!

  10. Chris Marx says:

    Hi,
    Yeah, that example is very clear, so really, how a case like this gets handled is going to depend on how the annotations get processed. In my case, I’m using annotations from the Spring framework, Hibernate, etc., and some of them are designed to be placed on the interfaces, and spring has a special processor for finding the annotations on the interface – http://stackoverflow.com/questions/23994338/how-to-get-annotations-of-interface-or-abstract-class-methods-in-java

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*