CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-typesafe-play--play-java

Java API for the Play Framework providing web application development capabilities including form handling, validation, dependency injection, and utility libraries

Pending
Overview
Eval results
Files

validation.mddocs/

Validation

Play Framework's validation system provides comprehensive form and data validation capabilities using JSR-303 Bean Validation with built-in constraints, custom validators, and detailed error reporting. The validation framework integrates seamlessly with form processing and provides both annotation-based and programmatic validation approaches.

Capabilities

Validation Framework Core

Central validation utilities and JSR-303 integration for comprehensive data validation.

/**
 * Validation helpers and JSR-303 integration
 */
public class Validation {
    /** Get the underlying JSR-303 validator instance */
    public static Validator getValidator();
}

/**
 * Represents a form or field validation error
 */
public class ValidationError {
    /** Create validation error with key and message */
    public ValidationError(String key, String message);
    
    /** Create validation error with message arguments */
    public ValidationError(String key, String message, List<Object> arguments);
    
    /** Create validation error with multiple messages */
    public ValidationError(String key, List<String> messages, List<Object> arguments);
    
    /** Get the field key or path */
    public String key();
    
    /** Get the primary error message */
    public String message();
    
    /** Get all error messages */
    public List<String> messages();
    
    /** Get message template arguments */
    public List<Object> arguments();
}

Built-in Validation Constraints

Comprehensive set of built-in validation constraints with factory methods for programmatic validation.

/**
 * Built-in validation constraints and validator factories
 */
public class Constraints {
    /** Convert constraint descriptors to human-readable format */
    public static List<Tuple<String,List<Object>>> displayableConstraint(Set<ConstraintDescriptor<?>> constraints);
    
    /** Create required field validator */
    public static Validator<Object> required();
    
    /** Create minimum numeric value validator */
    public static Validator<Number> min(long value);
    
    /** Create maximum numeric value validator */
    public static Validator<Number> max(long value);
    
    /** Create minimum string length validator */
    public static Validator<String> minLength(long value);
    
    /** Create maximum string length validator */
    public static Validator<String> maxLength(long value);
    
    /** Create email format validator */
    public static Validator<String> email();
    
    /** Create regex pattern validator */
    public static Validator<String> pattern(String regex);
}

/**
 * Base class for all Play Framework validators
 */
public abstract class Constraints.Validator<T> {
    /** Validate the given object */
    public abstract boolean isValid(T object);
    
    /** Validate with JSR-303 context */
    public boolean isValid(T object, ConstraintValidatorContext constraintContext);
    
    /** Get error message key and arguments */
    public abstract Tuple<String, Object[]> getErrorMessageKey();
}

Validation Annotations

Complete set of validation annotations for declarative model validation.

/** Field is required and cannot be null or empty */
@interface Required {}

/** Numeric field must be at least the specified value */
@interface Min { 
    long value(); 
}

/** Numeric field must be at most the specified value */
@interface Max { 
    long value(); 
}

/** String field must have at least the specified length */
@interface MinLength { 
    long value(); 
}

/** String field must have at most the specified length */
@interface MaxLength { 
    long value(); 
}

/** String field must be a valid email address */
@interface Email {}

/** String field must match the specified regex pattern */
@interface Pattern { 
    String value(); 
    String message() default ""; 
}

/** Use custom validator class for validation */
@interface ValidateWith { 
    Class<? extends Constraints.Validator> value(); 
}

Usage Examples:

import play.data.validation.Constraints.*;

public class User {
    @Required
    @MinLength(2)
    @MaxLength(50)
    public String name;
    
    @Required
    @Email
    public String email;
    
    @Required
    @MinLength(8)
    @Pattern("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$")
    public String password;
    
    @Min(18)
    @Max(120)
    public Integer age;
    
    @MaxLength(500)
    public String bio;
}

public class Product {
    @Required
    public String name;
    
    @Required
    @Min(0)
    public BigDecimal price;
    
    @Required
    @Pattern("^[A-Z]{2,3}-\\d{4}$") // Format: AB-1234
    public String sku;
}

Built-in Validator Implementations

Pre-built validator classes that power the validation annotations.

/** Validates that a field is not null or empty */
public class RequiredValidator extends Constraints.Validator<Object> {
    public boolean isValid(Object object);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates minimum numeric values */
public class MinValidator extends Constraints.Validator<Number> {
    public MinValidator(long min);
    public boolean isValid(Number value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates maximum numeric values */
public class MaxValidator extends Constraints.Validator<Number> {
    public MaxValidator(long max);
    public boolean isValid(Number value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates minimum string length */
public class MinLengthValidator extends Constraints.Validator<String> {
    public MinLengthValidator(long minLength);
    public boolean isValid(String value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates maximum string length */
public class MaxLengthValidator extends Constraints.Validator<String> {
    public MaxLengthValidator(long maxLength);
    public boolean isValid(String value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates email address format */
public class EmailValidator extends Constraints.Validator<String> {
    public boolean isValid(String value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates strings against regex patterns */
public class PatternValidator extends Constraints.Validator<String> {
    public PatternValidator(String pattern);
    public boolean isValid(String value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

/** Validates using custom validator classes */
public class ValidateWithValidator extends Constraints.Validator<Object> {
    public ValidateWithValidator(Class<? extends Constraints.Validator> validatorClass);
    public boolean isValid(Object value);
    public Tuple<String, Object[]> getErrorMessageKey();
}

Usage Examples

Basic Model Validation

import play.data.Form;
import play.data.validation.Constraints.*;
import play.mvc.Controller;
import play.mvc.Result;

public class RegistrationForm {
    @Required
    @MinLength(3)
    @MaxLength(20)
    public String username;
    
    @Required
    @Email
    public String email;
    
    @Required
    @MinLength(8)
    @Pattern("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]+$")
    public String password;
    
    @Required
    @Min(13)
    public Integer age;
    
    @MaxLength(200)
    public String bio;
}

public class UserController extends Controller {
    public Result register() {
        Form<RegistrationForm> form = Form.form(RegistrationForm.class).bindFromRequest();
        
        if (form.hasErrors()) {
            // Get all validation errors
            Map<String, List<ValidationError>> errors = form.errors();
            return badRequest(Json.toJson(errors));
        }
        
        RegistrationForm registration = form.get();
        // Process valid registration
        return ok("Registration successful");
    }
}

Custom Validation Logic

import play.data.validation.Constraints.Validator;

// Custom validator for business logic
public class UniqueEmailValidator extends Constraints.Validator<String> {
    
    @Override
    public boolean isValid(String email) {
        // Check if email already exists in database
        return !userService.emailExists(email);
    }
    
    @Override
    public Tuple<String, Object[]> getErrorMessageKey() {
        return Tuple.create("validation.email.unique", new Object[]{});
    }
}

// Using custom validator
public class User {
    @Required
    @Email
    @ValidateWith(UniqueEmailValidator.class)
    public String email;
}

Validation Groups

// Validation groups for different contexts
public interface CreateGroup {}
public interface UpdateGroup {}

public class User {
    @Required(groups = {CreateGroup.class, UpdateGroup.class})
    public String name;
    
    @Required(groups = CreateGroup.class) // Only required on creation
    @Email
    public String email;
    
    @MinLength(value = 8, groups = CreateGroup.class) // Only validate on creation
    public String password;
}

// Using validation groups
public Result createUser() {
    Form<User> form = Form.form("user", User.class, CreateGroup.class).bindFromRequest();
    // Validation will only apply constraints in CreateGroup
}

public Result updateUser() {
    Form<User> form = Form.form("user", User.class, UpdateGroup.class).bindFromRequest();
    // Validation will only apply constraints in UpdateGroup
}

Programmatic Validation

import play.data.validation.Constraints;

public class ValidationService {
    
    public Result validateUserData(String email, String password, Integer age) {
        List<ValidationError> errors = new ArrayList<>();
        
        // Validate email
        if (!Constraints.email().isValid(email)) {
            errors.add(new ValidationError("email", "Invalid email format"));
        }
        
        // Validate password length
        if (!Constraints.minLength(8).isValid(password)) {
            errors.add(new ValidationError("password", "Password must be at least 8 characters"));
        }
        
        // Validate age
        if (!Constraints.min(18).isValid(age)) {
            errors.add(new ValidationError("age", "Must be at least 18 years old"));
        }
        
        if (!errors.isEmpty()) {
            return badRequest(Json.toJson(errors));
        }
        
        return ok("Validation passed");
    }
}

Error Message Customization

// Custom error messages in model
public class Product {
    @Required(message = "Product name is required")
    @MinLength(value = 3, message = "Product name must be at least 3 characters")
    public String name;
    
    @Required(message = "Price is required")
    @Min(value = 0, message = "Price must be positive")
    public BigDecimal price;
}

// Accessing detailed error information
public Result processProduct() {
    Form<Product> form = Form.form(Product.class).bindFromRequest();
    
    if (form.hasErrors()) {
        for (Map.Entry<String, List<ValidationError>> entry : form.errors().entrySet()) {
            String field = entry.getKey();
            for (ValidationError error : entry.getValue()) {
                Logger.info("Field '{}': {}", field, error.message());
            }
        }
        return badRequest(form.errorsAsJson());
    }
    
    return ok("Product is valid");
}

Advanced Validation Patterns

Conditional Validation

public class ConditionalValidator extends Constraints.Validator<MyModel> {
    @Override
    public boolean isValid(MyModel model) {
        // Validate field A only if field B has a specific value
        if ("premium".equals(model.accountType)) {
            return model.creditLimit != null && model.creditLimit > 0;
        }
        return true;
    }
    
    @Override
    public Tuple<String, Object[]> getErrorMessageKey() {
        return Tuple.create("validation.conditional.failed", new Object[]{});
    }
}

Cross-Field Validation

public class PasswordConfirmationValidator extends Constraints.Validator<PasswordForm> {
    @Override
    public boolean isValid(PasswordForm form) {
        return Objects.equals(form.password, form.confirmPassword);
    }
    
    @Override
    public Tuple<String, Object[]> getErrorMessageKey() {
        return Tuple.create("validation.password.mismatch", new Object[]{});
    }
}

public class PasswordForm {
    @Required
    @MinLength(8)
    public String password;
    
    @Required
    public String confirmPassword;
    
    @ValidateWith(PasswordConfirmationValidator.class)
    public PasswordForm getThis() {
        return this;
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-typesafe-play--play-java

docs

dependency-injection.md

form-processing.md

formatting.md

index.md

routing.md

streaming.md

utilities.md

validation.md

tile.json