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 notnull
@AssertTrue
/@AssertFalse
- checks that the field is true or false@Pattern(regex=, flags=)
- checks that the field matches the givenregex
, with the givenflags
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.