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

Jackson JSON 트러블슈팅을 위한 각 오류별 구체적인 예제와 JUnit 기반 테스트 코드

B컷개발자 2025. 5. 19. 11:07
728x90

Jackson JSON 트러블슈팅을 위한 각 오류별 구체적인 예제와 JUnit 기반 테스트 코드를 정리한 Java 코드 문서를 생성했습니다. 이 문서에는 다음과 같은 내용을 포함하고 있습니다:

  • UnrecognizedPropertyException (정의되지 않은 필드)
  • InvalidFormatException (타입 불일치)
  • JavaTimeModule 미등록으로 인한 날짜 오류
  • Enum 역직렬화 실패
  • 순환 참조 문제와 @JsonManagedReference, @JsonBackReference 사용 예제
// Java JSON 처리 실전 – Jackson 트러블슈팅 확장 예제 모음

// 1. UnrecognizedPropertyException 예제

public class User {
    private String name;
    private int age;
    // getter, setter
}

@Test
void testUnrecognizedField() throws Exception {
    String json = "{\"name\":\"홍길동\", \"age\":30, \"unknown\":\"test\"}";
    ObjectMapper mapper = new ObjectMapper();
    Assertions.assertThrows(UnrecognizedPropertyException.class, () -> {
        mapper.readValue(json, User.class);
    });
}

// 해결: 무시 설정 추가
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserSafe {
    private String name;
    private int age;
}

// 2. InvalidFormatException 예제

public class AgeUser {
    private int age;
}

@Test
void testInvalidFormat() throws Exception {
    String json = "{\"age\":\"abc\"}";
    ObjectMapper mapper = new ObjectMapper();
    Assertions.assertThrows(InvalidFormatException.class, () -> {
        mapper.readValue(json, AgeUser.class);
    });
}

// 3. JavaTimeModule 미등록 예제

public class DateUser {
    private LocalDateTime createdAt;
}

@Test
void testMissingJavaTimeModule() throws Exception {
    String json = "{\"createdAt\":\"2025-05-10T15:00:00\"}";
    ObjectMapper mapper = new ObjectMapper();
    Assertions.assertThrows(InvalidDefinitionException.class, () -> {
        mapper.readValue(json, DateUser.class);
    });
}

// 해결: 모듈 등록
@Test
void testWithJavaTimeModule() throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    String json = "{\"createdAt\":\"2025-05-10T15:00:00\"}";
    DateUser user = mapper.readValue(json, DateUser.class);
    Assertions.assertNotNull(user.getCreatedAt());
}

// 4. Enum 역직렬화 오류 및 해결

public enum Role {
    ADMIN, USER
}

public class RoleUser {
    private Role role;
}

@Test
void testEnumFail() throws Exception {
    String json = "{\"role\":\"admin\"}";
    ObjectMapper mapper = new ObjectMapper();
    Assertions.assertThrows(IllegalArgumentException.class, () -> {
        mapper.readValue(json, RoleUser.class);
    });
}

// 해결: 대소문자 무시
@Test
void testEnumSuccessWithInsensitive() throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true);
    String json = "{\"role\":\"admin\"}";
    RoleUser user = mapper.readValue(json, RoleUser.class);
    Assertions.assertEquals(Role.ADMIN, user.getRole());
}

// 5. 순환 참조 문제 해결

@Data
@NoArgsConstructor
@AllArgsConstructor
class Parent {
    public String name;

    @JsonManagedReference
    public Child child;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Child {
    public String name;

    @JsonBackReference
    public Parent parent;
}

@Test
void testCyclicReference() throws Exception {
    Parent parent = new Parent("부모", null);
    Child child = new Child("자식", parent);
    parent.setChild(child);

    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(parent);
    Assertions.assertTrue(json.contains("부모"));
    Assertions.assertTrue(json.contains("자식"));
    Assertions.assertFalse(json.contains("parent")); // 역참조 제외됨
}

 

Spring Boot 통합 테스트 형식 주요 특징은 다음과 같습니다:

  • @SpringBootTest, @AutoConfigureMockMvc를 사용한 테스트 환경 구성
  • MockMvc를 통한 실제 HTTP 요청 시뮬레이션
  • /user 엔드포인트: 정의되지 않은 필드(UnrecognizedPropertyException) 테스트
  • /role 엔드포인트: 대소문자 민감한 Enum 역직렬화 오류와 그 해결 테스트
  • Jackson2ObjectMapperBuilderCustomizer를 활용한 설정 커스터마이징 예제 포함
// Jackson 트러블슈팅 – Spring Boot 통합 테스트 기반 예제

@SpringBootTest
@AutoConfigureMockMvc
public class JacksonErrorIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @RestController
    static class TestController {

        @PostMapping("/user")
        public ResponseEntity<String> createUser(@RequestBody User user) {
            return ResponseEntity.ok("OK");
        }

        @PostMapping("/role")
        public ResponseEntity<String> assignRole(@RequestBody RoleUser roleUser) {
            return ResponseEntity.ok("OK");
        }
    }

    static class User {
        public String name;
        public int age;
    }

    static class RoleUser {
        public Role role;
    }

    enum Role {
        ADMIN, USER
    }

    @Test
    void unrecognizedFieldReturns400() throws Exception {
        String invalidJson = "{\"name\":\"홍길동\", \"age\":30, \"unknown\":\"???\"}";

        mockMvc.perform(post("/user")
                .contentType(MediaType.APPLICATION_JSON)
                .content(invalidJson))
            .andExpect(status().isBadRequest());
    }

    @Test
    void invalidEnumValueReturns400() throws Exception {
        String json = "{\"role\":\"admin\"}";

        mockMvc.perform(post("/role")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json))
            .andExpect(status().isBadRequest());
    }

    @TestConfiguration
    static class CustomConfig {
        @Bean
        public Jackson2ObjectMapperBuilderCustomizer customizer() {
            return builder -> builder.featuresToEnable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
        }
    }

    @Test
    void validEnumWithInsensitiveEnabled() throws Exception {
        String json = "{\"role\":\"admin\"}";

        mockMvc.perform(post("/role")
                .contentType(MediaType.APPLICATION_JSON)
                .content(json))
            .andExpect(status().isOk());
    }
}

 

이제 이 코드를 실제 Spring Boot 프로젝트의 통합 테스트로 실행할 수 있으며, 실무 현장에서 JSON 처리 트러블슈팅을 자동화 테스트로 검증하는 데 활용하실 수 있습니다.

728x90