Kotlin에서 reflection을 사용하여 JSON deserialization 해보기

JhoonP·2023년 3월 19일
0

Kotlin에서 reflection을 사용하여 JSON serialization 해보기에 이어서, deserialization을 구현해본다.


  1. 변환을 위해서는 변환할 JSON Map 객체와 변환할 타입형인 KClass가 필요하다. 함수 parameter로 KClass type을 사용해 변환할 class type을 받는다.
fun <TR: Any> deserializeMap(type: KClass<TR>, map: Map<String, Any>): TR
  1. KClass.primaryConstructor로 기본 생성자 정보를 가져올 수 있다. 생성자의 parameter 정보들을 KParameter type으로 가져와 parameterInfo에 저장할 것이다
val parameterInfo = mutableMapOf<KParameter, Any?>()
type.primaryConstructor?.parameters?.forEach {
	...
}
  1. KClass.primaryConstructor.name으로 생성자 parameter의 이름, 즉 member value를 가져올 수 있다. JSON Map에서 member value를 key로 가진 item을 찾는다
val item = map[it.name]
if(item is JSONObject) {
	//	Performing recursive transformations
} else if(item is JSONArray) {
    //	Deserialize each item in an array and store it in a List
} else if(item != null) {
    //	Ignore
} else {
    //	Ignore
}
  1. item이 data type(String, int 등)이 아닌 object type일 경우 한 번 더 deserialize 해야한다. parameterInfoKParamter와 deserialize한 value 값을 저장한다.
if(item is JSONObject) {
	//	Performing recursive transformations
    parameterInfo[it] = deserializeMap(it.type.classifier as KClass<*>, jsonObjectToMap(item))
}
  1. item이 Array type인 경우 Kotlin List으로 변환해야 한다. 각 array item들 순회하면서 deserialize를 수행한 후 List에 저장한다.
    Array는 Generic class이기 때문에 타입을 추출하여 deserialize 하는데 넘겨줘야 한다.
} else if(item is JSONArray) {
    val list = mutableListOf<Any?>()
    val template = it.type.arguments[0].type!!.classifier
    for(subItem in jsonListToList(item)) {
        if(subItem is JSONObject) {
            list.add(deserializeMap(template as KClass<*>, jsonObjectToMap(subItem)))
        }
    }
    parameterInfo[it] = list
}
  1. 그 외 값들에 대해서는 그대로 사용하면 된다.
} else if(item != null) {
    parameterInfo[it] = item
} else {
    parameterInfo[it] = null
}
  1. 이렇게 얻은 List<KParameter, Any?> 값을 생성자의 parameter로 넘겨 실행하면 deserialize된 instance를 얻을 수 있다.
return type.primaryConstructor?.callBy(parameterInfo)!!

결과

fun deserialize(): Any {
    val jsonString = """
        {
         "age": 30,
         "height": 171.2,
         "name": "John Doe",
         "subWorkplace": [
          {
           "isLargeEnterprise": true,
           "name": "Google"
          }
         ],
         "workplace": {
          "isLargeEnterprise": true,
          "name": "Google"
         }
        }
    """.trimIndent()
    
    val result = JJson().deserializeMap(Person::class, JJson.jsonStringToMap(jsonString))
    Log.d(TAG, "Deserialize result: $result")
    return result
}
Deserialize result: Person(name=John Doe, age=30, height=171.2, workplace=Company(name=Google, isLargeEnterprise=true, numOfEmployees=null), subWorkplace=[Company(name=Google, isLargeEnterprise=true, numOfEmployees=null)])
profile
배울게 끝이 없네 끝이 없어

0개의 댓글