Class GlobalResponseWrapper

java.lang.Object
io.github.og4dev.advice.GlobalResponseWrapper
All Implemented Interfaces:
org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<Object>

@RestControllerAdvice @NullMarked public class GlobalResponseWrapper extends Object implements org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<Object>
Global response interceptor that automatically wraps REST controller outputs into the standardized ApiResponse format.

This wrapper is conditionally activated only for controllers or specific methods annotated with the @AutoResponse annotation. It provides a seamless developer experience by eliminating the need to manually return ResponseEntity<ApiResponse<T>> from every controller method.

Core Functionalities:

  • Automatic Encapsulation: Intercepts raw DTOs, Lists, or primitive responses and packages them into the content field of an ApiResponse.
  • Status Code Preservation: Dynamically reads the current HTTP status of the response (e.g., set via @ResponseStatus(HttpStatus.CREATED)) and ensures it is accurately reflected in the final ApiResponse.
  • String Payload Compatibility: Safely intercepts raw String returns and manually serializes them to prevent ClassCastException when Spring utilizes the StringHttpMessageConverter.
  • Safety Mechanisms: Intelligently skips wrapping if the response is already formatted to prevent double-wrapping errors or interference with standard error handling protocols.
Since:
1.4.0
Version:
1.4.0
Author:
Pasindu OG
See Also:
  • Constructor Summary

    Constructors
    Constructor
    Description
    GlobalResponseWrapper(tools.jackson.databind.ObjectMapper objectMapper)
    Constructs a new GlobalResponseWrapper with the provided ObjectMapper.
  • Method Summary

    Modifier and Type
    Method
    Description
    @Nullable Object
    beforeBodyWrite(@Nullable Object body, org.springframework.core.MethodParameter returnType, org.springframework.http.MediaType selectedContentType, Class<? extends org.springframework.http.converter.HttpMessageConverter<?>> selectedConverterType, org.springframework.http.server.ServerHttpRequest request, org.springframework.http.server.ServerHttpResponse response)
    Intercepts the response body before it is written to the output stream and encapsulates it within an ApiResponse.
    boolean
    supports(org.springframework.core.MethodParameter returnType, Class<? extends org.springframework.http.converter.HttpMessageConverter<?>> converterType)
    Determines whether the current response should be intercepted and wrapped.

    Methods inherited from class java.lang.Object

    equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice

    determineWriteHints
  • Constructor Details

    • GlobalResponseWrapper

      public GlobalResponseWrapper(tools.jackson.databind.ObjectMapper objectMapper)
      Constructs a new GlobalResponseWrapper with the provided ObjectMapper.
      Parameters:
      objectMapper - The Jackson object mapper used for explicit string serialization.
  • Method Details

    • supports

      @NullMarked public boolean supports(org.springframework.core.MethodParameter returnType, Class<? extends org.springframework.http.converter.HttpMessageConverter<?>> converterType)
      Determines whether the current response should be intercepted and wrapped.

      This method evaluates two main conditions before allowing the response to be wrapped:

      1. Annotation Presence: The target controller class or the specific handler method must be annotated with AutoResponse.
      2. Type Exclusion: The return type must not be one of the explicitly excluded types.

      To guarantee application stability and adherence to standard HTTP protocols, this method specifically excludes the following return types from being wrapped:

      • ApiResponse - Prevents recursive double-wrapping (e.g., ApiResponse<ApiResponse<T>>).
      • ResponseEntity - Skips manual responses to respect developer's explicit configurations.
      • ProblemDetail - Excludes RFC 9457 error responses generated by exception handlers.

      Note: Unlike standard wrappers, raw String payloads are supported and handled appropriately during the write phase.

      Specified by:
      supports in interface org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<Object>
      Parameters:
      returnType - The return type of the controller method.
      converterType - The selected HTTP message converter.
      Returns:
      true if annotated with @AutoResponse and not an excluded type; false otherwise.
    • beforeBodyWrite

      public @Nullable Object beforeBodyWrite(@Nullable Object body, org.springframework.core.MethodParameter returnType, org.springframework.http.MediaType selectedContentType, Class<? extends org.springframework.http.converter.HttpMessageConverter<?>> selectedConverterType, org.springframework.http.server.ServerHttpRequest request, org.springframework.http.server.ServerHttpResponse response)
      Intercepts the response body before it is written to the output stream and encapsulates it within an ApiResponse.

      This method extracts the actual HTTP status code set on the current response (defaulting to 200 OK). Based on whether the status code represents a success (2xx) or another state, it dynamically assigns an appropriate message ("Success" or "Processed") to the API response.

      Special String Handling: If the intercepted payload is a raw String, it is explicitly serialized to a JSON string using the configured ObjectMapper, and the response Content-Type is strictly set to application/json. This prevents standard message converter conflicts.

      Specified by:
      beforeBodyWrite in interface org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<Object>
      Parameters:
      body - The raw object returned by the controller method.
      returnType - The return type of the controller method.
      selectedContentType - The selected content type for the response.
      selectedConverterType - The selected HTTP message converter.
      request - The current server HTTP request.
      response - The current server HTTP response.
      Returns:
      The newly wrapped ApiResponse object ready to be serialized, or a pre-serialized JSON String if the original payload was a raw string.