Thursday, December 17, 2015

A story about Junit, Hibernate Spatial, Spring and H2

Lately, I've been tinkering (yes, tinkering, so do not expect the article of a guru who can explain you all the hidden and nearly magical mechanics beyond the code) with geospatial stuff.

Interesting subject, definitely. Had been working with the same subject also five years ago, but the evolution of both the standards and the implementations was so huge that, now, it is basically a brand new subject.

Anyway, to start diving into it, I set some fixed point:
1. Hibernate
2. Spring
3. JPA

Although some DBMS seem to be better than others, right now (on this subject PostgreSQL seems to be a step forward,  but it's difficult to read all the documentation possible), the first aim is to remain agnostic about the implementation in data layer.

That's the reason beyond the choice of Hibernate and JPA. JPA does not support geospatial operations oout of the box, but using HQL or Hibernate criterias does the trick.

And, in all fairness, it's definitely easy. Latest versions of Hibernate Spatial (5+) handle natively geometric types. In previous versions you had to annotate the entity property and, back when I first worked on the subject, it was almost a nightmare reading and writing geospatial data. Now, everything is so straightforward that persisting a geometric field is as difficult as persisting an integer.

After a bit of coding, I wanted to test what I did (and bully myself, of course :-) ). Though having everything wired up correctly was far less easy that coding.

As I said, I opted for libraries that are almost standards, nowadays, and above all, with very large communities, and started building up a unit test over them.
The DB chosen was H2 which, reading a bit around, is the one DB who can run in memory (essential for unit testing) and has geospatial extensions, via third party libraries. Amongst them, I've been looking at geodb and h2gis and opted for the first, for the simple reason that I found more literature and tutorials on the web.

Enough chat, and a bit of code.

The dependencies added in Maven for testing:

<repositories>
 <repository>
  <id>OSGEO GeoTools repo</id>
  <url>http://download.osgeo.org/webdav/geotools</url>
 </repository>
 <repository>
  <id>Map Fish repo</id>
  <url>http://dev.mapfish.org/maven/repository/repository</url>
 </repository>
</repositories>

...

<dependency>
 <groupId>com.h2database</groupId>
 <artifactId>h2</artifactId>
 <version>1.4.190</version>
 <scope>test</scope>
</dependency>
<dependency>
 <groupId>org.opengeo</groupId>
 <artifactId>geodb</artifactId>
 <version>0.7</version>
 <scope>test</scope>
</dependency>

plus, of course, hibernate-spatial:5.0.5.Final and all the needed dependencies of Spring Framework (core, context and data, mostly).

Then, set up the persistence context

<persistence 
 xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 version="2.0" 
 xsi:schemaLocation="
  http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
 <persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
  <class>org.jcz.persistence.ogc.jpa.model.GeoEntity</class>
  <exclude-unlisted-classes>true</exclude-unlisted-classes>
  <properties>
   <property name="hibernate.connection.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;IGNORECASE=TRUE" />
   <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
            <property name="hibernate.dialect" value="org.hibernate.spatial.dialect.h2geodb.GeoDBDialect" />
   <property name="hibernate.hbm2ddl.auto" value="create-drop" />
   <property name="hibernate.show_sql" value="true"/>
   <property name="hibernate.format_sql" value="true"/>
  </properties>
 </persistence-unit>
</persistence>

Note above all the dielect used. Hibernate Spatial comes shipped with lots of dialects for geospatial operations, including MySql, PostgreSQL (Postgis), SqlServer and Oracle.

And the Spring context (only the essential part of it to wire up DB connections and transactions)

   <bean class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" id="dataSource">
       <property name="driverClassName" value="org.h2.Driver"/>
       <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;IGNORECASE=TRUE"/>
       <property name="testOnBorrow" value="true"/>
       <property name="testOnReturn" value="true"/>
       <property name="testWhileIdle" value="true"/>
       <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
       <property name="numTestsPerEvictionRun" value="3"/>
       <property name="minEvictableIdleTimeMillis" value="1800000"/>
   </bean>
   
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
 id="transactionManager">
 <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean
 class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
 id="entityManagerFactory">
 <property name="persistenceUnitName" value="testPU" />
 <property name="dataSource" ref="dataSource" />
</bean>

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />

The entity class is a very simple one:

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import com.vividsolutions.jts.geom.Geometry;

@Table(name = "GEO_ENTITY")
public class GeoEntity {

 private static final long serialVersionUID = 6672700707065815510L;
 
 @Id
 private int id;
 
 @Column(unique = true)
 private String name;
 
 private Geometry location;
 
 public int getId() {
  return id;
 }
 
 public int setId(int id) {
  this.id = id;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public Geometry getLocation() {
  return location;
 }
 
 public void setLocation(Geometry location) {
  this.location = location;
 }
 
}

Note the type `Geometry` used for the property `location`: it comes shipped with Hibernate Spatial, so you don't have to worry about digging some myterious maven repo to find it. Hibernate, as said, handles it natively and you don't have o worry about that.
There is a particular way for creating Geometry objects, which is provided by the library itself. Just have a look at the documentation of WKTReader.

So far, it was quite straightforward, wasn't it?
And actually, it won't become overly complicated all of a sudden.
You can now write the first unit test. Persisting an entity with geospatial data inside and check that everything worked as planned.

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:META-INF/spring/context.xml")
@Transactional
public class CreationTestCase implements TestCaseData {
 
 private static final Logger log = LoggerFactory.getLogger(CreationTestCase.class);
 
 @Autowired
 private GeoEntityService geoEntityService;
  
 /**
  * @return the geoEntityService
  */
 public GeoEntityService getGeoEntityService() {
  return geoEntityService;
 }
 
 /**
  * @param geoEntityService the geoEntityService to set
  */
 public void setGeoEntityService(GeoEntityService geoEntityService) {
  this.geoEntityService = geoEntityService;
 }


 @Test
 public void creation() throws ParseException {
  GeoEntity geoEntity = geoEntityService.createTargetInstance();
  geoEntity.setName("GEO_1");
  Geometry g = new WKTReader().read(WKT_POLYGON_1);  
  geoEntity.setLocation(g);
  
  geoEntityService.save(geoEntity);
  assertThat(geoEntityService.count(), is(1L));
  
  log.debug("Reading entity");
  GeoEntity geoEntity2 = geoEntityService.findById(geoEntity.getId());
  
  assertThat(geoEntity.getId(), is(geoEntity2.getId()));
  assertThat(geoEntity.getLocation(), is(geoEntity2.getLocation()));
 }
}

There are some things to say about this class:
  1. it's a junit4 test case
  2. uses Spring runner instead of standard Junit runner (it permits lo load the Spring context)
  3. it's marked as `Transactional` which means that the DB connection is dropped and recreated at every test. Combined with the persistence.xml, it means that every test starts with a clean DB, as it should.
  4. the GeoEntityService is a class which exposes methods for saving and reading objects from the DB. It depends on your preference how to implement it (native Hibernate, Spring JPA, ...) and its implementation is beyond the scope of this article.

Last but not least!

When it comes to query the DB with geospatial fuctions the situation became a little frustrating, because I got an error who drove me crazy for a bit, before solving it:

[ERROR] 2015-12-16 11:16:15,000: org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions:129: Function "ST_CONTAINS" not found; SQL statement:
select geoentity0_.id as id1_0_, geoentity0_.location as location2_0_, geoentity0_.name as name3_0_ from GEO_ENTITY geoentity0_ where ST_Contains(geoentity0_.location, ?)=1 [90022-190]

Looked like Hibernate wasn't able to find the correct function, but it's false. The problem is that H2, natively, does not know the functions "ST_*", and it must be instructed to add them. Fortunately, you can instruct H2 to map Java code as native functions, which is where `geodb` comes in.

At start, H2 searches for a file named `import.sql` in classpath root to initialize the DB (the name and the location of the file can be changed, but it's a useless complexity for a local unit test). And that's the point to tweak it. Just create this file, and put this content into it

CREATE ALIAS AddGeometryColumn for "geodb.GeoDB.AddGeometryColumn"
CREATE ALIAS CreateSpatialIndex for "geodb.GeoDB.CreateSpatialIndex"
CREATE ALIAS DropGeometryColumn for "geodb.GeoDB.DropGeometryColumn"
CREATE ALIAS DropGeometryColumns for "geodb.GeoDB.DropGeometryColumns"
CREATE ALIAS DropSpatialIndex for "geodb.GeoDB.DropSpatialIndex"
CREATE ALIAS EnvelopeAsText for "geodb.GeoDB.EnvelopeAsText"
CREATE ALIAS GeometryType for "geodb.GeoDB.GeometryType"
CREATE ALIAS ST_Area FOR "geodb.GeoDB.ST_Area"
CREATE ALIAS ST_AsEWKB FOR "geodb.GeoDB.ST_AsEWKB"
CREATE ALIAS ST_AsEWKT FOR "geodb.GeoDB.ST_AsEWKT"
CREATE ALIAS ST_AsHexEWKB FOR "geodb.GeoDB.ST_AsHexEWKB"
CREATE ALIAS ST_AsText FOR "geodb.GeoDB.ST_AsText"
CREATE ALIAS ST_BBOX FOR "geodb.GeoDB.ST_BBox"
CREATE ALIAS ST_Buffer FOR "geodb.GeoDB.ST_Buffer"
CREATE ALIAS ST_Centroid FOR "geodb.GeoDB.ST_Centroid"
CREATE ALIAS ST_Crosses FOR "geodb.GeoDB.ST_Crosses"
CREATE ALIAS ST_Contains FOR "geodb.GeoDB.ST_Contains"
CREATE ALIAS ST_DWithin FOR "geodb.GeoDB.ST_DWithin"
CREATE ALIAS ST_Disjoint FOR "geodb.GeoDB.ST_Disjoint"
CREATE ALIAS ST_Distance FOR "geodb.GeoDB.ST_Distance"
CREATE ALIAS ST_Envelope FOR "geodb.GeoDB.ST_Envelope"
CREATE ALIAS ST_Equals FOR "geodb.GeoDB.ST_Equals"
CREATE ALIAS ST_GeoHash FOR "geodb.GeoDB.ST_GeoHash"
CREATE ALIAS ST_GeomFromEWKB FOR "geodb.GeoDB.ST_GeomFromEWKB"
CREATE ALIAS ST_GeomFromEWKT FOR "geodb.GeoDB.ST_GeomFromEWKT"
CREATE ALIAS ST_GeomFromText FOR "geodb.GeoDB.ST_GeomFromText"
CREATE ALIAS ST_GeomFromWKB FOR "geodb.GeoDB.ST_GeomFromWKB"
CREATE ALIAS ST_Intersects FOR "geodb.GeoDB.ST_Intersects"
CREATE ALIAS ST_IsEmpty FOR "geodb.GeoDB.ST_IsEmpty"
CREATE ALIAS ST_IsSimple FOR "geodb.GeoDB.ST_IsSimple"
CREATE ALIAS ST_IsValid FOR "geodb.GeoDB.ST_IsValid"
CREATE ALIAS ST_MakePoint FOR "geodb.GeoDB.ST_MakePoint"
CREATE ALIAS ST_MakeBox2D FOR "geodb.GeoDB.ST_MakeBox2D"
CREATE ALIAS ST_Overlaps FOR "geodb.GeoDB.ST_Overlaps"
CREATE ALIAS ST_SRID FOR "geodb.GeoDB.ST_SRID"
CREATE ALIAS ST_SetSRID FOR "geodb.GeoDB.ST_SetSRID"
CREATE ALIAS ST_Simplify FOR "geodb.GeoDB.ST_Simplify"
CREATE ALIAS ST_Touches FOR "geodb.GeoDB.ST_Touches"
CREATE ALIAS ST_Within FOR "geodb.GeoDB.ST_Within"
CREATE ALIAS Version FOR "geodb.GeoDB.Version"

And that's it! Junit test environment is ready for use.

Cheers,
Stefano

Thursday, February 21, 2013

Multiple pre and post actions with JPA using AspectJ

JPA provides you with some annotations to denotate methods (in the entities class) to be executed before / after persist / update / remove operations.
For example, @PrePersist could be used to generate a UUID for your entity (as JPA does not provide a way to fully customize the ID generator).
@PrePersist
private void ensureId(){
 setId(UUID.randomUUID().toString());
}
There is a limitation: just one method can be annotated with each of the annotation. For example, you can't have two methods marked as @PrePersist.

My solution is to create my own annotations and then write an aspect that inject in every @Entity class a method marked as @PrePersist / @PostPersist / ... that inspects the class looking for the methods marked with my own annotation and invoke them on the current object. This is really much more difficult to say than to implement... :-)

Annotations definition is quite straight forward
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface PrePersistAction {

 int value() default 0;

 String description() default "";
 
 boolean alwaysBefore() default false;

}
For brevity, I only pasted the code for the pre persist actions annotations. You can notice that every anotation holds some property:

  1. value: to create an order between action. If two actions hold the same value, then the order in which they are declared will be respected.
  2. description: usefull for logging
  3. alwaysBefore: this action must be executed before non-alwaysBefore annotations (for exampe, create an UUID). If multiple actions are marked as alwaysBefore, then refer to value to know the prder in which they'll be invoked

Once we have annotations, we can go on with our aspect. Pay particular attention to the pointcut which matches all the @javax.persistence.Entity classes.
public aspect ActionSupportAspect {
 
 private static interface EntitySupport {};
 
 declare parents : @Entity * implements EntitySupport;

 private void EntitySupport.invokeActions(Class annotationType) {
  Logger log = LoggerFactory.getLogger(this.getClass());

  Comparator comparator = this.retrieveComparatorForAction(annotationType);
  if (comparator == null)
   return;

  List actions = new ArrayList(ClassUtils.getMethods(this.getClass(),
    annotationType, true));
  Collections.sort(actions, comparator);

  if (actions.isEmpty()) {
   log.trace("\tNo action to execute");
  } else {
   for (Method action : actions) {
    Annotation annotation = action.getAnnotation(annotationType);
    String description = this.retrieveDescriptionForAction(annotation);
    log.trace(String.format("Executing action @ <%s>: %s", action.toString(), description));
    action.setAccessible(true);
    try {
     action.invoke(this);
    }
    catch (Exception e) {
     log.error(
       String.format("Can't perform action: %s @ <%s>", description,
         this.getClass()), e);
    }
   }
  }
 }

 @PrePersist
 private void EntitySupport.doPrePersist() {
  Logger log = LoggerFactory.getLogger(this.getClass());
  log.trace(String.format("Executing pre persist actions on <%s>", this.toSuperString()));
  this.invokeActions(PrePersistAction.class);
  log.trace(String.format("Executed pre persist actions on <%s>", this.toSuperString()));
 }

 @PostPersist
 private void EntitySupport.doPostPersist() {
  Logger log = LoggerFactory.getLogger(this.getClass());
  log.trace(String.format("Executing post persist actions on <%s>", this.toSuperString()));
  this.invokeActions(PostPersistAction.class);
  log.trace(String.format("Executed post persist actions on <%s>", this.toSuperString()));
 }

 @PreUpdate
 private void EntitySupport.doPreUpate() {
  Logger log = LoggerFactory.getLogger(this.getClass());
  log.trace(String.format("Executing pre update actions on <%s>", this.toSuperString()));
  this.invokeActions(PreUpdateAction.class);
  log.trace(String.format("Executed pre update actions on <%s>", this.toSuperString()));
 }

 @PostUpdate
 private void EntitySupport.doPostUpdate() {
  Logger log = LoggerFactory.getLogger(this.getClass());
  log.trace(String.format("Executing post update actions on <%s>", this.toSuperString()));
  this.invokeActions(PostUpdateAction.class);
  log.trace(String.format("Executed post update actions on <%s>", this.toSuperString()));
 }

 @PreRemove
 private void EntitySupport.doPreRemove() {
  Logger log = LoggerFactory.getLogger(this.getClass());
  log.trace(String.format("Executing pre remove actions on <%s>", this.toSuperString()));
  this.invokeActions(PreRemoveAction.class);
  log.trace(String.format("Executed pre remove actions on <%s>", this.toSuperString()));
 }

 @PostRemove
 private void EntitySupport.doPostRemove() {
  Logger log = LoggerFactory.getLogger(this.getClass());
  log.trace(String.format("Executing post remove actions on <%s>", this.toSuperString()));
  this.invokeActions(PostRemoveAction.class);
  log.trace(String.format("Executed post remove actions on <%s>", this.toSuperString()));
 }

}
[Please note that this is only an excerpt of the aspect. Full code is available via SVN.]

As you can see, this aspect inject into every @javax.persistence.Entity class methods marked as @PrePersist, etc... that internally invoke @PrePersistAction, etc... methods simulating to have the @PrePersist method split in various classes.
This is it! You can check out the full code (fully featured, along with some test) here!

Hope you'll find this useful,
Stefano

Monday, February 4, 2013

Spring 3 - Version 3.2.1 and NoUniqueBeandefinitionException

For those who are migrating from spring 3.1.x.RELEASE to the latest 3.2.1.RELEASE, I would like to signal a known bug.

The solution is however quite easy: just remove the version 3.2.1.RELEASE from your build.
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-xxx</artifactId>
 <version>[3.0.0, 3.2.1.RELEASE),(3.2.1.RELEASE,4.0.0)</version>
</dependency>

This stole me a week of life... but... what do you want? That's the developer life.

Hope this can save some of your time,
Stefano

Saturday, January 19, 2013

How to get rid of lazy collection initialization in Hibernatee4

Is there anybody out there who never hit the error
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: [...], no session or session was closed?

Well, now with Hibernate4 (starting from version 4.1.6.Final) the troubles are gone, hopefully once for all!

The trick is very simple. Just locate your persistence.xml file and add

<property name="hibernate.enable_lazy_load_no_trans" value="true"/>

under the "properties" node.


Monday, November 26, 2012

JPA 2.0 and Spring - persistence.xml not validated

Yesterday, while running a simple application that required JPA 2.0 and Spring framework, I hit a strange error.
Value '2.0' of attribute 'version' of element 'persistence' is not valid with respect to the corresponding attribute use. Attribute 'version' has a fixed value of '1.0'. junit
The solution is actually very simple one you understand the cause.
The problem is releted to the dependencies: the project held a denpendency to spring-jpa-2.0.8 which implements the JPA 1 specification.

So, to solve, I simply changed the dependency to spring-data-jpa-1.1.0.RELEASE.

Monday, July 23, 2012

Placing your custom tags inside a JAR with Maven

I recently wrote an article about packaging a TLD file inside a JAR and how to reference it to enable systematic reuse for these resources.
Other resources that likely you want to reuse are your custom tags.
This is very similar to packaging TLDs function files.
Let's start with a simple tag that substitutes the well-known IE checks for the CSS.
So, instead of writing
<!--[if IE 8]>
<link rel="stylesheet" href="ie.css" type="text/css" />
<![endif]-->
we'll be able to write
<my:ie test="IE 8" css="ie.css" />

The tag itself is quite easy. It will look like that
<jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core"
 xmlns:fn="http://java.sun.com/jsp/jstl/functions"
 xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
 <jsp:output omit-xml-declaration="yes" />

 <jsp:directive.attribute name="check" required="true" />
 <jsp:directive.attribute name="css" required="false"/>
 
 <jsp:text><![CDATA[<!--[if ${check}]>]]></jsp:text>
 <c:if test="${not empty css}">
  <link rel="stylesheet" href="${css}" type="text/css" />
 </c:if>
 <jsp:doBody />
 <jsp:text><![CDATA[<![endif]-->]]></jsp:text>

</jsp:root>

Actually this tag does also something more, but that's out of the scope of this article.
Now all you need to do is to place this tag inside the src/resources/META-INF directory. If you want to be tidy, you can even place it under a subdirectory, "tags" for example.
Now all you need to do is to add a TLD file under the META-INF directory as explained in the aforementioned articles describing your new tag, like that:
<?xml version="1.0" encoding="UTF-8"?>
<taglib 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/j2eeweb-jsptaglibrary_2_0.xsd" version="2.0">
 <tlib-version>1.0</tlib-version>
 <uri>http://mynamespace.org/tags/</uri>
 
 <tag-file>
  <name>ie</name>
  <path>/META-INF/tags/ie.tagx</path>
 </tag-file>
 
</taglib>
Be careful to use the correct value for the URI tag because that's the trick to reference this file from your JSP projects.

Hope you can find this helpful,
Stefano

Tuesday, July 10, 2012

Simple form validation with Spring MVC

While developing a web application it's always wise to provide users with feedback about form validation rather that present them the error.
Here, I want to show how to accomplich this task within a Spring MVC application.
First, write down the model against which validation will be performed. A model is nothing more than a POJO.

public class FormModel {
 
 private String name;
 private String surname;
 private Long years = 0L;

        // getters and settes omitted
}

The model has just two String members and a Long member. Let's suppose that the two strings cannot be empty (means, not null and containing at least one char) and that the Long must be greater than 0.
What we need to do now is to write down a validator for this object. I'm not going to implement the Spring Validator interface here to keep things as simple as possible.

public class FormModelValidator {
 
 public void validate(FormModel model, BindingResult bindingResult){
  if(model.getName()==null || model.getName().length()==0){
   bindingResult.rejectValue("name", "validation_form_model_name");
  }
  
  if(model.getSurname()==null || model.getSurname().length()==0){
   bindingResult.rejectValue("surname", "validation_form_model_surname");
  }
  
  if(model.getYears()<=0){
   bindingResult.rejectValue("years", "validation_form_model_years");
  }
 }

}

You can see that in the rejectValue methods I've used a code rather than a phrase: this is to localize your error messages. Now, the controller class. This is the class responsible of the binding between the application logic and what the user sees. As I said before, I want to keep things simpe: this is not the formal definition af a controller, you can find it here on Wikipedia.

public class FormController {

 private FormModel model = null;

 @ModelAttribute("model")
 public FormModel injectModel() {
  if (model == null)
   model = new FormModel();
  return model;
 }

 @RequestMapping(method = RequestMethod.GET)
 public String index() {
  return "index";
 }

 @RequestMapping(method = RequestMethod.POST)
 public ModelAndView doPost(@ModelAttribute("model") FormModel model,
   BindingResult bindingResult) {
  FormModelValidator validator = new FormModelValidator();
  validator.validate(model, bindingResult);

  if (bindingResult.hasErrors())
   return new ModelAndView("index");

  ModelAndView mav = new ModelAndView("index");
  mav.addObject("model", model);
  mav.addObject("message", "VALUES SUCCESSFULLY VALIDATED");
  
  return mav;
 }
 
}

You can even skip the implementation class and move al the code in the controller class.
Let's take a look at the controller.
We can see that it responds on the root path. It injects in the model our object (what we need to validate). It also handles the POST of the form (this is where the validation is performed).
You can also notice that our FormModel object is stored as a member of the controller class. This allows persistence between different posts of the form.
The last thing we need to take a look at, is the form.

<form:form method="post" modelAttribute="model">
 <div class="rows">
  <div class="row">
   <label>NAME</label>
   <form:input path="name" />
   <form:errors path="name" cssClass="errors" />
  </div>
  <div class="row">
   <label>SURNAME</label>
   <form:input path="surname" />
   <form:errors path="surname" cssClass="errors" />
  </div>
  <div class="row">
   <label>YEARS</label>
   <form:input path="years" />
   <form:errors path="years" cssClass="errors" />
  </div>
 </div>
 <div class="submit">
  <input type="submit" value="VALIDATE" />
 </div>
</form:form>

As you can see it is very simple. Just don't forget to include the namespace
http://www.springframework.org/tags/form
in your page directives.

You can check out the code (as a Spring Roo project) at this repository.

Bye,
Stefano