Conditional Validation in Java Applications

Marko Antic
3 min readOct 29, 2020

--

1. Overview

Even though Java Bean Validation framework offers a great deal of solutions and possibilities for validation purposes, sometimes we need to define our own, custom validation logic to meet our project requirements.

In this article, we will talk about a way to provide conditional validation for a data model, the validation that depends on a correlation between several properties of an object.

We will go through a process of creating a custom annotation which will enable us to introduce suitable class-level validation constraints.

2. Introduction

Let’s assume that the following Partner class is our domain class where some validations should be applied:

There are two different kinds of partners: a private partner and a business partner. In the given data model, this is represented by a property kind.

Depending on the kind of a partner, some properties in this class are mandatory. For example, if we have a private partner, then his first name and last name are required. If we are talking about a business partner then its name must have a value, since that field represents a company name.

Let us introduce a custom class-level annotation that defines these conditions:

As we can see from the code above, our annotation has several parameters:

  • conditionalProperty - a name of the property that conditional validation depends on
  • values - values of the conditional property that turn conditional validation on
  • requiredProperties - properties that should meet the conditions defined by our validation
  • message - error message shown if validation is violated

3. How is this accomplished?

Okay, now let us explore the implementation of the ConditionalValidation annotation.

There are two important things to note here:

@Repeatable(ConditionalValidations.class) - the value of the @Repeatable meta-annotation, in parentheses, is the type of the container annotation that Java compiler generates to store repeating annotations. In our case, the containing annotation type is ConditionalValidations, so repeating @ConditionalValidation annotation is stored in one @ConditionalValidations annotation.

By using this, we can define different conditions in our Partner class, one for private and one for business partner.

@Constraint(validatedBy = ConditionalValidator.class) - marks the annotation type as constraint annotation and specifies the validator to be used to validate elements annotated with our custom annotation.

ConditionalValidator class does the actual validation logic. This validator implements ConstraintValidator interface from javax.validation package.

The initialize() method gives us access to the attribute values used in our annotation and allows us to store them in the fields of the validator.

The isValid() method contains the concrete validation logic. Using apache’s BeanUtils library we extract the value of the conditional property from our partner object. Then, in doConditionalValidation() method we check if that concrete value is contained in the values array from our annotation.

If that is not the case our isValid() method will just return true, since none of the fields need to be validated.

Otherwise, by iterating through the requiredProperties array in validateRequiredProperties() method we extract values of required properties one by one and check that the field’s value is not null and not empty.

If a value is not valid, using the passed ConstraintValidatorContext object we completely disable the default error message generation and add our own message from our custom annotation message attribute.

4. Test

Let’s now test our validator and check whether it behaves as expected.

5. Summary

In this article, we have seen how to perform conditional validation of Java Beans using custom annotations. This approach works great with existing Bean Validation annotations - you can conditionally check if attributes are required and additionally validate their values by using existing annotations, such as @Email, @IBAN, and so on.

I would like to finish by giving special thanks to Aleksandar Radulović for inspiring me to create this blog and supporting me throughout the process of writing it!

--

--