Custom Annotation Processing for Web Application

To know about how to declare custom annotations, what are the properties and options please refer to this post, which is very clear and simple.

What I will be discussing here is after you have declared and used your custom annotations, how to process them in run time for any web application.
Our aim is to find all the annotated classes and process their annotations at the time of servlet initialization i.e. in the init() method of the servlet. After getting those annotation attribute values we will be printing them just for this example. Lets build our custom annotation and one class annotated with that.

package com.annotated.classes.annotations;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Task {

	String id();

	String name();

	String uri();
}
package com.annotated.classes.example;

@Task(
		id = "Task1", 
		name = "Task1", 
		uri = "#task1"
)
public class Task1 {

}

The first thing we need to learn is how to get the class files from ‘WEB-INF/classes’ folder as well as all the classes from jars residing in ‘WEB-INF/lib’ folder. We are going to use ‘ServletContext’ to get the list of class files. We will be looking for all the class files under a specified package. So lets declare it at the very beginning with some other top level variables.

private String packageName = "com.annotated.classes";
private String packageNamePath = packageName.replace(".", "/");
private String classesPath = "/WEB-INF/classes/" + packageNamePath;
private String jarsPath = "/WEB-INF/lib";

‘WEB-INF/classes’
The ‘getResourcePaths’ method of ‘ServletContext’ gives us a list of resources (.class files and folders) under a specified path. If we encounter a sub folder under the path we need to get resources from that folder also. So its better to have a recursion to traverse the folder structure to get all the .class files.

private Set<String> getClassFiles(String path, ServletContext context, Set<String> finalList) {

	Set<String> resourceSet = context.getResourcePaths(path);
	if (resourceSet != null) {
		for (Iterator<String> iterator = resourceSet.iterator(); iterator.hasNext();) {
			String resourcePath = (String) iterator.next();

			if (resourcePath.endsWith(".class")) {
				finalList.add(resourcePath.substring(resourcePath.indexOf(packageNamePath)));
			} else {
				getClassFiles(resourcePath, context, finalList);
			}
		}
	}
	return finalList;
}

The method will be called like

ServletContext context = servletConfig.getServletContext();
Set<String> classFiles = new HashSet<String>();
classFiles = getClassFiles(classesPath, context, classFiles);

‘WEB-INF/lib’
Here we will be opening each jar we have in our lib folder and scan for the same package declared above and get the list of class files under them.

Set<String> libJars = context.getResourcePaths(jarsPath);
Set<String> allClasses = new HashSet<String>();

if (libJars != null) {
	for (String jar : libJars) {
		JarInputStream jarInputStream = new JarInputStream(context.getResourceAsStream(jar));
		JarEntry jarEntry;

		while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
			if ((jarEntry.getName().startsWith(packageNamePath)) && (jarEntry.getName().endsWith(".class"))) {
				allClasses.add(jarEntry.getName());
			}
		}
	}
}

Now we have all the class files we expect to have annotated with our custom annotation. To find what classes are annotated with our annotation we may use java reflection. But here we will be using Javassist as its much lighter. The tutorial can be found here and download from here.

First we need to add our class paths to the ClassPool object to be able to get the reference of the classes.

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(CustomAnnotationProcessor.class));
pool.appendClassPath(jarsPath);

The CtClass object from Javassist will give us the reference of the class. It expects the input as the fully qualified class name. We need to do some string manipulation to get the fully qualified class names from the list we got from above. Once we have the CtClass object we can check for its annotations and if present get the instance of the annotation with attribute values.

CtClass cc = pool.get(classFile);
Object[] annotations = cc.getAnnotations();
for (Object annotation : annotations) {
	if (annotation instanceof Task) {
		Task task = (Task) annotation;
		
		System.out.println("Id : " + task.id());
		System.out.println("Name : " + task.name());
		System.out.println("URI : " + task.uri());
	}
}

And with all it together we have

package com.annotated.classes.annotation;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;

public class CustomAnnotationProcessor {

	private String packageName = "com.annotated.classes";
	private String packageNamePath = packageName.replace(".", "/");
	private String classesPath = "/WEB-INF/classes/" + packageNamePath;
	private String jarsPath = "/WEB-INF/lib";

	public void processAnnotations(ServletConfig servletConfig) {

		ServletContext context = servletConfig.getServletContext();
		Set<String> classFiles = new HashSet<String>();
		classFiles = getClassFiles(classesPath, context, classFiles);

		Set<String> libJars = context.getResourcePaths(jarsPath);
		Set<String> allClasses = new HashSet<String>();

		if (!classFiles.isEmpty()) {
			allClasses.addAll(classFiles);
		}

		try {
			// Javassist to get classes from class paths
			ClassPool pool = ClassPool.getDefault();
			pool.insertClassPath(new ClassClassPath(AnnotationProcessor.class));
			pool.appendClassPath(jarsPath);

			// Get classes from Jar files
			if (libJars != null) {
				for (String jar : libJars) {
					JarInputStream jarInputStream = new JarInputStream(context.getResourceAsStream(jar));
					JarEntry jarEntry;

					while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
						if ((jarEntry.getName().startsWith(packageNamePath)) && (jarEntry.getName().endsWith(".class"))) {
							allClasses.add(jarEntry.getName());
						}
					}
				}
			}

			// Read Annotations
			for (String classFile : allClasses) {

				classFile = classFile.replace("/", ".").substring(0, classFile.indexOf(".class"));

				CtClass cc = pool.get(classFile);
				Object[] annotations = cc.getAnnotations();
				for (Object annotation : annotations) {
					if (annotation instanceof Task) {
						Task task = (Task) annotation;

						System.out.println("Id : " + task.id());
						System.out.println("View : " + task.viewClass());
						System.out.println("URI : " + task.uri());
					}
				}
			}
			
		} catch (NotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private Set<String> getClassFiles(String path, ServletContext context, Set<String> finalList) {

		Set<String> resourceSet = context.getResourcePaths(path);
		if (resourceSet != null) {
			for (Iterator<String> iterator = resourceSet.iterator(); iterator.hasNext();) {
				String resourcePath = (String) iterator.next();

				if (resourcePath.endsWith(".class")) {
					finalList.add(resourcePath.substring(resourcePath.indexOf(packageNamePath)));
				} else {
					getClassFiles(resourcePath, context, finalList);
				}
			}
		}
		return finalList;
	}

}
Advertisements

Simple REST Web Service – Spring

The Service :
Create a project with Maven for Eclipse Dynamic Web Project from here.

Here I have used Spring Annotation up to my knowledge. I believe there are more things which can be annotated.

The Deployment Descriptor (web.xml) is the simplest

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5" id="WebApp_1291891438549">

  	<display-name>Spring REST Example1</display-name>
  	<servlet>
		<servlet-name>person</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>person</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

So we must have the person-servlet.xml

<?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"
	xmlns:oxm="http://www.springframework.org/schema/oxm"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

	<context:component-scan base-package="com.dyuti.spring.rest" />

	<!-- Format Output -->
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
	<bean id="personXmlView"
		class="org.springframework.web.servlet.view.xml.MarshallingView">
		<constructor-arg>
			<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
				<property name="autodetectAnnotations" value="true" />
			</bean>
		</constructor-arg>
	</bean>
	<!--          -->

	<!-- Convert Input -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
			<list>
				<ref bean="marshallingHttpMessageConverter" />
			</list>
		</property>
	</bean>

	<bean id="marshallingHttpMessageConverter"
		class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
		<property name="marshaller" ref="jaxb2Marshaller" />
		<property name="unmarshaller" ref="jaxb2Marshaller" />
	</bean>

	<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
		<property name="classesToBeBound">
			<list>
				<value>com.dyuti.spring.rest.domain.Person</value>
			</list>
		</property>
	</bean>
	<!--          -->

	<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost/person" />
		<property name="username" value="root" />
		<property name="password" value="*****" />
	</bean>

	<bean id="mySessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="myDataSource" />
		<property name="annotatedClasses">
			<list>
				<value>com.dyuti.spring.rest.domain.Person</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<value>hibernate.dialect=org.hibernate.dialect.MySQLDialect</value>
		</property>
	</bean>

	<bean id="personDao" class="com.dyuti.spring.rest.dao.PersonDaoHibImpl">
		<property name="sessionFactory" ref="mySessionFactory" />
	</bean>
</beans>

We use org.springframework.oxm.xstream.XStreamMarshaller for converting Java Object to XML for sending through HTTP, and also converting HTTP XML data to corresponding Java Object.

The simple Person objec

package com.dyuti.spring.rest.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XmlRootElement
@XStreamAlias("person")
@Entity
@Table(name = "person")
public class Person implements Serializable {

	private static final long serialVersionUID = 2675617253130859687L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	@Column
	private String name;
	@Column
	private int age;

	// Generate getter & setter here
}

Now the DAO and the Hibernate Implementation

package com.dyuti.spring.rest.dao;

import com.dyuti.spring.rest.domain.Person;

public interface PersonDao {
	
	public boolean save(Person person);
	
	public Person get(int id);
}
package com.dyuti.spring.rest.dao;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.dyuti.spring.rest.domain.Person;

@Repository("personDao")
public class PersonDaoHibImpl extends HibernateDaoSupport implements PersonDao {

	@Override
	public boolean save(Person person) {
		int id = (Integer) getHibernateTemplate().save(person);
		return id > 0 ? true : false;
	}

	@Override
	public Person get(int id) {
		return (Person) getHibernateTemplate().get(Person.class, id);
	}
}

And the service and its implementation

package com.dyuti.spring.rest.service;

import com.dyuti.spring.rest.domain.Person;

public interface PersonService {

	public boolean savePerson(Person p);
	
	public Person getPerson(int id);
}
package com.dyuti.spring.rest.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dyuti.spring.rest.dao.PersonDao;
import com.dyuti.spring.rest.domain.Person;

@Service("personService")
public class PersonServiceImpl implements PersonService {

	@Autowired
	private PersonDao personDao;

	@Override
	public boolean savePerson(Person person) {
		return personDao.save(person);
	}

	@Override
	public Person getPerson(int id) {
		return personDao.get(id);
	}
}

The controller is the entry point and also the provider of the web service.

package com.dyuti.spring.rest.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.dyuti.spring.rest.domain.Person;
import com.dyuti.spring.rest.service.PersonService;

@Controller
public class PersonController {

	@Autowired
	private PersonService personService;

	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public ModelAndView getPerson(@PathVariable int id) {
		Person person = personService.getPerson(id);
		return new ModelAndView("personXmlView", BindingResult.MODEL_KEY_PREFIX
				+ "person", person);
	}

	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public ModelAndView addPerson(@RequestBody Person person) {
		boolean result = personService.savePerson(person);
		return new ModelAndView("personXmlView", BindingResult.MODEL_KEY_PREFIX
				+ "person", result);
	}
}

Finally the pom.xml

<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>com.dyuti.spring.rest</groupId>
	<artifactId>SpringREST</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>SpringREST</name>
	<url>http://maven.apache.org</url>

	<build>
		<finalName>SpringREST</finalName>
		<sourceDirectory>${basedir}/src/main/java</sourceDirectory>

		<resources>
			<resource>
				<directory>${basedir}/src/main/resources</directory>
			</resource>
		</resources>

		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<!-- configure the plugin here -->
						</configuration>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.0</version>
				<configuration>
					<webResources>
						<resource>
							<directory>${basedir}/src/main/webapp</directory>
							<filtering>false</filtering>
							<excludes>
								<exclude>WEB-INF/lib/*</exclude>
							</excludes>
						</resource>
					</webResources>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>${commons.beanutils.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>${commons.collections.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>${commons.lang.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>${commons.io.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>1.6</version>
			<exclusions>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.1</version>
			<exclusions>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xerces</groupId>
					<artifactId>xerces</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.2</version>
			<exclusions>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xerces</groupId>
					<artifactId>xerces</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate</artifactId>
			<version>${hibernate.version}</version>
			<exclusions>
				<exclusion>
					<artifactId>ehcache</artifactId>
					<groupId>net.sf.ehcache</groupId>
				</exclusion>
				<exclusion>
					<artifactId>commons-collections</artifactId>
					<groupId>commons-collections</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-annotations</artifactId>
			<version>${hibernate.annotations.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-commons-annotations</artifactId>
			<version>${hibernate.annotations.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.8</version>
		</dependency>

		<dependency>
			<groupId>org.apache.openejb</groupId>
			<artifactId>commons-dbcp-all</artifactId>
			<version>1.3</version>
		</dependency>

		<dependency>
			<groupId>javax.persistence</groupId>
			<artifactId>persistence-api</artifactId>
			<version>${jpa.version}</version>
		</dependency>

		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.0.0.GA</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		

		<dependency>
			<groupId>com.thoughtworks.xstream</groupId>
			<artifactId>xstream</artifactId>
			<version>1.3.1</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<properties>
		<spring.version>3.0.0.RELEASE</spring.version>
		<java.version>1.6</java.version>
		<servlet-api.version>2.5.0</servlet-api.version>
		<hibernate.annotations.version>3.3.0.ga</hibernate.annotations.version>
		<hibernate.version>3.2.6.ga</hibernate.version>
		<jpa.version>1.0</jpa.version>
		<commons.beanutils.version>1.7.0</commons.beanutils.version>
		<commons.collections.version>3.2</commons.collections.version>
		<commons.io.version>1.3.2</commons.io.version>
		<commons.lang.version>2.3</commons.lang.version>
	</properties>
</project>

So, the project is set up and deploy it on Tomcat.

The client :
The RestClient provided by Spring makes life very simple creating REST consumer.
Create another project (not necessary a web project, client can be anything, even if Ajax).

Create the same Person object from above.
Lets create the Spring context file, resides in the same package of the loader class under resource folder.

<?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"
	xmlns:oxm="http://www.springframework.org/schema/oxm"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

	<context:component-scan base-package="com.dyuti.spring.rest" />

	<bean id="personSave" class="com.dyuti.spring.rest.controller.SavePerson">
		<property name="restTemplate">
			<ref bean="restTemplate" />
		</property>
	</bean>
	<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"></bean>
</beans>

And the client class

package com.dyuti.spring.rest.controller;

import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.dyuti.spring.rest.domain.Person;

@Component
public class SavePerson {

	private RestTemplate restTemplate;

	private String restURL = "http://localhost:8080/SpringREST/";

	public void sendPerson() {
		Person person = new Person();
		person.setName("client");
		person.setAge(12);
		person.setId(3);

		Person p = restTemplate.getForObject(restURL + "2", Person.class);
		System.out.println(p.getName());

		String result = restTemplate.postForObject(restURL + "add", person,
				String.class);
		System.out.println(result);
	}

	public void setRestTemplate(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}
}

Run the client

package com.dyuti.spring.rest.controller;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RunRest {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml", RunRest.class);
		SavePerson savePerson = applicationContext.getBean("personSave",
				SavePerson.class);
		savePerson.sendPerson();
	}
}

I have used the same pom.xml for this project, which may require less packages.

Hibernate One-to-Many and Many-to-One Mapping using Annotation

person
id
name
age
sex
location

client
id
name

person_client
id
person_id
client_id

Person.java

package com.dyutiman.beans;

@Entity
@Table(name = "person")
public class Person {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;

	@OneToMany(mappedBy = "person")
	private List<PersonClient> personClients;

	@Column
	private String name;

	@Column
	private int age;

	@Column
	private String sex;

	@Column
	private String location;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public List<PersonClient> getPersonClients() {
		return personClients;
	}

	public void setPersonClients(List<PersonClient> personClients) {
		this.personClients = personClients;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}
}

Client.java

package com.dyutiman.beans;

@Entity
@Table(name = "client")
public class Client {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;

	@OneToMany(mappedBy = "client")
	private List<PersonClient> pc;

	@Column
	private String name;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public List<PersonClient> getPc() {
		return pc;
	}

	public void setPc(List<PersonClient> pc) {
		this.pc = pc;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

PersonClient.java

package com.dyutiman.beans;

@Entity
@Table(name = "person_client")
public class PersonClient {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;

	@ManyToOne
	@JoinColumn(name = "person_id")
	private Person person;

	@ManyToOne
	@JoinColumn(name = "client_id")
	private Client client;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}

	public Client getClient() {
		return client;
	}

	public void setClient(Client client) {
		this.client = client;
	}
}

Test

public void testLoad() {
	long id = 1;
	Client c = cd.load(id);

	List<PersonClient> pcList = c.getPc();
	for (PersonClient pc : pcList) {
		System.out.println(pc.getPerson().getName());
	}
}

public void testLoad() {
	long id = 1;
	Person p = pd.load(id);

	List<PersonClient> pcList = p.getPersonClients();
	for (PersonClient pc : pcList) {
		System.out.println(pc.getClient().getName());
	}
}

Simple Form on Spring Web MVC

Create the bean first

package com.dyutiman.spring.formbean;

public class Person {

	private String name;
	private int age;
	private String sex;
	private String location;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}
}

and a validator to validate this bean

package com.dyutiman.spring.validator;

public class PersonValidator implements Validator {

	@Override
	public boolean supports(Class<?> clazz) {

		return clazz == Person.class;
	}

	@Override
	public void validate(Object target, Errors errors) {

		Person p = (Person) target;

		ValidationUtils
				.rejectIfEmpty(errors, "name", "nameEmpty", "enter name");
		if (p.getAge() <= 0 || p.getAge() > 110) {
			errors.rejectValue("age", "wrongAge", "enter valid age");
		}
		ValidationUtils.rejectIfEmpty(errors, "sex", "sexEmpty", "select sex");
		ValidationUtils.rejectIfEmpty(errors, "location", "locationEmpty",
				"select location");
	}
}

Now, we create the controller where we register the validator for Person bean in the @InitBinder, a method to show the Person add form and another method to display the added Person

package com.dyutiman.spring.controller;

@Controller
public class PersonController {

	@InitBinder
	public void initModel(WebDataBinder binder) {

		Object target = binder.getTarget();
		
		if (target instanceof Person) {
			if (binder.getValidator() == null) {
				binder.setValidator(new PersonValidator());
			}
		}
	}

	@RequestMapping(value = "/index.htm")
	public ModelAndView showForm(Person p) {

		ModelAndView model = new ModelAndView("PersonForm");

		model.addObject("person", p);
		return model;
	}

	@RequestMapping(value = "/showPerson.htm", method = RequestMethod.POST)
	public ModelAndView submitPerson(@Valid Person p, BindingResult error) {

		// Submit to Database or else
		ModelAndView model = new ModelAndView();
		model.addObject("person", p);

		if (error.hasErrors()) {
			model.setViewName("PersonForm");
		}

		return model;
	}
}

As the controller is built, lets create the add form view first

<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%>

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Add Person</title>
<style type="text/css">
td span{color:red;}
</style>

</head>
<body>

<form:form commandName="person" action="showPerson.htm" method="post">
	<table>
		<tr>
			<th colspan="3">Add Person</th>
		</tr>
		<tr>
			<td width="49%" align="right">Name</td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><form:input path="name" /><form:errors path="name"/></td>
		</tr>
		<tr>
			<td width="49%" align="right">Age</td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><form:input path="age" /><form:errors path="age"/></td>
		</tr>
		<tr>
			<td width="49%" align="right">Sex</td>
			<td width="2%">&nbsp;</td>
			<td width="49%">Male: <form:radiobutton path="sex" value="male" />
			
			Female: <form:radiobutton path="sex" value="female" /><form:errors path="sex"/></td>
		</tr>
		<tr>
			<td width="49%" align="right">Location</td>
			<td width="2%">&nbsp;</td>
			<td width="49%">
				<form:select path="location">
					<form:option value="Bangalore" />
					<form:option value="Delhi" />
					<form:option value="Kolkata" />
					<form:option value="Mumbai" />
				</form:select><form:errors path="location"/></td>
		</tr>
		<tr>
			<td width="49%" align="right">&nbsp;</td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><input type="submit" value="Save Changes" /></td>
		</tr>
	</table>

</form:form>
</body>
</html>

and the display view

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<table>
		<tr>
			<th colspan="3">Added Person</th>
		</tr>
		<tr>
			<td width="49%" align="right"><b>Name</b></td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><c:out value="${person.name}"/></td>
		</tr>
		<tr>
			<td width="49%" align="right"><b>Age</b></td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><c:out value="${person.age}"/></td>
		</tr>
		<tr>
			<td width="49%" align="right"><b>Sex</b></td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><c:out value="${person.sex}"/></td>
		</tr>
		<tr>
			<td width="49%" align="right"><b>Location</b></td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><c:out value="${person.location}"/></td>
		</tr>
		<tr>
			<td width="49%" align="right">&nbsp;</td>
			<td width="2%">&nbsp;</td>
			<td width="49%"><a href="index.htm">go back</a></td>
		</tr>
	</table>
</body>
</html>

http://blog.jteam.nl/2009/05/14/simple-forms-with-spring-mvc-2-5/
http://maestric.com/doc/java/spring/form_validation

Simple Joining in Hibernate using Annotation

Using Hibernate with Annotation make life simpler.

Lets have 2 tables.
Country:
id bigint AUTO INCREAMENT
name varchar

and
State:
id bigint AUTO INCREAMENT
country_id bigint
name varchar

The relation is so obvious here. Our query will fetch a state with its country name.
The country class will look like

@Entity
@Table(name="country")
pulic class Country {
    
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;
	    
	@Column
	private String name;
}

and the state class

@Entity
@Table(name="state")
pulic class State {
    
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;

	@OneToOne
	@JoinColumn(name="country_id")
	private Country country;
	
	@Column
	private String name;
}

Thats it and thats all to define the relation between two tables.

Now when we load any state data, its also includes the country information

State s = (State) session.load(State.class, stateId);
System.out.println("State : " + s.getName());
System.out.println("Country : " + s.getCountry().getName());

and when we use HQL the scenario r3emains the same

State s = (State) session.createQuery("from " + State.class.getName() + " where id = " + stateId);
System.out.println("State : " + s.getName());
System.out.println("Country : " + s.getCountry().getName());