CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-dropwizard--dropwizard-project

Java framework for developing ops-friendly, high-performance, RESTful web applications

Pending
Overview
Eval results
Files

validation.mddocs/

Validation

Comprehensive input validation using Bean Validation (JSR-303) with custom Dropwizard validators for durations, data sizes, and other common types.

Capabilities

Bean Validation

Standard JSR-303 Bean Validation annotations for validating method parameters, request bodies, and configuration objects.

// Standard validation annotations
@NotNull         // Value must not be null
@NotEmpty        // String/Collection must not be null or empty
@NotBlank        // String must not be null, empty, or whitespace only
@Size(min = 1, max = 100)  // Collection/String size constraints
@Min(1)          // Numeric minimum value
@Max(100)        // Numeric maximum value
@Range(min = 1, max = 100)  // Numeric range
@Pattern(regexp = "\\d+")   // Regular expression pattern
@Email           // Valid email address format
@Valid           // Cascade validation to nested objects

// Usage in JAX-RS resources
@POST
public Response createUser(@Valid @NotNull User user) {
    // user is automatically validated before method execution
}

@GET
public User getUser(@PathParam("id") @NotNull @Min(1) Long id) {
    // id parameter is validated
}

Dropwizard Validation Annotations

Custom validation annotations specific to Dropwizard for common application configuration and input validation scenarios.

package io.dropwizard.validation;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DurationRangeValidator.class)
public @interface DurationRange {
    /**
     * Minimum duration value.
     */
    long min() default 0;
    
    /**
     * Maximum duration value.
     */
    long max() default Long.MAX_VALUE;
    
    /**
     * Time unit for min value.
     */
    TimeUnit minUnit() default TimeUnit.MILLISECONDS;
    
    /**
     * Time unit for max value.
     */
    TimeUnit maxUnit() default TimeUnit.MILLISECONDS;
}

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MinDurationValidator.class)
public @interface MinDuration {
    /**
     * Minimum duration value.
     */
    long value();
    
    /**
     * Time unit for the value.
     */
    TimeUnit unit() default TimeUnit.MILLISECONDS;
}

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MaxDurationValidator.class)
public @interface MaxDuration {
    /**
     * Maximum duration value.
     */
    long value();
    
    /**
     * Time unit for the value.
     */
    TimeUnit unit() default TimeUnit.MILLISECONDS;
}

Usage Example:

public class ServerConfiguration {
    @DurationRange(min = 1, minUnit = TimeUnit.SECONDS, max = 30, maxUnit = TimeUnit.SECONDS)
    private Duration connectionTimeout = Duration.seconds(5);
    
    @MinDuration(value = 100, unit = TimeUnit.MILLISECONDS)
    private Duration requestTimeout = Duration.milliseconds(500);
    
    @MaxDuration(value = 1, unit = TimeUnit.HOURS)
    private Duration sessionTimeout = Duration.minutes(30);
}

Data Size Validation

Validation annotations for data size constraints with support for various units (bytes, KB, MB, GB).

package io.dropwizard.validation;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DataSizeRangeValidator.class)
public @interface DataSizeRange {
    /**
     * Minimum data size value.
     */
    long min() default 0;
    
    /**
     * Maximum data size value.
     */
    long max() default Long.MAX_VALUE;
    
    /**
     * Unit for min value.
     */
    DataSize.Unit minUnit() default DataSize.Unit.BYTES;
    
    /**
     * Unit for max value.
     */
    DataSize.Unit maxUnit() default DataSize.Unit.BYTES;
}

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MinDataSizeValidator.class)
public @interface MinDataSize {
    /**
     * Minimum data size value.
     */
    long value();
    
    /**
     * Unit for the value.
     */
    DataSize.Unit unit() default DataSize.Unit.BYTES;
}

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MaxDataSizeValidator.class)
public @interface MaxDataSize {
    /**
     * Maximum data size value.
     */
    long value();
    
    /**
     * Unit for the value.
     */
    DataSize.Unit unit() default DataSize.Unit.BYTES;
}

Usage Example:

public class FileUploadConfiguration {
    @DataSizeRange(min = 1, minUnit = DataSize.Unit.KILOBYTES, 
                   max = 10, maxUnit = DataSize.Unit.MEGABYTES)
    private DataSize maxFileSize = DataSize.megabytes(5);
    
    @MinDataSize(value = 512, unit = DataSize.Unit.BYTES)
    private DataSize bufferSize = DataSize.kilobytes(8);
    
    @MaxDataSize(value = 100, unit = DataSize.Unit.MEGABYTES)
    private DataSize totalUploadLimit = DataSize.megabytes(50);
}

Enum and Choice Validation

Validation for restricting values to a specific set of allowed options.

package io.dropwizard.validation;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = OneOfValidator.class)
public @interface OneOf {
    /**
     * Array of allowed values.
     */
    String[] value();
    
    /**
     * Whether comparison should be case insensitive.
     */
    boolean ignoreCase() default false;
    
    /**
     * Whether whitespace should be ignored.
     */
    boolean ignoreWhitespace() default false;
}

Usage Example:

public class ApplicationConfiguration {
    @OneOf({"development", "staging", "production"})
    private String environment = "development";
    
    @OneOf(value = {"DEBUG", "INFO", "WARN", "ERROR"}, ignoreCase = true)
    private String logLevel = "INFO";
    
    @OneOf({"http", "https"})
    private String protocol = "http";
}

Port Range Validation

Validation for network port numbers with configurable ranges.

package io.dropwizard.validation;

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PortRangeValidator.class)
public @interface PortRange {
    /**
     * Minimum port number.
     */
    int min() default 1;
    
    /**
     * Maximum port number.
     */
    int max() default 65535;
}

Usage Example:

public class ServerConfiguration {
    @PortRange(min = 1024, max = 65535)
    private int applicationPort = 8080;
    
    @PortRange(min = 8000, max = 9000)
    private int adminPort = 8081;
}

Self-Validating Objects

Custom validation methods for complex business logic validation that cannot be expressed with simple annotations.

package io.dropwizard.validation.selfvalidating;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SelfValidating {
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidationMethod {
    /**
     * Error message when validation fails.
     */
    String message();
    
    /**
     * Groups for conditional validation.
     */
    Class<?>[] groups() default {};
}

Usage Example:

@SelfValidating
public class UserRegistration {
    @NotEmpty
    private String username;
    
    @NotEmpty
    private String password;
    
    @NotEmpty
    private String confirmPassword;
    
    @Email
    private String email;
    
    private int age;
    
    @ValidationMethod(message = "Passwords do not match")
    public boolean isPasswordValid() {
        return password != null && password.equals(confirmPassword);
    }
    
    @ValidationMethod(message = "User must be at least 13 years old")
    public boolean isAgeValid() {
        return age >= 13;
    }
    
    @ValidationMethod(message = "Username cannot be the same as email")
    public boolean isUsernameDistinct() {
        return !username.equals(email);
    }
}

Validation Groups

Conditional validation using groups to apply different validation rules in different contexts.

// Validation group interfaces
public interface CreateValidation {}
public interface UpdateValidation {}

public class User {
    @NotNull(groups = {CreateValidation.class, UpdateValidation.class})
    private String name;
    
    @NotNull(groups = CreateValidation.class)
    @Email(groups = {CreateValidation.class, UpdateValidation.class})
    private String email;
    
    @Null(groups = CreateValidation.class)
    @NotNull(groups = UpdateValidation.class)
    private Long id;
}

// Usage in resources
@POST
public User createUser(@Valid(CreateValidation.class) User user) {
    // Only CreateValidation constraints are applied
}

@PUT
@Path("/{id}")
public User updateUser(@PathParam("id") Long id, 
                      @Valid(UpdateValidation.class) User user) {
    // Only UpdateValidation constraints are applied
}

Custom Validators

Creating custom validation annotations and validators for application-specific validation requirements.

// Custom validation annotation
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CreditCardValidator.class)
public @interface CreditCard {
    String message() default "Invalid credit card number";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    
    CreditCardType[] acceptedTypes() default {CreditCardType.VISA, CreditCardType.MASTERCARD};
    
    enum CreditCardType {
        VISA, MASTERCARD, AMEX, DISCOVER
    }
}

// Custom validator implementation
public class CreditCardValidator implements ConstraintValidator<CreditCard, String> {
    private CreditCard.CreditCardType[] acceptedTypes;
    
    @Override
    public void initialize(CreditCard constraintAnnotation) {
        this.acceptedTypes = constraintAnnotation.acceptedTypes();
    }
    
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // Use @NotNull for null checks
        }
        
        // Remove spaces and hyphens
        String cleanNumber = value.replaceAll("[\\s-]", "");
        
        // Validate using Luhn algorithm
        if (!isValidLuhn(cleanNumber)) {
            return false;
        }
        
        // Check card type
        CreditCard.CreditCardType type = detectCardType(cleanNumber);
        return Arrays.asList(acceptedTypes).contains(type);
    }
    
    private boolean isValidLuhn(String number) {
        // Luhn algorithm implementation
        int sum = 0;
        boolean alternate = false;
        for (int i = number.length() - 1; i >= 0; i--) {
            int digit = Character.getNumericValue(number.charAt(i));
            if (alternate) {
                digit *= 2;
                if (digit > 9) {
                    digit = (digit % 10) + 1;
                }
            }
            sum += digit;
            alternate = !alternate;
        }
        return (sum % 10) == 0;
    }
    
    private CreditCard.CreditCardType detectCardType(String number) {
        if (number.startsWith("4")) {
            return CreditCard.CreditCardType.VISA;
        } else if (number.startsWith("5")) {
            return CreditCard.CreditCardType.MASTERCARD;
        } else if (number.startsWith("34") || number.startsWith("37")) {
            return CreditCard.CreditCardType.AMEX;
        } else if (number.startsWith("6")) {
            return CreditCard.CreditCardType.DISCOVER;
        }
        return CreditCard.CreditCardType.VISA; // Default
    }
}

Validation Error Handling

Validation Exception Mapping

Handling validation errors and converting them to appropriate HTTP responses with detailed error information.

@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
    @Override
    public Response toResponse(ConstraintViolationException exception) {
        List<String> errors = exception.getConstraintViolations()
                                       .stream()
                                       .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
                                       .collect(Collectors.toList());
        
        ErrorResponse errorResponse = new ErrorResponse("Validation failed", errors);
        
        return Response.status(Response.Status.BAD_REQUEST)
                      .entity(errorResponse)
                      .type(MediaType.APPLICATION_JSON)
                      .build();
    }
}

public class ErrorResponse {
    private String message;
    private List<String> errors;
    
    public ErrorResponse(String message, List<String> errors) {
        this.message = message;
        this.errors = errors;
    }
    
    // getters and setters
}

Install with Tessl CLI

npx tessl i tessl/maven-io-dropwizard--dropwizard-project

docs

authentication.md

configuration.md

core-application.md

database.md

index.md

metrics.md

rest-api.md

testing.md

validation.md

tile.json