Sunday, 17 July 2011

Using the Hibernate Validation Annotation Processor

A few days ago, I blogged on the possibilities and problems of misapplying JSR 303 Bean Validation Annotations and concluded that a little more consistency was required in how exceptions are thrown when annotations are misapplied.

There is, currently in development, an validation annotation processor that’s designed to check whether or not you’ve applied validation annotations to your bean’s attributes correctly. It’s fully documented by Hibernate and the idea here is that you can test whether or not you’ve applied your constraints correctly by throwing up errors at compile time.

I thought that I’d try the code out, but before doing so, I created a new car class - a FordCar and randomly misapplied a whole bunch of annotations. Note that this hasn’t been done in a methodical way.

public class FordCar {

 
@Size(min = 4, max = 5)
 
@Past
  @NotNull
 
private final int numWheels;

 
@Min(value = 5)
 
@Max(value = 6)
 
@Pattern(regexp = ".*")
 
@DecimalMin(value = "25")
 
private final boolean hasTax;

 
@AssertFalse
  @Future
  @Null
  @Valid
 
private final int engineSize;

 
@AssertTrue
 
private final String colour;

 
@Min(value = 6)
 
@Max(value = 10)
 
private final String modelName;

 
public FordCar(int numWheels, String modelName, boolean hasTax, String colour,
     
int engineSize) {

   
this.numWheels = numWheels;
   
this.modelName = modelName;
   
this.hasTax = hasTax;
   
this.colour = colour;
   
this.engineSize = engineSize;
 
}

 
public final int getNumWheels() {

   
return numWheels;
 
}

 
public final String getModelName() {

   
return modelName;
 
}

 
public final boolean isHasTax() {

   
return hasTax;
 
}

 
public final String getColour() {

   
return colour;
 
}

 
public final int getEngineSize() {

   
return engineSize;
 
}
}

The hibernate documentation gives a couple of setup options for the validation annotation processor with the first one being just to add the following to your Maven dependencies:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>4.2.0.CR1</version>
    <scope>compile</scope>
</dependency>

However, applying this made no difference at all; none, zilch, nothing.

The next thing that the manual suggests is to use a Maven plugin. Again, this seems to be an experimental piece of code and a couple of steps are required to set it up. Firstly, add the following repository plugin entry to your POM file:

<pluginRepositories>
    <pluginRepository>
        <id>maven-annotation-plugin-repo</id>
        <url>http://maven-annotation-plugin.googlecode.com/svn/trunk/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>

Secondly, add the following plugin entry to you POM file:

<plugin>
    <groupId>org.bsc.maven</groupId>
    <artifactId>maven-processor-plugin</artifactId>
    <version>1.3.4</version>
    <executions>
        <execution>
            <id>process</id>
            <goals>
                <goal>process</goal>
            </goals>
            <phase>process-sources</phase>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator-annotation-processor</artifactId>
            <version>${project.parent.version}</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</plugin>

Running Maven install on my test project that contains the FordCar class displays the following output:

C:\java_projects2\Tips\marin-tips-hibernate-validator\target\generated-sources\apt
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:47: The annotation @Min is disallowed for this data type.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:59: The annotation @AssertTrue is disallowed for this data type.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:48: The annotation @Max is disallowed for this data type.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:56: Fields of a primitive type must not annotated with @Valid.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:53: The annotation @AssertFalse is disallowed for this data type.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:49: The annotation @Pattern is disallowed for this data type.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:50: The annotation @DecimalMin is disallowed for this data type.
[INFO] diagnostic C:\java_projects2\Tips\marin-tips-hibernate-validator\src\main\java\uk\co\marinsolutions\misapplied\FordCar.java:42: The annotation @Size is disallowed for this data type.
[ERROR] execute error
java.lang.Exception: error during compilation
 at org.bsc.maven.plugin.processor.AbstractAnnotationProcessorMojo.executeWithExceptionsHandled(AbstractAnnotationProcessorMojo.java:230)
 at org.bsc.maven.plugin.processor.AbstractAnnotationProcessorMojo.execute(AbstractAnnotationProcessorMojo.java:123)
 at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
 at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:556)

Looking at the above output, you can see that the code works up to a point, but you can erroneously annotate an int with the following:
  • @Past
  • @NotNull
  • @Future
  • @Null
…without getting any errors. Likewise, you can erroneously annotate a String with the following:
  • @Min
  • @Max
…and still not get any errors.

You get the feeling that this is bleeding edge technology that still has a few problems, but I guess that it’ll be really useful when it works correctly.

No comments: