[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