programing

잭슨을 사용하여 Kotlin 컬렉션을 역직렬화하는 방법

megabox 2023. 2. 11. 09:08
반응형

잭슨을 사용하여 Kotlin 컬렉션을 역직렬화하는 방법

원하는 샘플 코드:

data class D(val a: String, val b: Int)
val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b":"2}]"""
// what I need
val listOfD: List<D> = jacksonObjectMapper().whatMethodAndParameter?

Jackson Kotlin 모듈의 최신 버전에서 풀 모듈 패키지 또는 특정 확장 기능을 가져오면 모든 확장 방법을 사용할 수 있습니다.예를 들어 다음과 같습니다.

import com.fasterxml.jackson.module.kotlin.*  
val JSON = jacksonObjectMapper()  // keep around and re-use
val myList: List<String> = JSON.readValue("""["a","b","c"]""")

따라서 Jackson Module for Kotlin은 올바른 유형을 추론할 수 있으며, 사용자는 이 유형을 추론할 필요가 없습니다.TypeReference사례.

따라서 (약간 데이터 클래스 이름 변경 및 수정, JSON)은 다음과 같습니다.

import com.fasterxml.jackson.module.kotlin.readValue

data class MyData(val a: String, val b: Int)
val JSON = jacksonObjectMapper()  

val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b": 2}]"""
val myList: List<MyData> = JSON.readValue(jsonStr)

다음의 폼도 사용할 수 있습니다.

val myList = JSON.readValue<List<MyData>>(jsonStr)

Import를 하지 않으면 확장 함수를 찾을 수 없기 때문에 오류가 발생합니다.

TL;DR

잭슨이랑2.6.3-2@syslog-minard의 조언에 따라 다음 명령을 사용합니다.

import com.fasterxml.jackson.module.kotlin.readValue

val listOfD: List<D> = jacksonMapper.readValue(jsonStr)

세부 사항

주석 없이 데이터 클래스를 역직렬화하려면 kotlin jackson 모듈이 필요하지만 컬렉션 역직렬화에는 Kotlin wrt가 특별히 필요한 것은 아닙니다.

즉, 리스트의 범용 파라미터를 추적하기 위해서는 고객의 케이스에 완전한 타입 정보가 필요합니다(D); 그 이외의 경우(예를 들어 를 사용하는 경우)readValue(jsonStr, List::class.java)Jackson은 그것을 지워진 유형으로만 인식합니다(즉,List(Kotlin이 명시하고 있는 것처럼)를 디시리얼라이즈 합니다.List<Map<String, String>>구축해야 한다는 것을 모르고 있습니다.Ds. 이는 익명의 서브클래스를 사용하여 해결됩니다.TypeReference잭슨이 런타임에 역직렬화 대상인 전체 재작성된 유형에 액세스할 수 있도록 합니다.

Jackson Java 코드를 문자 그대로 Kotlin으로 변환하면 다음과 같이 원하는 것을 얻을 수 있습니다(@eski의 코멘트와 같이, 예의 JSON은 무효입니다).

val jacksonMapper = ObjectMapper().registerModule(KotlinModule())

val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b":2}]"""
val listOfD: List<D> = jacksonMapper.readValue(jsonStr, object : TypeReference<List<D>>(){})

assertEquals(listOf(D("value1", 1), D("value2", 2)), listOfD)

이것은 약간 장황하고 보기 흉하기 때문에 Kotlin(확장) 함수(특히 여러 번 사용할 계획인 경우)에 숨길 수 있습니다.

inline fun <reified T> ObjectMapper.readValue(json: String): T = readValue(json, object : TypeReference<T>(){})

그러면 전화만 하면 됩니다.

val listOfD: List<D> = jacksonMapper.readValue(jsonStr)

그리고 이게 바로 이 제품에 포함된 내용입니다.2.6.3-2잭슨 코틀린 모듈

일반 콘텐츠 유형이 없는 경우 다음과 같이 하십시오.<MyData>를 참조해 주세요.

val value = context.readValue<List<MyData>>(parser, valueType)

이 기능을 구현하기 위해서는JsonSerialzier그뿐만 아니라ContextualDeserializer다음 코드 샘플과 같습니다(Java에서의 이 답변에 근거합니다).

class GenericListDeserializer : JsonDeserializer<List<*>>(), ContextualDeserializer {
    private var valueType: JavaType? = null

    override fun createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer<List<*>> {
        val wrapperType = property.type
        val valueType = wrapperType.containedType(0)
        val deserializer = GenericListDeserializer()
        deserializer.valueType = valueType
        return deserializer
    }

    override fun deserialize(parser: JsonParser, context: DeserializationContext): List<*> {
        val value :Any? = context.readValue(parser, valueType)
        return listOf(value)
    }
}

언급URL : https://stackoverflow.com/questions/33368328/how-to-use-jackson-to-deserialize-to-kotlin-collections

반응형