or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdframework-configuration.mdhttp-caching.mdindex.mdjsr310-parameters.mdoptional-handling.mdparameter-handling.mdsession-management.mdvalidation.md

validation.mddocs/

0

# Validation

1

2

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.

3

4

## Capabilities

5

6

### Validators Utility

7

8

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

9

10

```java { .api }

11

/**

12

* Utility class for Hibernate Validator configuration

13

* Provides factory methods for creating properly configured validators

14

*/

15

public class Validators {

16

17

/** Creates a new Validator with Dropwizard configuration */

18

public static Validator newValidator();

19

20

/** Creates a new ValidatorFactory with Dropwizard configuration */

21

public static ValidatorFactory newValidatorFactory();

22

23

/** Creates a new HibernateValidatorConfiguration with custom extractors */

24

public static HibernateValidatorConfiguration newConfiguration();

25

}

26

```

27

28

**Usage Examples:**

29

30

```java

31

import io.dropwizard.jersey.validation.Validators;

32

import jakarta.validation.Validator;

33

import jakarta.validation.ConstraintViolation;

34

import java.util.Set;

35

36

public class ValidationService {

37

38

private final Validator validator = Validators.newValidator();

39

40

public <T> void validate(T object) {

41

Set<ConstraintViolation<T>> violations = validator.validate(object);

42

if (!violations.isEmpty()) {

43

throw new ValidationException("Validation failed", violations);

44

}

45

}

46

47

public <T> void validateProperty(T object, String propertyName) {

48

Set<ConstraintViolation<T>> violations =

49

validator.validateProperty(object, propertyName);

50

if (!violations.isEmpty()) {

51

throw new ValidationException("Property validation failed", violations);

52

}

53

}

54

}

55

```

56

57

### Jersey Validation Exception

58

59

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

60

61

```java { .api }

62

/**

63

* Exception for Jersey validation violations

64

* Wraps constraint violations from Bean Validation

65

*/

66

public class JerseyViolationException extends ValidationException {

67

68

/** Creates exception with constraint violations */

69

public JerseyViolationException(Set<ConstraintViolation<?>> violations);

70

71

/** Gets the constraint violations that caused this exception */

72

public Set<ConstraintViolation<?>> getConstraintViolations();

73

74

/** Gets formatted error messages from constraint violations */

75

public List<String> getErrorMessages();

76

}

77

```

78

79

### Validation Exception Mapping

80

81

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

82

83

```java { .api }

84

/**

85

* Exception mapper for JerseyViolationException

86

* Converts validation violations to HTTP 422 responses with error details

87

*/

88

public class JerseyViolationExceptionMapper implements ExceptionMapper<JerseyViolationException> {

89

90

/** Maps JerseyViolationException to HTTP response with validation errors */

91

public Response toResponse(JerseyViolationException exception);

92

93

/** Creates validation error response with detailed field errors */

94

protected ValidationErrorMessage createErrorMessage(JerseyViolationException exception);

95

}

96

```

97

98

### Validation Error Message

99

100

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

101

102

```java { .api }

103

/**

104

* Structured validation error message with field-level errors

105

* Provides detailed information about validation failures

106

*/

107

public class ValidationErrorMessage {

108

109

/** Creates validation error message from error list */

110

public ValidationErrorMessage(Collection<String> errors);

111

112

/** Gets list of validation error messages */

113

public List<String> getErrors();

114

115

/** Gets validation errors grouped by field name */

116

public Map<String, List<String>> getFieldErrors();

117

}

118

119

/**

120

* Individual constraint violation message with field and error details

121

*/

122

public class ConstraintMessage {

123

124

/** Creates constraint message from violation */

125

public ConstraintMessage(ConstraintViolation<?> violation);

126

127

/** Gets the field or property path that failed validation */

128

public String getPath();

129

130

/** Gets the validation error message */

131

public String getMessage();

132

133

/** Gets the invalid value that caused the violation */

134

public Object getInvalidValue();

135

136

/** Gets the constraint annotation type */

137

public String getConstraintType();

138

}

139

```

140

141

### Parameter Value Extractors

142

143

Custom value extractors that enable validation on Dropwizard parameter types.

144

145

```java { .api }

146

/**

147

* Value extractor for AbstractParam types

148

* Enables Bean Validation on parameter wrapper classes

149

* @param <T> the wrapped parameter type

150

*/

151

public class ParamValueExtractor<T> implements ValueExtractor<AbstractParam<@ExtractedValue T>> {

152

153

/** Extracts the wrapped value for validation */

154

public void extractValues(AbstractParam<T> originalValue, ValueReceiver receiver);

155

156

/** Descriptor for registering the extractor */

157

public static final ValueExtractorDescriptor DESCRIPTOR;

158

}

159

160

/**

161

* Value extractor specifically for NonEmptyStringParam

162

* Provides specialized validation support for non-empty string parameters

163

*/

164

public class NonEmptyStringParamValueExtractor implements ValueExtractor<NonEmptyStringParam> {

165

166

/** Extracts string value for validation */

167

public void extractValues(NonEmptyStringParam originalValue, ValueReceiver receiver);

168

169

/** Descriptor for registering the extractor */

170

public static final ValueExtractorDescriptor DESCRIPTOR;

171

}

172

```

173

174

### Jersey Parameter Name Provider

175

176

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

177

178

```java { .api }

179

/**

180

* Parameter name provider for Jersey integration

181

* Provides parameter names from JAX-RS annotations for validation errors

182

*/

183

public class JerseyParameterNameProvider implements ParameterNameProvider {

184

185

/** Gets parameter names for method parameters using JAX-RS annotations */

186

public List<String> getParameterNames(Method method);

187

188

/** Gets parameter names for constructor parameters */

189

public List<String> getParameterNames(Constructor<?> constructor);

190

}

191

```

192

193

### Validation Configuration

194

195

```java { .api }

196

/**

197

* Hibernate Validation binder for Jersey integration

198

* Registers validation components with Jersey's dependency injection

199

*/

200

public class HibernateValidationBinder extends AbstractBinder {

201

202

/** Configures validation bindings */

203

protected void configure();

204

}

205

206

/**

207

* Mutable validator factory for constraint validators

208

* Allows dynamic constraint validator registration

209

*/

210

public class MutableValidatorFactory implements ConstraintValidatorFactory {

211

212

/** Creates or retrieves constraint validator instance */

213

public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key);

214

215

/** Releases constraint validator instance */

216

public void releaseInstance(ConstraintValidator<?, ?> instance);

217

}

218

219

/**

220

* Dropwizard-configured validator context resolver

221

* Provides configured validators for Jersey resources

222

*/

223

public class DropwizardConfiguredValidator implements ContextResolver<Validator> {

224

225

/** Gets configured validator instance */

226

public Validator getContext(Class<?> type);

227

}

228

```

229

230

### Fuzzy Enum Validation

231

232

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

233

234

```java { .api }

235

/**

236

* Parameter converter for enum types with fuzzy matching

237

* Provides case-insensitive and partial matching for enum parameters

238

* @param <T> the enum type

239

*/

240

public class FuzzyEnumParamConverter<T extends Enum<T>> implements ParamConverter<T> {

241

242

/** Converts string to enum with fuzzy matching */

243

public T fromString(String value);

244

245

/** Converts enum to string representation */

246

public String toString(T value);

247

248

/** Gets enum type being converted */

249

public Class<T> getEnumType();

250

}

251

252

/**

253

* Provider for fuzzy enum parameter converters

254

* Automatically provides converters for enum types

255

*/

256

public class FuzzyEnumParamConverterProvider implements ParamConverterProvider {

257

258

/** Gets parameter converter for enum types */

259

public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations);

260

}

261

```

262

263

## Validation Usage Patterns

264

265

### Resource Method Validation

266

267

```java

268

import io.dropwizard.jersey.params.UUIDParam;

269

import jakarta.validation.Valid;

270

import jakarta.validation.constraints.*;

271

import jakarta.ws.rs.*;

272

273

@Path("/users")

274

public class UserResource {

275

276

@POST

277

@Consumes(MediaType.APPLICATION_JSON)

278

public Response createUser(@Valid @NotNull CreateUserRequest request) {

279

// @Valid triggers validation of the request object

280

// @NotNull ensures request is not null

281

User user = userService.create(request);

282

return Response.status(201).entity(user).build();

283

}

284

285

@PUT

286

@Path("/{id}")

287

public Response updateUser(@PathParam("id") UUIDParam userId,

288

@Valid UpdateUserRequest request) {

289

// Both parameter and request body validation

290

User user = userService.update(userId.get(), request);

291

return Response.ok(user).build();

292

}

293

294

@GET

295

public List<User> getUsers(@QueryParam("page") @Min(1) @Max(1000) Integer page,

296

@QueryParam("size") @Min(1) @Max(100) Integer size,

297

@QueryParam("status") UserStatus status) {

298

// Parameter-level validation constraints

299

int actualPage = page != null ? page : 1;

300

int actualSize = size != null ? size : 10;

301

return userService.getUsers(actualPage, actualSize, status);

302

}

303

}

304

```

305

306

### Request Object Validation

307

308

```java

309

import jakarta.validation.constraints.*;

310

import jakarta.validation.Valid;

311

import java.time.LocalDate;

312

import java.util.List;

313

314

public class CreateUserRequest {

315

316

@NotBlank(message = "Name is required")

317

@Size(min = 2, max = 50, message = "Name must be between 2 and 50 characters")

318

private String name;

319

320

@NotBlank(message = "Email is required")

321

@Email(message = "Email must be a valid email address")

322

private String email;

323

324

@Min(value = 18, message = "Age must be at least 18")

325

@Max(value = 120, message = "Age must be less than 120")

326

private Integer age;

327

328

@Past(message = "Birth date must be in the past")

329

private LocalDate birthDate;

330

331

@Valid // Cascade validation to nested objects

332

@NotNull(message = "Address is required")

333

private Address address;

334

335

@Size(max = 5, message = "Maximum 5 phone numbers allowed")

336

private List<@Pattern(regexp = "\\d{10}", message = "Phone number must be 10 digits") String> phoneNumbers;

337

338

// getters and setters

339

}

340

341

public class Address {

342

343

@NotBlank(message = "Street is required")

344

private String street;

345

346

@NotBlank(message = "City is required")

347

private String city;

348

349

@Pattern(regexp = "\\d{5}", message = "ZIP code must be 5 digits")

350

private String zipCode;

351

352

// getters and setters

353

}

354

```

355

356

### Custom Validation Constraints

357

358

```java

359

import jakarta.validation.Constraint;

360

import jakarta.validation.ConstraintValidator;

361

import jakarta.validation.ConstraintValidatorContext;

362

import jakarta.validation.Payload;

363

import java.lang.annotation.*;

364

365

@Target({ElementType.FIELD, ElementType.PARAMETER})

366

@Retention(RetentionPolicy.RUNTIME)

367

@Constraint(validatedBy = ValidUserId.Validator.class)

368

@Documented

369

public @interface ValidUserId {

370

371

String message() default "Invalid user ID format";

372

Class<?>[] groups() default {};

373

Class<? extends Payload>[] payload() default {};

374

375

class Validator implements ConstraintValidator<ValidUserId, String> {

376

377

@Override

378

public boolean isValid(String value, ConstraintValidatorContext context) {

379

if (value == null) return true; // Let @NotNull handle null checks

380

381

// Custom validation logic

382

return value.matches("^[A-Z]{2}\\d{6}$");

383

}

384

}

385

}

386

387

// Usage

388

public class UserRequest {

389

@ValidUserId

390

@NotNull

391

private String userId;

392

}

393

```

394

395

### Group Validation

396

397

```java

398

import jakarta.validation.groups.Default;

399

400

public interface CreateGroup {}

401

public interface UpdateGroup {}

402

403

public class UserRequest {

404

405

@NotNull(groups = {CreateGroup.class, UpdateGroup.class})

406

private String name;

407

408

@NotNull(groups = CreateGroup.class)

409

@Null(groups = UpdateGroup.class, message = "ID cannot be specified for updates")

410

private String id;

411

412

@Email(groups = {CreateGroup.class, UpdateGroup.class})

413

private String email;

414

}

415

416

@Path("/users")

417

public class UserResource {

418

419

@POST

420

public Response createUser(@Valid(CreateGroup.class) UserRequest request) {

421

// Validates with CreateGroup constraints

422

return Response.ok().build();

423

}

424

425

@PUT

426

@Path("/{id}")

427

public Response updateUser(@PathParam("id") String id,

428

@Valid(UpdateGroup.class) UserRequest request) {

429

// Validates with UpdateGroup constraints

430

return Response.ok().build();

431

}

432

}

433

```

434

435

## Validation Error Handling

436

437

### Error Response Format

438

439

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

440

441

```json

442

{

443

"code": 422,

444

"message": "Validation failed",

445

"errors": [

446

"name: Name is required",

447

"email: Email must be a valid email address",

448

"age: Age must be at least 18"

449

],

450

"fieldErrors": {

451

"name": ["Name is required"],

452

"email": ["Email must be a valid email address"],

453

"age": ["Age must be at least 18"]

454

}

455

}

456

```

457

458

### Custom Validation Error Handler

459

460

```java

461

@Provider

462

public class CustomValidationExceptionMapper implements ExceptionMapper<JerseyViolationException> {

463

464

@Override

465

public Response toResponse(JerseyViolationException exception) {

466

Map<String, List<String>> fieldErrors = new HashMap<>();

467

List<String> globalErrors = new ArrayList<>();

468

469

for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {

470

String propertyPath = violation.getPropertyPath().toString();

471

String message = violation.getMessage();

472

473

if (propertyPath.isEmpty()) {

474

globalErrors.add(message);

475

} else {

476

fieldErrors.computeIfAbsent(propertyPath, k -> new ArrayList<>()).add(message);

477

}

478

}

479

480

ValidationErrorResponse error = new ValidationErrorResponse();

481

error.setMessage("Validation failed");

482

error.setFieldErrors(fieldErrors);

483

error.setGlobalErrors(globalErrors);

484

485

return Response.status(422).entity(error).build();

486

}

487

}

488

```

489

490

## Best Practices

491

492

### Validation Strategy

493

494

```java

495

public class ValidationBestPractices {

496

497

// Use appropriate validation annotations

498

@NotNull // For null checks

499

@NotBlank // For strings that should not be null, empty, or whitespace

500

@NotEmpty // For collections/arrays that should not be null or empty

501

502

@Size(min = 1, max = 100) // For length constraints

503

@Min(1) @Max(1000) // For numeric ranges

504

505

@Email // For email validation

506

@Pattern // For custom regex validation

507

@Past // For dates in the past

508

@Future // For dates in the future

509

510

// Cascade validation to nested objects

511

@Valid

512

private Address address;

513

514

// Validate collection elements

515

private List<@Valid ContactInfo> contacts;

516

517

// Group validation for different scenarios

518

@NotNull(groups = CreateGroup.class)

519

@Null(groups = UpdateGroup.class)

520

private String id;

521

}

522

```

523

524

### Parameter Validation

525

526

```java

527

@Path("/api")

528

public class ValidationExamples {

529

530

// Validate path parameters

531

@GET

532

@Path("/users/{id}")

533

public User getUser(@PathParam("id") @Pattern(regexp = "\\d+") String id) {

534

return userService.findById(Long.parseLong(id));

535

}

536

537

// Validate query parameters with defaults

538

@GET

539

@Path("/search")

540

public SearchResults search(

541

@QueryParam("q") @NotBlank @Size(min = 2, max = 100) String query,

542

@QueryParam("page") @Min(1) @DefaultValue("1") int page,

543

@QueryParam("size") @Min(1) @Max(100) @DefaultValue("10") int size) {

544

545

return searchService.search(query, page, size);

546

}

547

548

// Validate header parameters

549

@POST

550

@Path("/data")

551

public Response uploadData(

552

@HeaderParam("Content-Type") @Pattern(regexp = "application/.*") String contentType,

553

@Valid UploadRequest request) {

554

555

return Response.ok().build();

556

}

557

}

558

```