A valid Java Bean?

Michał Chmielarz
SoftwareMill Tech Blog
5 min readJan 25, 2019

--

JSR-380, also known as Bean Validation 2.0, is a standard. Should we use it everywhere then? Let’s consider pros and cons.

Photo by Lukas on stocksnap.io

I’m working on a project with a couple of smart guys. We’ve been discussing how to validate our data. I opted for manual, custom validation, based on Vavr’s Validation. However, one of my teammates pointed out we could consider using Java Bean validation and its custom validators.

Well, why not to give it a shot, I thought. I decided to try it shortly and to describe my experiences here. I treat it as an interesting exercise and a possibility to look at the problem of data validation from a different perspective.

The domain
So, here is our data: bank account data holding IBAN, BIC codes and a bank account number. Before we store it in our database, we would like to be sure that all fields are valid. iban4j is the library that provides all the mechanics required in our example.

You can find all the snippets and the complete code on Github.

Validate it!
How to construct a custom validation? You can find a detailed tutorial in the Hibernate documentation. Here, I focus on the basics. Thus we need to implement only two things:
- an annotation to apply it to a field or a method,
- also, a validator mechanism to run data checks.

First, the annotation — let’s create one for the IBAN field. Here is how it can look like:

What do we have here? First of all, we can apply the annotation to a field or a method. Next, a field annotated with the@Ibanis validated with IbanValidatorclass. And at least, for every JSR-380 compliant annotation, we can configure:
- a message (in the example I have provided a reference to a localised message, contained in the ValidationMessages.propertiesfile),
- groups constraints (constraints can be grouped in subsets so that they can be applied to particular objects),
- also, a payload (defines additional data used by validators).

Here is the mentioned validator itself:

As you can see, it implements theConstraintValidatorinterface. When a valueis invalid, the validation method returns false, otherwise true.

If we are using the Spring Framework, we can run the validation automatically by applying the@Validannotation on a body of a request received through a REST endpoint.

The Framework applies the validation to every incoming request to a given endpoint. In a case when it fails we get MethodArgumentNotValidException. The error contains information about validation issues. We can extract them with an exceptions handler or a controller advice and transform it into a response of our custom format. Or even we can do nothing and cede the handling of the error to the Spring.

We can run validation manually as well. It looks like the following:

What has surprised me after calling the code above is the thrown exception:
javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: com.softwaremill.jsr380.BankAccountValidator (…)

It turns out Spring and a default ValidatorFactory instantiates instances of validators differently. The former does not require validators being public classes while the latter does. After changing the access modifier to validators, I could try them manually. Here is an example of a response for malformed bank account data:

Ok, so does it work, right? Of course, it does!

But…

What I do not like here
In the example of running Bean Validation by hand, if I want to hide the validation mechanism inside thedomainpackage, I just simply can’t. I must expose validators classes to the whole world, so they are visible for instantiating. If you treat the validation as a part of a domain (like me), this can somewhat be frustrating that the standard pushes you to public things you would like to hide in a package.

Next, in the case of the Spring and validating data just before going into controllers methods, we don’t have to expose validators. As you can see, the behaviour depends on the implementation of the validator factory.
However, in this situation, there is yet another drawback. With such a solution, I am validating a domain-specific data outside the domain package. For me, a controller is just a gateway giving access to the domain, not being a part of it.

Any thoughts?
If you are going to use some library or a framework or a standard, you probably have to adjust your code to a tool you have chosen. The Java Bean Validation case is not different. As usual, keep in mind that using standards not always solve all of your issues and pains. What’s more, it sometimes can cause more headaches than anticipated or different ones. So… choose wisely :)

It makes me rather a proponent of manual validation instead of using framework mechanisms. Why? A custom form of validation gives me full control over classes required in the process and over what happens when data is invalid. With such solution, I can craft the exact shape of the data signalling error I need for my case. Moreover, I can hide classes inside the domain and publish them if there is a real requirement (e.g. I would like to reuse it somewhere else).

What I have found more, it is quite tricky to check one field in a context of the value of another field in a validated bean. For example, I would like to be sure that provided bank account number is in line with provided IBAN. It looks like this is doable with writing an annotation for a class instead of field however, it does not look as clean as I would expect or I could achieve with a custom code.

Also, Bean Validation uses annotations — if you didn’t know, they are considered harmful ;)

Did I miss something in this short tour that is valuable in Bean Validation? Do you have a different opinion or any other thoughts on the subject? Leave your comments below.

Looking for Scala and Java Experts?

Contact us!

We will make technology work for your business. See the projects we have successfully delivered.

--

--

Passionate software developer. Focused on a good design and the best quality.