How to perform JavaBeans Validation
Tags: codesecurity, applicationsecurity, java
Published: 2023-06-21 15:46:46

JavaBeans Validation (Bean Validation) is a validation model available since the introduction of the Java Enterprise Edition 6 platform. It provides a standard way for different Java applications to validate input data. In a previous post, we discussed how [Java DTOs are used in modern applications to prevent accidental data leaks](/blog/how-to-use-java-dtos/).


In this article, we’ll create a new Java application and validate some example strings to demonstrate how JavaBean Validation works. But first, let’s review what Beans are. 


JavaBeans are Java objects containing properties and methods to store and transfer data between different parts of a Java application. Beans are reusable components encapsulating a Java application’s data and behavior. They’re a standard way of representing objects, following certain design patterns and conventions. 


* JavaBeans contain properties, which are instance variables representing an object’s state. These variables should be private. They use getter and setter methods to access the data stored in a Bean.
* No-argument constructors are used to create an instance of a Bean. We can add constructors to provide different ways of initializing a Bean.
* JavaBeans are serializable, meaning their state can be saved to a file or transmitted over a network.
* JavaBeans follow naming conventions, such as using the `getXXX` and `setXXX` methods to access and set the value of the properties.
* JavaBeans often contain `BeanInfo` classes, which provide information about the bean to tools and IDEs.


We often use JavaBeans as building blocks to organize and structure data for larger applications. They typically contain instance variables (properties) and getter and setter (`getXXX` and `setXXX`) methods to access the data stored in a Bean. We also use JavaBeans to create custom objects we can reuse in different parts of an application, making it easier to maintain and update the code.


Using JavaBeans Validation
--------------------------


One of the primary uses of Beans is to validate user input by enabling us to specify constraints on the properties of a Bean, such as minimum and maximum lengths, allowed characters, and required fields. We then use these constraints to validate the data entered by users, ensuring that it meets the specified requirements before application processing.


The following example uses the [Hibernate Validator](https://hibernate.org/validator/) in an [Apache Maven project](https://maven.apache.org/). The Hibernate Validator is the reference implementation for Bean Validation.


Creating a Java app
-------------------


First, we need to create a dependency for the Hibernate Validator in our `pom.xml` file in Maven. Do so using the code below:



```

 org.hibernate
 hibernate-validator
 6.1.5.Final


```

Next, we add the Bean Validation API as a dependency in `pom.xml` using the following code:



```

 javax.validation
 validation-api
 2.0.1.Final

```

Now, we create a Java project in a new file called `BeanValidation.java` and import the necessary libraries:



```
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Pattern;
import java.util.Set;
import javax.validation.ConstraintViolation;
```

Next, we create a simple Bean with a property to validate using the code below:



```
public class ExampleBean {
    @NotNull
    @Size(min=2, max=10)
    private String exampleString;

//Getters
    public String getExampleString() {
        return exampleString;
    }

//Setters
    public void setExampleString(String exampleString) {
        this.exampleString = exampleString;
    }
}
```

This example uses the `@NotNull` and `@Size` annotations to specify that the `exampleString` property can’t be null and must have a minimum length of two and a maximum length of ten characters. We establish the `getExampleString` and `setExampleStrin` methods as the getters and setters for the `exampleString` property in the `ExampleBean` class.


Seeing how Bean Validation works
--------------------------------


To use the `BeanValidation` class to validate the Bean, we run the following:



```
public class BeanValidation {
    public static void main(String[] args) {
        ExampleBean bean = new ExampleBean();
        bean.setExampleString("hello");
// Create a Validator instance using the default validation factory      
  ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
// Validate an instance of the ExampleBean class and get a set of constraint violations, if any        
Set> violations = validator.validate(bean);
 if (!violations.isEmpty()) {
 System.out.println("Errors:");
 for (ConstraintViolation violation : violations) {
 System.out.println(violation.getMessage());
 }
 } else {
 System.out.println("Validation successful");
 }
 }
}
```

Since we’ve set the string value to `hello`, it passes the validation check. If we set the `exampleString` property to a value that doesn’t meet the constraints specified in a Bean, the validate method returns a set of `ConstraintViolation` objects that describe the errors.


To handle errors when strings fail validation, we create error-handling cases that check for violations and display an error message if one occurs.


Here’s the complete code for the `BeanValidation.java` file:



```
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.ConstraintViolation;

public class ExampleBean {
    @NotNull
    @Size(min=2, max=10)
    private String exampleString;

    public String getExampleString() {
        return exampleString;
    }

    public void setExampleString(String exampleString) {
        this.exampleString = exampleString;
    }
}

public class BeanValidation {
    public static void main(String[] args) {
        ExampleBean bean = new ExampleBean();
        bean.setExampleString("hello");

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        Set> violations = validator.validate(bean);

 if (!violations.isEmpty()) {
 System.out.println("Errors:");
 for (ConstraintViolation violation : violations) {
 System.out.println(violation.getMessage());
 }
 } else {
 System.out.println("Validation successful");
 }
 }
}
```

This example returns an error if the input string is shorter than two characters, longer than ten characters, or null. If the string doesn’t match those constraints, it prints an error message displaying the unmet requirement.


Here’s an example of constraints for validating user login input with the email and password fields:



```
public class UserBean {
    @NotNull
    @Size(min=5, max=30)
    @Pattern(regexp = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}")
    private String email;

    @NotNull
    @Size(min=8, max=15)
    @Pattern(regexp = "((?=.*[a-z])(?=.*\\d)(?=.*[A-Z])(?=.*[@#$%!]).{8,15})")
    private String password;

}
```

The `UserBean` class contains two properties: `email` and `password`. The `email` property ensures that inputs have a minimum length of five and a maximum length of thirty characters, and match the pattern of a valid email address. 


The `password` property ensures that the password isn’t null, has a minimum length of eight and a maximum length of fifteen characters, and contains at least one lowercase letter, one uppercase letter, one digit, and one special character. 


Understanding constraints
-------------------------


Constraints are defined using annotations — special types of metadata added to Java classes, fields, and methods. We can apply constraints to the properties of a Bean class in various places, including directly to the property, to a getter method for the property, or to a constructor parameter of the class.


Once constraints are defined for a Bean, validation uses a `Validator` object from the Bean Validation API. The `Validator` object is responsible for checking whether a Bean instance meets the constraints on its properties. If a Bean violates any constraints, the `Validator` returns a set of constraint violations indicating which properties failed validation and why.


JavaBeans have some built-in constraints available by default as part of the Bean Validation API, which we can use immediately. Some of the built-in constraints include `@NotNull`, `@Size`, `@Pattern`, `@Min`, `@Max`, `@DecimalMin`, and`@DecimalMax`. For a complete list of built-in constraints, review the [Hibernate Validator documentation](https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#section-builtin-constraints).


Custom constraints are constraints we define to meet specific validation requirements. We create them by defining a custom annotation and implementing a `ConstraintValidator` that defines the validation logic. 


Creating custom annotations
---------------------------


To create a custom constraint for Bean Validation, we must:


* Create a custom annotation class and annotate it with `@Constraint`. This indicates that the annotated class is a custom constraint.
* Implement the validation logic in a class that implements the `ConstraintValidator` interface. The class must have parameters with custom constraint annotation and the type of elements it can validate.
* Register the custom constraint by adding an entry in the validation XML configuration file or annotating the custom constraint class with `@Constraint(validatedBy=)`.


Here’s an example of a custom constraint named `ValidSearchTerm`:



```
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

@Documented
@Constraint(validatedBy = ValidSearchTermValidator.class)
@Target({ FIELD })
@Retention(RUNTIME)
public @interface ValidSearchTerm {

    String message() default "Search term contains invalid characters";

    Class[] groups() default {};

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

We can then implement the validation logic that uses regular expressions to create the constraint. In this case, we want an ordinary alphanumeric search string that doesn’t have any special characters:



```
public class ValidSearchTermValidator implements ConstraintValidator {

 @Override
 public boolean isValid(String value, ConstraintValidatorContext context) {
 if (value == null) {
 return true;
 }
 return value.matches("[A-Za-z0-9]+");
 }
}
```

Then, we use the custom constraint in a Bean like this:



```
public class SearchBean {
    @ValidSearchTerm
    private String searchTerm;

    public String getSearchTerm() {
        return searchTerm;
    }

    public void setSearchTerm(String searchTerm) {
        this.searchTerm = searchTerm;
    }
}
```

Final thoughts on Bean Validation
---------------------------------


Bean Validation provides a unified and consistent way of validating data in Java applications, making it easier for us to write and maintain code that ensures secure data processing. We can use the Bean Validation model to save time and effort otherwise spent writing custom validation logic.


With Bean Validation, we can specify constraints on the properties of a JavaBean using annotations. These annotations can be either built-in or custom, defining user input requirements to be considered valid. The model then uses these constraints to validate the Bean and identify any errors.


Bean Validation also provides a way for us to handle errors during validation. The framework returns a list of constraint violations, and we can use this information to provide specific feedback to a user. This helps to improve the user experience and provides a more robust and secure application.


Overall, Bean Validation is an essential tool for ensuring the quality and security of Java applications. By following best practices with this model, we can ensure that our applications are well-designed, maintainable, and secure.