Kotiln

Kotlin - jackson 을 이용하여 객체를 json 으로 변환할 때 주의점

블린더르 2021. 3. 24. 20:19
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule

fun main(args: Array<String>) {
    val testData = TestData("name", "code", false)
    println(testData)
    val objectMapper = ObjectMapper().registerModule(KotlinModule())
    val res = objectMapper.writeValueAsString(testData)
    println(res)
    val data = objectMapper.readValue(res, TestData::class.java)
    println(data)
}

data class TestData(
    val name: String,
    val aCode: String,
    val isUse: Boolean
)

위의 코드를 실행하면 다음과 같은 에러가 발생합니다.

TestData(name=name, aCode=code, isUse=false)
{"name":"name","acode":"code","use":false}
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `TestData` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"name":"name","acode":"code","use":false}"; line: 1, column: 2]
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
	at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1589)
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1055)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)
	at MainKt.main(Main.kt:9)

Process finished with exit code 1

출력된 결과를 확인해 보면 TestData 의 데이터는 잘 들어갔지만 json으로 변환하는 과정에서 뭔가 문제가 생긴 것을 확인할 수 있습니다.

TestData(name=name, aCode=code, isUse=false)
{"name":"name","acode":"code","use":false}

aCode 는 acode 로, isUse 는 use 로 바뀌어서 변환되었습니다.

코틀린 코드를 자바 코드로 변환해보면

위와 같은 메소드를 생성하여 값을 반환하게 되어 있습니다.

jackson 의 코드를 살펴보면

properties 를 _props 의 값으로 주게되는데 이때

getACode, isUse 메소드로 값을 가져온 결과가 acode, use 로 보여집니다.

aCode 의 경우

jackson 은 자바빈 네이밍 컨벤션을 따르며 그에 따라 객체 프로퍼티의 값을 가져옵니다.

그러므로 프로퍼티의 처음 두자리는 대문자로 시작하지 않는 것이 좋습니다

http://futuretask.blogspot.com/2005/01/java-tip-6-dont-capitalize-first-two.html

https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/

isUse 의 경우

메소드에서 get, set, is 의 뒤에 오는 것을 json 의 키로 사용합니다.

따라서 isUse 가 use 로 변경된 것입니다.

그대로 사용하려면?

위의 두 경우에서 그대로 key 값이 들어가길 원한다면 @JsonProperty 를 사용합니다.

data class TestData(
    val name: String,
    @get:JsonProperty("aCode")
    val aCode: String,
    @get:JsonProperty("isUse")
    val isUse: Boolean
)

getter@JsonProperty 를 추가하고 사용할 이름을 입력합니다.

자바 코드에서 @JsonProperty 가 잘 적용된 것을 확인할 수 있습니다.

이제 다시 실행시키면 원하던 결과가 출력됩니다.

출처

반응형