Validations in Spring Boot
Tags: java, spring, springboot
Published: 2020-02-06 00:26:01

---
title: Validations in Spring Boot
cover_image: "https://dev-to-uploads.s3.amazonaws.com/i/qrdw0iy2qrufcd2c2rfk.png"
published: true
date: 2019-09-30 19:27:12 UTC
tags: java,spring, springboot
canonical_url: http://kamerelciyar.com/validations-in-spring-boot/
---
Hello! In this article, I'm gonna cover validations in a Spring Boot app. The only requirement for you to understand this topic is to be able to create controllers in Spring Boot and of course, be comfortable with Java.

You can find source code for examples here: [https://github.com/kamer/validations-in-spring-boot](https://github.com/kamer/validations-in-spring-boot)

## Why do we need both client-side and server-side validation?

In web applications, we generally use both client-side and server-side validations for form data or any other data that goes to server-side. Why do we bother with both of them?

Because we use client-side validation to validate and respond quickly. For instance, we have a field that accepts phone number. So, first of all, we should prevent user to type any character other than numbers. Also, we have a pattern that validates phone number. If we control and reject any incorrect input value on the client-side we eliminate the time for this request to go server-side and get rejected. So we can say that client-side validations are mostly used to give user fast feedback and validate syntactical things. (e.g. pattern, length, characters)

But client-side validations can be considered useless since they can be easily manipulated or disabled. Here’s a great representation what it is like to trust any kind of client-side validation.

![Client Side Validation](https://dev-to-uploads.s3.amazonaws.com/i/e092mfd68a20l9p2ywzw.jpg)

If we go on with the above image, we should create a validation mechanism that rejects any other number than 911 as input. Here’s where server-side validation comes into play. Briefly, server-side validation is our last chance to reject incorrect inputs properly. Also, we validate constraints that need more logical operations on server-side. For instance, rejecting creation of an employee if the manager of the department is not assigned yet. Enough for introduction, let’s get our hands dirty.

### Javax Validation Constraints

_javax.validation_ is the top-level package for Bean Validation API and it has some predefined annotation-based constraints in _constraints_ package for us to use. Here are some examples.

- If we want to check a field if it’s null, we use `@NotNull`.
 
```java
  @NotNull(message = "Name cannot be null.")
  private String name;
```
In the above example _name_ field cannot be null. But it can be empty. If we use `@NotBlank` _name_ cannot be null and must contain at least non-whitespace one character or if we use `@NotEmpty` annotation _name_ cannot be null and `name.length() > 0`. So it can accept a String that has whitespace character.

-If we limit any number input we use `@Max` and `@Min` annotations.

```java
  @Min(value = 3, message = "Experience must be at least 3 years.")
  private Integer experienceInYears;

```

-`@Positive`, `@Negative`, `@PositiveOrZero` and `@NegativeOrZero` annotations do what their name suggests.

```java
  @PositiveOrZero(message = "You cannot have negative numbers of children.")
  private Integer numberOfChildren;
```

-`@Size` annotation gives minimum and maximum values for size of anything. (_CharSequence_, _Collection_, _Map_, _Array_)

```java
  @Size(min = 2, max = 35, message = "Surname must be 2-35 characters long.")
  private String surname;

```

-`@Past`, `@Future`, `@PastOrPresent`, `@FutureOrPresent` annotations validate date types according to their name.

```java
  @Past(message = "Date input is invalid for a birth date.")
  private LocalDate dateOfBirth;

```

-You can validate any regex pattern with `@Pattern` annotation.

```java
  @Pattern(regexp = "^4[0-9]{12}(?:[0-9]{3})?$", message = "Only Visa cards are accepted.")
  private String cardNumber;

```

-No need to explain `@Mail` annotation.

```java
  @Email(message = "Enter a valid email address.")
  private String email;

```

I explained the most important ones above. If you want to see the others you can find them [here.](https://docs.oracle.com/javaee/7/api/javax/validation/package-summary.html)

I created a dummy example to try these constraints and show validation messages on form inputs with Thymeleaf. We should annotate controller input with `@Valid` to activate these constraints.

```java
@PostMapping("/javax-constraints")
	String postJavaxConstraints(@Valid JavaxValidationConstraints javaxValidationConstraints, BindingResult bindingResult) {
        ...
        ...
        ...
    }

```

Then show error messages on Thymeleaf.

![Error Messages](https://dev-to-uploads.s3.amazonaws.com/i/1d6sngjwfq9694c8jc4j.png)

### Creating Your Own Validation Annotations

If you have followed previous chapter well you should’ve seen that you achieve almost anything with Javax Validation Constraints. But sometimes defining your own annotations can seem a much better option though.

Here’s one example. We want to validate _creditCard_ field with `@Pattern`.

```java
@NotEmpty(message = "You must enter a credit card number.")
@Pattern(regexp = "^(?:4[0-9]{12}(?:[0-9]{3})?|[25][1-7]" 
                + "[0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}" 
                + "|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])" 
                + "[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$",
            message = "Invalid card number.")
private String creditCard;
```

Do you see any problem here? It seems too ugly considering we will have at least 5 more fields with at least 2 validation annotations and so on. In this type of situation we can choose defining our own annotation.

First of all create an annotation as below.

```java
@Documented
@Constraint(validatedBy = CreditCardValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CreditCard { 
    
    String message() default "Invalid card number";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
 }
```

We want our annotation to serve at runtime, to be used with field types and to be validated by CreditCardValidator class.

So here’s our validator class.

```java
public class CreditCardValidator implements ConstraintValidator<CreditCard, String> {

	private static final String CREDIT_CARD_REGEX = "^(?:4[0-9]{12}(?:[0-9]{3})?|[25][1-7][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$";

	private static final Pattern CREDIT_CARD_PATTERN = Pattern.compile(CREDIT_CARD_REGEX);

	@Override
	public void initialize(CreditCard constraintAnnotation) {

	}

	@Override
	public boolean isValid(String creditCardNumber, ConstraintValidatorContext context) {

		Matcher matcher = CREDIT_CARD_PATTERN.matcher(creditCardNumber);

		return matcher.matches();

	}
}
```

We implement ConstraintValidator<[AnnotationsName], [TargetType]> and enforcedly override `initialize()` and `isValid()` methods. _initialize_ method is guaranteed to be run before any use of this validation and _isValid_ method is where we reject or accept any value.

Our annotation is ready. Let’s use them like the ones above.

```java
@PostMapping("/custom-constraint-annotation")
	String postCustomConstraint(@Valid CustomConstraintAnnotation customConstraintAnnotation, BindingResult bindingResult) {

		if(bindingResult.hasErrors()){

			return "custom-constraint-annotation";
		}
        ...
        ...
        ...
    }
}
```

All validation errors are saved in BindingResult object and we can show error messages with Thymeleaf.

```java
<form role="form" th:object="${customConstraintAnnotation}" th:action="@{/custom-constraint-annotation}" th:method="post">

    <div style="color: red;" th:if="${#fields.hasErrors('*')}">
        <p><strong>Errors</strong></p>
        <ul>
            <li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
        </ul>
    </div>

    <label>Credit Card Number</label>
    <br>
    <input type="text" id="creditCard" name="creditCard" th:field="*{creditCard}">
    <br>
    <input type="submit">
</form>
```

![Custom Annotation Error Message](https://dev-to-uploads.s3.amazonaws.com/i/1sfdowmttcc0ilmg18l3.png)

### Combining Multiple Annotations

Another way of implementing good validations is combining multiple validation annotations. Hibernate documentation calls it [Constraint composition](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=5.4#section-constraint-composition). It’s quite simple. First of all create an annotation type and fill as below.

```java
@NotEmpty
@Size(min = 8)
@Pattern(regexp = "\"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]$\"")
@Target({ METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface CombinedPasswordConstraint {

	String message() default "Invalid password.";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};
}
```

You can add different messages for each annotation. Then use it like the other constraints.

![Constraint Composition Error Message](https://dev-to-uploads.s3.amazonaws.com/i/jbudcxioo0nlbqbu88g2.png)

### Creating Custom Validator Class

We’ve been through constraints so far. It’s time to create a more complicated validation with a custom validator class. In previous examples we’ve validated syntactical things. But generally we need more complicated things that possibly need a database query.

I’m repeating prior example. You have created a department in your imaginary app. Then you try to add a new employee to this department. But you want to add a constraint that requires assigning a manager before assigning an employee. So you should add a validator that checks either this department has a manager or not. This is possible with custom validator. But you can also validate simple things like regex patterns.

Let’s create one.

I’m gonna show you a simplified example. First of all, create a dummy class and fill it as below.

```java
public class CustomValidationEntity {

	private String email;

	private Long departmentId;

	public Boolean existManagerByDepartmentId(Long departmentId) {

		return false;
	}

	public Boolean existEmployeeWithMail(String email) {

		return true;
	}

}
```

It will always say ‘department has no manager’ and ‘this email already exist’ whatever we enter.

Then create validator class as below. I’m gonna explain details.

```java
@Component
public class CustomValidator implements Validator {

	@Override
	public boolean supports(Class<?> clazz) {
		return CustomValidationEntity.class.isAssignableFrom(clazz);
	}

	@Override
	public void validate(Object target, Errors errors) {

		CustomValidationEntity customValidationEntity = (CustomValidationEntity) target;

		if (customValidationEntity.existEmployeeWithMail(customValidationEntity.getEmail())) {

			errors.rejectValue("email", null, "Employee with this email is already exists.");
		}

		if (!customValidationEntity.existManagerByDepartmentId(customValidationEntity.getDepartmentId())) {

			errors.reject(null, "Department does not have a manager.");
		}

	}
}
```

This Validator interface that we extend is `org.springframework.validation.Validator;`. Not javax… one. This interface gives us two methods. `supports()` method controls if the target object is what we intended to validate and `validate()` method is where we control and reject things. You can reject the whole object and add a global error message with `reject()` or reject a single value and add an error message for this value with `rejectValue()`. Then you should annotate this class with `@Component`.

Let’s use our validator. But we will do something different than using constraints. After annotating object parameter in the controller with `@Valid`, we will add an InitBinder method in that controller.

```java
@InitBinder
private void bindValidator(WebDataBinder webDataBinder) {
    webDataBinder.addValidators(customValidator);
}
```

This `@InitBinder` annotated method will initialize _WebDataBinder_. Since _WebDataBinder_ prepares objects that come from requests for controllers, it can validate before the request reaches controller. That’s it. Let’s try our example.

![Custom Validator Error Message](https://dev-to-uploads.s3.amazonaws.com/i/vui1fnq6r98uvlnwrqp6.png)

In this article we’ve gone through Validations in Spring Application.

For questions, suggestions or corrections feel free to reach me on:

**Email:** [kamer@kamerelciyar.com](mailto:kamer@kamerelciyar.com)

**Twitter:** [https://twitter.com/kamer\_ee](https://twitter.com/kamer_ee)