Spring annotation based AOP and intercepting the ball

Spring AOP and Annotation based AspectJ

The concept

Recently I had to work on a requirement that asked that logs be kept when anyone performs certain actions upon the database.

For example if some chose to remove an item from the database – the action, who performed it, when it was performed and any extra information should be noted in the database.

Implementing this can be performed in a variety of ways. We could have simply told developers to call a function within any database methods to log the action. However Spring AOP provides a better way of doing this.

The idea

To make it easier to store the logs I wanted users to simply be able to annotate any methods they felt needed logging in the message.

Then using AspectJ we would have code that would intercept the methods and log the action in the database. All developers would need to do is very simply annotate their methods.

The Annotation

First of all I had to create the Java Method annotation that can be placed above the required methods.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAction {
	String actionPerformed();
}

The annotation simply has one parameter that allows the developer to specify the action performed such as ‘object deleted’ etc.

The aspect class

Next was to write the Spring aspect class which will perform the actual logging of the action

First of all we write a simple class and add the @Aspect annotation before the class

@Aspect
public class MyAspect

Next we need to define the Pointcut. As a Spring defintion a Pointcut is:

Pointcut: a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default.

I’m writing a simple point cut that matches any public methods. This is coded like so:

@Pointcut(value="execution(public * *(..))")
public void anyPublicMethod() { }

The last part of the Aspect class is the Advice. Spring defines the advice as:

Advice: action taken by an aspect at a particular join point. Different types of advice include “around,” “before” and “after” advice. Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors around the join point.

I need my advice to handle the “around” advice and only methods with my @LogAction annotation

To do this I used the following method:

@Around("anyPublicMethod() && @annotation(logAction)")
public Object logAction(ProceedingJoinPoint pjp, LogAction logAction) throws Throwable {
}

The method uses my anyPublicMethod Pointcut and the @annotation(logAction) to match only public methods with the LogAction annotation specified.

I have also included the ProceedingJoinPoint parameter so I can access the various arguments in the annotated method.

The final Aspect class is as follows:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
 
@Aspect
public class MyAspect{
 
	@Pointcut(value="execution(public * *(..))")
	public void anyPublicMethod() {
	}
 
	@Around("anyPublicMethod() && @annotation(logAction)")
	public Object logAction(ProceedingJoinPoint pjp, LogAction logAction) throws Throwable {
 
		// Do what you want with the actionperformed
		String actionPerformed = logAction.actionPerformed();
 
		// Do what you want with the join point arguments
		for ( Object object : pjp.getArgs()) {
			System.out.println(object);
		}
 
		return pjp.proceed();
	}
}

Updating the Spring app config

To ensure that our @Aspect annotated class is picked up by Spring you simply need to add the following to your app-config.xml

<aop:aspectj-autoproxy/>
<bean id="myAspect" class="package.to.my.MyAspect" />

This assumes that you have the aop namespace within your app-config beans definition like so

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
 
.....
 
</beans>

Setting up intercepted methods

The final step is to mark the methods we want to be intercepted

This is as easy as doing the following

@LogAction(actionPerformed="doSomething")
public void doSomething(MyObject someParameter) {
}

Now whenever that method is executed we will firstly execute our Aspect code.

Spring JS – Lack of an API or Documentation

Hi all,

This is a bit of a call out to the readers of the blog. In particular any Spring developers.

Recently I have been attempting to use Spring Web Flow and in particular it’s Spring JS implementation to Ajaxify applications I am working on.

However the documentation on Spring 3 and its Javascript support is quite lacking. In fact it seems to only consist of:

http://static.springsource.org/spring-webflow/docs/2.0.x/reference/html/ch11s04.html

Literally that is all the ‘official’ documentation I can find the rest seems to be forum posts by the Spring community.

Can anyone share any experience? Or give any feedback on the framework? Could we (as a community) look to help the development of this documentation?

By the way this shouldn’t put anyone off using Spring for the web application development. As a whole the framework is very useful and effective!!

Spring 3 RESTful Web Services

Step One – Project Creation with Maven

This tutorial is slightly different to my previous examples. In recent development I have begun to use Maven to manage my project dependencies.

If you are comfortable with creating a Web application project and Maven please skip down to the example code.

First of all you will need to install the Maven 2 plugin for Eclipse.

After you have installed the plugin create a new ‘Dynamic Web Project’ in Eclipse. Call it ‘SpringRestfulExample’.

Click Next. On the next screen we need to edit the src folder and the output folder. First of all remove the current src folder and then click ‘Add Folder…’

On the Add folder dialog enter the value /src/main/java and click OK.

Then make sure the default output folder reads target/classes. Click next

On the change the Context directory to read /src/main/webapp. Continue on to create the project.

Next we need to introduce Maven. Assuming you have installed the Maven plugin correctly Right click the Project and you should see a Maven menu item.

Highlight Maven and click ‘Enable Dependency Management’.

The next screen will ask you a few Maven options leave everything as it is apart from Packaging – change this to war. Click Finish.

Now we need to ensure the project uses any Maven dependencies we setup. Right click the Project and choose Properties.

From the Properties menu click ‘Java EE Module Dependencies’. On the right hand pane you will see ‘Maven Dependencies’ simply add a tick in that box and click Apply

Step Two – Making the Web application work

Next we’re going to make sure the web application works OK before we introduce Spring and other requirements.

In your src/main/webapp folder create a file called index.jsp and add some sample content like below:

<html>
	<head>
		<title>Spring RESTful Example</title>
	</head>
	<body>
		<p>Your WebApplication is up and running....</p>
	</body>
</html>

(If you open your web.xml file you’ll see a list of welcome files we’re creating the index.jsp of that welcome file list)

I’ll assume you’re comfortable with setting up local servers in Eclipse. If you open up your Servers view in Eclipse and add your project to your server, then start you server. You should be able to visit http://localhost:8080/SpringRestfulExample/ and view the page you created.

Step Three – Introducing Spring

In the root of your project you’ll notice that there is a file called pom.xml – this manages all your Maven dependencies.

Open the file (choose the tab pom.xml in the editor if the file opens up in the Maven editor) and add the following content:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>SpringRestfulExample</groupId>
	<artifactId>SpringRestfulExample</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
 
 	<properties>
    	<org.springframework.version>3.0.0.RELEASE</org.springframework.version>
	</properties>
 	<build>
 		<defaultGoal>compile</defaultGoal>
 		<directory>target</directory>
 		<sourceDirectory>src/main/java</sourceDirectory>
 		<outputDirectory>target/classes</outputDirectory>
 	</build>
 
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
		  	<artifactId>spring-core</artifactId>
		  	<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
	  		<groupId>org.springframework</groupId>
	  		<artifactId>spring-expression</artifactId>
	  		<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-beans</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-aop</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-context</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-context-support</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-web</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-webmvc</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
  			<groupId>org.springframework</groupId>
  			<artifactId>spring-oxm</artifactId>
  			<version>${org.springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.4.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tiles</groupId>
			<artifactId>tiles-api</artifactId>
			<version>2.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tiles</groupId>
			<artifactId>tiles-core</artifactId>
			<version>2.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tiles</groupId>
			<artifactId>tiles-jsp</artifactId>
			<version>2.1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.1.2</version>
		</dependency>
		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>
 
	</dependencies>
 
</project>

This Maven configuration includes all the required elements for the Spring example we’re going to be working with. If you need to read up more on Maven and Spring please see the SpringSource recent blog post.

Step Four – Configuring Spring MVC

Although we’re going to make an application that serves up RESTful XML we need to integrate Spring Web MVC. First of all we’ll create some basic Pojo objects that we shall represent.

Right click the src/main/java folder and create a new package called ‘com.spring.datasource’

Within that package create a new class called ‘Student’. Add the following content:

package com.spring.datasource;
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 *
 */
public class Student {
	private int id = -1;
	private String name = null;
 
	public Student() {
 
	}
 
	public Student(int id, String name) {
		this.id = id;
		this.name = name;
	}
 
	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}
	/**
	 * @param id the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}
	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
}

In the same package create a class called ‘Classroom’ and add the following:

package com.spring.datasource;
 
import java.util.ArrayList;
 
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 *
 */
@XmlRootElement(name = "class")
public class Classroom {
 
	private String classId = null;
	private ArrayList<Student> students = null;
 
	public Classroom() {
 
	}
 
	public Classroom(String id) {
		this.classId = id;
		students = new ArrayList<Student>();
		Student studentOne = new Student(1, "Student One");
		Student studentTwo = new Student(2, "Student Two");
		students.add(studentOne);
		students.add(studentTwo);
	}
 
	/**
	 * @return the classId
	 */
	public String getClassId() {
		return classId;
	}
 
	/**
	 * @param classId the classId to set
	 */
	public void setClassId(String classId) {
		this.classId = classId;
	}
 
	/**
	 * @return the students
	 */
	@XmlElement(name="student")
	public ArrayList<Student> getStudents() {
		return students;
	}
 
	/**
	 * @param students the students to set
	 */
	public void setStudents(ArrayList<Student> students) {
		this.students = students;
	}
}

A classroom is just a collection of students – in this example I have hard coded two students but you can imagine that this may be a datasource. Also note the further use of the @XmlElement annotations.

Now create a new package called ‘com.spring.controller’.

This will contain our Spring MVC controller. Within that package create a new class called ‘StudentsController’ and add the following:

package com.spring.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
 
import com.spring.datasource.Classroom;
 
/**
 * @author Eggsy - eggsy_at_eggsylife.co.uk
 *
 */
@Controller
public class StudentsController {
 
	public static final String STUDENTS_VIEW_KEY = "studentsView";
 
	@RequestMapping(method=RequestMethod.GET,value="/students")
	public ModelAndView showStudentsPage() {
		Classroom classOfStudents = new Classroom("Class One");
		ModelAndView mav = new ModelAndView(STUDENTS_VIEW_KEY);
		mav.addObject("classRoom", classOfStudents);
		return mav;
	}
}

I’ll assume you are comfortable with the Spring controller annotations. If not you can have a quick lookover my previous Spring blog posts. We use the same controlller for REST requests as well as normal HTML requests. Also as you can see we always return the same view. In essence the controller doesn’t do anything special or anything different from previous controllers you may have written.

It is within the servlet.xml file configuration that takes over handling the REST requests.

<bean id="studentsView" class="org.springframework.web.servlet.view.xml.MarshallingView">
	<constructor-arg ref="jaxbMarshaller" />
</bean>
 
<!-- JAXB2 marshaller. Automagically turns beans into xml -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
	<property name="classesToBeBound">
		<list>
			<value>com.spring.datasource.Classroom</value>
			<value>com.spring.datasource.Student</value>
		</list>
	</property>
</bean>

Notice name a bean studentsView which is a Spring Mashalling view. This matches the view our controller returns. We then make use of another great Spring feature called the ContentNegotiatingViewResolver this bean allows us to handle XML requests and HTML requests and it basically makes decision on which view resolver to use. The bean is declared like so:

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
	<property name="mediaTypes">
	    <map>
	        <entry key="xml" value="application/xml"/>
	        <entry key="html" value="text/html"/>
	    </map>
	</property>
	<property name="viewResolvers">
	    <list>
	        <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
	        <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
			<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
		</bean>
	    </list>
	</property>
</bean>

The content resolver declares two media types that we can handle (You can add more such as JSON) and then for the two media types we declare two View resolvers. For XML requests we use the BeanNameViewResolver so in practice we use the studentsView bean discussed earlier. Then for normal HTML requests we use the standard UrlBasedViewResolver configured with Tiles2 defintions.

The complete file is as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd">
 
 
	<context:component-scan base-package="com.spring.controller" />
	<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
 
	<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
		<property name="definitions">
			<list>
      				<value>/WEB-INF/tiles-defs/templates.xml</value>
    			</list>
		</property>
	</bean>
 
	<bean id="studentsView" class="org.springframework.web.servlet.view.xml.MarshallingView">
		<constructor-arg ref="jaxbMarshaller" />
	</bean>
 
	<!-- JAXB2 marshaller. Automagically turns beans into xml -->
	<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
		<property name="classesToBeBound">
			<list>
				<value>com.spring.datasource.Classroom</value>
				<value>com.spring.datasource.Student</value>
			</list>
		</property>
	</bean>
 
	<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        	<property name="mediaTypes">
            		<map>
                		<entry key="xml" value="application/xml"/>
				<entry key="html" value="text/html"/>
            		</map>
		</property>
        	<property name="viewResolvers">
            		<list>
		                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
                		<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
					<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
				</bean>
            		</list>
       		</property>
    	</bean>
</beans>

To complete the application we should create the required JSP’s and Tiles configuration. Under the /src/main/webapp create a new folder called ‘pages’ and create a file named ’students.jsp’ within it. Add the following content:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<p>Classroom of students</p>
 
<c:forEach var="student" items="${classRoom.students}">
	${student.id} - ${student.name}<br/>
</c:forEach>

Finally we need to create the tiles defintion file the view. Create a new folder called ’tiles-defs’ in the WEB-INF folder and create a file called ‘templates.xml’ within it. (Notice this matches the location in our servlet.xml file

Add the following content to the templates.xml file:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
 
<tiles-definitions>
 
	<definition name="studentsView" template="/pages/students.jsp">
	</definition>
 
</tiles-definitions>

Step Five – Updating the web.xml

Finally we need to configure the web.xml to work with Spring Web MVC. Open your web.xml file (located in the webapp folder) and make sure it matches the following:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>SpringRestfulExample</display-name>
 
 
	<servlet>
		<servlet-name>SpringRestfulExample</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
 
	<servlet-mapping>
    		<servlet-name>SpringRestfulExample</servlet-name>
    		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>
 
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

That should just about be it. If you start your webserver and visit the page http://localhost:8080/SpringRestfulExample/app/students you should see the JSP page you created with the two students listed.

However if you perform a curl request (mocking an XML request) you should see the XML representation of the classroom:

curl -H 'Accept: application/xml' http://localhost:8080/SpringRestfulExample/app/students

Project download

I have made the project available for download on Google’s Project hosting. You can get hold of it at http://code.google.com/p/eggsy-spring3-restful-example/ or via SVN on the URL http://eggsy-spring3-restful-example.googlecode.com/svn/trunk/

Resources

Spring forum post and help from user Toxic: http://forum.springsource.org/showthread.php?t=82146

REST in Spring 3 – Spring source blog : http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/

Eyal Lupu’s Java Blog : http://www.jroller.com/eyallupu/entry/content_negotiation_using_spring_mvc

SpringSource.org – RESTful Services : http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch18s02.html

Test link....