TIL - 안드로이드
[안드로이드] 가변적인 json 키를 동일한 클래스로 파싱하기
cocokaribou
2023. 4. 18. 15:31
배경
같은 종류의 데이터가 각기 다른 json 키 이름으로 들어오는 api 가 있었다.
구글의 gson 라이브러리는 json 키와 데이터 클래스 변수명을 1:1로 매핑시키므로 별도의 처리가 필요했다.
예시
데이터 클래스
data class TestResponse(
// 키 이름이 다른 json 값들을 읽어서 List에 add.
val areaList: List<AreaData>?
) {
data class AreaData(
@SerializedName("itemType") val itemType: String?,
@SerializedName("imagePath") val imagePath: String?
)
}
응답값 json
{
"banner1" : {
"itemType" : "banner1",
"imagePath" : "banner1"
},
"banner2" : {
"itemType" : "banner2",
"imagePath" : "banner2"
},
"tab1" : {
"itemType" : "tab1",
"imagePath" : "tab1"
},
"goods1" : {
"itemType" : "goods1",
"imagePath" : "goods1"
},
"goods2" : {
"itemType" : "goods2",
"imagePath" : "goods2"
},
"tab2" : {
"itemType" : "tab2",
"imagePath" : "tab2"
}
}
방법
먼저 커스텀 TypeAdapter 를 만들어준다
class AreaDataTypeAdapter : TypeAdapter<TestResponse>() {
override fun write(out: com.google.gson.stream.JsonWriter?, value: TestResponse?) {
// not needed in this case
}
override fun read(reader: com.google.gson.stream.JsonReader?): TestResponse {
val list = mutableListOf<TestResponse.AreaData>()
var itemType: String? = null
var imgPath: String? = null
reader?.let {
reader.beginObject()
while (reader.hasNext()) {
val key = reader.nextName()
// json 키 패턴을 regex로 정의
val pattern = Regex("(banner|sns|goods|gallery|tab)\\d+")
if (pattern.matches(key)) {
reader.beginObject()
while (reader.hasNext()) {
val innerKey = reader.nextName()
when (innerKey) {
"itemType" -> itemType = reader.nextString()
"imagePath" -> imgPath = reader.nextString()
else -> reader.skipValue()
}
}
reader.endObject()
list.add(TestResponse.AreaData(itemType, imgPath))
} else {
reader.skipValue()
}
}
reader.endObject()
}
return TestResponse(list)
}
}
만든 TypeAdapter 를 register 해준다.
1) retrofit에 붙이기
val gson = GsonBuilder()
.registerTypeAdapter(TestResponse::class.java, AreaDataTypeAdapter())
.create()
return Retrofit.Builder()
.baseUrl(BASE_DOMAIN)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(client)
.build()
.create(ApiService::class.java)
2) json 로컬데이터를 쓸 때
val jsonString = getJsonFileToString("jsons/test.json", BaseApp.context)
val gson = GsonBuilder()
.registerTypeAdapter(TestResponse::class.java, AreaDataTypeAdapter())
.create()
val data = gson.fromJson(jsonString, TestResponse::class.java)
빌드해보고 에러가 난다면
json 키와 데이터 타입을 맞게 처리했는지 확인.
list 나 클래스처럼 뎁스가 깊어지면 그에 대한 처리도 필요.
참고
Android - Convert json which has uncertain keys to map using kotlin
I have a json like this. I need to convert it to data class { "0": { "id": "111", "type": "1", "items": [ ...
stackoverflow.com
728x90