개발/안드로이드 개발
여러 유형의 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을 이용하여 단순히 클래스 네임과 비교하는 부분과 코틀린 리플랙션을 사용하는 부분에서 더 나은 방법이 있을지 고민중이며 더 좋은 아이디어나 방법이 있다면 공유 부탁드립니다.
반응형