What's inside a violation?

What's Inside A Violation?

If the validator found a number of violations, what can we do with it? Let's have a look at the simple usages of violation objects.

Single Module Per Experiment

I copied the simple usage module for this purpose, so you can always look at the simplest possible code to learn JSR 303 in small steps. The module for this experiment is called beanvalidation.usage.violations.

Add some console logging...

I'm going to use simple output logging to learn about the properties the Violation objects provide. For this purpose, the parent pom is enhanced by a new dependency to the log4j framework:

    <!-- inside pom.xml of module beanvalidation.parent: ... -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

Now, to configure how log4j should do its logging, let's add a simple initial configuration file log4j.xml beneath src/test/resources.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
  <appender class="org.apache.log4j.ConsoleAppender" name="CONSOLE">
    <param name="Target" value="System.out"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%-4r [%t] %-5p %c %x - %m%n" />
    </layout>
  </appender>
  
  <root>
    <priority value ="INFO" />
    <appender-ref ref="CONSOLE" /> 
  </root>
</log4j:configuration>

Logging Violation Properties

Next is to add a logger object to the (copied) PersonTest.java:

@Test
public class PersonTest {

  private Validator validator;

  private static Logger log = Logger.getLogger(PersonTest.class);
  
  // ... same as before ...

For the actual logging, we enhance the test method, which we also rename to reflect its new purpose better:

  public void logViolationProperties() {
    Person peter = new Person(1999);
    Set<ConstraintViolation<Person>> violations = validator.validate(peter);

    assertThat(violations.size()).as("Number of violations").isEqualTo(1);
    ConstraintViolation<Person> violation = violations.iterator().next();

    log.info("Message Template: " + violation.getMessageTemplate());
    log.info("Message: '" + violation.getMessage() + "'");
    log.info("Invalid Value: " + violation.getInvalidValue());
    log.info("Property Path: " + violation.getPropertyPath());
  }

The output of this test, on my system, is as follows:

0    [main] INFO  org.hibernate.validator.util.Version  - Hibernate Validator 4.0.2.GA
112  [main] INFO  de.lightful.jsr303.examples.basic.PersonTest  - Message Template: {javax.validation.constraints.Min.message}
112  [main] INFO  de.lightful.jsr303.examples.basic.PersonTest  - Message: 'muss grössergleich 2000 sein'
112  [main] INFO  de.lightful.jsr303.examples.basic.PersonTest  - Invalid Value: 1999
112  [main] INFO  de.lightful.jsr303.examples.basic.PersonTest  - Property Path: yearlyIncome

Validator Craving For Recognition...?

I dislike the fact that Hibernate Validator dumps its version number without being asked for. Fortunately, the logger is configured to tell us the Java class which does the logging, so it's easy to switch it off using a simple log4j configuration statement:

    <!-- log4j.xml in beanvalidation.usage.violations: -->
    <appender-ref ref="CONSOLE" /> 
  </root>

  <logger name="org.hibernate.validator.util.Version">
    <level value="ERROR"/>
  </logger>

A closer look at the output

Stripping the log4j-generated context information, we get the following output:

Message Template: {javax.validation.constraints.Min.message}
Message: 'muss grössergleich 2000 sein'
Invalid Value: 1999
Property Path: yearlyIncome

As you might notice, the message returned by the validation is localized (German in this case), which is of course due to fact that the operating system of my computer is set to a German locale. The message template is made up of an NLS key in curly braces, allowing any user of the validation API to localize violation messages to one's heart's content. More on localization later.

The violation object is also capable of informing us about the actual value which was deemed invalid, using getInvalidValue(), and the path of the property which is invalid (getPropertyPath), relative to the so-called Root Bean. The root bean is basically the bean which is passed to the validate(Object) method. In our case, this should be the same object as "peter". This distinction is not too important here, but since JSR 303 also supports validation of object graphs, it does make sense in a broader context. For now, let's make sure the root bean is actually the same bean as "peter", using another assertion:

  public void logViolationProperties() {
    Person peter = new Person(1999);
    Set<ConstraintViolation<Person>> violations = validator.validate(peter);

    assertThat(violations.size()).as("Number of violations").isEqualTo(1);
    ConstraintViolation<Person> violation = violations.iterator().next();

    log.info("Message Template: " + violation.getMessageTemplate());
    log.info("Message: '" + violation.getMessage() + "'");
    log.info("Invalid Value: " + violation.getInvalidValue());
    log.info("Property Path: " + violation.getPropertyPath());

    log.info("Peter: " + peter);
    log.info("Root Bean: " + violation.getRootBean());
    assertThat(violation.getRootBean()).as("Root Bean").isSameAs(peter);
  }

Stripping the context information generated by log4j, we get two additional lines of output, plus a green test:

Peter: de.lightful.jsr303.examples.basic.Person@4979935d
Root Bean: de.lightful.jsr303.examples.basic.Person@4979935d