HttpMessageConverter

tokkaiiii·2025년 4월 29일

spring-mvc

목록 보기
11/27

ServletInvocableHandlerMethod 클래스의 핵심요소

  • 요청처리: 매개변수를 처리하는 ArgumentResolver
  • 응답처리: ReturnValueHandler

부모 클래스와 달리 응답처리 기능이 존재한다. 즉, 웹전용 클래스이다

@RequestBody/@ResponseBody

@RequestBody 로 파라미터를 찾을시 ArgumentResolver 구현체로 RequestResponseBodyMethodProcessor를 사용한다

(1) 파라미터가 RequestResponseBodyMethodProcessor 지원을 받을 수 있는지 확인

// ReqeustBody annotation이 있는지
  public boolean supportsParameter(MethodParameter parameter) {
   return parameter.hasParameterAnnotation(RequestBody.class);
 }

(2) HttpMessageConverter를 통해 읽는다

HttpMessageConverter 또한 여러 구현체가 있다

// 요청본문을 읽을 수 있는지 판단한다
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

(3) 요청 본문을 읽고 파라미터를 반환한다

 @Nullable
  protected Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
    ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
    Object arg = this.readWithMessageConverters(inputMessage, parameter, paramType);
    if (arg == null && this.checkRequired(parameter)) {
      throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage);
    } else {
      return arg;
    }
  }

(4) 응답은 returnValueHandlers를 찾는다

 this.returnValueHandlers.handleReturnValue

(5) @ResponseBody 존재 확인

 public boolean supportsReturnType(MethodParameter returnType) {
    return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
  }

hnadleReturnValue 실행

 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
    if (returnValue instanceof ProblemDetail detail) {
      outputMessage.setStatusCode(HttpStatusCode.valueOf(detail.getStatus()));
      if (detail.getInstance() == null) {
        URI path = URI.create(inputMessage.getServletRequest().getRequestURI());
        detail.setInstance(path);
      }

      this.invokeErrorResponseInterceptors(detail, (ErrorResponse)null);
    }

    this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
  }
}

writeWithMessageConverters 쓰기작업하면서 messageConverter 사용

 acceptableTypes = this.getAcceptableMediaTypes(request);

acceptable 한지 확인
일련의 과정 진행 후 하나의 컨버터가 선택된다
쓰기작업

 switch (converterTypeToUse) {
             case BASE -> converter.write(body, selectedMediaType, outputMessage);
             case GENERIC -> ((GenericHttpMessageConverter)converter).write(body, targetType, selectedMediaType, outputMessage);
             case SMART -> ((SmartHttpMessageConverter)converter).write(body, targetResolvableType, selectedMediaType, outputMessage, (Map)null);
           }
profile
풀스택 자바 개발자입니다

0개의 댓글