본문 바로가기
스프링부트

jackson for kotlin part1. 동작 원리

by pius712 2023. 12. 30.

 

kotlin 을 사용하면, kotlin 용의 jackson library를 설치해야한다.

implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

spring initializer 로 스프링 프로젝트를 구성하다보면, 자동으로 해당 라이브러리가 설치되어있기 때문에 별 생각없이 쓰게 된다.

개인적으로 토이 프로젝트를 하던 도중, 해당 라이브러리가 설치가 안되어있어서 json 변환관련 에러가 나서 도대체 이것이 뭔지 찾아보게 되었다.

왜 jackson-module-kotlin 없이는 변환이 안될까?

기본적으로 jackson 자체는 코틀린을 위한 라이브러리가 아니다.

코틀린의 data class 와 같은 것들은 기본 jackson library 가 이해하지 못하기 때문에, 변환을 할 수 없는 것이다.

코틀린의 jacksonObjectMapper() 는 무엇인가?

그리고 코드에서 사용할때는 보통 아래의 objectMapper를 쓰게 되는데,

*jacksonObjectMapper*() 의 실체는 무엇인가?

jsonMapper 라고 하는 ObjectMapper 의 구현체에 kotlinModule 을 추가한 것이다. ObjectMapper 중 json 에 특화된 구현체라고 보면된다.

fun jacksonObjectMapper(): ObjectMapper 
				= jsonMapper { addModule(kotlinModule()) }

어떻게 자동으로 등록되는가?

그런데 일반적으로 따로 설정을 하지 않아도, 해당 라이브러리만 설치하면 kotlin 에 맞게 json 변환이 이루어지는데 어떻게 가능한 것일까?

jackson 의 module class

jackson 라이브러리의 자동구성 대해 설명하기 전에, jackson 의 일부 개념에 대해서 짚고 넘어가보자.

ObjectMapper는 registerModule 을 통해서, 기능을 확장할 수 있다.

이 registerModule에 jackson 의 module 클래스 타입을 받게 된다.

자주 사용되는 아래의 모듈은 module 클래스를 확장하는 하위 타입들이다.

  • Jdk8Module
  • JavaTimeModule
  • KotlinModule
val objectMapper = ObjectMapper().apply {
            registerModule(Jdk8Module())
            registerModule(JavaTimeModule())
            registerModule(kotlinModule)
}

auto configuration

spring boot 에는 auto configuration 이라는게 있다.

→ 라이브러리를 설치하게 되면 자동으로 관련된 Bean 들을 등록해주게 되는데, 이를 auto configuration 이라고 한다.

Jackson 의 경우 JacksonAutoConfiguration 클래스를 통해서 자동구성이 된다.

 

해당 클래스의 내부(inner) 클래스에 JacksonObjectMapperConfiguration 클래스가 있는데, ObjectMapper 를 빈 메서드로 등록하는 코드이다.

// JacksonAutoConfiguration.class
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
static class JacksonObjectMapperConfiguration {

	@Bean
	@Primary
	@ConditionalOnMissingBean
	ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
		return builder.createXmlMapper(false).build();
	}

}

 

Jackson2ObjectMapperBuilder 를 빌드하게 되면,

ObjectMapper 의 static method 인 findModules를 호출하게 된다. 그러면 클래스 로더를 통해, jackson 의 Module 하위 클래스들을 모두 등록하게 된다.

// ObjectMapper.class
public static List<Module> findModules(ClassLoader classLoader)
    {
        ArrayList<Module> modules = new ArrayList<Module>();
        ServiceLoader<Module> loader = secureGetServiceLoader(Module.class, classLoader);
        for (Module module : loader) {
            modules.add(module);
        }
        return modules;
    }