ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Gson LinkedTreeMap cast 에러 해결
    Android📱/삽질 기록... 2024. 4. 19. 21:56

    이번에 회사에서 신규 피쳐 업무를 진행하며 발생했던 문제 사항을 공유해 보겠습니다.

     

    문제 발생

     

    일단 기존에 View로 되어있던 기능을 Compose로 개선하는 과정이었습니다.

    그래서 View와 Compose가 혼합되어 있는 형태의 UI였고,

    기존 프로젝트에서는 공유 ViewModel로 activity에서 상태를 관리하고, fragment를 컨트롤하는 로직이 너무 엮여있어서, 그 의존성을 분리하는 과정에서 발생한 문제였습니다.

     

    그러다 보니 fragment -> fragment로 데이터를 넘겨줄 때 activityViewModel을 이용해서 데이터를 가져다 쓰는 구조를 변경하기 위하여, bundle을 통해서 데이터를 넘겨주는 방식으로 변경을 하는 중이었습니다.

     

    List 형태의 데이터를 넘겨주어야 했고, List를 받아서 다음 Fragment에서 데이터를 보여주는 과정이었습니다.

    문제는 B fragment에서 arguments를 통해서 데이터를 꺼내 LazyColumn으로 데이터를 뿌려주려고 할 때 문제가 발생했습니다.

    java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to ${사용하려던 data class}

     

    해당 에러가 발생하며 앱이 종료되는 현상을 마주하게 되었습니다.

     

    해결 과정

     

    가설

     

    1. Compose 내부에서 객체를 저장할 때 LinkedTreeMap을 사용하고 있고, 이를 캐스팅하려다가 앱이 종료된다.

     

    2. data class 자체에 문제가 있을 것이다.

     

    3. items 혹은 item을 잘 못 사용해서 그렇다

     

    검증

     

    1.

    만약 맞다면 Compose Runtime의 문제일 것이고, 그렇다면 Preview로 동작하지 않아야 하는데 Preview는 동작했다.

    그리고 데이터를 하드 코딩으로 넣었을 때도 문제가 없었다. 

    제일 중요한 건 Compose 내부에서 Gson을 쓸 리가 없다.

    고로 해당 가설은 거짓이라고 판단했습니다.

     

    2.

    2번 가설도 마찬가지로 하드 코딩으로 직접 넣을 때도 문제가 없었고,

    데이터를 받아오자마자 객체에 접근해서 로그를 찍거나 index로 접근해서 데이터를 확인해도 문제가 없었으므로 거짓이라고 판단했습니다.

     

    3.

    이 부분은 직접 item, items 등을 바꾸어 적용했는데도 전부 같은 에러가 발생하였습니다.

    고로 이 가설도 거짓

     

    내가 예측한 부분이 전부 아니었고, 좀 더 근본적으로 Gson ClassCastException이 발생하는 원인을 찾아보기로 하였습니다.

    해당에러는 Gson에서 List를 역직렬화할 때 일어나는 에러로 제네릭이 사라지면서 Gson이 List 내부의 객체가 뭔지 알지 못해서 일단 LInkedTreeMap으로 캐스팅하려다가 일어나는 문제라는 부분에 집중을 하였습니다.

     

    해결

     

    문제의 원인은 결과적으로 데이터를 넘겨주고 받는 부분에 있었습니다.

    프로젝트에서 번들에 데이터를 넘길 때 getParcelable()류의 함수를 사용하지 않고, 직렬화를 해서 String 형태로 저장하고, 다시 역직렬화를 해서 받아서 사용하는 형태로 진행을 하고 있었습니다.

     

    바로 이 부분에서 List를 넘겨줄 경우 Gson이 역직렬화를 진행할 때

    List라는 것을 알고 실행이 되어서 Index로 접근도 되고 로그도 잘 나오지만

    직접 데이터를 사용하려고 접근하는 순간 내부 객체는 무슨 class인지 모르기 때문에 LinkedTreeMap으로 캐스팅을 시도하고, 에러가 발생하는 문제였다.

     

    얼마나 헤맸는지.... 결국 직렬화 역직렬화를 하지 않고, getParcelable()을 이용해서 문제를 해결하였다....

     

    아쉬운 점

     

    로그를 찍을 때부터 데이터에 직접 접근해보려고 했으면 좀 더 빨리 해결할 수 있었을 텐데 그냥 인덱스로 잘 찍히니까 문제없겠구나 했던 게 시간을 많이 잡아먹게 된 이유 같다....

     

    결론

     

    - fragment에서 Compose로 data 보여주려다가 에러남

    - Compose 문제인 줄 알고, 한참 헤매었는데 Gson으로 직렬화한 데이터 역직렬화로 받아올 때 나는 문제였음

    - putParcelableArrayList(), getParcelableArrayList() 써서 해결

     

    추가

    putParcelableArrayList, getParcelableArrayList 류의 함수를 쓸 때는 data class에 @Parcelize, Parcelable을 꼭 써야 하며

    티라미수 아래 버전에는 버그가 발생할 수 있으니 버전 분기가 필수입니다.

Designed by Tistory.