AllJava

Creating and reading Annotations & Reflection in Java

Annotations are very helpful tool while programming in Java. It is a alternative to the traditional XML based configurations. Spring has picked it up early and I must admit quite beautifully.
In case you are working on something and want to use annotations for your code, here is a small guide; it will definatly make your code look clean and also will kick off the trouble of reading XMLs.
For simplicity, lets create a mock of reading column name and its value, similar to JPA.

Step one is Creating a annotation class for a column –
 

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

 
Lets cut it down, any annotation must be declared with @interface type. It asks compiler to treat the underlying class file as an annotation.
Retention is an annotation which now provides meta data about your annotation to the Java compiler. This is the time till when Java needs to hold your annotation details. Possible values are RUNTIME / CLASS / SOURCE.
If the retention is to SOURCE level, compiler will not write the details to the class file, this are annotations like OVERRIDE which are usually used by compiler / IDEs to quickly warn you about your class not overriding the method.
For Retention type CLASS the annotation details are written to the class but VM might choose not to retain it; this is also the default behavior.
There is also retention type RUNTIME as we have in the example, which is retained by VM.
Another important aspect of annotations is Target, it can be TYPE (Class, Interface Enum etc), FIELD, METHOD, CONSTRUCTOR, PARAMETER, LOCAL_VARIABLE, PACKAGE, ANNOTATION_TYPE ( To be used as meta-annotations like Target / Retention etc). All these are self explanatory.
Now, we have discussed about annotations its time to use them for a simple table with one column with name COLUMN_NAME.
 

public class Table
{
  @Column(name="COLUMN_NAME")
  private String columnValue;
  ..
  ..
 // Getter & Setter
}

 
We can have all the fields defined by our annotation used by using key = value format, separated by comma.
So far, annotaions do not seem to be productive unless you can read it and its value at runtime.
For reading annotaion we have to use the traditional Java Reflection. And here you go .
First let us create a simple object of Table class

<pre>Table table = new Table();
table.setColumnValue("Roadtobe.com");

Now, what we need to do is to read the Column’s name and the corresponding value. Lets start by extracting all member variables from class. We can achieve this by using the method getDeclaredFields defined in class “Class”.
 

//Iterating over all fields
for(Field field : table.getClass().getDeclaredFields())
{
     // Using isAnnotaionPresent method from Field class.
     if (field.isAnnotationPresent(Column.class))
     {
         readAndPrint(field);
         System.out.println(getFieldValue(table, field.getName()));
     }
}

Now, we are able to read all fields of a class and check if they are annotated. Let us try to fetch the annotation and field value.

<pre>private void readAndPrint(Field field) {
   // Since there can be multiple annotations on a field,
   // You can use getAnnotaion to read particular annotation class
   Column column = field.getAnnotation(Column.class);
   // Now read the value we have set in Name (This will return COLUMN_NAME)
   String columnName = column.name();
   System.out.println("Column Name "+ columnName);
}

Last step, is to read the value; below method can help you with this. It takes two argument, one Object from which value is required and other field name –

public static Object getFieldValue(Object object, String fieldName) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
    {
	Field field = object.getClass().getDeclaredField(fieldName);
	field.setAccessible(true);
	Object returnValue = (Object) field.get(object);
	field.setAccessible(false);
	return returnValue;
    }

Precisely when you are working with production applications do not also forget to add code to fetch fields from parent class. You can use a while loop with the condition

while(clazz.getSuperclass() != null){
clazz = clazz.getSuperclass() ;
//Fetch all fields ..
}

[ad#in-block]
Below is a ReflectionUtil class that I had created for some project way back in 2010. Hope it helps –

<pre>/**
 * @author Supal
 *
 */
public class ReflectionUtil
{
    public static void setField(Object object, String fieldName, Object value) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
    {
	Field field = object.getClass().getDeclaredField(fieldName);
	field.setAccessible(true);
	field.set(object, value);
	field.setAccessible(false);
    }
    public static Object getFieldValue(Object object, String fieldName) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
    {
	Field field = object.getClass().getDeclaredField(fieldName);
	field.setAccessible(true);
	Object returnValue = (Object) field.get(object);
	field.setAccessible(false);
	return returnValue;
    }
    public static Object copyValues(Object sourceObject, Class targetClass) throws APIDaoException
    {
	Object targetValue = null;
	try
	{
	    targetValue = (Object) targetClass.newInstance();
	    for (Field field : sourceObject.getClass().getDeclaredFields())
	    {
		try
		{
		    setField(targetValue, field.getName(), getFieldValue(sourceObject, field.getName()));
		}
		catch (NoSuchFieldException e)
		{
		    //IgnoreLogging.logInfo(ReflectionUtil.class, "Ignored Field " + field.getName());
		}
	    }
	}
	catch (Exception e)
	{
	    throw new APIDaoException(e);
	}
	return targetValue;

One thought on “Creating and reading Annotations & Reflection in Java

Leave a Reply

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