ObjectMapper와 HttpMessageConverter: 스프링 직렬화 이해와 Security Filter에서 처리

2026. 6. 6. 14:43·🍃SpringBoot

Spring Boot로 REST API를 개발하다 보면 다음과 같은 코드를 매우 자주 작성한다.

@PostMapping("/login")
public LoginResponse login(@RequestBody LoginRequest request) {
    return authService.login(request);
}

 

개발자는 DTO만 주고받는데, 실제로는 다음과 같은 작업이 자동으로 일어나고 있다.

  • JSON → Java 객체 변환
  • Java 객체 → JSON 변환
  • HTTP Body 읽기
  • HTTP Response 쓰기

이번 글에서는 Spring Boot에서 JSON 직렬화가 어떻게 동작하는지, 그리고 ObjectMapper와 MappingJackson2HttpMessageConverter가 각각 어떤 역할을 담당하는지 정리해본다.

1. JSON Mapper란?

JSON Mapper는 JSON 문자열과 Java 객체 사이의 변환을 담당하는 컴포넌트이다. 대표적으로 Jackson 라이브러리의 ObjectMapper가 가장 널리 사용된다. ObjectMapper는 크게 두 가지 기능을 제공한다.

1) 직렬화 (Serialization)

Java 객체를 JSON 문자열로 변환한다.

String json = objectMapper.writeValueAsString(member);

변환 결과

{
  "id": 1,
  "email": "test@test.com"
}

2) 역직렬화 (Deserialization)

JSON 문자열을 Java 객체로 변환한다.

Member member = objectMapper.readValue(json, Member.class);

변환 전

{
  "id": 1,
  "email": "test@test.com"
}

변환 후

Member{id=1, email='test@test.com'}

2. 직렬화가 필요한 이유

Java 객체는 JVM 메모리 안에만 존재한다. 예를 들어 다음 객체는 메모리에만 존재할 뿐이다.

Member member = new Member(1L, "test@test.com");

이 상태로는

  • 네트워크 전송 불가
  • 파일 저장 불가
  • Redis 저장 불가
  • Kafka 전송 불가

따라서 저장하거나 전송 가능한 형태로 변환해야 한다.

{
  "id": 1,
  "email": "test@test.com"
}

이 과정을 직렬화(Serialization)라고 한다. 반대로 JSON을 객체로 복원하는 과정을 역직렬화(Deserialization)라고 한다.

3. 실무에서 직렬화가 사용되는 곳

1) Redis 저장

redisTemplate.opsForValue().set("member:1", member);

실제로는 다음과 같이 JSON 문자열 형태로 저장된다.

{
  "id": 1,
  "email": "test@test.com"
}

 

2) Kafka / RabbitMQ 메시지 전송

회원가입 이벤트를 예로 들어보자.

MemberCreatedEvent event = new MemberCreatedEvent(...);

이 객체를 그대로 브로커에 전송할 수는 없다. 따라서 다음 과정을 거친다.

  1. 회원가입이 완료되어 MemberCreatedEvent라는 Java 객체를 생성
  2. 현재 Producer 서버의 메모리 안에 저장된 객체를 직렬화 수행해서 JSON 문자열로 변환
  3. 브로커 전송(Kafka, RabbitMQ)
  4. Consumer 서버가 큐에서 JSON 텍스트를 객체 혹은 딕셔너리로 역직렬화하여 비즈니스 로직을 처리

 

3) 파일 저장

objectMapper.writeValue(
    new File("member.json"),
    member
);

결과

{
  "id": 1,
  "email": "test@test.com"
}

 

4) 스프링 예시

개발자는 DTO만 신경 쓰면 된다.

1. 요청(Request)

  • 사용자가 아이디, 비밀번호를 입력하고 로그인 버튼을 누르면, 브라우저는 HTTP Body 안에 JSON 문자열을 담아서 Spring 서버로 로그인을 요청
  • Controller에서 `@RequestBody` 만나면, 받은 JSON 텍스트를 LoginRequest DTO로 변환

2. 서비스 처리

  • DTO 덕분에 request.getEmail() 코드처럼 편리하게 비즈니스 로직을 처리

3. 응답(Response)

  • LoginResponse DTO를 반환
  • Controler에서 `@ResponseBody` 또는 `@RestController` 가 붙어 있으면, Spring에서 해당 객체를 JSON 문자열로 변환

4. Spring MVC에서는 누가 JSON 변환을 수행할까?

Spring MVC에서는 개발자가 직접 ObjectMapper를 호출하지 않는 경우가 많다.

@PostMapping("/login")
public LoginResponse login(
        @RequestBody LoginRequest request
) {
    return authService.login(request);
}

하지만 내부적으로는 여전히 JSON 변환이 일어나고 있다. 그 역할을 담당하는 것이 바로 MappingJackson2HttpMessageConverter 이다.

5. ObjectMapper와 HttpMessageConverter의 관계

많은 개발자가 두 컴포넌트를 헷갈려한다. 둘의 역할은 명확하게 다르다.

 

ObjectMapper: Jackson 라이브러리가 제공하는 JSON 변환기

objectMapper.readValue(...)
objectMapper.writeValue(...)

실제 직렬화/역직렬화를 수행한다.

 

MappingJackson2HttpMessageConverter: Spring MVC가 제공하는 HTTP 메시지 변환기

  • 요청 Body 읽기
  • 응답 Body 쓰기
  • 적절한 시점에 ObjectMapper 호출

정리하자면,

  • ObjectMapper = 실제 변환 담당
  • HttpMessageConverter = 변환 작업을 관리하는 관리자

라고 생각하면 된다. 굳이 왜 MappingJackson2HttpMessageConverter 를 사용할까? 만약, 컨버터가 없다고 생각해보자. 따라서 Spring MVC가 자동 변환을 지원하지 않는다면 매번 다음과 같은 코드를 작성해야 한다.

@PostMapping("/login")
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
    // 1. HTTP 요청 바디에서 JSON 텍스트 직접 읽어오기
    String jsonBody = request.getReader().lines().collect(Collectors.joining());
    
    // 2. ObjectMapper로 개발자가 직접 역직렬화 코드 호출하기
    LoginRequest loginRequest = objectMapper.readValue(jsonBody, LoginRequest.class);
    
    // 3. 비즈니스 로직 처리
    LoginResponse loginResponse = authService.login(loginRequest);
    
    // 4. 응답 설정 및 ObjectMapper로 직접 직렬화해서 HTTP 바디에 쓰기
    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    String jsonResponse = objectMapper.writeValueAsString(loginResponse);
    response.getWriter().write(jsonResponse);
}

비즈니스 로직보다 JSON 처리 코드가 더 많아진다.
실제로는 HttpMessageConverter가 다음 과정을 자동으로 수행한다.

HTTP Request(JSON)
        ↓
HttpMessageConverter
        ↓
ObjectMapper
        ↓
LoginRequest DTO
        ↓
Controller
        ↓
LoginResponse DTO
        ↓
ObjectMapper
        ↓
HttpMessageConverter
        ↓
HTTP Response(JSON)

덕분에 개발자는 DTO만 신경쓰면 된다.

@PostMapping("/login")
public LoginResponse login(@RequestBody LoginRequest loginRequest) {
    // 1. @RequestBody를 보고 컨버터가 알아서 JSON -> 객체로 변환해줌 (컨트롤러 진입 전 완료)
    
    // 2. 개발자는 오직 비즈니스 로직에만 집중!
    return authService.login(loginRequest);
    
    // 3. 반환된 객체를 보고 컨버터가 알아서 객체 -> JSON으로 변환해 응답 보냄
}

6. 내가 격은 실무 예외 상황

그런데 왜 Security Filter에서는 ObjectMapper를 직접 사용할까? 실무에서 예외적인 상황이 하나 있다.  

예를 들어 인증 실패 응답을 처리하는 컴포넌트를 보자.

jsonMapper.writeValue(
    response.getWriter(),
    errorResponse
);

왜 Spring MVC처럼 객체만 반환하지 않을까? 그 이유는 바로, Spring Security Filter는 MVC보다 먼저 실행된다.

스프링을 공부한 모든 사람이라면 알고 있을 것이다. Spring MVC의 JSON 자동 변환 기능은 DispatcherServlet 이후에 동작한다. 하지만 인증 실패(401), 권한 부족(403)은 대부분 Filter 단계에서 발생한다.

따라서 Controller에 도달하기 전에 응답을 내려야 한다. 이 제약 조건으로 인해 다음과 같은 상태가 된다.

  • @ResponseBody 사용 불가
  • HttpMessageConverter 사용 불가
  • Spring MVC 자동 직렬화 사용 불가

그래서 직접 JSON 응답을 만들어야 한다. Filter 영역에서는 서블릿 API를 직접 다뤄야 한다.

핵심 차이점은 바로 다음과 같이 정리할 수 있다.

  • Controller 영역 → HttpMessageConverter 자동 사용
  • Filter 영역 → ObjectMapper(JsonMapper) 직접 사용

마무리

정리하면 다음과 같다.

  • ObjectMapper는 JSON 변환을 실제 수행하는 Jackson의 핵심 클래스
  • MappingJackson2HttpMessageConverter는 Spring MVC에서 ObjectMapper를 호출하는 관리자 역할
  • @RequestBody, @ResponseBody는 내부적으로 HttpMessageConverter를 사용
  • Spring Security Filter는 MVC 이전 단계에서 실행되므로 자동 변환기를 사용할 수 없음
  • 따라서 Filter에서는 JsonMapper(ObjectMapper)를 직접 사용하여 JSON 응답을 작성만 가능

평소에는 보이지 않지만, Spring Boot의 JSON 처리 대부분은 ObjectMapper와 HttpMessageConverter의 협업으로 동작하고 있다.

'🍃SpringBoot' 카테고리의 다른 글

JWT[2/3]: SpringBoot에서 JWT 인증 구조와 정책(Spring Security)  (1) 2026.06.07
JWT[1/3]: JWT 이해(이론)  (0) 2026.06.06
JUnit 5: JUnit 이론  (1) 2026.01.25
Spring Boot: Spring Data JPA With Auditing  (0) 2025.10.23
Spring Boot: Gradle(+ 멀티 모듈 고도화 전략 + 의존성 버전 관리)  (0) 2025.10.22
'🍃SpringBoot' 카테고리의 다른 글
  • JWT[2/3]: SpringBoot에서 JWT 인증 구조와 정책(Spring Security)
  • JWT[1/3]: JWT 이해(이론)
  • JUnit 5: JUnit 이론
  • Spring Boot: Spring Data JPA With Auditing
limdaeil
limdaeil
limdaeil 님의 블로그 입니다.
  • limdaeil
    limdaeil
    limdaeil
  • 전체
    오늘
    어제
    • 분류 전체보기 (50)
      • 💭Retrospective (16)
      • 🐬MySQL (1)
      • 🐍Python (5)
      • 🍃SpringBoot (14)
      • ♾️Devops (1)
      • 🌎Network (2)
      • 📚Read & 👨‍🏫Course (10)
      • 🥕Fortinet (0)
      • Programmers (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    mcp
    한빛미디어
    맛있는 디자인 피그마 With AI
    클린 아키텍처 with 파이썬
    한빛아카데미
    레이스 컨디션
    이것이 스프링 AI다
    distributed lock
    Concurrency
    나는리뷰어다
    redis
    회고
    spring boot
    Python
    HttpMessageConverter
    서평단
    jwt
    MySQL
    gradle
    optimistic rock
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
limdaeil
ObjectMapper와 HttpMessageConverter: 스프링 직렬화 이해와 Security Filter에서 처리
상단으로

티스토리툴바