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
```