Java Getting Annotation Attributes Example

0

In this article, we will see how to extract annotation attributes. An annotation attribute is like a non-void method that has no parameters. An attribute can itself be another annotation.

Let’s first define an annotation.

Define Annotations

Below is a simple annotation that represents a programming language. You can specify the default values using default. The attributes are declared just the way we define methods in an interface. Attribute scriptingLang() is a nested annotation that again returns an annotation.

Lang:

package com.javarticles.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface Lang {
    String[] value() default {};
    String[] name() default {};
    String ver() default "";
    boolean backwardCompatible() default true; 
    Class<?>[] classes() default {};
    ScriptingLang[] scriptingLang() default [email protected]("Groovy")};
}

Here is the definition of scripting language annotation.

ScriptingLang:

package com.javarticles.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface ScriptingLang {
    String[] value() default {"Groovy"};
    String ver() default "";
}

classes attribute returns an array of Class type. We will use the below classes when we get to the usage of annotation.
A:

package com.javarticles.annotations;

public class A {
}

B:

package com.javarticles.annotations;

public class B {
}

Getting Annotation Attributes

In the below main class, we use annotation @Lang and define the attributes. Attribute scriptingLang returns an array of nested annotations.
Few things to note about:

  1. Before we start reading the attributes, we need to first get the annotation
    Annotation annotation = AnnotationAttributesExample.class.getDeclaredAnnotation(Lang.class)
    
  2. Attributes are like methods so to get the attributes use:
    Method[] methods = annotation.annotationType().getDeclaredMethods();
    
  3. Annotation attributes are methods without any parameter and they always return something.
    if (method.getParameterTypes().length == 0
                        && method.getReturnType() != void.class) {
    //get the attribute value
    }
    
  4. Next we need to get the attribute value.
    Object value = method.invoke(annotation);
    
  5. Finally, we convert the attribute value to a simpler type. For example, if the attribute type is Class, we return class name. If it is a nested annotation, we further parse the annotation to get the attributes as Map

AnnotationAttributesExample:

package com.javarticles.annotations;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;

@Lang(name = "Java", ver = "1.8", scriptingLang = 
[email protected](value="Jython", ver="2.5.2"), @ScriptingLang(value="Groovy", ver="2.4")}, 
backwardCompatible = false, classes = {A.class, B.class })
public class AnnotationAttributesExample {
    public static void main(String[] args) {
        Annotation annotation = AnnotationAttributesExample.class
                .getDeclaredAnnotation(Lang.class);
        LinkedHashMap<String, Object> attributes = getAnnotationAttributesAsMap(
                annotation, true, true);
        printAttributes(attributes);
    }

    static void printAttributes(LinkedHashMap<String, Object> attributes) {
        for (String key : attributes.keySet()) {
            Object value = attributes.get(key);
            if (String[].class.isInstance(value)) {
                value = Arrays.asList((String[]) value);
            }
            if (LinkedHashMap[].class.isInstance(value)) {
                LinkedHashMap<String, Object>[] nestedAttrbutes = (LinkedHashMap<String, Object>[]) value;
                for (LinkedHashMap<String, Object> nestedAttributeMap : nestedAttrbutes) {
                    printAttributes(nestedAttributeMap);
                }
            } else {
                System.out.println(key + "->" + value);
            }
        }
    }

    public static LinkedHashMap<String, Object> getAnnotationAttributesAsMap(
            Annotation annotation, boolean classValuesAsString,
            boolean nestedAnnotationsAsMap) {

        LinkedHashMap<String, Object> attrs = new LinkedHashMap<String, Object>();
        Method[] methods = annotation.annotationType().getDeclaredMethods();
        for (Method method : methods) {
            if (method.getParameterTypes().length == 0
                    && method.getReturnType() != void.class) {
                try {
                    Object value = method.invoke(annotation);
                    attrs.put(
                            method.getName(),
                            extractAttributeValue(value, classValuesAsString,
                                    nestedAnnotationsAsMap));
                } catch (Exception ex) {
                    throw new IllegalStateException(
                            "Could not obtain annotation attribute values", ex);
                }
            }
        }
        return attrs;
    }

    static Object extractAttributeValue(Object value, boolean classValuesAsString,
            boolean nestedAnnotationsAsMap) {
        if (classValuesAsString) {
            if (value instanceof Class) {
                value = ((Class<?>) value).getName();
            } else if (value instanceof Class[]) {
                Class<?>[] clazzArray = (Class[]) value;
                String[] newValue = new String[clazzArray.length];
                for (int i = 0; i < clazzArray.length; i++) {
                    newValue[i]= clazzArray[i].getName();
                }
                value = newValue;
            }
        }
        if (nestedAnnotationsAsMap && value instanceof Annotation) {
            return getAnnotationAttributesAsMap((Annotation) value,
                    classValuesAsString, true);
        } else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
            Annotation[] nestedAnnotations = (Annotation[]) value;
            LinkedHashMap<String, Object>[] mappedAnnotations = new LinkedHashMap[nestedAnnotations.length];
            for (int i = 0; i < nestedAnnotations.length; i++) {
                mappedAnnotations[i]= getAnnotationAttributesAsMap(
                        nestedAnnotations[i], classValuesAsString, true);
            }
            return mappedAnnotations;
        } else {
            return value;
        }
    }
}

We print the extracted attributes.

Output:

name->[Java]
value->[]
classes->[com.javarticles.annotations.A, com.javarticles.annotations.B]
backwardCompatible->false
ver->1.8
value->[Jython]
ver->2.5.2
value->[Groovy]
ver->2.4

Download the source code

This was an example about getting annotation attributes.

You can download the source code here: javaGetAnnotationAttributesExample.zip

About Author

Ram's expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring. You can reach him at [email protected]

Comments are closed.