RequestBodyArgumentResolver.java

package sprout.mvc.argument.builtins;

import com.fasterxml.jackson.databind.ObjectMapper;
import sprout.beans.annotation.Component;
import sprout.mvc.annotation.RequestBody;
import sprout.mvc.argument.ArgumentResolver;
import sprout.mvc.exception.BadRequestException;
import sprout.mvc.http.HttpRequest;
import sprout.mvc.http.ResponseCode;

import java.lang.reflect.Parameter;
import java.util.Map;

@Component
public class RequestBodyArgumentResolver implements ArgumentResolver {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean supports(Parameter parameter) {
        return parameter.isAnnotationPresent(RequestBody.class);
    }

    @Override
    public Object resolve(Parameter parameter, HttpRequest<?> request, Map<String, String> pathVariables) throws Exception {
        // HttpRequest의 바디가 String 타입으로 넘어올 것을 예상
        String rawBody = (String) request.getBody();

        if (rawBody == null || rawBody.isBlank()) {
            // @RequestBody가 붙었지만 바디가 비어있는 경우, null을 반환하거나 예외를 던질 수 있음
            return null;
        }

        try {
            // String 타입의 rawBody를 직접 대상 타입으로 변환
            return objectMapper.readValue(rawBody.trim(), parameter.getType());
        } catch (Exception e) { // JsonProcessingException 등 ObjectMapper에서 발생할 수 있는 모든 예외 처리
            // BadRequestException을 던져 클라이언트에 400 Bad Request 응답
            throw new BadRequestException(
                    "Failed to parse request body as JSON or convert to '" + parameter.getType().getName() + "'. " +
                            "Check JSON format and target type. Cause: " + e.getMessage(), ResponseCode.BAD_REQUEST, e);
        }
    }
}