Http 요청을 통해 서버 시간 가져오기(2)

송준희·2021년 5월 8일
0

Back

목록 보기
5/7

World Time Api를 호출해서 Response에 들어있는 datetime 값을 가져와야 했다.
datetime 값만 따로 뽑아올 수 있었지만 Api Response를 Class로 받아오고 싶었다.
그래서 Response 값을 전부 받을 수 있는 WorldClockApiResponse class를 만들었다.

data class WorldClockApiResponse(
    val abbreviation: String,
    val clientIp: String,
    val datetime: LocalDateTime,
    val dayOfWeek: Int,
    val dayOfYear: Int,
    val dst: Boolean,
    val dstFrom: String?,
    val dstOffset: Int,
    val dstUntil: String?,
    val rawOffset: Int,
    val timezone: String,
    val unixtime: Long,
    val utcDatetime: LocalDateTime,
    val utcOffset: String,
    val weekNumber: Int
)

Response를 WorldClockApiResponse class로 파싱하기 위해
val worldClockApiResponse = Gson().fromJson(httpResponse, WorldClockApiResponse::class.java)를 실행했는데 다음과 같은 에러가 발생했다.

Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 65 path $.datetime
원인은 WorldClockApiResponse의 LocalDateTime에 있었다.

    public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
        Object object = this.fromJson((String)json, (Type)classOfT);
        return Primitives.wrap(classOfT).cast(object);
    }

Gson의 fromJson()은 json 문자열 Primitive 타입으로 형변환하여 class에 저장하는데
LocalDateTime는 Primitive 타입이 아니기 때문에 문제가 발생한 것이었다.

val gson = GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .registerTypeAdapter(
                LocalDateTime::class.java,
                JsonDeserializer { json, _, _ ->
                    LocalDateTime.parse(json.asString, DateTimeFormatter.ISO_DATE_TIME)
                }).create()

문제를 해결하기 위해 GsonBuilder()를 사용했다.
GsonBuilder로 json 문자열을 파싱할 때 LocalDateTime 타입을 인식하게 했고
Response가 snack_casing으로 되어있었기 때문에 Kotlin의 naming convention인 camelCasing으로 변환하기 위해
FieldNameingPolicy를 LOWER_CASE_WITH_UNDERSCORES로 설정했다.

그 결과, WorldClockApiResponse를 이쁘게 받아올 수 있었다.

profile
오늘 달리면 내일 걸을 수 있다!

0개의 댓글