or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

http-abstractions.mdhttp-clients.mdindex.mdmessage-conversion.mdreactive-web.mdweb-binding.mdweb-utilities.md

web-binding.mddocs/

0

# Web Binding and Annotations

1

2

Annotation-driven web development with parameter binding, data validation, and controller configuration. Provides the foundation for building REST APIs and web controllers with declarative configuration.

3

4

## Capabilities

5

6

### Request Mapping Annotations

7

8

Core annotations for mapping HTTP requests to controller methods and handling different HTTP operations.

9

10

```java { .api }

11

/**

12

* Maps HTTP requests to handler methods of MVC and REST controllers

13

*/

14

@Target({ElementType.TYPE, ElementType.METHOD})

15

@Retention(RetentionPolicy.RUNTIME)

16

@Documented

17

@Mapping

18

@interface RequestMapping {

19

/** Request mapping name */

20

String name() default "";

21

/** URL patterns - primary mapping attribute */

22

String[] value() default {};

23

/** Alias for value() */

24

String[] path() default {};

25

/** HTTP request methods */

26

RequestMethod[] method() default {};

27

/** Request parameters conditions */

28

String[] params() default {};

29

/** Request header conditions */

30

String[] headers() default {};

31

/** Consumable media types */

32

String[] consumes() default {};

33

/** Producible media types */

34

String[] produces() default {};

35

}

36

37

/**

38

* HTTP methods enumeration

39

*/

40

enum RequestMethod {

41

GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE

42

}

43

44

/**

45

* Composed annotation for HTTP GET requests

46

*/

47

@Target(ElementType.METHOD)

48

@Retention(RetentionPolicy.RUNTIME)

49

@Documented

50

@RequestMapping(method = RequestMethod.GET)

51

@interface GetMapping {

52

String name() default "";

53

String[] value() default {};

54

String[] path() default {};

55

String[] params() default {};

56

String[] headers() default {};

57

String[] consumes() default {};

58

String[] produces() default {};

59

}

60

61

/**

62

* Composed annotation for HTTP POST requests

63

*/

64

@Target(ElementType.METHOD)

65

@Retention(RetentionPolicy.RUNTIME)

66

@Documented

67

@RequestMapping(method = RequestMethod.POST)

68

@interface PostMapping {

69

String name() default "";

70

String[] value() default {};

71

String[] path() default {};

72

String[] params() default {};

73

String[] headers() default {};

74

String[] consumes() default {};

75

String[] produces() default {};

76

}

77

78

/**

79

* Composed annotation for HTTP PUT requests

80

*/

81

@Target(ElementType.METHOD)

82

@Retention(RetentionPolicy.RUNTIME)

83

@Documented

84

@RequestMapping(method = RequestMethod.PUT)

85

@interface PutMapping {

86

String name() default "";

87

String[] value() default {};

88

String[] path() default {};

89

String[] params() default {};

90

String[] headers() default {};

91

String[] consumes() default {};

92

String[] produces() default {};

93

}

94

95

/**

96

* Composed annotation for HTTP DELETE requests

97

*/

98

@Target(ElementType.METHOD)

99

@Retention(RetentionPolicy.RUNTIME)

100

@Documented

101

@RequestMapping(method = RequestMethod.DELETE)

102

@interface DeleteMapping {

103

String name() default "";

104

String[] value() default {};

105

String[] path() default {};

106

String[] params() default {};

107

String[] headers() default {};

108

String[] consumes() default {};

109

String[] produces() default {};

110

}

111

112

/**

113

* Composed annotation for HTTP PATCH requests

114

*/

115

@Target(ElementType.METHOD)

116

@Retention(RetentionPolicy.RUNTIME)

117

@Documented

118

@RequestMapping(method = RequestMethod.PATCH)

119

@interface PatchMapping {

120

String name() default "";

121

String[] value() default {};

122

String[] path() default {};

123

String[] params() default {};

124

String[] headers() default {};

125

String[] consumes() default {};

126

String[] produces() default {};

127

}

128

```

129

130

**Usage Examples:**

131

132

```java

133

@RestController

134

@RequestMapping("/api/users")

135

public class UserController {

136

137

@GetMapping

138

public List<User> getAllUsers() {

139

return userService.findAll();

140

}

141

142

@GetMapping("/{id}")

143

public User getUserById(@PathVariable Long id) {

144

return userService.findById(id);

145

}

146

147

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)

148

public ResponseEntity<User> createUser(@RequestBody User user) {

149

User created = userService.create(user);

150

return ResponseEntity.status(HttpStatus.CREATED).body(created);

151

}

152

153

@PutMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)

154

public User updateUser(@PathVariable Long id, @RequestBody User user) {

155

return userService.update(id, user);

156

}

157

158

@DeleteMapping("/{id}")

159

public ResponseEntity<Void> deleteUser(@PathVariable Long id) {

160

userService.delete(id);

161

return ResponseEntity.noContent().build();

162

}

163

}

164

```

165

166

### Parameter Binding Annotations

167

168

Annotations for binding HTTP request data to method parameters with type conversion and validation.

169

170

```java { .api }

171

/**

172

* Binds web request parameter to method parameter

173

*/

174

@Target(ElementType.PARAMETER)

175

@Retention(RetentionPolicy.RUNTIME)

176

@Documented

177

@interface RequestParam {

178

/** Alias for name() */

179

String value() default "";

180

/** Parameter name to bind to */

181

String name() default "";

182

/** Whether parameter is required */

183

boolean required() default true;

184

/** Default value if parameter is not present */

185

String defaultValue() default ValueConstants.DEFAULT_NONE;

186

}

187

188

/**

189

* Binds URI template variable to method parameter

190

*/

191

@Target(ElementType.PARAMETER)

192

@Retention(RetentionPolicy.RUNTIME)

193

@Documented

194

@interface PathVariable {

195

/** Alias for name() */

196

String value() default "";

197

/** Path variable name to bind to */

198

String name() default "";

199

/** Whether path variable is required */

200

boolean required() default true;

201

}

202

203

/**

204

* Binds HTTP request body to method parameter

205

*/

206

@Target(ElementType.PARAMETER)

207

@Retention(RetentionPolicy.RUNTIME)

208

@Documented

209

@interface RequestBody {

210

/** Whether body content is required */

211

boolean required() default true;

212

}

213

214

/**

215

* Binds request header to method parameter

216

*/

217

@Target(ElementType.PARAMETER)

218

@Retention(RetentionPolicy.RUNTIME)

219

@Documented

220

@interface RequestHeader {

221

/** Alias for name() */

222

String value() default "";

223

/** Header name to bind to */

224

String name() default "";

225

/** Whether header is required */

226

boolean required() default true;

227

/** Default value if header is not present */

228

String defaultValue() default ValueConstants.DEFAULT_NONE;

229

}

230

231

/**

232

* Binds cookie value to method parameter

233

*/

234

@Target(ElementType.PARAMETER)

235

@Retention(RetentionPolicy.RUNTIME)

236

@Documented

237

@interface CookieValue {

238

/** Alias for name() */

239

String value() default "";

240

/** Cookie name to bind to */

241

String name() default "";

242

/** Whether cookie is required */

243

boolean required() default true;

244

/** Default value if cookie is not present */

245

String defaultValue() default ValueConstants.DEFAULT_NONE;

246

}

247

248

/**

249

* Binds request attribute to method parameter

250

*/

251

@Target(ElementType.PARAMETER)

252

@Retention(RetentionPolicy.RUNTIME)

253

@Documented

254

@interface RequestAttribute {

255

/** Alias for name() */

256

String value() default "";

257

/** Attribute name to bind to */

258

String name() default "";

259

/** Whether attribute is required */

260

boolean required() default true;

261

}

262

263

/**

264

* Binds session attribute to method parameter

265

*/

266

@Target(ElementType.PARAMETER)

267

@Retention(RetentionPolicy.RUNTIME)

268

@Documented

269

@interface SessionAttribute {

270

/** Alias for name() */

271

String value() default "";

272

/** Attribute name to bind to */

273

String name() default "";

274

/** Whether attribute is required */

275

boolean required() default true;

276

}

277

278

/**

279

* Binds matrix variables to method parameter

280

*/

281

@Target(ElementType.PARAMETER)

282

@Retention(RetentionPolicy.RUNTIME)

283

@Documented

284

@interface MatrixVariable {

285

/** Alias for name() */

286

String value() default "";

287

/** Matrix variable name to bind to */

288

String name() default "";

289

/** Path segment to extract matrix variables from */

290

String pathVar() default ValueConstants.DEFAULT_NONE;

291

/** Whether matrix variable is required */

292

boolean required() default true;

293

/** Default value if matrix variable is not present */

294

String defaultValue() default ValueConstants.DEFAULT_NONE;

295

}

296

```

297

298

**Usage Examples:**

299

300

```java

301

@RestController

302

public class ExampleController {

303

304

@GetMapping("/users")

305

public List<User> getUsers(

306

@RequestParam(defaultValue = "0") int page,

307

@RequestParam(defaultValue = "10") int size,

308

@RequestParam(required = false) String search) {

309

return userService.findUsers(page, size, search);

310

}

311

312

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

313

public User getUserById(@PathVariable Long id) {

314

return userService.findById(id);

315

}

316

317

@PostMapping("/users")

318

public User createUser(@RequestBody @Valid User user) {

319

return userService.create(user);

320

}

321

322

@GetMapping("/profile")

323

public User getProfile(

324

@RequestHeader("Authorization") String authHeader,

325

@CookieValue(value = "sessionId", required = false) String sessionId) {

326

return userService.getProfile(authHeader, sessionId);

327

}

328

329

@GetMapping("/cars/{model}/features;color={color};year={year}")

330

public Car getCar(

331

@PathVariable String model,

332

@MatrixVariable String color,

333

@MatrixVariable int year) {

334

return carService.findCar(model, color, year);

335

}

336

}

337

```

338

339

### Response Handling Annotations

340

341

Annotations for configuring response handling and serialization.

342

343

```java { .api }

344

/**

345

* Indicates method return value should be bound to web response body

346

*/

347

@Target({ElementType.TYPE, ElementType.METHOD})

348

@Retention(RetentionPolicy.RUNTIME)

349

@Documented

350

@interface ResponseBody {

351

// No attributes - marker annotation

352

}

353

354

/**

355

* Marks method or exception class with status code and reason

356

*/

357

@Target({ElementType.TYPE, ElementType.METHOD})

358

@Retention(RetentionPolicy.RUNTIME)

359

@Documented

360

@interface ResponseStatus {

361

/** Alias for code() */

362

HttpStatus value() default HttpStatus.INTERNAL_SERVER_ERROR;

363

/** HTTP status code to return */

364

HttpStatus code() default HttpStatus.INTERNAL_SERVER_ERROR;

365

/** Reason phrase for the status */

366

String reason() default "";

367

}

368

369

/**

370

* Used to bind model attributes to session

371

*/

372

@Target({ElementType.TYPE})

373

@Retention(RetentionPolicy.RUNTIME)

374

@Documented

375

@interface SessionAttributes {

376

/** Alias for names() */

377

String[] value() default {};

378

/** Names of model attributes to store in session */

379

String[] names() default {};

380

/** Types of model attributes to store in session */

381

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

382

}

383

384

/**

385

* Binds method parameter or return value to model attribute

386

*/

387

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

388

@Retention(RetentionPolicy.RUNTIME)

389

@Documented

390

@interface ModelAttribute {

391

/** Alias for name() */

392

String value() default "";

393

/** Name of model attribute */

394

String name() default "";

395

/** Whether parameter binding is required */

396

boolean binding() default true;

397

}

398

```

399

400

### Controller Configuration Annotations

401

402

Annotations for configuring controller classes and global behavior.

403

404

```java { .api }

405

/**

406

* Specialization of @Component for controller classes

407

*/

408

@Target({ElementType.TYPE})

409

@Retention(RetentionPolicy.RUNTIME)

410

@Documented

411

@Component

412

@interface Controller {

413

/** Component name */

414

String value() default "";

415

}

416

417

/**

418

* Convenience annotation combining @Controller and @ResponseBody

419

*/

420

@Target({ElementType.TYPE})

421

@Retention(RetentionPolicy.RUNTIME)

422

@Documented

423

@Controller

424

@ResponseBody

425

@interface RestController {

426

/** Component name */

427

String value() default "";

428

}

429

430

/**

431

* Specialization of @Component for global controller configuration

432

*/

433

@Target(ElementType.TYPE)

434

@Retention(RetentionPolicy.RUNTIME)

435

@Documented

436

@Component

437

@interface ControllerAdvice {

438

/** Alias for basePackages() */

439

String[] value() default {};

440

/** Base packages to scan for controllers */

441

String[] basePackages() default {};

442

/** Base package classes for type-safe package specification */

443

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

444

/** Controller types to assist */

445

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

446

/** Annotations that controllers must have */

447

Class<? extends Annotation>[] annotations() default {};

448

}

449

450

/**

451

* Convenience annotation combining @ControllerAdvice and @ResponseBody

452

*/

453

@Target(ElementType.TYPE)

454

@Retention(RetentionPolicy.RUNTIME)

455

@Documented

456

@ControllerAdvice

457

@ResponseBody

458

@interface RestControllerAdvice {

459

/** Alias for basePackages() */

460

String[] value() default {};

461

/** Base packages to scan for controllers */

462

String[] basePackages() default {};

463

/** Base package classes for type-safe package specification */

464

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

465

/** Controller types to assist */

466

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

467

/** Annotations that controllers must have */

468

Class<? extends Annotation>[] annotations() default {};

469

}

470

```

471

472

**Usage Examples:**

473

474

```java

475

@RestController

476

@RequestMapping("/api")

477

public class ApiController {

478

479

@GetMapping("/health")

480

@ResponseStatus(HttpStatus.OK)

481

public Map<String, String> health() {

482

return Map.of("status", "UP", "timestamp", Instant.now().toString());

483

}

484

}

485

486

@RestControllerAdvice

487

public class GlobalExceptionHandler {

488

489

@ExceptionHandler(UserNotFoundException.class)

490

@ResponseStatus(HttpStatus.NOT_FOUND)

491

public ErrorResponse handleUserNotFound(UserNotFoundException ex) {

492

return new ErrorResponse("USER_NOT_FOUND", ex.getMessage());

493

}

494

495

@ExceptionHandler(ValidationException.class)

496

@ResponseStatus(HttpStatus.BAD_REQUEST)

497

public ErrorResponse handleValidation(ValidationException ex) {

498

return new ErrorResponse("VALIDATION_ERROR", ex.getMessage());

499

}

500

}

501

```

502

503

### Exception Handling Annotations

504

505

Annotations for handling exceptions and errors in web controllers.

506

507

```java { .api }

508

/**

509

* Marks method as exception handler for specific exception types

510

*/

511

@Target(ElementType.METHOD)

512

@Retention(RetentionPolicy.RUNTIME)

513

@Documented

514

@interface ExceptionHandler {

515

/** Exception types handled by this method */

516

Class<? extends Throwable>[] value() default {};

517

}

518

519

/**

520

* Binds method parameter to exception and its cause

521

*/

522

@Target(ElementType.PARAMETER)

523

@Retention(RetentionPolicy.RUNTIME)

524

@Documented

525

@interface ExceptionAttribute {

526

/** Exception attribute name */

527

String value() default "";

528

}

529

```

530

531

**Usage Examples:**

532

533

```java

534

@ControllerAdvice

535

public class ExceptionHandlerController {

536

537

@ExceptionHandler({UserNotFoundException.class, ProductNotFoundException.class})

538

@ResponseStatus(HttpStatus.NOT_FOUND)

539

public ResponseEntity<ErrorResponse> handleNotFound(Exception ex) {

540

ErrorResponse error = new ErrorResponse("RESOURCE_NOT_FOUND", ex.getMessage());

541

return ResponseEntity.notFound().build();

542

}

543

544

@ExceptionHandler(MethodArgumentNotValidException.class)

545

@ResponseStatus(HttpStatus.BAD_REQUEST)

546

public ResponseEntity<ValidationErrorResponse> handleValidation(

547

MethodArgumentNotValidException ex) {

548

549

List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();

550

ValidationErrorResponse error = new ValidationErrorResponse();

551

552

for (FieldError fieldError : fieldErrors) {

553

error.addError(fieldError.getField(), fieldError.getDefaultMessage());

554

}

555

556

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

557

}

558

559

@ExceptionHandler(Exception.class)

560

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

561

public ResponseEntity<ErrorResponse> handleGeneral(Exception ex) {

562

ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred");

563

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);

564

}

565

}

566

```

567

568

### Cross-Origin Resource Sharing (CORS)

569

570

Annotations for configuring CORS support in web controllers.

571

572

```java { .api }

573

/**

574

* Marks class or method as accepting cross-origin requests

575

*/

576

@Target({ElementType.TYPE, ElementType.METHOD})

577

@Retention(RetentionPolicy.RUNTIME)

578

@Documented

579

@interface CrossOrigin {

580

/** Alias for origins() */

581

String[] value() default {};

582

/** Allowed origins for cross-origin requests */

583

String[] origins() default {};

584

/** Allowed origin patterns */

585

String[] originPatterns() default {};

586

/** Allowed request headers */

587

String[] allowedHeaders() default {};

588

/** Headers exposed to client */

589

String[] exposedHeaders() default {};

590

/** Allowed HTTP methods */

591

RequestMethod[] methods() default {};

592

/** Whether credentials are allowed */

593

boolean allowCredentials() default "";

594

/** Pre-flight cache duration in seconds */

595

long maxAge() default -1;

596

}

597

```

598

599

**Usage Examples:**

600

601

```java

602

@RestController

603

@CrossOrigin(origins = "https://example.com", maxAge = 3600)

604

public class ApiController {

605

606

@GetMapping("/public-data")

607

public List<Data> getPublicData() {

608

return dataService.getPublicData();

609

}

610

611

@PostMapping("/secure-endpoint")

612

@CrossOrigin(origins = "https://secure.example.com", allowCredentials = true)

613

public ResponseEntity<String> secureOperation(@RequestBody SecureRequest request) {

614

return ResponseEntity.ok("Operation completed");

615

}

616

}

617

618

@RestController

619

public class FileController {

620

621

@PostMapping("/upload")

622

@CrossOrigin(

623

origins = {"https://app.example.com", "https://admin.example.com"},

624

methods = {RequestMethod.POST, RequestMethod.OPTIONS},

625

allowedHeaders = {"Content-Type", "Authorization"},

626

exposedHeaders = {"Upload-Status"},

627

maxAge = 1800

628

)

629

public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {

630

// Handle file upload

631

return ResponseEntity.ok().header("Upload-Status", "SUCCESS").body("File uploaded");

632

}

633

}

634

```

635

636

### Data Binding Support

637

638

Core classes for web data binding, validation, and type conversion.

639

640

```java { .api }

641

/**

642

* Special DataBinder for web request parameter binding

643

*/

644

class WebDataBinder extends DataBinder {

645

WebDataBinder(Object target);

646

WebDataBinder(Object target, String objectName);

647

648

/** Set prefix for field markers (e.g., "_fieldName" for checkboxes) */

649

void setFieldMarkerPrefix(String fieldMarkerPrefix);

650

/** Get field marker prefix */

651

String getFieldMarkerPrefix();

652

653

/** Set prefix for field defaults */

654

void setFieldDefaultPrefix(String fieldDefaultPrefix);

655

/** Get field default prefix */

656

String getFieldDefaultPrefix();

657

658

/** Bind parameters from web request */

659

void bind(ServletRequest request);

660

/** Bind multipart files */

661

void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, ServletRequest request);

662

663

/** Check for field markers indicating empty fields */

664

protected void checkFieldMarkers(MutablePropertyValues mpvs);

665

/** Check for field defaults */

666

protected void checkFieldDefaults(MutablePropertyValues mpvs);

667

/** Determine if empty string should be treated as null */

668

protected boolean isEmptyInputField(String field);

669

}

670

671

/**

672

* Exception thrown when data binding fails

673

*/

674

class BindException extends Exception implements BindingResult {

675

BindException(BindingResult bindingResult);

676

BindException(Object target, String objectName);

677

678

/** Get the binding result */

679

BindingResult getBindingResult();

680

}

681

682

/**

683

* Exception thrown when method argument binding/validation fails

684

*/

685

class MethodArgumentNotValidException extends BindException {

686

MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult);

687

688

/** Get the method parameter that failed validation */

689

MethodParameter getParameter();

690

}

691

692

/**

693

* Exception thrown when web exchange binding fails

694

*/

695

class WebExchangeBindException extends ResponseStatusException implements BindingResult {

696

WebExchangeBindException(MethodParameter parameter, BindingResult bindingResult);

697

698

/** Get the method parameter */

699

MethodParameter getMethodParameter();

700

/** Get the binding result */

701

BindingResult getBindingResult();

702

}

703

```

704

705

### Validation Support

706

707

Integration with Bean Validation (JSR-303/JSR-380) for request validation.

708

709

```java { .api }

710

/**

711

* Marks parameter for validation

712

*/

713

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

714

@Retention(RetentionPolicy.RUNTIME)

715

@Documented

716

@interface Valid {

717

// Marker annotation for validation

718

}

719

720

/**

721

* JSR-303 validation groups

722

*/

723

@Target({ElementType.PARAMETER})

724

@Retention(RetentionPolicy.RUNTIME)

725

@Documented

726

@interface Validated {

727

/** Validation groups to apply */

728

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

729

}

730

```

731

732

**Usage Examples:**

733

734

```java

735

// Entity with validation annotations

736

public class User {

737

@NotNull(message = "Name is required")

738

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

739

private String name;

740

741

@Email(message = "Email should be valid")

742

@NotBlank(message = "Email is required")

743

private String email;

744

745

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

746

@Max(value = 100, message = "Age should not exceed 100")

747

private Integer age;

748

749

// getters and setters

750

}

751

752

@RestController

753

public class UserController {

754

755

@PostMapping("/users")

756

public ResponseEntity<User> createUser(@Valid @RequestBody User user) {

757

User createdUser = userService.create(user);

758

return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);

759

}

760

761

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

762

public User updateUser(

763

@PathVariable Long id,

764

@Valid @RequestBody User user,

765

BindingResult bindingResult) {

766

767

if (bindingResult.hasErrors()) {

768

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

769

}

770

771

return userService.update(id, user);

772

}

773

774

// Validation with groups

775

interface CreateValidation {}

776

interface UpdateValidation {}

777

778

@PostMapping("/users-grouped")

779

public User createUserWithGroups(@Validated(CreateValidation.class) @RequestBody User user) {

780

return userService.create(user);

781

}

782

}

783

784

// Custom validation exception handler

785

@ControllerAdvice

786

public class ValidationExceptionHandler {

787

788

@ExceptionHandler(MethodArgumentNotValidException.class)

789

@ResponseStatus(HttpStatus.BAD_REQUEST)

790

public Map<String, Object> handleValidationExceptions(MethodArgumentNotValidException ex) {

791

Map<String, Object> errors = new HashMap<>();

792

ex.getBindingResult().getAllErrors().forEach((error) -> {

793

String fieldName = ((FieldError) error).getField();

794

String errorMessage = error.getDefaultMessage();

795

errors.put(fieldName, errorMessage);

796

});

797

return Map.of("errors", errors, "message", "Validation failed");

798

}

799

}

800

```

801

802

### Content Negotiation

803

804

Support for content negotiation and media type handling.

805

806

```java { .api }

807

/**

808

* Annotation to specify consumable media types

809

*/

810

// Part of @RequestMapping and its variants

811

String[] consumes() default {};

812

813

/**

814

* Annotation to specify producible media types

815

*/

816

// Part of @RequestMapping and its variants

817

String[] produces() default {};

818

```

819

820

**Usage Examples:**

821

822

```java

823

@RestController

824

@RequestMapping("/api/content")

825

public class ContentController {

826

827

@GetMapping(value = "/users/{id}", produces = {

828

MediaType.APPLICATION_JSON_VALUE,

829

MediaType.APPLICATION_XML_VALUE

830

})

831

public User getUser(@PathVariable Long id) {

832

return userService.findById(id); // Content type negotiated by Accept header

833

}

834

835

@PostMapping(

836

value = "/users",

837

consumes = MediaType.APPLICATION_JSON_VALUE,

838

produces = MediaType.APPLICATION_JSON_VALUE

839

)

840

public ResponseEntity<User> createUser(@RequestBody User user) {

841

User created = userService.create(user);

842

return ResponseEntity.status(HttpStatus.CREATED).body(created);

843

}

844

845

@PostMapping(

846

value = "/users/bulk",

847

consumes = {MediaType.APPLICATION_JSON_VALUE, "application/vnd.api+json"},

848

produces = MediaType.APPLICATION_JSON_VALUE

849

)

850

public List<User> createUsers(@RequestBody List<User> users) {

851

return userService.createAll(users);

852

}

853

}

854

```