IT 프로그래밍-Android

Retrofit + spring 사용 시 JsonObject 파싱 에러

godsangin 2020. 6. 18. 15:13
반응형

안녕하세요. 오늘은 최근 서버+클라이언트 개발하는 과정에서 겪게된 오류에 대한 글을 공유해볼까합니다.

 

클라이언트와 서버를 함께 개발하려니 머리가 아주 복잡해지더군요..ㅠㅠㅠ

api포멧도 맞춰야하고, 서버 테스팅을 위해 하루에 commit만 몇번을 했는지...

 

각설하고, 오늘 겪은 이슈에 대해 이야기해보겠습니다.

 

많은 분들이 안드로이드 통신을 위해 Retrofit 라이브러리를 사용하실텐데요 !!

혹시 올바른 Json형식으로 서버에서 보낸 응답을 클라이언트에서 제대로 받지 못하는 현상을 겪으신 적이 있으신가요 ?? 아래의 오류와 함께 말이죠..!

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 10 path $.body

분명 Json형식과 Retrofit응답 형식은 아래와 같이 올바르게 작성되었는데 이처럼 계속해서 오류가 발생하게됩니다..

 

package com.myhome.realload.model

import org.json.JSONObject

class ApiResponse: JSONObject() {
    var responseCode:Int? = 0
    var body:Map<String, Any>? = null
    override fun toString(): String {
        return responseCode.toString() + body.toString()
    }
}
package com.myhome.realload.utils

import com.google.gson.JsonObject
import com.myhome.realload.model.ApiArrayResponse
import com.myhome.realload.model.ApiResponse
import com.myhome.realload.model.Place
import com.myhome.realload.model.User
import retrofit2.Call
import retrofit2.http.*

@JvmSuppressWildcards
interface RetrofitAPI {
    ...
    @GET("/friends/uid/{uid}")
    fun getFriends(@Path("uid") uid:Long):Call<ApiResponse>
	...
}

몇 번의 테스트 결과 Spring에서 작성된 JSONObject객체와 Retrofit통신에서 받는 JsonObject객체가 jackson라이브러리와 gson라이브러리로 서로 다른 형식을 갖고 있어 Json객체를 다른 방식으로 파싱하고 있었습니다..!

따라서 클라이언트에서 커스텀한 ApiResponse객체를 사용하는 대신 gson라이브러리의 JsonObject객체를 사용하여 문제를 해결할 수 있었습니다.

아래는 gson라이브러리의 JsonObject객체를 사용한 Json파싱 예제입니다.

package com.myhome.realload.utils

import com.google.gson.JsonObject
import com.myhome.realload.model.ApiArrayResponse
import com.myhome.realload.model.ApiResponse
import com.myhome.realload.model.Place
import com.myhome.realload.model.User
import retrofit2.Call
import retrofit2.http.*

@JvmSuppressWildcards
interface RetrofitAPI {
    ...
    @GET("/friends/uid/{uid}")
    fun getFriends(@Path("uid") uid:Long):Call<JsonObject>
	...
}
...

val apiResult = retrofitAPI.getFriends(uid)
val retrofitCallback = object : Callback<JsonObject> {
            override fun onFailure(call: Call<JsonObject>, t: Throwable) {
                t.printStackTrace()
            }

            override fun onResponse(
                call: Call<JsonObject>,
                response: Response<JsonObject>
            ) {
                val result = response.body()
                if((result?.get("responseCode")?.asInt) == 200){
                    val bodyArray = result?.get("body")?.asJsonArray ?: JsonArray()
                    val users = ArrayList<User>()
                    for(userResult in bodyArray){
                        val user = User()
                        user.name = userResult.asJsonObject.get("name").asString
                        user.locationPermission = userResult.asJsonObject.get("locationPermission").asInt
                        user.id = userResult.asJsonObject.get("id").asLong
                        users.add(user)
                    }
                }

            }
        }
        apiResult.enqueue(retrofitCallback)
        ...

 

Json관련한 오류가 발생했다면 한번 참고해볼만한 이슈일것 같습니다.