Omgo's Blog

October 25, 2009

Creating a JSR 303 style unique value annotation and using it in Spring 3 MVC

Filed under: Hibernate, Spring, Validation — aswin @ 4:18 am

I am currently playing with the new JSR 303 validation feature and it looks great.  This post shows how to create a simple annotation that validates whether an input field already exists in the database or not (useful for unique username situations).

So you start by defining a validation annotation for this purpose and would call it “Unique”

package com.omgo.security.domain.validator;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;

@Target({METHOD, FIELD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueIDValidator.class)
@Documented
public @interface Unique {
    String message() default "{com.omgo.security.domain.validator.constraints.uniques}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    /**
     * The mapped hibernate/jpa entity class
     */
    Class<?> entity();

    /**
     * The property of the entity we want to validate for uniqueness. Default name is "id"
     */
    String property() default "id";
}

Now to actually creating the implementation of the validator which we would name as UniqueIDValidator. This validator has dependencies on the Hibernate SessionFactory and this would be injected by Spring as it hooks into the validator framework using the  SpringConstraintValidatorFactory.  Luckily this is all done transparently by the org.springframework.validation.beanvalidation.LocalValidatorFactoryBean, so just declare this in your spring configuration and things would be smooth :).

package com.omgo.security.domain.validator;
import java.io.Serializable;
import java.util.List;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class UniqueIDValidator implements ConstraintValidator<Unique, Serializable> {

	HibernateTemplate hibernateTemplate;

	private Class<?> entityClass;
	private String uniqueField;

	public void initialize(Unique unique) {
		entityClass = unique.entity();
		uniqueField = unique.property();
	}

	public boolean isValid(Serializable property, ConstraintValidatorContext cvContext) {

		String query = String.format("from %s where %s = ? ", entityClass.getName(), uniqueField);
		List<?> list = hibernateTemplate.find(query, property);

		return list != null && list.size() > 0;
	}

	public SessionFactory getSessionFactory() {
		return hibernateTemplate != null ? hibernateTemplate.getSessionFactory() : null;
	}

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.hibernateTemplate = new HibernateTemplate(sessionFactory);
	}
}

So now that we have a validator that could be used to validate an object, we can use it to annotate our domain objects as follows .

@Entity
@Table(schema = "security", name = "company")
public class Company {
	@Id	@GeneratedValue(strategy=GenerationType.SEQUENCE)
	private Long id;

	@NotNull @Unique(entity=Company.class)
	private String name;
   ..........
   ..........
 }

With our entity object marked with all meta data needed for validation we should try putting this to real use, say by using this in a Spring MVC controller. It is pretty simple to do that with the annotated Spring MVC controller as you can declare the model attribute with a @Valid parameter annotation in your request handler method as the following example shows

	@RequestMapping(method=RequestMethod.POST)
	public String saveCompany(@Valid Company company, BindingResult results) {

	if (results.hasErrors()) {
			return newFormView(modelMap);
		} else {
		    //save the company
			return "redirect:/companies/" + company.getId();
		}
	}

Spring MVC would bind the user submitted form values to the Command/Form object (in this case Company) and apply the validation rules before handing over the bean and the results to your controller for taking further actions. In this example the action was to just forwarded it to the original form page ,in the case of error, where the errors could be displayed.

The spring context has to configured to use the JSR 303 as explained in this post. You could also manually validate this using the Validator as the following spring based JUnit test shows (make sure that you have the spring xml named UniqueValidatorTest-context.xml with the dependencies wired).  In fact there are limitations in the usage of validators in the current version of spring mvc (3.0.0.RC1) and one may need  to  fall back to the not so automatic way of validating  the beans.  For example currently Spring MVC does not allow you to specify cofiguring validation groups directly on your requesthandler methods. You could achieve a lot this by using the JSR 303 redefining default group feature , but if you need control over validations it is really simple, the following test case shows how to run the validators programmatically

package com.idinsight.security.domain.validator;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.idinsight.security.domain.Company;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration()
public class UniqueValidatorTest {

	@Autowired Validator validator;

	@Test
	public void test(){
		TestEntity entity = new TestEntity("inexistant", 10000l);
		Set<ConstraintViolation<TestEntity>> constraintViolations = validator.validate(entity);
		Assert.assertTrue(constraintViolations.size() > 0);
	}
}

class TestEntity {
	@NotNull @Unique(entity=Company.class, property="name")
	String name;

	@NotNull @Unique(entity=Company.class)
	Long id;

       TestEntity(String name, Long id){
            this.name = name;
            this.id = id;
       }
}

The Hibernate validator site has pretty detailed documentation on using the validation framework and includes lots of examples of creating custom validator annotations.  One very interesting features is the ability to group the validations, this would help in segregating validations belonging to multiple layers of the applications. There could be validators that are executed within the service layer (cases where the validators themselves may need to run under a transactional context) and other groups of validations aimed specifically at the presentation tier and such.

October 24, 2009

Spring MVC 3.x @Valid (JSR 303) Annotation Support

Filed under: Spring — Tags: , , , — aswin @ 1:53 am

The spring controllers have become really snazzy with annotation based controllers the 2.5 release and it continues to evolve in that direction.  The  old approach (extending framework classes such as SimpleFormController)  is deprecated as of  Spring 3.x and the new design seems to be going in the right direction .  There are of course certain disciplines one has to adopt to make these new styled controllers maintainable , otherwise this flexibility would be very reason for troubles.  This blog has a very good suggestions on designing controllers with Spring MVC annotations using Spring 2.5.  As mentioned in the blog , in Spring 2.5 one had to explicitly call the validate on the form objects, but Spring 3.x version adds the support to annotate the RequetMapping method argument with a @Valid annotation so you don’t have to explicitly validate your form/command objects.  So you would do the following to get the framework validate the command object for you

import javax.validation.Valid;
......

@RequestMapping(method=RequestMethod.POST)
	public String postNewUser(@Valid User user, BindingResult results, ModelMap mmap)  {

             if (results.hasErrors()) {
                   return formView(mmap);
             }
             return successView(mmap);
        }

The formView() and successView() methods from this example are local methods that are used to populate the model values and also to return the view names to forward to.  This style would be really useful to deal with certain issues when not using @ModelAttribute annotation to populate the  model. I will write about this in a later post.

Of course, for this to work you need to have the following in your spring applicationcontext.xml.


<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<!-- Configures Spring MVC DataBinder instances -->
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator" />
</bean>
</property>
</bean>

<!-- Creates the JSR-303 Validator -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

The official spring documentation reference that explains this in detail is here. For this to work you would need a JSR 303 validator framework in the classpath and using maven this is as simple as adding the following in your pom.xml.   This  post has lot more information on the JSR 303 itself.

<dependency>
<groupId>org.hibernate</groupId></pre>
<artifactId>hibernate-validator</artifactId>
<version>4.0.0.GA</version>
</dependency>
<pre>

References

Validation Annotations Reference (including Hibernate custom ones)

Spring documentation on validaton

October 21, 2009

Expandometaclass gotcha

Filed under: Groovy — aswin @ 9:10 pm

I hit a gotcha while trying out some basic Meta stuff in groovy. Say you wanted to replace the default “toString()” method of your String class with the following groovy code

String.metaClass.toString = {"completely useless"}
println new String("world saver").toString()

I was expecting to see the “completely useless” as answer, but turns out that the toString() method did not get overridden. After spending some time analyzing what was going on looks like the method being used for the invocation is actually the one from the super interface of String , CharSequence. This handle is used by the metaclass system and it resolves to the actual toString method implemented in the String class itself , completely ignoring the metaclass version we added. So what needs to be done to get the effect is to rewrite the code to look like

CharSequence.metaClass.toString = {"completely useless"}
println new String("world saver").toString()

and you get “completely useless”.  This is not exactly what one would want,  as this would affect all the subclasses that has implemented this method and all of them would return “completly useless” when their toString() method is invoked.   In short if you have a superinterface method you are trying to override (or replace I must say) using ExpandoMetaclass facility , the chances are that it would have this issue, so plan ahead 😉

ExpandoMetaClass and Metaclass system itself is getting rewritten for the Groovy 2 release I guess, so hopefully these kind of issues would go away.

Blog at WordPress.com.