Project

General

Profile

CdmValidation » History » Version 4

Ben Clark, 10/19/2009 04:32 PM

1 1 Ben Clark
2
# Common Data Model Validation
3
 
4
5
The CDM Validation infrastructure is a set of components that let you check the validity (correctness) of a CDM Java Bean. It works by applying rules or constraints to the properties of the object. Because it is possible to use the CDM Java Library to build a variety of applications, some rules or constraints are only applicable to certain categories of application and will therefore be ignored by other applications. Conversely, some rules are universal - violating these constraints will cause any application to behave in an undefined (or defined but *bad*) way.
6
7
8
The validation component (or _Validator_) is a simple spring managed bean that can be used throughout the application to check a data object for correctness and allow the application to react accordingly. It is a standard component from the _javax.validation_ or JSR 303 - Bean Valiation specification. The CDM Library uses hibernate validator, which is the reference implementation of the specification, as the standard validation service, and uses the spring framework's LocalValidatorFactoryBean to manage the validator and to hook the validation infrastructure into spring's data binding and validation components.
9
10
11
It is configured thus:
12
13
14
~~~
15
<bean id="validatorFactory" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
16
  <property name="mappingLocations">
17
    <set>              
18
      <value>classpath:/eu/etaxonomy/cdm/validation/name/TaxonNameBase-Constraints.xml</value>
19
    </set>
20
  </property>
21
</bean>
22
~~~
23
24
Most of the constraints are standard constraints that are part of the specification or provided as part of the cdmlib-model package. Some (those which depend upon services in the cdmlib-service package) require a bit of extra magic in the form of an xml file that specifies the validator at runtime.
25
26
27
28
## Using the validator
29
30
31
All possible uses of the bean validation specification or spring's data binding and validation infrastructure are beyond the scope of this page, so please refer to the hibernate validator website (http://validator.hibernate.org - note: make sure you're looking at the latest version of this project as the older version is not used by the CDM and is significantly different); Also check out the spring website (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ch05.html).
32
33
34
Fundamenally, the validation of an object works like this:
35
36
37
~~~
38
  T t = // Object is of some CDM Class
39
  Set<ConstraintViolation<T>> constraintViolations  = validator.validate(t);
40
41
  if(constraintViolations.isEmpty()) {
42
    // Object is valid, no problems here
43
  } else {
44
    // inspect the list of constraint violations and do something
45
  }
46
~~~
47
48
The ConstraintViolation object contains information about the constraint which has been violated, and a localized message suitable for display to the user.
49
50
51
52
## Validation Groups
53
54
55
As mentioned previously, some constraints are universal, wheras others may be ignored. We distinguish between constraints by putting them into groups. The `validate` method allows you to pass one or more extra arguments that specify which groups of constraints you want to check against. Calling `validate` without specifying a group validates at the default level (which all applications should conform to). As an example: 
56
57
~~~
58
  // Validate at Level2 and Level3
59
  Set<ConstraintViolation<T>> constraintViolations  = validator.validate(t, Level2.class, Level3.class);
60
~~~
61
62
Currently, the available validation levels are `Default` which is simple constraints such as String lengths etc, `Level2` which is context (database)-independent rules such as having correct epithets for a name of a given rank, and `Level3` which are context dependent rules that involve a database query (e.g. to check if an identical name exists).
63
64
65
66
## Validation Using Spring MVC
67
68
Spring MVC has a comprehensive data binding and validation infrastructure and it is quite straightforward to hook the validation annotations into this, by registering the validator factory as the valiator that should be used by the default web binding initializer (this can be customized on a per-controller basis if neccessary).
69
70
71
~~~
72
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
73
    <property name="webBindingInitializer">
74
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
75
            <property name="validator" ref="validatorFactory" />
76
        </bean>
77
    </property>
78
</bean>
79
~~~
80
81
Then annotating command objects as being `@Valid` (which is a JSR 303 annotation, not something provided by spring):
82
83
84
~~~
85
@Controller
86
public class NameController {
87
    
88
    @Autowired
89
    INameService service;
90
91
    @RequestMapping("/name", method=RequestMethod.POST)
92
    public void doPost(@Valid @ModelAttribute TaxonNameBase name, BindingResult result) {
93
      if(result.hasErrors()) {
94
        return new ModelAndView("name/edit");
95
      } else {
96
        service.save(name);
97
        ModelAndView mav = new ModelAndView("name/created");
98
        mav.addObject(name);
99
        return mav;
100
      }
101
    }
102
}
103
~~~
104
105 2 Ben Clark
This will cause spring to validate the object just after binding the request parameters to it. Any constraint violations are expressed as either FieldErrors (if the error is related to a particular field) or GlobalErrors if the error is related to the object as a whole. These errors are found in the BindingResult object. A common pattern upon failing a model constraint is to return the user to the original form view and display the error messages alongside the relevant form fields so that the user can correct the values and resubmit. Depending on the view technology you're using (e.g. jsp, velocity, freemarker) you might want to use the spring tag / macro libraries thus:
106
107
108
~~~
109
<form:form commandName="name" >
110
      <table>
111
          <tr>
112 3 Ben Clark
              <td>Genus or Uninomial:</td>
113 2 Ben Clark
              <td><form:input path="genusOrUninomial"/></td>
114
              <td><form:errors path="genusOrUninomial"/></td>
115
          </tr>
116
          <tr>
117
              <td>Generic Epithet:</td>
118
              <td><form:input path="genericEpithet"/></td>
119
              <td><form:errors path="genericEpithet"/></td>
120
          </tr>
121
  . . .
122 1 Ben Clark
~~~
123 3 Ben Clark
124 4 Ben Clark
An example of a global error: 
125 1 Ben Clark
126 4 Ben Clark
![](Object_Error.png)
127
128
and an example of a field error:
129
130
![](Field_Error.png)