CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-dropwizard--dropwizard-jersey

Dropwizard Jersey Support - Jersey integration module for the Dropwizard Java framework

Pending
Overview
Eval results
Files

validation.mddocs/

Validation

Hibernate Validator integration providing comprehensive validation support for JAX-RS resources with custom parameter extractors and constraint violation handling. Enables Bean Validation annotations on resource methods and request objects.

Capabilities

Validators Utility

Utility class for creating and configuring Hibernate validators with Dropwizard-specific enhancements.

/**
 * Utility class for Hibernate Validator configuration
 * Provides factory methods for creating properly configured validators
 */
public class Validators {
    
    /** Creates a new Validator with Dropwizard configuration */
    public static Validator newValidator();
    
    /** Creates a new ValidatorFactory with Dropwizard configuration */
    public static ValidatorFactory newValidatorFactory();
    
    /** Creates a new HibernateValidatorConfiguration with custom extractors */
    public static HibernateValidatorConfiguration newConfiguration();
}

Usage Examples:

import io.dropwizard.jersey.validation.Validators;
import jakarta.validation.Validator;
import jakarta.validation.ConstraintViolation;
import java.util.Set;

public class ValidationService {
    
    private final Validator validator = Validators.newValidator();
    
    public <T> void validate(T object) {
        Set<ConstraintViolation<T>> violations = validator.validate(object);
        if (!violations.isEmpty()) {
            throw new ValidationException("Validation failed", violations);
        }
    }
    
    public <T> void validateProperty(T object, String propertyName) {
        Set<ConstraintViolation<T>> violations = 
            validator.validateProperty(object, propertyName);
        if (!violations.isEmpty()) {
            throw new ValidationException("Property validation failed", violations);
        }
    }
}

Jersey Validation Exception

Exception class for Jersey-specific validation violations with detailed constraint violation information.

/**
 * Exception for Jersey validation violations
 * Wraps constraint violations from Bean Validation
 */
public class JerseyViolationException extends ValidationException {
    
    /** Creates exception with constraint violations */
    public JerseyViolationException(Set<ConstraintViolation<?>> violations);
    
    /** Gets the constraint violations that caused this exception */
    public Set<ConstraintViolation<?>> getConstraintViolations();
    
    /** Gets formatted error messages from constraint violations */
    public List<String> getErrorMessages();
}

Validation Exception Mapping

Exception mapper that converts validation exceptions to appropriate HTTP responses with detailed error information.

/**
 * Exception mapper for JerseyViolationException
 * Converts validation violations to HTTP 422 responses with error details
 */
public class JerseyViolationExceptionMapper implements ExceptionMapper<JerseyViolationException> {
    
    /** Maps JerseyViolationException to HTTP response with validation errors */
    public Response toResponse(JerseyViolationException exception);
    
    /** Creates validation error response with detailed field errors */
    protected ValidationErrorMessage createErrorMessage(JerseyViolationException exception);
}

Validation Error Message

Structured error message format for validation failures with field-level error details.

/**
 * Structured validation error message with field-level errors
 * Provides detailed information about validation failures
 */
public class ValidationErrorMessage {
    
    /** Creates validation error message from error list */
    public ValidationErrorMessage(Collection<String> errors);
    
    /** Gets list of validation error messages */
    public List<String> getErrors();
    
    /** Gets validation errors grouped by field name */
    public Map<String, List<String>> getFieldErrors();
}

/**
 * Individual constraint violation message with field and error details
 */
public class ConstraintMessage {
    
    /** Creates constraint message from violation */
    public ConstraintMessage(ConstraintViolation<?> violation);
    
    /** Gets the field or property path that failed validation */
    public String getPath();
    
    /** Gets the validation error message */
    public String getMessage();
    
    /** Gets the invalid value that caused the violation */
    public Object getInvalidValue();
    
    /** Gets the constraint annotation type */
    public String getConstraintType();
}

Parameter Value Extractors

Custom value extractors that enable validation on Dropwizard parameter types.

/**
 * Value extractor for AbstractParam types
 * Enables Bean Validation on parameter wrapper classes
 * @param <T> the wrapped parameter type
 */
public class ParamValueExtractor<T> implements ValueExtractor<AbstractParam<@ExtractedValue T>> {
    
    /** Extracts the wrapped value for validation */
    public void extractValues(AbstractParam<T> originalValue, ValueReceiver receiver);
    
    /** Descriptor for registering the extractor */
    public static final ValueExtractorDescriptor DESCRIPTOR;
}

/**
 * Value extractor specifically for NonEmptyStringParam
 * Provides specialized validation support for non-empty string parameters
 */
public class NonEmptyStringParamValueExtractor implements ValueExtractor<NonEmptyStringParam> {
    
    /** Extracts string value for validation */
    public void extractValues(NonEmptyStringParam originalValue, ValueReceiver receiver);
    
    /** Descriptor for registering the extractor */
    public static final ValueExtractorDescriptor DESCRIPTOR;
}

Jersey Parameter Name Provider

Parameter name provider that integrates with Jersey to provide meaningful parameter names for validation error messages.

/**
 * Parameter name provider for Jersey integration
 * Provides parameter names from JAX-RS annotations for validation errors
 */
public class JerseyParameterNameProvider implements ParameterNameProvider {
    
    /** Gets parameter names for method parameters using JAX-RS annotations */
    public List<String> getParameterNames(Method method);
    
    /** Gets parameter names for constructor parameters */
    public List<String> getParameterNames(Constructor<?> constructor);
}

Validation Configuration

/**
 * Hibernate Validation binder for Jersey integration
 * Registers validation components with Jersey's dependency injection
 */
public class HibernateValidationBinder extends AbstractBinder {
    
    /** Configures validation bindings */
    protected void configure();
}

/**
 * Mutable validator factory for constraint validators
 * Allows dynamic constraint validator registration
 */
public class MutableValidatorFactory implements ConstraintValidatorFactory {
    
    /** Creates or retrieves constraint validator instance */
    public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key);
    
    /** Releases constraint validator instance */
    public void releaseInstance(ConstraintValidator<?, ?> instance);
}

/**
 * Dropwizard-configured validator context resolver
 * Provides configured validators for Jersey resources
 */
public class DropwizardConfiguredValidator implements ContextResolver<Validator> {
    
    /** Gets configured validator instance */
    public Validator getContext(Class<?> type);
}

Fuzzy Enum Validation

Parameter converter that provides fuzzy matching for enum values with validation support.

/**
 * Parameter converter for enum types with fuzzy matching
 * Provides case-insensitive and partial matching for enum parameters
 * @param <T> the enum type
 */
public class FuzzyEnumParamConverter<T extends Enum<T>> implements ParamConverter<T> {
    
    /** Converts string to enum with fuzzy matching */
    public T fromString(String value);
    
    /** Converts enum to string representation */
    public String toString(T value);
    
    /** Gets enum type being converted */
    public Class<T> getEnumType();
}

/**
 * Provider for fuzzy enum parameter converters
 * Automatically provides converters for enum types
 */
public class FuzzyEnumParamConverterProvider implements ParamConverterProvider {
    
    /** Gets parameter converter for enum types */
    public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations);
}

Validation Usage Patterns

Resource Method Validation

import io.dropwizard.jersey.params.UUIDParam;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import jakarta.ws.rs.*;

@Path("/users")
public class UserResource {
    
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createUser(@Valid @NotNull CreateUserRequest request) {
        // @Valid triggers validation of the request object
        // @NotNull ensures request is not null
        User user = userService.create(request);
        return Response.status(201).entity(user).build();
    }
    
    @PUT
    @Path("/{id}")
    public Response updateUser(@PathParam("id") UUIDParam userId,
                              @Valid UpdateUserRequest request) {
        // Both parameter and request body validation
        User user = userService.update(userId.get(), request);
        return Response.ok(user).build();
    }
    
    @GET
    public List<User> getUsers(@QueryParam("page") @Min(1) @Max(1000) Integer page,
                              @QueryParam("size") @Min(1) @Max(100) Integer size,
                              @QueryParam("status") UserStatus status) {
        // Parameter-level validation constraints
        int actualPage = page != null ? page : 1;  
        int actualSize = size != null ? size : 10;
        return userService.getUsers(actualPage, actualSize, status);
    }
}

Request Object Validation

import jakarta.validation.constraints.*;
import jakarta.validation.Valid;
import java.time.LocalDate;
import java.util.List;

public class CreateUserRequest {
    
    @NotBlank(message = "Name is required")
    @Size(min = 2, max = 50, message = "Name must be between 2 and 50 characters")
    private String name;
    
    @NotBlank(message = "Email is required")
    @Email(message = "Email must be a valid email address")
    private String email;
    
    @Min(value = 18, message = "Age must be at least 18")
    @Max(value = 120, message = "Age must be less than 120")
    private Integer age;
    
    @Past(message = "Birth date must be in the past")
    private LocalDate birthDate;
    
    @Valid // Cascade validation to nested objects
    @NotNull(message = "Address is required")
    private Address address;
    
    @Size(max = 5, message = "Maximum 5 phone numbers allowed")
    private List<@Pattern(regexp = "\\d{10}", message = "Phone number must be 10 digits") String> phoneNumbers;
    
    // getters and setters
}

public class Address {
    
    @NotBlank(message = "Street is required")
    private String street;
    
    @NotBlank(message = "City is required")
    private String city;
    
    @Pattern(regexp = "\\d{5}", message = "ZIP code must be 5 digits")
    private String zipCode;
    
    // getters and setters
}

Custom Validation Constraints

import jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidUserId.Validator.class)
@Documented
public @interface ValidUserId {
    
    String message() default "Invalid user ID format";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    
    class Validator implements ConstraintValidator<ValidUserId, String> {
        
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (value == null) return true; // Let @NotNull handle null checks
            
            // Custom validation logic
            return value.matches("^[A-Z]{2}\\d{6}$");
        }
    }
}

// Usage
public class UserRequest {
    @ValidUserId
    @NotNull
    private String userId;
}

Group Validation

import jakarta.validation.groups.Default;

public interface CreateGroup {}
public interface UpdateGroup {}

public class UserRequest {
    
    @NotNull(groups = {CreateGroup.class, UpdateGroup.class})
    private String name;
    
    @NotNull(groups = CreateGroup.class)
    @Null(groups = UpdateGroup.class, message = "ID cannot be specified for updates")
    private String id;
    
    @Email(groups = {CreateGroup.class, UpdateGroup.class})
    private String email;
}

@Path("/users")
public class UserResource {
    
    @POST
    public Response createUser(@Valid(CreateGroup.class) UserRequest request) {
        // Validates with CreateGroup constraints
        return Response.ok().build();
    }
    
    @PUT
    @Path("/{id}")
    public Response updateUser(@PathParam("id") String id,
                              @Valid(UpdateGroup.class) UserRequest request) {
        // Validates with UpdateGroup constraints
        return Response.ok().build();
    }
}

Validation Error Handling

Error Response Format

Validation errors are returned as HTTP 422 responses with detailed field information:

{
  "code": 422,
  "message": "Validation failed",
  "errors": [
    "name: Name is required",
    "email: Email must be a valid email address",
    "age: Age must be at least 18"
  ],
  "fieldErrors": {
    "name": ["Name is required"],
    "email": ["Email must be a valid email address"],
    "age": ["Age must be at least 18"]
  }
}

Custom Validation Error Handler

@Provider
public class CustomValidationExceptionMapper implements ExceptionMapper<JerseyViolationException> {
    
    @Override
    public Response toResponse(JerseyViolationException exception) {
        Map<String, List<String>> fieldErrors = new HashMap<>();
        List<String> globalErrors = new ArrayList<>();
        
        for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
            String propertyPath = violation.getPropertyPath().toString();
            String message = violation.getMessage();
            
            if (propertyPath.isEmpty()) {
                globalErrors.add(message);
            } else {
                fieldErrors.computeIfAbsent(propertyPath, k -> new ArrayList<>()).add(message);
            }
        }
        
        ValidationErrorResponse error = new ValidationErrorResponse();
        error.setMessage("Validation failed");
        error.setFieldErrors(fieldErrors);
        error.setGlobalErrors(globalErrors);
        
        return Response.status(422).entity(error).build();
    }
}

Best Practices

Validation Strategy

public class ValidationBestPractices {
    
    // Use appropriate validation annotations
    @NotNull  // For null checks
    @NotBlank // For strings that should not be null, empty, or whitespace
    @NotEmpty // For collections/arrays that should not be null or empty
    
    @Size(min = 1, max = 100) // For length constraints
    @Min(1) @Max(1000)        // For numeric ranges
    
    @Email      // For email validation
    @Pattern    // For custom regex validation
    @Past       // For dates in the past
    @Future     // For dates in the future
    
    // Cascade validation to nested objects
    @Valid
    private Address address;
    
    // Validate collection elements
    private List<@Valid ContactInfo> contacts;
    
    // Group validation for different scenarios
    @NotNull(groups = CreateGroup.class)
    @Null(groups = UpdateGroup.class)
    private String id;
}

Parameter Validation

@Path("/api")
public class ValidationExamples {
    
    // Validate path parameters
    @GET
    @Path("/users/{id}")
    public User getUser(@PathParam("id") @Pattern(regexp = "\\d+") String id) {
        return userService.findById(Long.parseLong(id));
    }
    
    // Validate query parameters with defaults
    @GET
    @Path("/search")
    public SearchResults search(
        @QueryParam("q") @NotBlank @Size(min = 2, max = 100) String query,
        @QueryParam("page") @Min(1) @DefaultValue("1") int page,
        @QueryParam("size") @Min(1) @Max(100) @DefaultValue("10") int size) {
        
        return searchService.search(query, page, size);
    }
    
    // Validate header parameters
    @POST
    @Path("/data")
    public Response uploadData(
        @HeaderParam("Content-Type") @Pattern(regexp = "application/.*") String contentType,
        @Valid UploadRequest request) {
        
        return Response.ok().build();
    }
}

Install with Tessl CLI

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

docs

error-handling.md

framework-configuration.md

http-caching.md

index.md

jsr310-parameters.md

optional-handling.md

parameter-handling.md

session-management.md

validation.md

tile.json