or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

base-validation.mddata-size-validation.mdduration-validation.mdindex.mdmethod-validation.mdself-validation.mdvalue-validation.md

method-validation.mddocs/

0

# Method Validation

1

2

Annotations and utilities for validating method parameters and enabling bean predicate validation, supporting advanced validation scenarios beyond field-level constraints. This provides method-level validation capabilities for Dropwizard applications.

3

4

## Capabilities

5

6

### Validated Annotation

7

8

Specifies validation groups for method parameters and return values, extending beyond the limitations of standard `@Valid` annotation.

9

10

```java { .api }

11

@Target({PARAMETER, METHOD})

12

@Retention(RUNTIME)

13

public @interface Validated {

14

/**

15

* Specify one or more validation groups to apply to the validation.

16

*

17

* @return Validation groups

18

*/

19

Class<?>[] value() default {Default.class};

20

}

21

```

22

23

**Usage Examples:**

24

25

```java

26

import io.dropwizard.validation.Validated;

27

import javax.validation.groups.Default;

28

29

public interface CreateUser {}

30

public interface UpdateUser {}

31

32

@Path("/users")

33

public class UserResource {

34

35

@POST

36

@Path("/create")

37

public Response createUser(@Validated(CreateUser.class) UserData userData) {

38

// Method parameter validated with CreateUser group

39

return Response.ok().build();

40

}

41

42

@PUT

43

@Path("/{id}")

44

public Response updateUser(

45

@PathParam("id") Long id,

46

@Validated({UpdateUser.class, Default.class}) UserData userData

47

) {

48

// Method parameter validated with both UpdateUser and Default groups

49

return Response.ok().build();

50

}

51

52

@POST

53

@Path("/batch")

54

public Response createUsers(@Validated List<@Validated(CreateUser.class) UserData> users) {

55

// Both the list and individual elements are validated

56

return Response.ok().build();

57

}

58

}

59

```

60

61

### ValidationMethod Annotation

62

63

Validates bean predicate methods as returning true. Bean predicates must be of the form `isSomething` or they'll be silently ignored.

64

65

```java { .api }

66

@Target({TYPE, ANNOTATION_TYPE, METHOD})

67

@Retention(RUNTIME)

68

@Constraint(validatedBy = MethodValidator.class)

69

public @interface ValidationMethod {

70

/**

71

* The validation message for this constraint.

72

*

73

* @return the message

74

*/

75

String message() default "is not valid";

76

77

/**

78

* The groups the constraint belongs to.

79

*

80

* @return an array of classes representing the groups

81

*/

82

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

83

84

/**

85

* The payloads of this constraint.

86

*

87

* @return the array of payload classes

88

*/

89

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

90

}

91

```

92

93

**Usage Examples:**

94

95

```java

96

import io.dropwizard.validation.ValidationMethod;

97

98

public class UserConfiguration {

99

private String username;

100

private String password;

101

private int age;

102

private String email;

103

104

@ValidationMethod(message = "Username and password cannot be the same")

105

public boolean isUsernameAndPasswordDifferent() {

106

return username == null || password == null || !username.equals(password);

107

}

108

109

@ValidationMethod(message = "User must be at least 18 years old")

110

public boolean isAgeValid() {

111

return age >= 18;

112

}

113

114

@ValidationMethod(message = "Email domain must be from approved list")

115

public boolean isEmailDomainApproved() {

116

if (email == null) return true;

117

118

String[] approvedDomains = {"company.com", "partner.org", "trusted.net"};

119

String domain = email.substring(email.lastIndexOf("@") + 1);

120

121

return Arrays.asList(approvedDomains).contains(domain);

122

}

123

124

// getters and setters...

125

}

126

```

127

128

## Advanced Usage

129

130

### Combining Method Validation with Field Validation

131

132

```java

133

import io.dropwizard.validation.ValidationMethod;

134

import javax.validation.constraints.NotNull;

135

import javax.validation.constraints.Size;

136

import javax.validation.constraints.Email;

137

138

public class RegistrationData {

139

@NotNull

140

@Size(min = 3, max = 50)

141

private String username;

142

143

@NotNull

144

@Size(min = 8)

145

private String password;

146

147

@NotNull

148

@Email

149

private String email;

150

151

private String confirmPassword;

152

private boolean termsAccepted;

153

154

// Method validation for business rules

155

@ValidationMethod(message = "Password and confirmation must match")

156

public boolean isPasswordConfirmed() {

157

return password != null && password.equals(confirmPassword);

158

}

159

160

@ValidationMethod(message = "Terms and conditions must be accepted")

161

public boolean isTermsAccepted() {

162

return termsAccepted;

163

}

164

165

@ValidationMethod(message = "Username cannot be the same as email prefix")

166

public boolean isUsernameUniqueFromEmail() {

167

if (username == null || email == null) return true;

168

169

String emailPrefix = email.substring(0, email.indexOf("@"));

170

return !username.equalsIgnoreCase(emailPrefix);

171

}

172

}

173

```

174

175

### Method Validation with Groups

176

177

```java

178

import io.dropwizard.validation.ValidationMethod;

179

180

public interface BasicValidation {}

181

public interface AdvancedValidation {}

182

183

public class SecurityConfiguration {

184

private int passwordMinLength;

185

private int maxLoginAttempts;

186

private boolean requireTwoFactor;

187

188

@ValidationMethod(

189

message = "Password minimum length must be at least 8 characters",

190

groups = BasicValidation.class

191

)

192

public boolean isPasswordMinLengthSufficient() {

193

return passwordMinLength >= 8;

194

}

195

196

@ValidationMethod(

197

message = "Max login attempts must be reasonable (3-10)",

198

groups = BasicValidation.class

199

)

200

public boolean isMaxLoginAttemptsReasonable() {

201

return maxLoginAttempts >= 3 && maxLoginAttempts <= 10;

202

}

203

204

@ValidationMethod(

205

message = "Two-factor authentication should be enabled for password lengths less than 12",

206

groups = AdvancedValidation.class

207

)

208

public boolean isTwoFactorAppropriate() {

209

return passwordMinLength >= 12 || requireTwoFactor;

210

}

211

}

212

213

// Validate with specific groups

214

Validator validator = BaseValidator.newValidator();

215

Set<ConstraintViolation<SecurityConfiguration>> basicViolations =

216

validator.validate(config, BasicValidation.class);

217

Set<ConstraintViolation<SecurityConfiguration>> advancedViolations =

218

validator.validate(config, AdvancedValidation.class);

219

```

220

221

### JAX-RS Resource Method Validation

222

223

```java

224

import io.dropwizard.validation.Validated;

225

import javax.validation.Valid;

226

import javax.validation.constraints.NotNull;

227

228

@Path("/api/orders")

229

public class OrderResource {

230

231

@POST

232

@Path("/create")

233

public Response createOrder(

234

@Valid @NotNull OrderRequest request,

235

@Validated(CreateOrder.class) @NotNull OrderMetadata metadata

236

) {

237

// Both request and metadata are validated

238

// request uses standard validation, metadata uses CreateOrder group

239

return Response.ok().build();

240

}

241

242

@PUT

243

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

244

public Response updateOrder(

245

@PathParam("id") @NotNull Long orderId,

246

@Validated({UpdateOrder.class, Default.class}) OrderRequest request

247

) {

248

// request validated with both UpdateOrder and Default groups

249

return Response.ok().build();

250

}

251

252

@GET

253

@Path("/search")

254

public Response searchOrders(

255

@Validated(SearchCriteria.class) @BeanParam OrderSearchParams params

256

) {

257

// Query parameters validated with SearchCriteria group

258

return Response.ok().build();

259

}

260

}

261

262

// Validation groups

263

public interface CreateOrder {}

264

public interface UpdateOrder {}

265

public interface SearchCriteria {}

266

```

267

268

### Complex Business Rule Validation

269

270

```java

271

import io.dropwizard.validation.ValidationMethod;

272

273

public class FinancialConfiguration {

274

private BigDecimal interestRate;

275

private int loanTermMonths;

276

private BigDecimal maxLoanAmount;

277

private BigDecimal minDownPayment;

278

private String creditScoreRequirement;

279

280

@ValidationMethod(message = "Interest rate must be positive and reasonable (0.1% to 50%)")

281

public boolean isInterestRateValid() {

282

if (interestRate == null) return true;

283

284

BigDecimal minRate = new BigDecimal("0.001"); // 0.1%

285

BigDecimal maxRate = new BigDecimal("0.50"); // 50%

286

287

return interestRate.compareTo(minRate) >= 0 &&

288

interestRate.compareTo(maxRate) <= 0;

289

}

290

291

@ValidationMethod(message = "Loan term must be between 6 months and 30 years")

292

public boolean isLoanTermReasonable() {

293

return loanTermMonths >= 6 && loanTermMonths <= 360;

294

}

295

296

@ValidationMethod(message = "Down payment cannot exceed maximum loan amount")

297

public boolean isDownPaymentAppropriate() {

298

if (minDownPayment == null || maxLoanAmount == null) return true;

299

300

return minDownPayment.compareTo(maxLoanAmount) <= 0;

301

}

302

303

@ValidationMethod(message = "Higher interest rates require lower credit score requirements")

304

public boolean isCreditScoreConsistentWithRate() {

305

if (interestRate == null || creditScoreRequirement == null) return true;

306

307

// Business logic: higher rates should allow lower credit scores

308

BigDecimal highRateThreshold = new BigDecimal("0.10"); // 10%

309

310

if (interestRate.compareTo(highRateThreshold) > 0) {

311

// High rate should allow lower credit requirements

312

return !creditScoreRequirement.equals("EXCELLENT");

313

}

314

315

return true;

316

}

317

}

318

```

319

320

## Integration Notes

321

322

### JAX-RS Integration

323

324

- `@Validated` works with JAX-RS resource methods for parameter validation

325

- Integrates with Dropwizard's Jersey validation to provide detailed error responses

326

- Can be combined with `@Valid` for comprehensive validation coverage

327

- Supports validation of `@BeanParam`, `@QueryParam`, `@PathParam`, and request body parameters

328

329

### Bean Validation Integration

330

331

- `@ValidationMethod` integrates seamlessly with standard Bean Validation annotations

332

- Method validation occurs in addition to field-level validation

333

- Supports validation groups for conditional validation scenarios

334

- Works with inheritance - validation methods in parent classes are also executed

335

336

### Best Practices

337

338

- Use `@Validated` when you need specific validation groups or ordered validation

339

- Use `@ValidationMethod` for cross-field validation and complex business rules

340

- Method names for `@ValidationMethod` should follow the `isSomething()` pattern

341

- Combine method validation with field validation for comprehensive coverage

342

- Consider performance implications of complex validation methods in high-throughput scenarios

343

344

### Error Handling

345

346

- Method validation violations are reported alongside field validation violations

347

- Custom error messages are supported and recommended for business rule clarity

348

- Violations can be processed using `ConstraintViolations.format()` utility methods