FATAL EXCEPTION: main
Process: com.poketmonencyclopedia, PID: 2854
kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 334: Encountered an unknown key 'evolves_from_species' at path: $.evolution_chain
Use 'ignoreUnknownKeys = true' in 'Json {}' builder to ignore unknown keys.
JSON input: ...../api/v2/evolution-chain/1/"},"evolves_from_species":null,"fl.....
at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24)
at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32)
at kotlinx.serialization.json.internal.AbstractJsonLexer.fail(AbstractJsonLexer.kt:598)
at kotlinx.serialization.json.internal.AbstractJsonLexer.failOnUnknownKey(AbstractJsonLexer.kt:593)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.handleUnknown(StreamingJsonDecoder.kt:254)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeObjectIndex(StreamingJsonDecoder.kt:240)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeElementIndex(StreamingJsonDecoder.kt:175)
at com.poketmonencyclopedia.detail.model.species.SpeciesResponse$$serializer.deserialize(SpeciesResponse.kt:5)
at com.poketmonencyclopedia.detail.model.species.SpeciesResponse$$serializer.deserialize(SpeciesResponse.kt:5)
...
request <-> response에서 kotlin-serialize 라이브러리 사용 중 발생함.
서버의 response를 받는 데이터 포맷(json)이 일치하지 않음.
@Serializable
data class SpeciesResponse(
val base_happiness: Int,
val capture_rate: Int,
val color: Color,
val egg_groups: List<EggGroup>,
val evolution_chain: EvolutionChain,
val evolves_from_species: Any,
val flavor_text_entries: List<FlavorTextEntry>,
val form_descriptions: List<Any>,
val forms_switchable: Boolean,
val gender_rate: Int
...
)
data class SpeciesResponse(
val base_happiness: Int,
val capture_rate: Int,
val color: Color,
val egg_groups: List<EggGroup>,
val evolution_chain: EvolutionChain,
@Contextual val evolves_from_species: Any,
val flavor_text_entries: List<FlavorTextEntry>,
val form_descriptions: List<@Contextual Any>,
val forms_switchable: Boolean,
val gender_rate: Int
...
)
@Contextual
어노테이션 사용.@Contextual
어노테이션을 추가하면, 직렬화 및 역직렬화의 동작이 Serializer 컨텍스트에 따라 결정됨.@Contextual
어노테이션은 특정 타입에 대해 커스텀 직렬화 동작을 제공하려는 경우에 사용됨. 그런데 Any 타입의 경우 어떤 실제 타입이 할당될지 알 수가 없음.'ignoreUnknownKeys = true'
는 JSON 문자열에 알 수 없는 키가 포함되어 있을 경우 무시하도록 하는 옵션임.@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Singleton
@Provides
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
val jsonConfig = Json { ignoreUnknownKeys = true } // 기존엔 없었음.
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://pokeapi.co/api/v2/")
.addConverterFactory(jsonConfig.asConverterFactory("application/json".toMediaType()))
.build()
}
kotlin-serialization 직렬화 라이브러리 사용시엔 json 데이터가 일치해야 하는 것을 확인할 것.
1. 공공 api, 무료로 배포되어 있는 api의 문서를 잘 보고 타입 맞추기.
2. 사용 안하는 데이터일 경우 ignoreUnknownKeys = true
추가.
3. kotlinx.serialization에서 지원하지 않는 직렬화, 역직렬화 타입이라면 @Contextual
사용하기.
@Serializable
+ data class로 사용 가능함.