Backend/Spring

Spring에서 Jackson 사용 시 snake_case 매핑 문제 해결하기

cojoop 2025. 7. 7. 10:16
 

API를 구현하고 테스트하는 중, 분명히 요청 JSON에 값이 들어있는데도 DTO의 필드 값이 null로 들어오는 이슈가 있었다. 

 

코드도 문제 없고, 필드명도 잘 맞췄다고 생각했는데, 알고 보니 클라이언트는 snake_case로 JSON을 보내고 있었고, 서버는 camelCase로 작성된 DTO로 값을 받도록 설계되어 있었던 것이 원인이었다.

 

이에 따라 이번 포스팅에서는 Jackson 라이브러리에서의 snake_case JSON 매핑 이슈와 그 해결 방법에 대해 정리해보려 한다.


💡 문제 상황

다음과 같은 요청 JSON이 클라이언트로부터 들어올 때,

{
  "user_id": "kim123",
  "user_name": "kim"
}

DTO는 일반적으로 자바 컨벤션을 따라 camelCase로 정의하고 있다.

public class UserDto {
    private String userId;
    private String userName;

    // getters, setters
}

이때, 별도 설정 없이 Jackson 라이브러리를 사용할 경우 위 JSON은 제대로 매핑되지 않고, userIduserName 필드는 null로 남게 된다.


🔎 원인 분석

Jackson은 기본적으로 camelCase 규칙에 따라 JSON과 Java 객체를 매핑한다.

따라서 JSON 필드가 snake_case로 들어오면 이를 Java 필드와 일치시키지 못하고 매핑 실패가 발생한다.


✅ 해결 방법

Jackson은 다양한 속성명 변환 전략(Naming Strategy) 을 제공한다.

snake_casecamelCase 자동 변환을 위해서는 아래 설정이 필요하다.

 

1. ObjectMapper에 NamingStrategy 설정

Spring에서는 Jackson의 ObjectMapper를 직접 설정하여 사용할 수 있다.

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

이 설정을 통해 user_id와 같은 필드가 DTO의 userId로 자동 변환되어 매핑된다.

 

 

2. 전역 설정

Jackson 설정을 전역 HTTP 요청/응답에 적용하려면, MappingJackson2HttpMessageConverterObjectMapper를 주입해야 한다.

@Bean
public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
    return new MappingJackson2HttpMessageConverter(objectMapper);
}

XML 설정 방식

<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
  <property name="objectMapper">
    <bean class="com.fasterxml.jackson.databind.ObjectMapper">
      <property name="propertyNamingStrategy">
        <util:constant static-field="com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE"/>
      </property>
    </bean>
  </property>
</bean>

📌 주의할 점  

1. DTO 필드는 반드시 camelCase로 유지

Jackson이 변환을 자동으로 해주기 때문에, DTO 클래스는 자바 컨벤션을 따라 camelCase로 작성해야 한다.

public class UserDto {
    private String userId;     // OK
    private String user_name;  // ❌ 비추천
}

user_name처럼 필드를 snake_case로 작성하면 오히려 매핑이 중복되거나 문제가 생길 수 있다.

 

2. 일부 필드만 매핑하려면 @JsonProperty 사용

전역 설정이 불가능하거나, 특정 필드만 다르게 매핑하고 싶을 경우 아래처럼 @JsonProperty 어노테이션을 사용할 수 있다.

public class UserDto {

    @JsonProperty("user_id")
    private String userId;

    @JsonProperty("user_name")
    private String userName;
}

단, 필드마다 반복적으로 선언해야 하므로 유지보수성이 떨어지고, 전체적으로 snake_case를 사용하는 구조라면 전역 설정이 훨씬 효율적이다.


✅ 정리

설정 방법 설명
전역 설정 ObjectMapper + NamingStrategy 전체 DTO에 자동 매핑 적용
개별 설정 @JsonProperty("user_id") 필드 단위 수동 매핑
매핑 전략 camelCasesnake_case 자동 변환 가능 (설정 필요)

 

마무리

이번 경험을 통해 클라이언트와 서버 간 네이밍 컨벤션의 차이가 단순한 스타일 문제가 아니라, 실제 동작 오류로 이어질 수 있다는 점을 알게 되었다.

 

특히 Jackson을 사용할 때, 클라이언트가 snake_case, 서버가 camelCase를 사용하는 구조라면, PropertyNamingStrategy 설정은 필수적이라는 것도 알게 되었다.

 

앞으로는 API 설계 시 초기 단계에서 네이밍 컨벤션을 명확히 정하고, 전역 설정을 통해 매핑 이슈를 미리 방지하려 한다.