ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Kotlin - jackson 을 이용하여 객체를 json 으로 변환할 때 주의점
    Kotiln 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 가 잘 적용된 것을 확인할 수 있습니다.

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

    출처

    반응형

    댓글

Designed by Tistory.