Bean validation in Apache Camel

Updated:

Bean validation in Apache Camel

If I had £1 for every time I’ve written an if statement. If statements to check whether a field is missing. If statements to check for nulls. If statements, if statements, if statements.

But there is a often-overlooked part of Java that gives you everything you need to perform simple validation of Java objects, without writing dozens of if statements.

It’s Bean Validation. And when combined with Camel’s ability to swim between Java and dozens of other data formats, it makes it easy to validate data in an elegant way.

Why do we validate, and how

We almost always need to validate data in our apps. For incoming data, you might need to check that all fields have been filled in before beginning to process it.

And if your Camel application also produces some outgoing data for another system, you might also have a requirement to check that the data you’re pushing out isn’t missing anything.

In Java, there is an under-loved API for doing validation on Java objects. It’s called the Bean Validation API (sometimes referred to by its snappy nickname JSR-303) and it’s been a part of Java for a long time now.

It consists of a set of APIs that allow you to set validation rules on Java classes using simple annotations. These annotations can, for example, state which fields in a class must be not null, and whether their values must match certain conditions, and so on.

And it’s all done using simple annotations, because who doesn’t love annotations?

Of course, there’s great support for this in Camel.

Validating your Java object in Camel

Support for Bean Validation starts with the bean-validator component, which requires the camel-bean-validator dependency to be added to your Maven POM.

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-bean-validator</artifactId>
</dependency>

The reference implementation (the actual thing that implements the JSR-303 standard) is Hibernate Validator. This is included when you pull in camel-bean-validator. (At the time of writing, Camel 2.21.1 uses Hibernate Validator 5.4.2.)

Defining validation rules

Start by adding validation annotations to fields in your Java class. These are defined in the package javax.validation.constraints. Some of the most common ones in from the JSR-303 API are:

  • @NotNull - checks that the field is not null
  • @AssertTrue/@AssertFalse - checks that the field is true or false
  • @Pattern(regex=, flags=) - checks that the field matches the given regex, with the given flags

There are also some Hibernate-specific annotations in org.hibernate.validator.constraints, like:

  • @Email - checks that the field contains a valid email address
  • @CreditCardNumber - this one’s probably obvious
  • @NotEmpty - checks whether the annotated field is not null nor empty

See the full Javadocs for Hibernate Validator here.

An annotated class might look like this:

public class Student {

  // No validation rules on these fields
  private String firstName;
  private String lastName;

  // This field can't be null
  @NotNull
  private String grade;

  // This field must be true
  @AssertTrue
  private boolean graduated;
  
  // your getters and setters would appear here,
  // but your author has omitted them for sanity
}

Validate the object

To validate your Java object in Camel, you just route it through a Bean Validator endpoint, by adding a step to your Camel route, like this:

.to("bean-validator:myvalidatorname")

Where myvalidatorname can be any name you like.

You don’t need to specify your validation rules, because they’re already defined as annotations on your Java class. The component knows to simply execute any rules that you have defined on your current Java class. Neat, huh.

When validation fails

When your POJO fails validation, Camel will throw an exception, which you can catch.

This example exception says that two fields failed validation: graduated (because it wasn’t true) and grade (because it was null):

org.apache.camel.component.bean.validator.BeanValidationException: Validation failed for: StudentWithValidation{firstName=’John’, lastName=’doe’, grade=’null’} errors: [property: graduated; value: false; constraint: must be true; property: grade; value: null; constraint: may not be null; ].

Note how the validator gives the “bad” value, and throws only one exception, even if there are many validation failures.

Since it’s a Java exception, you can do what you like. For example, if you’re processing a batch of records, you might want to catch the exception and store it in a List for adding to an error log.

Example: validating object from JSON using Bean Validation

In this example, I receive a JSON file using a File component, convert (unmarshal) it into a POJO, and then validate it using the Bean Validator.

I’m using the same Student class as shown earlier in this article.

public void configure() throws Exception {
    
  // Set up a JSON format so we can unmarshal to a POJO
  JsonDataFormat json = new JsonDataFormat(JsonLibrary.Jackson);
  
  // Set the target class that I want to convert the JSON to
  json.setUnmarshalType(Student.class);

  // Read a JSON file
  from("file:files/input/json")
  
      // convert to a Java object
      .unmarshal(json) 
      
      // Validate the Java object
      .to("bean-validator:myvalidator")
        
      .to("mock:output");
}

When should you use it?

Are you building a Camel application that transforms data? You might find Bean Validation useful if you have structured data that you need to apply certain rules to – especially if these are simple constraints, like checking for null values, or checking that a number is between a certain range.

Typically you’ll only use this component when you’re working with POJOs.

To get your message to a POJO, you’re first going to need to unmarshal from any text-based format you’re receiving (like XML or JSON) into your Java object.

Then you can simply add a bean-validation: endpoint to your Camel route, and apply your validation rules. (And hopefully say bye-bye to if statements.)

Since the component will throw an exception, you can easily catch it using Camel’s exception handling features, and then you can choose to log or do something else with the message.

If you need more complex validation, then you can write your own custom validator.

If Bean Validation is your bag and you want to see what’s coming round the corner, check out Bean Validation 2.0.

Got any questions about Bean Validation? Post your comments below.

Leave a Comment

You can use Markdown in your comment. To write code, indent lines by 4 spaces.