Posts Spring Boot에서 ObjectMapper 최적화 - JSON 파싱 에러 해결 및 성능 개선
Post
Cancel

Spring Boot에서 ObjectMapper 최적화 - JSON 파싱 에러 해결 및 성능 개선

1. 문제 정의: JSON 구조 변화와 400 Bad Request 발생# Spring Boot에서 ObjectMapper 최적화: JSON 파싱 오류 해결 및 역할별 구성 전략

1. 문제 정의: JSON 구조 변화와 400 Bad Request 발생

Spring Boot의 ObjectMapper는 JSON 데이터를 DTO로 변환하는 중요한 역할을 한다. 그러나 최근 API 개발 과정에서 다음과 같은 문제가 발생했다.

📌 최근 경험한 주요 이슈:

  • DTO에 정의되지 않은 필드가 포함된 요청을 받을 경우 400 Bad Request 발생
  • ObjectMapper 설정이 변경되면서 JSON 구조가 예상과 다르게 변형됨 (예뻤던 JSON이 클래스로…)
  • 상황에 따라 적절한 ObjectMapper가 적용되지 않아 JSON 직렬화/역직렬화가 혼란스러움

🚀 이슈 발생 배경:

  • Spring Boot의 기본 설정에서는 DTO에 없는 필드가 포함된 JSON 요청을 허용하지 않음.
  • ObjectMapper의 activateDefaultTyping 설정이 JSON 구조를 예상과 다르게 변형함.
  • 역할에 따라 ObjectMapper가 다르게 동작해야 하지만, 전역 설정으로 인해 동일한 방식으로 적용됨.

👉 결론: ObjectMapper 설정을 최적화하여 유연한 JSON 처리, DTO 구조 유지, 역할별 ObjectMapper 적용이 필요했다.

strong-dev

공통 서비스를 변경할 때는.. 주요 서비스가 아녀도 한 번쯤 확인해주라…

2. 원인 분석: ObjectMapper의 기본 동작과 예상치 못한 영향

🔎 400 Bad Request 발생 원인

Jackson의 기본 설정에서는 DTO에 정의되지 않은 필드가 포함되면 예외를 발생시킨다.
이유는 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 설정이 기본적으로 true이기 때문.

📌 ObjectMapper의 기본 동작 1️⃣ JSON 요청을 DTO로 변환할 때, DTO에 없는 필드가 포함되면 예외 발생
2️⃣ Spring Boot의 기본 ObjectMapper 설정이 FAIL_ON_UNKNOWN_PROPERTIES = true이므로 엄격한 검증 수행
3️⃣ API 확장 시, 새로운 필드가 추가되면 DTO 변경이 필요 → 유지보수 부담 증가

🔎 activateDefaultTyping이 JSON 구조를 변형한 이유

기존 설정에서 activateDefaultTyping(DefaultTyping.EVERYTHING)을 활성화했을 때, JSON 데이터가 예상과 다르게 변경되었다.

  • 원인: Jackson이 다형성 지원을 위해 JSON 객체에 추가적인 타입 정보를 포함시킴.
  • 결과: JSON이 배열 또는 클래스로 변환되어, 클라이언트가 예상한 포맷과 다르게 출력됨.

📌 예상과 다르게 변형된 JSON 예시
🚨 기존 JSON (기대했던 모습)

1
2
3
4
{
    "name": "John",
    "email": "john.doe@example.com"
}

🚨 activateDefaultTyping 적용 후 (예상치 못한 변화)

1
2
3
4
["com.bcg.sto.issue.backofficeapi.member.dto.AdminInvestInformDto$InvestQualSearchOption", {
    "name": "John",
    "email": "john.doe@example.com"
}]

→ JSON 구조가 바뀌면서 API 응답이 깨짐 😭

📌 이슈 요약:

  • DTO 필드와 JSON 불일치로 인한 400 Bad Request 발생
  • activateDefaultTyping으로 인해 JSON 구조가 배열/클래스로 변환됨
  • API 요청마다 적절한 ObjectMapper를 적용할 필요성 증가

3. 해결 방법: ObjectMapper 설정 최적화 및 역할별 구성

🚀 핵심 해결 전략:

  • DTO에 없는 필드를 무시하도록 설정하여 API 요청의 유연성을 높임
  • activateDefaultTyping을 제거하고, JSON 구조를 변형시키지 않도록 설정
  • 웹 요청/내부 데이터 직렬화 등 역할에 따라 다른 ObjectMapper를 사용하도록 구성

🔹 문제 해결을 위한 새로운 ObjectMapper 설정

1
2
3
4
5
6
fun webObjectMapper(): ObjectMapper {
    return ObjectMapper()
        .registerModule(JavaTimeModule()) // Java 8 Date/Time 지원
        .registerModule(kotlinModule { enable(KotlinFeature.SingletonSupport) }) // Kotlin 지원 강화
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) // DTO에 없는 필드 무시
}

📌 변경된 사항:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES = falseDTO에 없는 필드가 있어도 예외 발생 안 함
activateDefaultTyping 제거 → JSON 구조가 예상대로 유지됨
KotlinFeature.SingletonSupport 활성화 → Kotlin 객체 직렬화/역직렬화 안정성 강화

🔹 역할별 ObjectMapper 구성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Bean
@Primary
fun defaultObjectMapper(): ObjectMapper {
    return ObjectMapper()
        .registerModule(JavaTimeModule())
        .registerKotlinModule()
}

@Bean
@Qualifier("webObjectMapper")
fun webObjectMapper(): ObjectMapper {
    return ObjectMapper()
        .registerModule(JavaTimeModule())
        .registerModule(kotlinModule { enable(KotlinFeature.SingletonSupport) })
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
}

📌 왜 역할별로 ObjectMapper를 분리했을까?
1️⃣ 웹 요청 처리용 (webObjectMapper)

  • DTO 필드에 없는 JSON 데이터가 포함되어도 API가 정상적으로 동작하도록 유연성 확보
  • Kotlin 싱글톤 지원 활성화

2️⃣ 내부 데이터 변환용 (defaultObjectMapper)

  • 보다 엄격한 데이터 직렬화/역직렬화 적용 가능
  • JSON 데이터의 무결성을 유지하면서도, 일부 DTO에서는 유연성을 확보

💡 결과: API 요청별로 적절한 ObjectMapper가 적용되어 예상치 못한 JSON 변환을 방지하고, DTO 확장성을 확보할 수 있게 됨.

4. 기술적 인사이트: ObjectMapper의 유연성과 안정성 확보

🚀 Spring Boot에서 JSON 처리를 최적화하는 핵심 개념 정리

DTO와 JSON 구조가 불일치할 때 예외 발생을 방지하려면?

  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES = false 설정으로 DTO에 없는 필드 무시
  • API가 확장될 때 유지보수 비용을 최소화할 수 있음

activateDefaultTyping을 신중하게 사용해야 하는 이유

  • JSON 객체의 구조를 변경시키므로, 예상치 못한 API 응답 문제 발생 가능
  • 다형성을 고려해야 하는 경우 @JsonTypeInfo를 DTO 개별 필드에 적용하는 것이 더 안전함

API 요청별로 다른 ObjectMapper를 사용해야 하는 이유

  • 웹 API에서는 DTO의 유연성을 높이고, 내부 데이터 직렬화는 더 엄격하게 관리 가능
  • ObjectMapper를 @Qualifier로 분리하여 역할에 맞는 설정을 적용할 수 있음

5. 결론: ObjectMapper 최적화로 API 안정성 및 확장성 확보

이슈 해결 후 효과

  • JSON 요청에서 DTO에 없는 필드가 있어도 API가 정상적으로 동작
  • activateDefaultTyping 제거로 JSON 구조가 깨지지 않음
  • 역할별 ObjectMapper 적용으로 유연성과 데이터 무결성을 동시에 확보

📌 Spring Boot 기반 API 개발 시 고려할 점:
1️⃣ DTO의 엄격한 검증과 API 확장성을 어떻게 균형 맞출 것인가?
2️⃣ JSON 변환 로직이 API의 일관성을 해치지 않도록 설정을 신중하게 구성하자
3️⃣ 역할별 ObjectMapper 설정을 분리하여 유지보수성과 확장성을 극대화하자

🚀 이 글이 ObjectMapper 설정을 고민하는 모든 개발자에게 도움이 되길 바랍니다!

This post is licensed under CC BY 4.0 by the author.

Spring 6 HTTP Interface 도입기

Kubernetes Ingress 413 오류 해결 과정과 최적화 전략

Comments powered by Disqus.