티스토리 뷰

[Android] Retrofit HTTP Converter 결과값 파싱이 null 로 올 때 ☠️

안드로이드 앱 에서 Retrofit 을 통해 HTTP 통신(POST)을 했을 때, 일부 값이 응답에는 제대로 온 것을 확인 하였으나, Converter.Factory() 를 통과하면 null 로 값이 떨어지는 이슈가 있어서 삽질을 좀 하였다..(원인은 정말 어이가 없었다는 결말)

debug 상황 재현

interface MyService {
    /**
     * # 거래 id 생성 for 등록
     */
    @POST("/MyService")
    suspend fun postMyService(@Body body: MyServiceParams): MyServiceModel?
}

회사 프로젝트 코드를 그대로 가져올 수는 없으니 해당 인터페이스를 사용하여 레스로핏 서비스를 빌드 한다고 가정한다. 이때 요청 body 의 경우는 응답은 로그상 잘 받아온 것으로 확인되어 확인할 필요는 없고 응답으로 떨어지느 MyServiceModel 과 ConverterFactory 를 붙여줄 때 넘기는 컨버터에 버그가 있다고 판단했다.

    return Retrofit.Builder()
        .baseUrl(baseUrl)
        .client(getHttpClient())
        .addConverterFactory(getConverterFactory(envelopeClass))
        .addConverterFactory(defaultConverterFactory)
        .build()
        .create()

현재 프로젝트에서 사용중인 레트로핏 빌드를 하는 사내 api 가 있는데 여기서 addConverterFactory 를 통해서 컨버터 팩토리를 붙여준다.

예를 들어, 응답이 아래와 같다면

{
  "Result": {
    "ResultCode": "string",
    "ResultMessage": "string",
    "ResultData": {
      "name": "string",
      "nickname": "string"
    }
  },
  "ResultBase": {
    "ErrorMsg": "string",
    "ErrorCode": "string",
  }
}

이런식으로 응답이 오는 경우, 여기서 응답이 성공한 경우에는 ResultData 항목(이름, 닉네임)만 받아서 처리할 수 있게 데이터를 컨버팅 하여 보내주는 식이다.

이를통해 api 그룹 별로 각 결과가 동일한 형식으로 오기 때문에, 매번 새로운 데이터 클래스에 중복 정의해야하는 비효율 또한 개선이 가능하다. (즉 ResultData 만 별도로 제네릭 타입으로 빼서 정의 해 두면 된다.)

data class MyServiceModel(

    @SerializedName("Name")
    val name: String,

    @SerializedName("NickName")
    val nickname: String,
)

무튼, 그리하여 우리가 필요한 데이터는 위와 같은 형식의 데이터가 된다. 여기 까지 봤을 때 아무 문제가 없어보인다.

하지만! 앱을 run 시켜보면..

D/OkHttp: {"Result":{"ResultCode":"000","ResultMessage":"success","ResultData":{"name":"kim","nickname":"wow"}},"ResultBase":{"ReturnDomain":"0","ReturnCode":"000","ReturnValue":null,"ErrorMessage":null,"ProcCnt":0}}

요런식으로 Log 상에는 찍여서 제대로 응답이 온 것을 확인 할 수 있다. 하지만! 계속 실제 사용처에서 출력 값은 null 이 나왔다.

하여 파싱하는 곳을 break point 로 걸어 디버그 해본 결과, 기본 result (resultCode, resultMessage 등) 영역의 데이터는 잘 파싱이 되는 듯 하였지만, 서비스 모델의 부분은 null 로 파싱되는 문제가 발견되었다.

"왜 되지" 보다 심각한 "왜 안되지"

그런데 아무리 코드를 둘러보고, 파싱하는 부분을 다르게 바꿔보고 해볼 수 있는 건 다 해보았지만 안되었고 코드상으로 문제가 전혀 없어보였다. 도대체 왜 안되지?

그러다 기적같이 혹시 하는 생각으로 아래 녀석을 의심하게된다.

@SerializedName

@SerializedName 은 gson 파싱 시, 파싱 데이터의 타겟 이름을 지칭하고 이를 변환하여 우리가 정해준 변수명을 가지는 타입으로 적절하게 변환해주는 역할을 하는데 이 녀석이 잘못 동작하는거 아닌가 하는 킹리적 갓심을 하게 된다.

import com.서드파티라이브러리.gson.annotations.SerializedName

그런데 진짜 이왜진! 심상치 않은 녀석이 import 되어있었다. 최근에 추가된 라이브러리로 내부적으로는 gson 어노테이션과 내용은 동일 하였으나, 이것이 문제가 되는 것 같았다.

import com.google.gson.annotations.SerializedName

이거 바꿔서 되면 정말 어이없을 것 같은데 하는 마음으로 위 import 로 교체 하고 재빌드 후 실행하였다.

결과는? ... 아주 잘 동작한다.

더 황당 했던 것은 IDE 에서 import 할 수 있는 어노테이션이 중복인데도 불구하고 이를 선택하겠냐는 물음도 없이 문제의 패키지를 import 하였다는 점이다.

그래도 해결되서 정말 기뻤고 앞으로는 IDE를 좀 더 의심해보고 import 문도 debug 항목에 포함 해야겠다는 다짐을 하게되었다.

2022.08.23 - [SELECT *] - [Android] 해상도별 drawable 이미지 리소스 추가하기 (dpi 별)

2022.04.24 - [SELECT *] - [Hilt] Hilt Gradle 빌드 설정하기

2022.04.23 - [SELECT *] - [Hilt] Hilt 를 사용 하면 좋은 점 (Dagger2 에비해 장점)

 
댓글
최근에 올라온 글
최근에 달린 댓글
네이버 이웃추가
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함