or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

array-utilities.mdbuilders.mdconcurrent-utilities.mddate-time-utilities.mdexception-utilities.mdindex.mdmath-utilities.mdobject-utilities.mdstring-utilities.mdvalidation-utilities.md

validation-utilities.mddocs/

0

# Validation Utilities

1

2

Apache Commons Lang provides comprehensive validation utilities through the Validate class, offering 51 static methods for argument validation, precondition checking, and defensive programming. These utilities throw clear, informative exceptions with consistent error messages.

3

4

## Core Validation Class

5

6

### Validate - Comprehensive Argument Validation

7

8

The Validate class provides fluent, null-safe validation methods that throw IllegalArgumentException with descriptive messages:

9

10

```java { .api }

11

import org.apache.commons.lang3.Validate;

12

```

13

14

#### Null Validation

15

16

```java { .api }

17

// Null checking methods

18

public static <T> T notNull(T object)

19

public static <T> T notNull(T object, String message, Object... values)

20

21

// Object validation

22

public static void validIndex(Object[] array, int index)

23

public static void validIndex(Object[] array, int index, String message, Object... values)

24

public static void validIndex(Collection<?> collection, int index)

25

public static void validIndex(Collection<?> collection, int index, String message, Object... values)

26

public static void validIndex(CharSequence chars, int index)

27

public static void validIndex(CharSequence chars, int index, String message, Object... values)

28

```

29

30

**Usage Examples:**

31

```java { .api }

32

public class UserService {

33

34

public User createUser(String name, String email, Integer age) {

35

// Basic null validation

36

Validate.notNull(name, "Name cannot be null");

37

Validate.notNull(email, "Email cannot be null");

38

Validate.notNull(age, "Age cannot be null");

39

40

// Validation with formatted message

41

Validate.notNull(name, "User %s field cannot be null", "name");

42

43

return new User(name, email, age);

44

}

45

46

public String getCharacterAt(String text, int index) {

47

Validate.notNull(text, "Text cannot be null");

48

Validate.validIndex(text, index, "Invalid index %d for text of length %d", index, text.length());

49

50

return String.valueOf(text.charAt(index));

51

}

52

53

public <T> T getElementAt(List<T> list, int index) {

54

Validate.notNull(list, "List cannot be null");

55

Validate.validIndex(list, index, "Index %d is out of bounds for list of size %d", index, list.size());

56

57

return list.get(index);

58

}

59

}

60

```

61

62

#### Empty and Blank Validation

63

64

```java { .api }

65

// Collection and array validation

66

public static <T extends Collection<?>> T notEmpty(T collection)

67

public static <T extends Collection<?>> T notEmpty(T collection, String message, Object... values)

68

public static <T> T[] notEmpty(T[] array)

69

public static <T> T[] notEmpty(T[] array, String message, Object... values)

70

71

// Map validation

72

public static <T extends Map<?, ?>> T notEmpty(T map)

73

public static <T extends Map<?, ?>> T notEmpty(T map, String message, Object... values)

74

75

// String validation

76

public static <T extends CharSequence> T notEmpty(T chars)

77

public static <T extends CharSequence> T notEmpty(T chars, String message, Object... values)

78

public static <T extends CharSequence> T notBlank(T chars)

79

public static <T extends CharSequence> T notBlank(T chars, String message, Object... values)

80

```

81

82

**Usage Examples:**

83

```java { .api }

84

public class ValidationExamples {

85

86

public void processData(List<String> items, String[] categories, Map<String, Object> config) {

87

// Collection validation

88

Validate.notEmpty(items, "Items list cannot be empty");

89

Validate.notEmpty(categories, "Categories array cannot be empty");

90

Validate.notEmpty(config, "Configuration map cannot be empty");

91

92

// Process data...

93

}

94

95

public User authenticateUser(String username, String password) {

96

// String validation (notEmpty allows whitespace-only strings)

97

Validate.notEmpty(username, "Username cannot be empty");

98

Validate.notEmpty(password, "Password cannot be empty");

99

100

// Blank validation (rejects whitespace-only strings)

101

Validate.notBlank(username, "Username cannot be blank");

102

Validate.notBlank(password, "Password cannot be blank");

103

104

return authenticate(username.trim(), password);

105

}

106

107

public void saveConfiguration(Map<String, String> settings) {

108

Validate.notEmpty(settings, "Settings cannot be empty");

109

110

// Validate individual entries

111

for (Map.Entry<String, String> entry : settings.entrySet()) {

112

Validate.notBlank(entry.getKey(), "Setting key cannot be blank");

113

Validate.notBlank(entry.getValue(), "Setting value for '%s' cannot be blank", entry.getKey());

114

}

115

}

116

}

117

```

118

119

#### Numeric Range Validation

120

121

```java { .api }

122

// Inclusive range validation

123

public static void inclusiveBetween(double start, double end, double value)

124

public static void inclusiveBetween(double start, double end, double value, String message, Object... values)

125

public static void inclusiveBetween(long start, long end, long value)

126

public static void inclusiveBetween(long start, long end, long value, String message, Object... values)

127

public static <T> void inclusiveBetween(T start, T end, Comparable<T> value)

128

public static <T> void inclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values)

129

130

// Exclusive range validation

131

public static void exclusiveBetween(double start, double end, double value)

132

public static void exclusiveBetween(double start, double end, double value, String message)

133

public static void exclusiveBetween(long start, long end, long value)

134

public static void exclusiveBetween(long start, long end, long value, String message)

135

public static <T> void exclusiveBetween(T start, T end, Comparable<T> value)

136

public static <T> void exclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values)

137

```

138

139

**Usage Examples:**

140

```java { .api }

141

public class RangeValidationExamples {

142

143

public void setAge(int age) {

144

Validate.inclusiveBetween(0, 150, age, "Age must be between 0 and 150, got: %d", age);

145

this.age = age;

146

}

147

148

public void setPercentage(double percentage) {

149

Validate.inclusiveBetween(0.0, 100.0, percentage, "Percentage must be between 0 and 100");

150

this.percentage = percentage;

151

}

152

153

public void setTemperature(double celsius) {

154

Validate.inclusiveBetween(-273.15, 1000.0, celsius, "Temperature must be above absolute zero");

155

this.temperature = celsius;

156

}

157

158

public void setScore(int score) {

159

// Exclusive range: score must be > 0 and < 100

160

Validate.exclusiveBetween(0, 100, score, "Score must be greater than 0 and less than 100");

161

this.score = score;

162

}

163

164

public void setGrade(String grade) {

165

Validate.notBlank(grade, "Grade cannot be blank");

166

167

// Using Comparable validation with strings

168

Validate.inclusiveBetween("A", "F", grade, "Grade must be between A and F");

169

this.grade = grade;

170

}

171

172

// Date range validation

173

public void setEventDate(Date eventDate) {

174

Validate.notNull(eventDate, "Event date cannot be null");

175

176

Date now = new Date();

177

Date maxFutureDate = DateUtils.addYears(now, 5);

178

179

Validate.inclusiveBetween(now, maxFutureDate, eventDate,

180

"Event date must be between now and 5 years in the future");

181

182

this.eventDate = eventDate;

183

}

184

}

185

```

186

187

#### Finite Number Validation

188

189

```java { .api }

190

// Finite number validation (not NaN or Infinity)

191

public static void finite(double value)

192

public static void finite(double value, String message, Object... values)

193

public static void finite(float value)

194

public static void finite(float value, String message, Object... values)

195

```

196

197

**Usage Examples:**

198

```java { .api }

199

public class FiniteValidationExamples {

200

201

public void calculateDistance(double x1, double y1, double x2, double y2) {

202

// Ensure all coordinates are finite numbers

203

Validate.finite(x1, "x1 coordinate must be finite");

204

Validate.finite(y1, "y1 coordinate must be finite");

205

Validate.finite(x2, "x2 coordinate must be finite");

206

Validate.finite(y2, "y2 coordinate must be finite");

207

208

double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));

209

Validate.finite(distance, "Calculated distance is not finite");

210

211

return distance;

212

}

213

214

public void setPrice(double price) {

215

Validate.finite(price, "Price cannot be NaN or infinite: %f", price);

216

Validate.inclusiveBetween(0.0, Double.MAX_VALUE, price, "Price must be non-negative");

217

218

this.price = price;

219

}

220

221

public Money convertCurrency(Money amount, double exchangeRate) {

222

Validate.notNull(amount, "Amount cannot be null");

223

Validate.finite(exchangeRate, "Exchange rate must be finite: %f", exchangeRate);

224

Validate.exclusiveBetween(0.0, Double.MAX_VALUE, exchangeRate, "Exchange rate must be positive");

225

226

double convertedValue = amount.getValue() * exchangeRate;

227

Validate.finite(convertedValue, "Converted amount is not finite");

228

229

return new Money(convertedValue, targetCurrency);

230

}

231

}

232

```

233

234

#### Boolean State Validation

235

236

```java { .api }

237

// Boolean state validation

238

public static void isTrue(boolean expression)

239

public static void isTrue(boolean expression, String message, Object... values)

240

```

241

242

**Usage Examples:**

243

```java { .api }

244

public class StateValidationExamples {

245

246

public void transferFunds(Account from, Account to, BigDecimal amount) {

247

Validate.notNull(from, "Source account cannot be null");

248

Validate.notNull(to, "Destination account cannot be null");

249

Validate.notNull(amount, "Transfer amount cannot be null");

250

251

// Boolean state validation

252

Validate.isTrue(amount.compareTo(BigDecimal.ZERO) > 0,

253

"Transfer amount must be positive: %s", amount);

254

255

Validate.isTrue(from.getBalance().compareTo(amount) >= 0,

256

"Insufficient funds: balance=%s, requested=%s", from.getBalance(), amount);

257

258

Validate.isTrue(!from.equals(to),

259

"Cannot transfer to the same account");

260

261

Validate.isTrue(from.isActive(),

262

"Source account %s is not active", from.getAccountNumber());

263

264

Validate.isTrue(to.isActive(),

265

"Destination account %s is not active", to.getAccountNumber());

266

267

// Perform transfer...

268

}

269

270

public void processOrder(Order order) {

271

Validate.notNull(order, "Order cannot be null");

272

273

// Validate order state

274

Validate.isTrue(order.hasItems(), "Order must contain at least one item");

275

Validate.isTrue(order.getCustomer() != null, "Order must have a customer");

276

Validate.isTrue(order.getTotalAmount().compareTo(BigDecimal.ZERO) > 0,

277

"Order total must be positive");

278

279

// Validate business rules

280

Validate.isTrue(order.getItems().size() <= 100,

281

"Order cannot contain more than 100 items");

282

283

Validate.isTrue(order.getTotalAmount().compareTo(new BigDecimal("10000")) <= 0,

284

"Order total cannot exceed $10,000");

285

}

286

287

public void setUserPermissions(User user, Set<Permission> permissions) {

288

Validate.notNull(user, "User cannot be null");

289

Validate.notEmpty(permissions, "Permissions cannot be empty");

290

291

// Validate user state

292

Validate.isTrue(user.isActive(), "Cannot set permissions for inactive user: %s", user.getUsername());

293

Validate.isTrue(!user.isLocked(), "Cannot set permissions for locked user: %s", user.getUsername());

294

295

// Validate permission constraints

296

boolean hasAdminPermission = permissions.contains(Permission.ADMIN);

297

boolean hasUserPermissions = permissions.stream().anyMatch(p -> p.getType() == PermissionType.USER);

298

299

Validate.isTrue(!hasAdminPermission || user.getRole() == Role.ADMINISTRATOR,

300

"Only administrators can have admin permissions");

301

302

Validate.isTrue(permissions.size() <= 20,

303

"User cannot have more than 20 permissions");

304

}

305

}

306

```

307

308

## Advanced Validation Patterns

309

310

### Custom Validation Methods

311

312

```java { .api }

313

public final class CustomValidators {

314

315

// Email validation

316

public static String validateEmail(String email) {

317

Validate.notBlank(email, "Email cannot be blank");

318

Validate.isTrue(email.contains("@"), "Email must contain @ symbol: %s", email);

319

Validate.isTrue(email.indexOf("@") != 0, "Email cannot start with @: %s", email);

320

Validate.isTrue(email.lastIndexOf("@") != email.length() - 1, "Email cannot end with @: %s", email);

321

Validate.isTrue(email.indexOf("@") == email.lastIndexOf("@"), "Email cannot contain multiple @ symbols: %s", email);

322

323

return email.toLowerCase().trim();

324

}

325

326

// Phone number validation

327

public static String validatePhoneNumber(String phone) {

328

Validate.notBlank(phone, "Phone number cannot be blank");

329

330

// Remove common formatting

331

String cleaned = phone.replaceAll("[\\s\\-\\(\\)\\.\\+]", "");

332

Validate.isTrue(cleaned.matches("\\d+"), "Phone number can only contain digits and formatting: %s", phone);

333

Validate.inclusiveBetween(7, 15, cleaned.length(),

334

"Phone number must be between 7 and 15 digits: %s", phone);

335

336

return cleaned;

337

}

338

339

// URL validation

340

public static String validateUrl(String url) {

341

Validate.notBlank(url, "URL cannot be blank");

342

343

String lowerUrl = url.toLowerCase();

344

Validate.isTrue(lowerUrl.startsWith("http://") || lowerUrl.startsWith("https://"),

345

"URL must start with http:// or https://: %s", url);

346

347

try {

348

new URL(url); // Additional validation

349

return url;

350

} catch (MalformedURLException e) {

351

throw new IllegalArgumentException("Invalid URL format: " + url, e);

352

}

353

}

354

355

// Credit card validation (simplified)

356

public static String validateCreditCard(String cardNumber) {

357

Validate.notBlank(cardNumber, "Credit card number cannot be blank");

358

359

String cleaned = cardNumber.replaceAll("[\\s\\-]", "");

360

Validate.isTrue(cleaned.matches("\\d+"), "Credit card number can only contain digits: %s", cardNumber);

361

Validate.inclusiveBetween(13, 19, cleaned.length(),

362

"Credit card number must be between 13 and 19 digits: %s", cardNumber);

363

364

// Luhn algorithm validation

365

Validate.isTrue(isValidLuhn(cleaned), "Invalid credit card number: %s", cardNumber);

366

367

return cleaned;

368

}

369

370

private static boolean isValidLuhn(String cardNumber) {

371

int sum = 0;

372

boolean alternate = false;

373

374

for (int i = cardNumber.length() - 1; i >= 0; i--) {

375

int digit = Character.getNumericValue(cardNumber.charAt(i));

376

377

if (alternate) {

378

digit *= 2;

379

if (digit > 9) {

380

digit = (digit % 10) + 1;

381

}

382

}

383

384

sum += digit;

385

alternate = !alternate;

386

}

387

388

return (sum % 10) == 0;

389

}

390

391

// Password strength validation

392

public static String validatePassword(String password) {

393

Validate.notNull(password, "Password cannot be null");

394

Validate.inclusiveBetween(8, 128, password.length(),

395

"Password must be between 8 and 128 characters");

396

397

Validate.isTrue(password.matches(".*[a-z].*"), "Password must contain at least one lowercase letter");

398

Validate.isTrue(password.matches(".*[A-Z].*"), "Password must contain at least one uppercase letter");

399

Validate.isTrue(password.matches(".*\\d.*"), "Password must contain at least one digit");

400

Validate.isTrue(password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*"),

401

"Password must contain at least one special character");

402

403

return password;

404

}

405

}

406

```

407

408

### Fluent Validation Builder

409

410

```java { .api }

411

public class FluentValidator<T> {

412

413

private final T value;

414

private final String fieldName;

415

416

private FluentValidator(T value, String fieldName) {

417

this.value = value;

418

this.fieldName = fieldName;

419

}

420

421

public static <T> FluentValidator<T> validate(T value, String fieldName) {

422

return new FluentValidator<>(value, fieldName);

423

}

424

425

public FluentValidator<T> notNull() {

426

Validate.notNull(value, "%s cannot be null", fieldName);

427

return this;

428

}

429

430

public FluentValidator<T> notEmpty() {

431

if (value instanceof Collection) {

432

Validate.notEmpty((Collection<?>) value, "%s cannot be empty", fieldName);

433

} else if (value instanceof CharSequence) {

434

Validate.notEmpty((CharSequence) value, "%s cannot be empty", fieldName);

435

} else if (value instanceof Object[]) {

436

Validate.notEmpty((Object[]) value, "%s cannot be empty", fieldName);

437

}

438

return this;

439

}

440

441

public FluentValidator<T> notBlank() {

442

if (value instanceof CharSequence) {

443

Validate.notBlank((CharSequence) value, "%s cannot be blank", fieldName);

444

}

445

return this;

446

}

447

448

public FluentValidator<T> inclusiveBetween(Comparable<T> start, Comparable<T> end) {

449

if (value instanceof Comparable) {

450

Validate.inclusiveBetween(start, end, (Comparable<T>) value,

451

"%s must be between %s and %s", fieldName, start, end);

452

}

453

return this;

454

}

455

456

public FluentValidator<T> isTrue(boolean condition, String message, Object... args) {

457

Validate.isTrue(condition, message, args);

458

return this;

459

}

460

461

public FluentValidator<T> custom(Predicate<T> validator, String message, Object... args) {

462

Validate.isTrue(validator.test(value), message, args);

463

return this;

464

}

465

466

public T get() {

467

return value;

468

}

469

}

470

471

// Usage examples

472

public class FluentValidationExamples {

473

474

public User createUser(String name, String email, Integer age) {

475

String validatedName = FluentValidator.validate(name, "name")

476

.notNull()

477

.notBlank()

478

.isTrue(name.length() <= 100, "Name cannot exceed 100 characters")

479

.get();

480

481

String validatedEmail = FluentValidator.validate(email, "email")

482

.notNull()

483

.notBlank()

484

.custom(e -> e.contains("@"), "Email must contain @ symbol")

485

.get();

486

487

Integer validatedAge = FluentValidator.validate(age, "age")

488

.notNull()

489

.inclusiveBetween(0, 150)

490

.get();

491

492

return new User(validatedName, validatedEmail, validatedAge);

493

}

494

}

495

```

496

497

### Validation Exception Handling

498

499

```java { .api }

500

@ControllerAdvice

501

public class ValidationExceptionHandler {

502

503

private static final Logger log = LoggerFactory.getLogger(ValidationExceptionHandler.class);

504

505

@ExceptionHandler(IllegalArgumentException.class)

506

public ResponseEntity<ErrorResponse> handleValidationError(IllegalArgumentException ex) {

507

log.warn("Validation error: {}", ex.getMessage());

508

509

ErrorResponse error = new ErrorResponse(

510

"VALIDATION_ERROR",

511

ex.getMessage(),

512

System.currentTimeMillis()

513

);

514

515

return ResponseEntity.badRequest().body(error);

516

}

517

518

@ExceptionHandler(NullPointerException.class)

519

public ResponseEntity<ErrorResponse> handleNullPointerError(NullPointerException ex) {

520

log.error("Null pointer error: {}", ex.getMessage(), ex);

521

522

ErrorResponse error = new ErrorResponse(

523

"NULL_VALUE_ERROR",

524

"A required value was null",

525

System.currentTimeMillis()

526

);

527

528

return ResponseEntity.badRequest().body(error);

529

}

530

}

531

532

// Custom validation service

533

@Service

534

public class ValidationService {

535

536

public <T> T validateAndReturn(T value, Consumer<T> validator, String context) {

537

try {

538

validator.accept(value);

539

return value;

540

} catch (IllegalArgumentException e) {

541

throw new ValidationException(context + ": " + e.getMessage(), e);

542

}

543

}

544

545

public void validateBusinessRules(Object entity) {

546

if (entity instanceof User) {

547

validateUser((User) entity);

548

} else if (entity instanceof Order) {

549

validateOrder((Order) entity);

550

} else {

551

throw new UnsupportedOperationException("Validation not supported for: " + entity.getClass());

552

}

553

}

554

555

private void validateUser(User user) {

556

Validate.notNull(user, "User cannot be null");

557

558

FluentValidator.validate(user.getEmail(), "email")

559

.notBlank()

560

.custom(email -> email.length() <= 255, "Email cannot exceed 255 characters")

561

.custom(this::isValidEmailFormat, "Invalid email format");

562

563

FluentValidator.validate(user.getAge(), "age")

564

.notNull()

565

.inclusiveBetween(13, 120); // Business rule: minimum age 13

566

}

567

568

private void validateOrder(Order order) {

569

Validate.notNull(order, "Order cannot be null");

570

Validate.notEmpty(order.getItems(), "Order must contain items");

571

572

// Validate total amount matches item sum

573

BigDecimal calculatedTotal = order.getItems().stream()

574

.map(OrderItem::getPrice)

575

.reduce(BigDecimal.ZERO, BigDecimal::add);

576

577

Validate.isTrue(order.getTotal().equals(calculatedTotal),

578

"Order total %s does not match calculated total %s",

579

order.getTotal(), calculatedTotal);

580

}

581

}

582

```

583

584

## Integration Examples

585

586

### Spring Boot Integration

587

588

```java { .api }

589

@RestController

590

public class UserController {

591

592

@PostMapping("/users")

593

public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {

594

// Validate request

595

Validate.notNull(request, "Request body cannot be null");

596

597

String name = FluentValidator.validate(request.getName(), "name")

598

.notBlank()

599

.isTrue(request.getName().length() <= 100, "Name cannot exceed 100 characters")

600

.get();

601

602

String email = FluentValidator.validate(request.getEmail(), "email")

603

.notBlank()

604

.custom(CustomValidators::isValidEmail, "Invalid email format")

605

.get();

606

607

User user = userService.createUser(name, email);

608

return ResponseEntity.ok(user);

609

}

610

}

611

612

@Component

613

public class ConfigurationValidator {

614

615

@EventListener

616

public void validateConfiguration(ApplicationReadyEvent event) {

617

validateDatabaseConfiguration();

618

validateCacheConfiguration();

619

validateSecurityConfiguration();

620

}

621

622

private void validateDatabaseConfiguration() {

623

String url = environment.getProperty("spring.datasource.url");

624

Validate.notBlank(url, "Database URL must be configured");

625

626

String username = environment.getProperty("spring.datasource.username");

627

Validate.notBlank(username, "Database username must be configured");

628

}

629

}

630

```

631

632

The validation utilities in Apache Commons Lang provide a comprehensive foundation for defensive programming, argument validation, and precondition checking that helps create robust, reliable applications with clear error messages and consistent validation patterns.