Using Hamcrest and valid4j With DBC Techniques To Throw Recoverable Exceptions
In this article, we discuss input validation as one of the most important concerns in methods, especially when you have methods called between classes.
Join the DZone community and get the full member experience.Join For Free
Input validation is one of the most important concerns in methods, especially in the case that you have methods calling between classes; consider a case in which you have a class called
CALLER that has a method which calls a specific method in
These pieces of code are one of the worst things a programmer can do in his life. Please don't try it at work, university, or even at home (lest bad habits can form). Let's take a closer look at the above codes. It is clear that neither the caller nor the callee knows its responsibilities. Everything is based on probabilities.
The caller code is an example of a bad implementation of defensive programing. Regardless of the basic concepts, it is a validation hell. Everything is based on an
if then else clause and programming errors are hidden under a bunch of codes. In fact, programming errors should not be dealt with this way.
So what should we do? The solution is using contract-based programming. Design by contract (DBC), also known as contract programming, programming by contract, and design-by-contract, is an approach that uses some contracts to developing software. That's super easy!
Programming by contract is a contract between the software developer and software user or between caller and the callee. Every method starts with a precondition that must be satisfied by the caller and ends with postconditions, which the callee guarantees to be true, and finally, there are invariants—they guarantee the object is in a valid state. At this time, I don't want to delve too deep into DBC, you can find lots of articles about design by contract on the web.
In this article, I want to introduce hamcrest-matchers and valid4j, which helps us implement DBC in Java.
Hamcrest is an amazing framework that consists of matcher libraries that helps software developers to perform unit tests. Hamcrest is usually used with test-related tools such as Junit, TestNg Mockito, Jmockit, etc. and it may be used directly in the application codes. Let's look at an example:
The result is:
If you look at the above codes, there is a sacred word within it:
assertThat is a magical method in Hamcrest that takes everything and does everything. Let's look at some examples:
There are lots of matchers like
is; you can see the list of all matchers here. Aside from that, Hamcrest allows you to implement your own matches. Look at the following example:
The above code describes matchers that are used to check if the parameter is a number or not; when using Hamcrest in your code, just add following dependencies in your Maven dependencies as well as JUnit dependency and enjoy it!.
valid4j is an assertion and validation library for Java which makes it possible to use your favorite Hamcrest-matchers to express pre and post-conditions in your code in a design by contract style. When using these libraries in your codes, just add following dependency to your Maven POM file :
This library consists of two major parts; design by contract (assertions) and validations:
- Design by Contract: This part consists mostly of preconditions and postconditions, of which have already been introduced. There is a keyword,
require, which is used to specify preconditions. Let's look at some examples:
Postconditions, on the other hand, use a keyword called
ensure, and are used to satisfy postconditions. Here is a piece of sample codes:
The input parameters validation is an example of validation in valid4j; checking if parameters are null or making sure that a specific format is observed in the parameter or not is not considered a responsibility of this library:
You can find documentation about valid4j here.
Time To Do It Right
Let's get back to the point—tackling the luck-based programming in the caller/callee example. Now we are ready to get our hands dirty and rewrite those ridiculous codes with valid4j with, of course, design by contract concepts:
As you can see, this code is more clear and every class knows its responsibilities; it’s easy to see what assumptions we can rely on and which conditions we can achieve. The readability of the code is improved. Any if-else statements or try-catch clauses deal with proper error handling and fault tolerance, not programming errors. Code to the point!
Opinions expressed by DZone contributors are their own.