Just when you think your Java application’s data validation is becoming complex, Apache Commons Validator steps in to simplify your life. 

As you go through this comprehensive guide, you’ll discover how this powerful library can streamline your validation requirements with its rich set of built-in validators. 

Whether you’re building a web application or processing data in a standalone Java program, you’ll find Apache Commons Validator offers an elegant solution to validate emails, URLs, credit cards, and more. 

Your journey to robust data validation starts here, with a library trusted by developers worldwide.

Getting Started

Apache Commons Validator is a versatile library that helps you implement data validation with minimal effort in your Java applications. 

This powerful tool provides a collection of validators for common data types and allows you to create custom validation rules tailored to your needs.

Environment Setup

Commons Validator can be easily added to your project using Maven. 

Add the following dependency to your pom.xml:

<dependency>
  <groupId>commons-validator</groupId>
  <artifactId>commons-validator</artifactId>
  <version>1.9.0</version>
</dependency>

If you are using Gradle, then add below dependency

implementation 'commons-validator:commons-validator:1.9.0'

Basic Validation Architecture

Started with version 1.9.0, Apache Commons Validator follows a component-based architecture where each validator is responsible for a specific type of validation. 

The library provides both simple validators for basic data types and complex validators for more sophisticated validation scenarios.

Steps in the validation process involve 

  1. creating appropriate validator instances, 
  2. configuring validation rules, and 
  3. executing validation checks. 

Here’s an example demonstrating the basic validation flow:

public class ValidationExample { 
  public static void main(String[] args) { 
    // Create validator instance 
    EmailValidator validator = EmailValidator.getInstance(); 
    // Perform validation 
    String email = "user@example.com"; 
    if (validator.isValid(email)) { 
      System.out.println("Email is valid!"); 
    } else { 
      System.out.println("Invalid email format"); 
    } 
  } 
}

Standard Validators Implementation

All standard validators in Apache Commons Validator provide you with ready-to-use validation functionality for common data types. 

These validators are thread-safe and highly optimized, saving you time and effort in implementing validation logic from scratch. 

Let’s explore the main categories of validators available in version 1.9.0.

1. String and Text Validators

With String validators, you can perform various text-based validations efficiently. 

The library offers EmailValidator, UrlValidator and RegexValidator for common text validation scenarios. 

Email Validation

Here’s a quick example of email validation:

EmailValidator emailValidator = EmailValidator.getInstance(); 
boolean isValid = emailValidator.isValid("user@example.com");

URL Validation

You can easily check if a URL is in standard format or not with its URLValidator class as shown below

UrlValidator validator = UrlValidator.getInstance();
boolean isURLValid = validator.isValid("www.example.com"); // false
boolean isURLValid = validator.isValid("http://example.com");  // true

Regex Validation

Assuming you need to validate complex string patterns, you can use the RegexValidator class.

This powerful feature allows you to define multiple patterns and customize matching behavior:

RegexValidator v = new RegexValidator("^[a-z0–9._%+-]+@[a-z0–9.-]+\\.[a-z]{2,6}$"}); 
boolean isValid = v.isValid("your.email@domain.com");

Development of regex-based validation can be enhanced by combining multiple patterns and using case-sensitive matching.

Domain Validation

You can check if a given string represents a valid domain name format using its DomainValidator class:

DomainValidator dv = DomainValidator.getInstance();
boolean valid = dv.isValid("google.com"); // true
valid = dv.isValid("google"); // false

2. Numeric Validators

Validators for numeric values help you validate integers, decimals, and currency amounts. 

These include IntegerValidator, DoubleValidator and CurrencyValidator, ensuring your numeric inputs meet specific format and range requirements.

You can use these validators to check

  1. If a number is in specific format.
  2. If a number falls within an acceptable range. 

Here’s how you can validate an integer range:

int value = 10;
IntegerValidator intValidator = IntegerValidator.getInstance(); 
boolean isValid = intValidator.isInRange(value, 1, 100); // true

// For currency validation 
BigDecimalValidator currencyValidator = CurrencyValidator.getInstance(); 
boolean isValidAmount = currencyValidator.isValid("$1234.56", Locale.US);

3. Date and Time Validators

On the date and time front, Apache Commons Validator provides you with robust validation for various date formats, time zones, and calendar systems. 

The DateValidator helps ensure your date inputs conform to specified patterns and ranges.

Validators in this category allow you to check date formats across different locales and validate against custom patterns. 

Here’s an example:

DateValidator dateValidator = DateValidator.getInstance(); 
String pattern = "yyyy-MM-dd"; 
boolean isValid = dateValidator.isValid("2023–12–31", pattern); 

// With specific locale 
boolean isValidLocale = dateValidator.isValid("31/12/2023", "dd/MM/yyyy", 
                                              Locale.UK);

You can also use DateValidator to convert a string to a java.util.Date object with its validate() method 

DateValidator instance = DateValidator.getInstance();
Date date = instance.validate("25-12-2024", "dd/MM/yyyy");
System.out.println(date); // Wed Dec 25 00:00:00 IST 2024

If the specified date is not in the format provided, then validate() will return null.

Testing Strategies

If you want to ensure your validation logic works correctly, you’ll need to implement comprehensive unit tests. 

JUnit 5 works perfectly with Apache Commons Validator, allowing you to test individual validators in isolation. 

Here’s a simple example of testing an EmailValidator:

@Test 
void testEmailValidation() { 
  EmailValidator validator = EmailValidator.getInstance(); 
  assertTrue(validator.isValid("user@domain.com")); 
  assertFalse(validator.isValid("invalid.email@")); 
  assertFalse(validator.isValid("@domain.com")); 
}

Validation Scenarios

You should create a comprehensive set of test scenarios covering both valid and invalid inputs. 

This includes edge cases, boundary values, and common user input patterns that your application might encounter.

It’s beneficial to organize your test scenarios into categories based on validation types. 

Consider this example of testing different credit card formats:

@Test 
void testCreditCardScenarios() { 
  CreditCardValidator validator = new CreditCardValidator(); 
  assertTrue(validator.isValid("4111111111111111")); 
  
  // Visa 
  assertTrue(validator.isValid("5500000000000004")); 
  
  // MasterCard 
  assertFalse(validator.isValid("1111111111111111")); 
  
  // Invalid 
  assertFalse(validator.isValid(""));
}

Security Considerations

Input Sanitization

Your validation strategy should always include proper input sanitization.

On top of using Apache Commons Validator’s built-in validators, you should implement additional security measures to prevent injection attacks.
Here’s an example of combining validation with sanitization:

public boolean validateAndSanitizeEmail(String email) { 
  // First, sanitize the input 
  String sanitizedEmail = email.
                          trim().
                          replaceAll("[\\n\\r]", "").
                          toLowerCase(); 
  // Then validate using EmailValidator 
  EmailValidator validator = EmailValidator.getInstance(); 
  return validator.isValid(sanitizedEmail); 
}

Validation Boundaries

There’s a need to set appropriate boundaries for your validation rules. String lengths, numeric ranges, and other constraints should be carefully defined to prevent buffer overflow attacks and resource exhaustion.

The implementation of boundary validation can be achieved using custom validators or by combining multiple validators.
Here’s an example:

public class BoundedStringValidator { 
private static final int MAX_LENGTH = 255; 

public boolean isValid(String input) { 
  return input != null &&
         input.length() <= MAX_LENGTH && 
         input.matches("^[a-zA-Z0–9\\s.-]*$"); 
  } 
}

Code Organization

Organization of your validation code should follow a clear, modular structure. 

You can create separate validator classes for different domains of your application, making your code more maintainable and testable.

Implementation of your validation logic should be centralized in dedicated classes or services.

Consider this example of a well-organized validation service:

public class UserValidationService { 
  private final EmailValidator emailValidator; 
  private final RegexValidator passwordValidator; 

  public UserValidationService() { 
    this.emailValidator = EmailValidator.getInstance(); 
    this.passwordValidator = new RegexValidator("^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$"); } 

  public ValidationResult validateUser(User user) { 
    ValidationResult result = new ValidationResult(); 
    if (!emailValidator.isValid(user.getEmail())) { 
      result.addError("email", "Invalid email format"); } 
      // Add more validation logic return result; 
  } 
}

Conclusion

We explored the comprehensive capabilities of Apache Commons Validator, equipping you with powerful tools for robust data validation in your Java applications. 

You can implement validations using simple code like EmailValidator.getInstance().isValid(“user@domain.com”) .

Using Apache Commons library, you’re well-prepared to implement reliable validation logic that ensures data integrity across your applications.