기술과 산업/언어 및 프레임워크

Java JSON 처리 실전 시리즈 5화 – JSON 필드명 자동 변환: CamelCase ↔ Snake_Case 대응 전략

B컷개발자 2025. 5. 19. 10:50
728x90

Jackson을 이용해 JSON 필드명을 자동으로 camelCase ↔ snake_case로 변환하는 방법을 소개합니다. @JsonProperty, @JsonNaming, application.yml 설정까지 실무 예제 기반으로 정리합니다.


백엔드 개발자라면 이런 상황을 한 번쯤 겪어봤을 것입니다.

  • Java 객체는 camelCase로 선언
  • 프론트엔드나 외부 API는 snake_case JSON 포맷 요구

이때마다 @JsonProperty("user_name")을 필드마다 붙이자니 번거롭고, 유지보수성도 떨어집니다.
이 글에서는 Jackson에서 제공하는 자동 네이밍 전략을 통해 코드는 camelCase로 유지하면서, JSON은 snake_case로 제공하는 방법을 설명합니다.


1. 문제 예시

public class User {
    private String userName;
    private LocalDateTime createdAt;
}

기본 직렬화 결과:

{
  "userName": "홍길동",
  "createdAt": "2025-05-10T10:00:00"
}

→ 원하는 결과는 다음과 같은 snake_case 포맷일 수 있습니다:

{
  "user_name": "홍길동",
  "created_at": "2025-05-10T10:00:00"
}

2. 해결 방법 ①: application.yml 전역 설정

Spring Boot에서는 application.yml 설정만으로 Jackson의 네이밍 전략을 전역 적용할 수 있습니다.

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE

설정 적용 후 컨트롤러 반환값 예시:

@GetMapping("/user")
public User getUser() {
    return new User("홍길동", LocalDateTime.now());
}

출력 결과:

{
  "user_name": "홍길동",
  "created_at": "2025-05-10T10:00:00"
}

유지보수 관점에서 가장 간단하고 강력한 방법입니다.


3. 해결 방법 ②: 클래스 단위 @JsonNaming 적용

특정 클래스에서만 네이밍 전략을 다르게 적용하고 싶은 경우 유용합니다.

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class User {
    private String userName;
    private LocalDateTime createdAt;
}

이 방식은 글로벌 설정을 변경하지 않고, 클래스 단위로 snake_case 변환을 적용합니다.

DTO 객체나 외부 API 모델 클래스에 주로 사용됩니다.


4. 해결 방법 ③: 필드 단위 @JsonProperty

public class User {
    @JsonProperty("user_name")
    private String userName;

    @JsonProperty("created_at")
    private LocalDateTime createdAt;
}

가장 낮은 우선순위를 가지며, 명시적 제어가 필요한 경우 사용합니다. 전역 설정 + 일부 필드만 예외 처리할 때 유용합니다.


5. SnakeCase ↔ CamelCase 매핑 테스트 예제

테스트 코드 예시 (Spring Boot Test + ObjectMapper 사용):

@SpringBootTest
public class JsonNamingTest {

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    void testSnakeCaseMapping() throws Exception {
        String json = "{\"user_name\":\"홍길동\",\"created_at\":\"2025-05-10T10:00:00\"}";
        User user = objectMapper.readValue(json, User.class);
        Assertions.assertEquals("홍길동", user.getUserName());
    }
}

이 테스트는 역직렬화 방향에서도 snake_case → camelCase 매핑이 자동 적용되는지를 확인합니다.


6. 커스텀 네이밍 전략이 필요한 경우

Jackson은 기본적으로 UPPER_CAMEL_CASE, SNAKE_CASE, LOWER_CASE, KEBAB_CASE 등을 제공합니다.
하지만 복합적인 규칙이 필요한 경우에는 커스텀 전략 클래스를 작성할 수도 있습니다.

public class CustomNamingStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase {
    @Override
    public String translate(String input) {
        // 사용자 정의 네이밍 규칙 작성
        return "custom_" + input.toLowerCase();
    }
}

그리고 다음과 같이 적용:

@JsonNaming(CustomNamingStrategy.class)
public class User {
    ...
}

결론 및 실무 팁 요약

전략 적용 대상 특징

application.yml 전체 전역 가장 간단하고 강력
@JsonNaming 클래스 단위 DTO 분리 시 유용
@JsonProperty 필드 단위 예외 상황 대응용
  • 전역 네이밍 전략은 yml로 적용하고, 예외 상황만 어노테이션으로 보완하는 것이 유지보수에 유리합니다.
  • 팀 내 API 명세 스타일을 정하고, 일관되게 전략을 유지하는 것이 중요합니다.

다음 회차 예고

6화에서는 Spring MVC 컨트롤러에서 JSON 요청과 응답을 어떻게 처리하는지 흐름을 파악하고, @RequestBody, @ResponseBody, HttpMessageConverter 동작 원리를 Jackson과 함께 분석합니다.

728x90