Jan 9, 2014

Creating Custom annotations

Let’s see how we can create a new annotation. We will create some annotation slightly more serious then Hello World. We will create an annotation that will have parameters to connect to database and in our class we will use these values to connect to DB and populate values in annoted class.

To create an annotation we will create a class with keyword @interface. Also we provide information like what this annotation can be applied to and when this annotation will be available. This information is provided by following two annotations

@Target: Will tell JVM to what kind of elements this annotation can be applied possible values are Constructor, Local variable, field (instance variable),  method, package, Parameter (not sure how) and Class (ElementType.TYPE).

@Retention: This will provide information about retention policy for this annotation. Options are Source, Runtime, Class

We want our annotation information to be available at run time and can be applied to Class level. Also  we want to use four properties with this annotation so following will be our annotation class.

package com.techcielo.corejava.annotation;

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

@Target(value=ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConnectionObject
{
       String username() default "root";
       String password() default "";
       String url();
       String dirverClass();
}

Notice that for two properties (username and password) we are setting default values but for other two we have not set any default values so when we will use this annotation with our bean class it will give compilation error that these values need to be set. Following is the screenshot for the same.

 

So we will create following class with appropriate annotations.

package com.techcielo.corejava.annotation.bean;

import com.techcielo.corejava.annotation.ConnectionObject;

@ConnectionObject(dirverClass="com.mysql.jdbc.Driver",
                           password="",
                           url="jdbc:mysql://localhost:3306/northwind",
                           username="root")
public class SampleBean {
       private String employeeId;

       public String getEmployeeId() {
              return employeeId;
       }
       public void setEmployeeId(String employeeId) {
              this.employeeId = employeeId;
       }
}


We will create a utility class with two methods one that will accept annotation as an argument and will return Connection object. Another method will accept a bean class and get annotation from it and pass it to other method.

package com.techcielo.corejava.annotation.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import com.techcielo.corejava.annotation.ConnectionObject;

public class CustomAnnotationUtil {
           
            public static <T> T loadBean(Class<T> obj) {
                        Connection conn = null;
                        //Get annotation values from bean class
                        ConnectionObject connAnn = obj.getAnnotation(ConnectionObject.class);
                        if(connAnn != null){
                                    conn = getDetailsFromAnnotation(connAnn);
                                    //Method can be extended to get more details from DB and populate in bean class and return
                                    //this bean class
                        }
                        try {
                                    conn.close();
                        } catch (SQLException e1) {
                                    e1.printStackTrace();
                        }
                        return null;
            }
           
            /**
             * Utility method that will be called to get parameters from annoted class
             * @param obj
             * @return
             */
            public static Connection getDetailsFromAnnotation(ConnectionObject obj){                       
                        String user = obj.username();
                        String passwd = obj.password();
                        String url = obj.url();
                        String drivername = obj.dirverClass();
                        System.out.println("==>"+user+":"+passwd+":"+url+":"+drivername);
                        Connection conn = null;
                        try{
                                    Class.forName(drivername);
                                    conn = DriverManager.getConnection(url,user,passwd);
                                    return conn;
                        }
                        catch(Exception e){
                                    e.printStackTrace();
                        }
                        return null;
            }
}



We can create a bean class and pass it to this utility class to get details from table (interested user can extend the utility class and Bean utils to set values in this bean class)

package com.techcielo.corejava.annotation.main;

import com.techcielo.corejava.annotation.bean.SampleBean;
import com.techcielo.corejava.annotation.util.CustomAnnotationUtil;

public class Main {
       public static void main(String[] args) {
              SampleBean bean = CustomAnnotationUtil.loadBean(SampleBean.class);        
       }
}

Following will be output.

==>root::jdbc:mysql://localhost:3306/northwind:com.mysql.jdbc.Driver