룬아님의 취중코딩

여러 유형의 Response type을 Gson를 이용하여 Sealed Class로 받기 본문

개발/안드로이드 개발

여러 유형의 Response type을 Gson를 이용하여 Sealed Class로 받기

룬아님 2023. 4. 14. 16:30
"attach" : {
     "type" : "image"
     "imageUrl" : "string"
}

"attach" : {
     "type" : "video"
     "videoUrl" : "string"
     "size" : 0
}

이런 형태의 Json으로 type에 따라 다른 parameter가 내려올 때

data class Attach(
    val type: AttachType,
    val imageUrl: String?,
    val videoUrl: Stirng?,
    val size: Int?
}

이런 방법으로 전부 nullable을 이용하여 받아오는 방법이 있을 것이다.
다만 사용하지 않는 파라미터까지 모두 가지고 있는 객체와 이후 받아야 하는 파라미터가 더 많아 진다면 더 복잡하고 거대하여 어떤 역할을 하는지 알아보기도 힘들게 될 것이다.

그래서 Gson의 JsonDeserializer와 Kotlin reflection을 이용하여 type을 판단하여 적절한 class로 변환해주는 방법을 이용해 보았다.

    sealed class Attach {
        data class Video(
            val videoUrl: String,
            val size: Int
        ) : Attach()

        data class Image(
            val imageUrl: String
        ) : Attach()
    }

우선 type에 따라 class를 만들고

    private object AttachDeserializer : JsonDeserializer<Attach> {
        override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Attach {
            val type = json.asJsonObject.get("type").asString
            val item = Attach::class.sealedSubclasses.find {
                it.simpleName == type.split('_').joinToString("", transform = String::capitalize)
            }
            return context.deserialize(json, item?.java)
        }
    }

받아온 type을 Camel case 형태로 바꾸어 Attach의 sealedSubclasses와 같은 네이밍인지 판다하여 같다면 해당 객체로 deserialize해주는 JsonDeserializer을 구현하였다.

    @JsonAdapter(AttachDeserializer::class)
    sealed class Attach {

JsonAdapter 어노테이션을 이용하여 해당 JsonDeserializer와 연결을 해주면 데이터를 가져올 때 알아서 해당 객체를 deserialize하여 가져오게 된다.

type을 이용하여 단순히 클래스 네임과 비교하는 부분과 코틀린 리플랙션을 사용하는 부분에서 더 나은 방법이 있을지 고민중이며 더 좋은 아이디어나 방법이 있다면 공유 부탁드립니다.

반응형
Comments