retrofit2와 모시와 enum
하고 싶었던 일
retrofit + moshi에서 API 응답 (json)을 enum으로 deserialize하고 반환하십시오.
예: 월의 화명을 반환하는 API
앱 측에서 월(1~12)을 서버에 요청하면 응답으로 월의 화명이 반환되는 연계가 있으며,
앱 측과 서버 측 모두에서 반환 값으로 Enum이 정의되어 있다고 가정합니다.
상수
값
MUTSUKI
0
KISARAGI
1
YAYOI
2
UDUKI
3
SATSUKI
4
MINADUKI
5
FUMIDUKI
6
HADUKI
7
NAGATUKI
8
KANNADUKI
9
Shimotuki
10
시와수
11
UNKNOWN
12
형식
// リクエスト
{
"month": 1
}
// レスポンス(名前で返す)
{
"month_jpn": "MUTSUKI"
}
// レスポンス(序数で返す)
{
"month_jpn": 0
}
앱 측
// Enumの定義
enum class Wareki {
// 縦に長いので折り返してます
MUTSUKI, KISARAGI, YAYOI, UDUKI,
SATSUKI, MINADUKI, FUMIDUKI, HADUKI,
NAGATUKI, KANNADUKI, SHIMOTUKI, SHIWASU,
UNKNOWN
}
// レスポンスを受け取るオブジェクトのクラス
data class ResData(
@Json(name = "month_jpn")
val monthJpn: Wareki
)
// APIをコールする箇所
suspend fun fetchMonthJpn(month: Int) {
try {
// ここ
val res = Api.service.fetchMonthJpn(ReqData(month))
Log.d("TEST", res.raw().toString())
val monthJpn = res.body()!!.monthJpn
monthJpn.let {
Log.d("TEST", it.name + ":" + it.javaClass)
}
} catch (e: JsonDataException) {
Log.e("TEST", e.message!!)
}
}
// moshiとretrofit
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.build()
1. enum을 캐릭터 라인으로서 받는 경우(이름으로 반환의 경우)
enum을 문자열로 받는 경우는, 특히 궁리 없이 그대로 Enum으로서 디시리얼라이즈 해 준다.
D/TEST: Response{protocol=http/1.1, code=200, message=OK, url=http://10.0.2.2:8000/api/fetch_month_jpn/}
D/TEST: KISARAGI:class jp.co.sample.Wareki
2. enum을 수치로서 받는 경우(서수로 반환의 경우)
서수로 받으면 디시리얼라이즈 할 수 없으며 예외가 발생합니다.
E/TEST: Expected one of [MUTSUKI, KISARAGI, YAYOI, UDUKI, SATSUKI, MINADUKI, FUMIDUKI, HADUKI, NAGATUKI, KANNADUKI, SHIMOTUKI, SHIWASU, UNKNOWN] but was 1 at path $.month_jpn
어댑터 도입
이런 경우에는 어댑터를 도입하면 잘 됐다.
우선 이런 어댑터를 만든다.
class WarekiAdapter {
@FromJson
fun fromJson(monthJpn: Int): Wareki {
return Wareki.values().find { it.ordinal == monthJpn } ?: throw IllegalArgumentException()
}
}
moshi에 add하는 어댑터에는 FromJson 또는 ToJson이 필요합니다.
이번에는 deserialize 만이므로 FromJson 만 정의하고 json에서받은 값과 해당 enum 값을
find에서 찾고 반환합니다. 발견되지 않는 경우는 예외를 발행하는 것 같은 느낌으로 작성했다.
이것을 moshi에 add한다.
private val moshi = Moshi.Builder()
.add(WarekiAdapter()) // ここ
.add(KotlinJsonAdapterFactory())
.build()
이상.
다시 API를 호출하면 괜찮은 디시리얼라이즈 해준다.
D/TEST: Response{protocol=http/1.1, code=200, message=OK, url=http://10.0.2.2:8000/api/fetch_month_jpn/}
D/TEST: KISARAGI:class jp.co.sample.Wareki
appendix
덧붙여서, 위의 어댑터를 추가 한 상태에서 "1. enum을 문자열로받는 경우"를 수행하면 오류가 발생했습니다.
E/TEST: Expected an int but was KISARAGI at path $.month_jpn
어느 쪽이든 deserialize 해주는 방법을 모집하고 있습니다.
Reference
이 문제에 관하여(retrofit2와 모시와 enum), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/Chiku_Qiita/items/cfbc46ffae3de17a48e1
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
앱 측에서 월(1~12)을 서버에 요청하면 응답으로 월의 화명이 반환되는 연계가 있으며,
앱 측과 서버 측 모두에서 반환 값으로 Enum이 정의되어 있다고 가정합니다.
상수
값
MUTSUKI
0
KISARAGI
1
YAYOI
2
UDUKI
3
SATSUKI
4
MINADUKI
5
FUMIDUKI
6
HADUKI
7
NAGATUKI
8
KANNADUKI
9
Shimotuki
10
시와수
11
UNKNOWN
12
형식
// リクエスト
{
"month": 1
}
// レスポンス(名前で返す)
{
"month_jpn": "MUTSUKI"
}
// レスポンス(序数で返す)
{
"month_jpn": 0
}
앱 측
// Enumの定義
enum class Wareki {
// 縦に長いので折り返してます
MUTSUKI, KISARAGI, YAYOI, UDUKI,
SATSUKI, MINADUKI, FUMIDUKI, HADUKI,
NAGATUKI, KANNADUKI, SHIMOTUKI, SHIWASU,
UNKNOWN
}
// レスポンスを受け取るオブジェクトのクラス
data class ResData(
@Json(name = "month_jpn")
val monthJpn: Wareki
)
// APIをコールする箇所
suspend fun fetchMonthJpn(month: Int) {
try {
// ここ
val res = Api.service.fetchMonthJpn(ReqData(month))
Log.d("TEST", res.raw().toString())
val monthJpn = res.body()!!.monthJpn
monthJpn.let {
Log.d("TEST", it.name + ":" + it.javaClass)
}
} catch (e: JsonDataException) {
Log.e("TEST", e.message!!)
}
}
// moshiとretrofit
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.build()
1. enum을 캐릭터 라인으로서 받는 경우(이름으로 반환의 경우)
enum을 문자열로 받는 경우는, 특히 궁리 없이 그대로 Enum으로서 디시리얼라이즈 해 준다.
D/TEST: Response{protocol=http/1.1, code=200, message=OK, url=http://10.0.2.2:8000/api/fetch_month_jpn/}
D/TEST: KISARAGI:class jp.co.sample.Wareki
2. enum을 수치로서 받는 경우(서수로 반환의 경우)
서수로 받으면 디시리얼라이즈 할 수 없으며 예외가 발생합니다.
E/TEST: Expected one of [MUTSUKI, KISARAGI, YAYOI, UDUKI, SATSUKI, MINADUKI, FUMIDUKI, HADUKI, NAGATUKI, KANNADUKI, SHIMOTUKI, SHIWASU, UNKNOWN] but was 1 at path $.month_jpn
어댑터 도입
이런 경우에는 어댑터를 도입하면 잘 됐다.
우선 이런 어댑터를 만든다.
class WarekiAdapter {
@FromJson
fun fromJson(monthJpn: Int): Wareki {
return Wareki.values().find { it.ordinal == monthJpn } ?: throw IllegalArgumentException()
}
}
moshi에 add하는 어댑터에는 FromJson 또는 ToJson이 필요합니다.
이번에는 deserialize 만이므로 FromJson 만 정의하고 json에서받은 값과 해당 enum 값을
find에서 찾고 반환합니다. 발견되지 않는 경우는 예외를 발행하는 것 같은 느낌으로 작성했다.
이것을 moshi에 add한다.
private val moshi = Moshi.Builder()
.add(WarekiAdapter()) // ここ
.add(KotlinJsonAdapterFactory())
.build()
이상.
다시 API를 호출하면 괜찮은 디시리얼라이즈 해준다.
D/TEST: Response{protocol=http/1.1, code=200, message=OK, url=http://10.0.2.2:8000/api/fetch_month_jpn/}
D/TEST: KISARAGI:class jp.co.sample.Wareki
appendix
덧붙여서, 위의 어댑터를 추가 한 상태에서 "1. enum을 문자열로받는 경우"를 수행하면 오류가 발생했습니다.
E/TEST: Expected an int but was KISARAGI at path $.month_jpn
어느 쪽이든 deserialize 해주는 방법을 모집하고 있습니다.
Reference
이 문제에 관하여(retrofit2와 모시와 enum), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/Chiku_Qiita/items/cfbc46ffae3de17a48e1
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
D/TEST: Response{protocol=http/1.1, code=200, message=OK, url=http://10.0.2.2:8000/api/fetch_month_jpn/}
D/TEST: KISARAGI:class jp.co.sample.Wareki
서수로 받으면 디시리얼라이즈 할 수 없으며 예외가 발생합니다.
E/TEST: Expected one of [MUTSUKI, KISARAGI, YAYOI, UDUKI, SATSUKI, MINADUKI, FUMIDUKI, HADUKI, NAGATUKI, KANNADUKI, SHIMOTUKI, SHIWASU, UNKNOWN] but was 1 at path $.month_jpn
어댑터 도입
이런 경우에는 어댑터를 도입하면 잘 됐다.
우선 이런 어댑터를 만든다.
class WarekiAdapter {
@FromJson
fun fromJson(monthJpn: Int): Wareki {
return Wareki.values().find { it.ordinal == monthJpn } ?: throw IllegalArgumentException()
}
}
moshi에 add하는 어댑터에는 FromJson 또는 ToJson이 필요합니다.
이번에는 deserialize 만이므로 FromJson 만 정의하고 json에서받은 값과 해당 enum 값을
find에서 찾고 반환합니다. 발견되지 않는 경우는 예외를 발행하는 것 같은 느낌으로 작성했다.
이것을 moshi에 add한다.
private val moshi = Moshi.Builder()
.add(WarekiAdapter()) // ここ
.add(KotlinJsonAdapterFactory())
.build()
이상.
다시 API를 호출하면 괜찮은 디시리얼라이즈 해준다.
D/TEST: Response{protocol=http/1.1, code=200, message=OK, url=http://10.0.2.2:8000/api/fetch_month_jpn/}
D/TEST: KISARAGI:class jp.co.sample.Wareki
appendix
덧붙여서, 위의 어댑터를 추가 한 상태에서 "1. enum을 문자열로받는 경우"를 수행하면 오류가 발생했습니다.
E/TEST: Expected an int but was KISARAGI at path $.month_jpn
어느 쪽이든 deserialize 해주는 방법을 모집하고 있습니다.
Reference
이 문제에 관하여(retrofit2와 모시와 enum), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/Chiku_Qiita/items/cfbc46ffae3de17a48e1
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
E/TEST: Expected an int but was KISARAGI at path $.month_jpn
Reference
이 문제에 관하여(retrofit2와 모시와 enum), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Chiku_Qiita/items/cfbc46ffae3de17a48e1텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)