Handling Request and Response

1. Using @RequestBody for JSON Deserialization

Aspect Detail
Default converter MappingJackson2HttpMessageConverter
Records Supported natively (Java 17+)
Validation Combine with @Valid
Required @RequestBody(required=false) for optional

2. Using @ResponseBody for JSON Serialization

Example: @ResponseBody on @Controller method

@Controller
public class ApiController {
  @GetMapping("/api/me")
  @ResponseBody
  public UserDto me(Principal p) { return service.byEmail(p.getName()); }
}
Note: Implicit on every method when class is annotated with @RestController.

3. Customizing Jackson ObjectMapper Configuration

Property Effect
spring.jackson.serialization.indent_output Pretty-print
spring.jackson.serialization.write_dates_as_timestamps ISO vs epoch
spring.jackson.deserialization.fail_on_unknown_properties Strict mode
spring.jackson.property-naming-strategy SNAKE_CASE, KEBAB_CASE
spring.jackson.default-property-inclusion NON_NULL, NON_EMPTY

Example: Configure ObjectMapper with JavaTimeModule

@Bean
Jackson2ObjectMapperBuilderCustomizer jackson() {
  return b -> b.modules(new JavaTimeModule())
               .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}

4. Handling Date and Time Formats (@JsonFormat)

Example: Format date-time field as ISO string

public record EventDto(
  String name,
  @JsonFormat(shape=Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ssXXX")
  OffsetDateTime startsAt
) {}
Attribute Use
shape STRING, NUMBER, OBJECT
pattern SimpleDateFormat / DateTimeFormatter pattern
timezone e.g. UTC
locale BCP-47 tag

5. Ignoring Null Fields (@JsonInclude)

Include Strategy Behavior
ALWAYS Default
NON_NULL Skip nulls
NON_EMPTY Skip null + empty collections/strings
NON_DEFAULT Skip default values

6. Using Custom Serializers and Deserializers

Example: Custom serializer for value type

public class MoneySerializer extends JsonSerializer<Money> {
  @Override public void serialize(Money m, JsonGenerator g, SerializerProvider sp) throws IOException {
    g.writeString(m.amount() + " " + m.currency());
  }
}

@JsonSerialize(using = MoneySerializer.class)
public record Money(BigDecimal amount, String currency) {}

7. Working with Multipart File Uploads (MultipartFile)

Example: Multipart file upload with path traversal guard

@PostMapping(value="/upload", consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> upload(@RequestPart("file") MultipartFile file,
                                     @RequestPart("meta") MetaDto meta) throws IOException {
  Path dest = Path.of("/data", UUID.randomUUID() + "-" + file.getOriginalFilename());
  file.transferTo(dest);
  return ResponseEntity.ok(dest.toString());
}
Method Returns
getOriginalFilename() Client-provided name
getContentType() MIME type
getSize() Bytes
getInputStream() Streaming read
transferTo(File/Path) Save to disk

8. Configuring Max File Size

Example: Multipart upload size limits

spring:
  servlet:
    multipart:
      max-file-size: 25MB
      max-request-size: 100MB
      file-size-threshold: 2KB
      location: /tmp/uploads
Property Default
max-file-size 1MB
max-request-size 10MB
enabled true

9. Handling Form Data (@ModelAttribute)

Example: Form binding with validation

@PostMapping(value="/login", consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String login(@ModelAttribute @Valid LoginForm form, BindingResult br) {
  if (br.hasErrors()) return "login";
  // …
  return "redirect:/home";
}

public record LoginForm(@NotBlank String username, @NotBlank String password) {}

10. Using HttpServletRequest and HttpServletResponse

API Use
request.getRemoteAddr() Client IP (behind proxy: use X-Forwarded-For)
request.getHeader("…") Read header
response.setStatus(int) Direct status set
response.addCookie(...) Set cookie
Warning: Prefer abstractions (@RequestHeader, ResponseEntity) over raw servlet API.

11. Using HttpEntity for Request/Response Handling

Example: Echo request body with custom header

@PostMapping("/echo")
public HttpEntity<Map<String,Object>> echo(HttpEntity<String> req) {
  HttpHeaders headers = new HttpHeaders();
  headers.add("X-Length", String.valueOf(req.getBody().length()));
  return new HttpEntity<>(Map.of("body", req.getBody()), headers);
}
Type Description
HttpEntity<T> Body + headers (no status)
RequestEntity<T> Adds method + URL
ResponseEntity<T> HttpEntity + status