Spring Web module providing web application infrastructure including HTTP integration, servlet filters, Spring web MVC framework, and reactive web stack support
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.
Core annotations for mapping HTTP requests to controller methods and handling different HTTP operations.
/**
* Maps HTTP requests to handler methods of MVC and REST controllers
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@interface RequestMapping {
/** Request mapping name */
String name() default "";
/** URL patterns - primary mapping attribute */
String[] value() default {};
/** Alias for value() */
String[] path() default {};
/** HTTP request methods */
RequestMethod[] method() default {};
/** Request parameters conditions */
String[] params() default {};
/** Request header conditions */
String[] headers() default {};
/** Consumable media types */
String[] consumes() default {};
/** Producible media types */
String[] produces() default {};
}
/**
* HTTP methods enumeration
*/
enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
/**
* Composed annotation for HTTP GET requests
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
@interface GetMapping {
String name() default "";
String[] value() default {};
String[] path() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
/**
* Composed annotation for HTTP POST requests
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.POST)
@interface PostMapping {
String name() default "";
String[] value() default {};
String[] path() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
/**
* Composed annotation for HTTP PUT requests
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.PUT)
@interface PutMapping {
String name() default "";
String[] value() default {};
String[] path() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
/**
* Composed annotation for HTTP DELETE requests
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.DELETE)
@interface DeleteMapping {
String name() default "";
String[] value() default {};
String[] path() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
/**
* Composed annotation for HTTP PATCH requests
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.PATCH)
@interface PatchMapping {
String name() default "";
String[] value() default {};
String[] path() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}Usage Examples:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> createUser(@RequestBody User user) {
User created = userService.create(user);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@PutMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.update(id, user);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}Annotations for binding HTTP request data to method parameters with type conversion and validation.
/**
* Binds web request parameter to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface RequestParam {
/** Alias for name() */
String value() default "";
/** Parameter name to bind to */
String name() default "";
/** Whether parameter is required */
boolean required() default true;
/** Default value if parameter is not present */
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
/**
* Binds URI template variable to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface PathVariable {
/** Alias for name() */
String value() default "";
/** Path variable name to bind to */
String name() default "";
/** Whether path variable is required */
boolean required() default true;
}
/**
* Binds HTTP request body to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface RequestBody {
/** Whether body content is required */
boolean required() default true;
}
/**
* Binds request header to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface RequestHeader {
/** Alias for name() */
String value() default "";
/** Header name to bind to */
String name() default "";
/** Whether header is required */
boolean required() default true;
/** Default value if header is not present */
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
/**
* Binds cookie value to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface CookieValue {
/** Alias for name() */
String value() default "";
/** Cookie name to bind to */
String name() default "";
/** Whether cookie is required */
boolean required() default true;
/** Default value if cookie is not present */
String defaultValue() default ValueConstants.DEFAULT_NONE;
}
/**
* Binds request attribute to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface RequestAttribute {
/** Alias for name() */
String value() default "";
/** Attribute name to bind to */
String name() default "";
/** Whether attribute is required */
boolean required() default true;
}
/**
* Binds session attribute to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface SessionAttribute {
/** Alias for name() */
String value() default "";
/** Attribute name to bind to */
String name() default "";
/** Whether attribute is required */
boolean required() default true;
}
/**
* Binds matrix variables to method parameter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface MatrixVariable {
/** Alias for name() */
String value() default "";
/** Matrix variable name to bind to */
String name() default "";
/** Path segment to extract matrix variables from */
String pathVar() default ValueConstants.DEFAULT_NONE;
/** Whether matrix variable is required */
boolean required() default true;
/** Default value if matrix variable is not present */
String defaultValue() default ValueConstants.DEFAULT_NONE;
}Usage Examples:
@RestController
public class ExampleController {
@GetMapping("/users")
public List<User> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String search) {
return userService.findUsers(page, size, search);
}
@GetMapping("/users/{id}")
public User getUserById(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping("/users")
public User createUser(@RequestBody @Valid User user) {
return userService.create(user);
}
@GetMapping("/profile")
public User getProfile(
@RequestHeader("Authorization") String authHeader,
@CookieValue(value = "sessionId", required = false) String sessionId) {
return userService.getProfile(authHeader, sessionId);
}
@GetMapping("/cars/{model}/features;color={color};year={year}")
public Car getCar(
@PathVariable String model,
@MatrixVariable String color,
@MatrixVariable int year) {
return carService.findCar(model, color, year);
}
}Annotations for configuring response handling and serialization.
/**
* Indicates method return value should be bound to web response body
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ResponseBody {
// No attributes - marker annotation
}
/**
* Marks method or exception class with status code and reason
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ResponseStatus {
/** Alias for code() */
HttpStatus value() default HttpStatus.INTERNAL_SERVER_ERROR;
/** HTTP status code to return */
HttpStatus code() default HttpStatus.INTERNAL_SERVER_ERROR;
/** Reason phrase for the status */
String reason() default "";
}
/**
* Used to bind model attributes to session
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface SessionAttributes {
/** Alias for names() */
String[] value() default {};
/** Names of model attributes to store in session */
String[] names() default {};
/** Types of model attributes to store in session */
Class<?>[] types() default {};
}
/**
* Binds method parameter or return value to model attribute
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ModelAttribute {
/** Alias for name() */
String value() default "";
/** Name of model attribute */
String name() default "";
/** Whether parameter binding is required */
boolean binding() default true;
}Annotations for configuring controller classes and global behavior.
/**
* Specialization of @Component for controller classes
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@interface Controller {
/** Component name */
String value() default "";
}
/**
* Convenience annotation combining @Controller and @ResponseBody
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
@interface RestController {
/** Component name */
String value() default "";
}
/**
* Specialization of @Component for global controller configuration
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@interface ControllerAdvice {
/** Alias for basePackages() */
String[] value() default {};
/** Base packages to scan for controllers */
String[] basePackages() default {};
/** Base package classes for type-safe package specification */
Class<?>[] basePackageClasses() default {};
/** Controller types to assist */
Class<?>[] assignableTypes() default {};
/** Annotations that controllers must have */
Class<? extends Annotation>[] annotations() default {};
}
/**
* Convenience annotation combining @ControllerAdvice and @ResponseBody
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
@interface RestControllerAdvice {
/** Alias for basePackages() */
String[] value() default {};
/** Base packages to scan for controllers */
String[] basePackages() default {};
/** Base package classes for type-safe package specification */
Class<?>[] basePackageClasses() default {};
/** Controller types to assist */
Class<?>[] assignableTypes() default {};
/** Annotations that controllers must have */
Class<? extends Annotation>[] annotations() default {};
}Usage Examples:
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/health")
@ResponseStatus(HttpStatus.OK)
public Map<String, String> health() {
return Map.of("status", "UP", "timestamp", Instant.now().toString());
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleUserNotFound(UserNotFoundException ex) {
return new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
}
@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleValidation(ValidationException ex) {
return new ErrorResponse("VALIDATION_ERROR", ex.getMessage());
}
}Annotations for handling exceptions and errors in web controllers.
/**
* Marks method as exception handler for specific exception types
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ExceptionHandler {
/** Exception types handled by this method */
Class<? extends Throwable>[] value() default {};
}
/**
* Binds method parameter to exception and its cause
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ExceptionAttribute {
/** Exception attribute name */
String value() default "";
}Usage Examples:
@ControllerAdvice
public class ExceptionHandlerController {
@ExceptionHandler({UserNotFoundException.class, ProductNotFoundException.class})
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<ErrorResponse> handleNotFound(Exception ex) {
ErrorResponse error = new ErrorResponse("RESOURCE_NOT_FOUND", ex.getMessage());
return ResponseEntity.notFound().build();
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<ValidationErrorResponse> handleValidation(
MethodArgumentNotValidException ex) {
List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
ValidationErrorResponse error = new ValidationErrorResponse();
for (FieldError fieldError : fieldErrors) {
error.addError(fieldError.getField(), fieldError.getDefaultMessage());
}
return ResponseEntity.badRequest().body(error);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity<ErrorResponse> handleGeneral(Exception ex) {
ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
}Annotations for configuring CORS support in web controllers.
/**
* Marks class or method as accepting cross-origin requests
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface CrossOrigin {
/** Alias for origins() */
String[] value() default {};
/** Allowed origins for cross-origin requests */
String[] origins() default {};
/** Allowed origin patterns */
String[] originPatterns() default {};
/** Allowed request headers */
String[] allowedHeaders() default {};
/** Headers exposed to client */
String[] exposedHeaders() default {};
/** Allowed HTTP methods */
RequestMethod[] methods() default {};
/** Whether credentials are allowed */
boolean allowCredentials() default "";
/** Pre-flight cache duration in seconds */
long maxAge() default -1;
}Usage Examples:
@RestController
@CrossOrigin(origins = "https://example.com", maxAge = 3600)
public class ApiController {
@GetMapping("/public-data")
public List<Data> getPublicData() {
return dataService.getPublicData();
}
@PostMapping("/secure-endpoint")
@CrossOrigin(origins = "https://secure.example.com", allowCredentials = true)
public ResponseEntity<String> secureOperation(@RequestBody SecureRequest request) {
return ResponseEntity.ok("Operation completed");
}
}
@RestController
public class FileController {
@PostMapping("/upload")
@CrossOrigin(
origins = {"https://app.example.com", "https://admin.example.com"},
methods = {RequestMethod.POST, RequestMethod.OPTIONS},
allowedHeaders = {"Content-Type", "Authorization"},
exposedHeaders = {"Upload-Status"},
maxAge = 1800
)
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
// Handle file upload
return ResponseEntity.ok().header("Upload-Status", "SUCCESS").body("File uploaded");
}
}Core classes for web data binding, validation, and type conversion.
/**
* Special DataBinder for web request parameter binding
*/
class WebDataBinder extends DataBinder {
WebDataBinder(Object target);
WebDataBinder(Object target, String objectName);
/** Set prefix for field markers (e.g., "_fieldName" for checkboxes) */
void setFieldMarkerPrefix(String fieldMarkerPrefix);
/** Get field marker prefix */
String getFieldMarkerPrefix();
/** Set prefix for field defaults */
void setFieldDefaultPrefix(String fieldDefaultPrefix);
/** Get field default prefix */
String getFieldDefaultPrefix();
/** Bind parameters from web request */
void bind(ServletRequest request);
/** Bind multipart files */
void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, ServletRequest request);
/** Check for field markers indicating empty fields */
protected void checkFieldMarkers(MutablePropertyValues mpvs);
/** Check for field defaults */
protected void checkFieldDefaults(MutablePropertyValues mpvs);
/** Determine if empty string should be treated as null */
protected boolean isEmptyInputField(String field);
}
/**
* Exception thrown when data binding fails
*/
class BindException extends Exception implements BindingResult {
BindException(BindingResult bindingResult);
BindException(Object target, String objectName);
/** Get the binding result */
BindingResult getBindingResult();
}
/**
* Exception thrown when method argument binding/validation fails
*/
class MethodArgumentNotValidException extends BindException {
MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult);
/** Get the method parameter that failed validation */
MethodParameter getParameter();
}
/**
* Exception thrown when web exchange binding fails
*/
class WebExchangeBindException extends ResponseStatusException implements BindingResult {
WebExchangeBindException(MethodParameter parameter, BindingResult bindingResult);
/** Get the method parameter */
MethodParameter getMethodParameter();
/** Get the binding result */
BindingResult getBindingResult();
}Integration with Bean Validation (JSR-303/JSR-380) for request validation.
/**
* Marks parameter for validation
*/
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface Valid {
// Marker annotation for validation
}
/**
* JSR-303 validation groups
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface Validated {
/** Validation groups to apply */
Class<?>[] value() default {};
}Usage Examples:
// Entity with validation annotations
public class User {
@NotNull(message = "Name is required")
@Size(min = 2, max = 50, message = "Name must be between 2 and 50 characters")
private String name;
@Email(message = "Email should be valid")
@NotBlank(message = "Email is required")
private String email;
@Min(value = 18, message = "Age should be at least 18")
@Max(value = 100, message = "Age should not exceed 100")
private Integer age;
// getters and setters
}
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
User createdUser = userService.create(user);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
@PutMapping("/users/{id}")
public User updateUser(
@PathVariable Long id,
@Valid @RequestBody User user,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new ValidationException("Validation failed", bindingResult);
}
return userService.update(id, user);
}
// Validation with groups
interface CreateValidation {}
interface UpdateValidation {}
@PostMapping("/users-grouped")
public User createUserWithGroups(@Validated(CreateValidation.class) @RequestBody User user) {
return userService.create(user);
}
}
// Custom validation exception handler
@ControllerAdvice
public class ValidationExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, Object> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, Object> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return Map.of("errors", errors, "message", "Validation failed");
}
}Support for content negotiation and media type handling.
/**
* Annotation to specify consumable media types
*/
// Part of @RequestMapping and its variants
String[] consumes() default {};
/**
* Annotation to specify producible media types
*/
// Part of @RequestMapping and its variants
String[] produces() default {};Usage Examples:
@RestController
@RequestMapping("/api/content")
public class ContentController {
@GetMapping(value = "/users/{id}", produces = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE
})
public User getUser(@PathVariable Long id) {
return userService.findById(id); // Content type negotiated by Accept header
}
@PostMapping(
value = "/users",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<User> createUser(@RequestBody User user) {
User created = userService.create(user);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@PostMapping(
value = "/users/bulk",
consumes = {MediaType.APPLICATION_JSON_VALUE, "application/vnd.api+json"},
produces = MediaType.APPLICATION_JSON_VALUE
)
public List<User> createUsers(@RequestBody List<User> users) {
return userService.createAll(users);
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-web