Android

[android gson] gson.fromJson으로 데이터를 가져오지 못할 때 확인해야할 사항(코드 난독화)

gson.fromJson 라이브러리 사용시 난독화 이슈

gson라이브러리를 이용하여, json타입의데이터를 가져오는 작업을 하였다. 정상적으로 동작하던 코드가 난독화를 하고 난 후부터 동작을 제대로 하지 않는 문제가 발생하였다. 예전에도 이런 케이스가 있었으나 이번엔 좀 다른 부분이 있다.

■build.gradle(:app)

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        debug {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

■DownModel

public class DownModel {
    int eventRound;
    String eventDate;
    String winnerNumbers;
    int bonusNumber;


    public DownModel(){

    }


    public int getEventRound() {
        return eventRound;
    }

    public void setEventRound(int eventRound) {
        this.eventRound = eventRound;
    }

    public String getEventDate() {
        return eventDate;
    }

    public void setEventDate(String eventDate) {
        this.eventDate = eventDate;
    }

    public String getWinnerNumbers() {
        return winnerNumbers;
    }

    public void setWinnerNumbers(String winnerNumbers) {
        this.winnerNumbers = winnerNumbers;
    }

    public int getBonusNumber() {
        return bonusNumber;
    }

    public void setBonusNumber(int bonusNumber) {
        this.bonusNumber = bonusNumber;
    }


    @Override
    public String toString() {
        return "WinerNumbers [eventRound=" + eventRound + ", eventDate=" + eventDate + ", winnerNumbers=" + winnerNumbers + ", bonusNumber=" + bonusNumber + "]";
    }
}

■ Activity클래스 내에서 Gson 사용 코드

//getResponseData :
[
{'eventRound':'913','winnerNumbers':'6,14,16,21,27,37','bonusNumber':'40','eventDate':'2020.05.30'}
,{'eventRound':'912','winnerNumbers':'5,8,18,21,22,38','bonusNumber':'10','eventDate':'2020.05.23'}
]

DownModel[] model = gson.fromJson(getResponseData.toString(), DownModel[].class);
if(model!=null&& model.length > 0) {
   for (DownModel item : model) {
	   Log.d(DefaultSettings.TAG, "#### : saveData :" + item.toString());
   }
}

로그 내용
#### : saveData :WinerNumbers [eventRound=0, eventDate=null, winnerNumbers=null, bonusNumber=0]    

로그를 찍었으나 모든 데이터가 없다. 왜 이런 현상이 발생하는 것일까?

정상적으로 동작하던 로직이 코드 난독화를 하였더니 제대로 동작하지 않는다. 그해서 난독화에서 예외처리를 하였다.

■progudard-rules.pro

##—————Begin: proguard configuration for Gson ———-
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
-keepattributes *Annotation*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }

# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

##—————End: proguard configuration for Gson ———-

하지만 여전히 문제가 있다. DownModel을 배열로 받아서 발생하는 것일까?

model.length 값을 찍어보아도 데이터 개수는 정상이다. 혹시나 하는 마음에 코딩 방식을 바꾸어 보아도 여전히 동일한 문제가 발생하였다

Type collectionType = new TypeToken<Collection<DownModel>>(){}.getType();
Collection<DownModel> model = gson.fromJson(getResponseData.toString(), collectionType);

for문을 돌려, 데이터를 찍어보았다. 아뿔싸!!!, 데이터 개수는 맞으나… 데이터가 비어있다.

2020-06-03 14:28:58.748 : ####  : winerNumbers[0].toString() :WinerNumbers [eventRound=0, eventDate=null, winnerNumbers=null, bonusNumber=0]
2020-06-03 14:28:58.748 : ####  : winerNumbers[1].toString() :WinerNumbers [eventRound=0, eventDate=null, winnerNumbers=null, bonusNumber=0]

난독화 때문에 DownModel 클래스의 멤버변수도 난독화되어 매칭인되서 데이터 발생하는 문제일까, 싶어서 SerializeName 어노테이션도 사용해보았고, DownModel 클래스의 난독화도 제외 시켜보았다. 하지만 여전히 증상은 동일하다.

public class DownModel{

    @SerializedName("eventRound")
    int eventRound;

    @SerializedName("eventDate")
    String eventDate;

    @SerializedName("winnerNumbers")
    String winnerNumbers;

    @SerializedName("bonusNumber")
    int bonusNumber;
    
    ......................
    
public class DownModel implements Serializable {
    int eventRound;
    String eventDate;
    String winnerNumbers;
    int bonusNumber;
    
    ..........................
public class DownModel implements Serializable {

    @SerializedName("eventRound")
    int eventRound;

    @SerializedName("eventDate")
    String eventDate;

    @SerializedName("winnerNumbers")
    String winnerNumbers;

    @SerializedName("bonusNumber")
    int bonusNumber;
    ...................

결국은, gson.fromJosn이 일을 제대로 하고 있지 않다는 뜻이다. 몇 시간의 삽질 끝에 원인을 찾았다.

원인은 새로운 R8 코드 난독화였다. R8 정보는 링크를 클릭하자. 해결방법은 2가지가 있다

첫번째 방법은 gradle.properties파일을 열고 android.enableR8=false 처리하면 된다.

두번째 방법은 proguard-rules.pro 파일에 R8 방지코드를 추가한다.

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

두가지 방법 중에 아무 방법이나 사용해도 문제는 되지않지만, 두번째 방법을 추천한다. 아무 이유없이 R8을 만들었겠는가????

gson 관련 자료

https://github.com/google/gson/blob/master/UserGuide.md

https://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples

https://stackoverflow.com/questions/36628427/gson-fromjson-with-complex-jsonobject-not-working

https://howtodoinjava.com/gson/gson-parse-json-array/

https://stackoverflow.com/questions/16210787/gson-fromjson-returns-object-with-null-attrubutes

https://stackoverflow.com/questions/16563916/proguard-issue-while-using-gson

https://stackoverflow.com/questions/23826171/proguard-for-android-and-gson

https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg

https://www.python2.net/questions-332776.htm

https://miniminis.github.io/2020/03/02/android-proguard/

Leave a Reply

error: Content is protected !!