Friday, August 31, 2007

Annotation and Dependency Injection in Struts1.2 application


Annotation is an attribute oriented programming. Means, a meta-data will be passed to the piece of code. There are two types of Annotation. Compile time and Run Time. Compile time annotation as you know, is taken care at the time of compilation time and the latter is happening at run time.

Now let us talk about ‘Dependency Injection’. This paradigm is to inject the dependencies into the code. Let us talk about one practical example.

Since the introduction of the EJB3.0, enterprise bean development became very easy. There are no hurdles like creating remote and local interfaces and the respective deployment descriptor files. These have been eliminated from the development life cycle.

What exactly happened here inside the enterprise bean, we can specify what type of bean it is? Is it a stateless or statefull and what type of interfaces that you are going to use.

Let us look at the following example:

@Stateless

Public class HelloBean implements Hello{

Public void hello(String str){

System.out.println (“ Hello “+str);

}

This is an attribute to the EJB3.0 container that this bean is a stateless session bean. Likewise, take a look at the following interface how an interface is marked as ‘Remote’.

@Remote

Public interface Hello{

public void hello(String str){};

}

So these informations can be available to the ejb3.0 container by the help of Dependency Injection. In earlier ejb specifications, it was the responsibility of the developer to develop home, remote interface components and giving entries in the ejb-jar xml file and this approach was taking a lot of development time.Since the attribute oriented programming can save a lot of development time.

Let us take a look at struts 1.2 application where in Dependency Injection can be implemented. But if you are already using Struts2 framework, then in many situations they are using this feature readily. Here we are worried about Struts 1.2 application where dependency injection can be achieved using custom annotation.

In order to achieve the above, we have written a custom annotation that will serve this purpose. The custom annotation in this scenario is like the following:

package test;

import static java.lang.annotation.ElementType.FIELD;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;

import java.lang.annotation.Target;

@Target({ FIELD})

@Retention(RUNTIME)

public @interface VarRef {

}

This custom annotation binds the strVal variable in the TestAction class and specifies Retention policy is RUNTIME.

We use a RequestProcessor to pre-process the request and a public variable in the action class will be pre-populated with some value before the action class is executed. What really happens is the CustomRequestProcessor will check whether the variable is binding to an annotation of type FIELD. If any annotation is present on the variable, then the CustomRequestProcessor will process the variable and will invoke the setter method of the action class. The variable will be set to its value inside checkAnnotation(Object obj) method when set method was invoked.

The variable is a public variable in the TestAction class.

package process;

import java.io.IOException;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.action.RequestProcessor;

import test.VarRef;

public class CustomRequestProcessor extends RequestProcessor {

protected ActionForward processActionPerform(HttpServletRequest

request,

HttpServletResponse response, Action action,ActionForm form,

ActionMapping mapping) throws IOException, ServletException{

ActionForward forward = null;

checkAnnotation(action);

forward = super.processActionPerform( request, response,action, form, mapping);

return forward;

}

public Object checkAnnotation(Object obj){

String args[] = new String[1];

try{

Field [] fArray = obj.getClass().getDeclaredFields();

for(int i=0; i

Field ff = fArray[i];

String strFieldName = ff.getName();

if(ff.isAnnotationPresent(VarRef.class)){

if (obj instanceof Action) {

Method m = obj.getClass().getDeclaredMethod("set"+strFieldName,String.class);

args[0]="hello";

m.invoke(obj,args[0]);

}

}

}

}catch(Exception e){

e.printStackTrace();

}

return null;

}

}

Take a closer look at the checkAnnotation method in the CustomRequestProcessor class. This method takes Object is an argument and determines what type of class was invoked. If the invoking class is of type ACTION type, then it will call the setstrVar method in the action class using reflection and the corresponding variable will be set to ‘hello’ value. The check annotation method is invoked from the processActionPerform method.

So this gives us an idea that dependency injection can be achieved in struts application. This will lead to many ideas of implementing dependency injection like getting the datasource name; the ejb references etc in the struts 1.2 based applications as and when required. Also this will minimize number of lines in the code. All can be achieved in 2-3 lines of code.

The action class in this scenario is,

package test;

import java.io.IOException;

import javax.naming.InitialContext;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

public class TestAction extends Action{

@VarRef public String strVar="";

public ActionForward execute(ActionMapping mapping,

ActionForm form,

HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException

{

System.out.println(" the strVar "+strVar);

return mapping.findForward("success");

}

public void setstrVar(String strVar) {

this.strVar=strVar;

}

}

You can see output in the tomcat console when the action class was invoked.

The strVar variable will be set to hello at the time of TestAction was invoked.


So annotation opens up plethora of innovative ideas when it comes to attribute oriented programming. It can be applied almost anywhere without much difficulty. You have to define what the application will be doing when it sees such Meta data.