Payday Loans Payday Loan
Home > Java EE 5, Spring MVC, Spring Webflow > Model Validation with JSR 303, Spring Webflow and Spring MVC

Model Validation with JSR 303, Spring Webflow and Spring MVC

February 8th, 2010 Leave a comment Go to comments

Spring 3.0 supports the new JSR-303 validation. JSR-303 standardizes validation constraint declaration and metadata for the Java platform.  The following model object has its fields annotated with JSR-303 (javax.validation.*).

 
@Entity(name = "partner")
@Indexed
public class Partner extends NamedEntity implements Serializable {
	@Column
	@javax.validation.constraints.NotNull(message = "partnerType must not be null.")
	private PartnerType partnerType;

	@javax.validation.NotEmpty(message = "Lanaguage can't be empty")
	private String language;
	@javax.validation.NotEmpty(message = "contact person can't be empty")
	private String contactPerson;

}

Spring 3.0 reference guide.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/new-in-3.html#new-feature-validation

explains how to configure and use JSR-303 in Spring 3.0 , but there is no clear way of doing samething in Spring Webflow.

Model validation is needed whenever you want to bind a model with data from a form submitted by a user and with JSR-303, anytime you want to valide an bean class. In this post, I am going to explain how you can configure JSR-303 validator factory in spring context as a bean and use it in both Spring MVC and Spring Webflow.

Add the following bean in your mvc application context.

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

You could also get the default validator factory in controller or validator class.

   private Validator validator= Validation.buildDefaultValidatorFactory().getValidator();
  1. Spring MVC

In mvc, there are several ways that you can use the above validator in your web controller:

Assuming that you using annotation driven mvc/controller.

	<!-- Dispatches requests mapped to POJO @Controllers implementations -->
	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="webBindingInitializer">
			<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
				<property name="validator" ref="validator" />
			</bean>
		</property>
	</bean>

if you are using the new mvc schema namespace.

<mvc:annotation-driven conversion-service="conversionService"  validator="validator"/> 

you can also dependency inject the validator to your controller

	@Autowired private javax.validation.Validator  validator 

To activate the validation in your controller, you can either add @Valid annotion in the respected method as a parameter before the model object. This will atutomaticly validate the model object, and update BindingResult with constraint messages.

	@RequestMapping(value = "/partner/", method = RequestMethod.POST)
	public String createPartner(@ModelAttribute("partner") @Valid Partner partner, BindingResult result) {
		Assert.notNull(partner, "Partner must be provided.");
		if (result.hasErrors())
			return "partner_create";
		partnerService.persist(partner);

		return "redirect:/partner/" + partner.getId();
	} 

or manually activate the validation against the model.

	
      @RequestMapping(value = "/partner/", method = RequestMethod.POST)
	public String createPartner(@ModelAttribute("partner") Partner partner, BindingResult result) {
		Assert.notNull(partner, "Partner must be provided.");		
		 for (ConstraintViolation<Partner> constraint : validator.validate(partner)) {
		  result.rejectValue(constraint.getPropertyPath().toString(), "",
		  constraint.getMessage()); }
		 
		if (result.hasErrors())
			return "partner_create";
		partnerService.persist(partner);

		return "redirect:/partner/" + partner.getId();
	}

The above finishes what you need to do to utilize the new JSR-303 in spring MVC, next I will show you how to acheive samething in your webflow.

  1. Spring Webflow

Say you are building an application that guides the user the business process of your application. The Spring webflow is great! technology of building a process driven application. I personally don’t like when I am filling an application online that asks me or displays fields to be filled out all at once. I am going to explain how to build page flow in Spring flow. The Spring webflow has excellent reference guide and there are lot of tutorial online.

 from Spring Web flow:  There are two ways to perform model validation programatically. The first is to implement validation logic in your model object. The second is to implement an external Validator. Both ways provide you with a ValidationContext to record error messages and access information about the current user.

In first case, just create a method with the name validate${state}, where ${state} is the id of your view-state. Say we have a state(choosePartnerType) which asks the user to select/enter a partner type(see code below). The will add a method with name validateChoosePartnerType in the following Partner model.

 
@Entity(name = "partner")
@Indexed
public class Partner extends NamedEntity implements Serializable {

	@Column
	@javax.validation.constraints.NotNull(message = "partnerType must not be null.")
	private PartnerType partnerType;

	@javax.validation.NotEmpty(message = "Lanaguage can't be empty")
	private String language;
	@javax.validation.NotEmpty(message = "contact person can't be empty")
	private String contactPerson;

	public void validateChoosePartnerType(Partner partner, ValidationContext context) {
		MessageContext messages = context.getMessageContext();
	  if (partnerType != null) {
    		messages.addMessage(new MessageBuilder().error().source("partnerType").
        	defaultText("partnerType must not be null.").build());
		 } 
		}
	 }

}

In the code above, you have to check every field and validate them. Let us change the code, and use JSR-303 to validate all fields through their constrainsts.If there are errors, we will add them to message context. The method only takes ValidationContext, MessageContext or Error Object, but not BindingResult.

 
@Entity(name = "partner")
public class Partner extends NamedEntity implements Serializable {
	@Column
	@javax.validation.constraints.NotNull(message = "partnerType must not be null.")
	private PartnerType partnerType;

	@javax.validation.NotEmpty(message = "Lanaguage can't be empty")
	private String language;
	@javax.validation.NotEmpty(message = "contact person can't be empty")
	private String contactPerson;

	public void validateChoosePartnerType(Partner partner, ValidationContext context) {
		BindingResult result = new BeanPropertyBindingResult(partner, "partner");
		for (ConstraintViolation<Partner> constraint : validator.validate(partner)) {
			result.rejectValue(constraint.getPropertyPath().toString(), "", constraint.getMessage());
		}
		MessageContext messages = context.getMessageContext();
		if (result.hasErrors()) {
			for (FieldError fieldError : result.getFieldErrors()) {
				messages.addMessage(new MessageBuilder().error().source(fieldError.getField()).defaultText(
						fieldError.getDefaultMessage()).build());
			}
		}
	}
}
  1. santhoshsd
    November 15th, 2010 at 07:58 | #1

    I have set the validator in the mvc application context

    and in the entity definition I have autowired the validator
    @Autowired
    private javax.validation.Validator validator;

    finally I have defined the validateState method in the entity as mentioned in the last code example.

    I am getting the following error:
    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.webflow.execution.repository.snapshot.SnapshotCreationException: Could not serialize flow execution; make sure all objects stored in flow or flash scope are serializable

    org.springframework.webflow.execution.repository.snapshot.SnapshotCreationException: Could not serialize flow execution; make sure all objects stored in flow or flash scope are serializable

    java.io.NotSerializableException: org.springframework.validation.beanvalidation.LocalValidatorFactoryBean

    thank you

  2. Runar
    May 27th, 2011 at 06:46 | #2

    Where is the ‘validator’ variable in the last example (SPW) defined? I’m very curious to know how you made this example work.

  3. August 2nd, 2012 at 13:18 | #3

    Hey superb website! Does running a blog such as this take a lot of work? I have absolutely no understanding of coding but I was hoping to start my own blog soon. Anyway, if you have any recommendations or tips for new blog owners please share. I know this is off subject however I simply needed to ask. Thanks a lot!

  4. Cayn
    November 13th, 2012 at 03:00 | #4

    Official documentation:
    http://static.springsource.org/spring-webflow/docs/2.3.x/reference/html/ch05s10.html

    For the automatic way of validating beans it is enough to add a validator to flow registry builder service. You may need though to put validation=”false” on cancel / abort transitions because they will be validated too by default.

  1. No trackbacks yet.