Using GSON with proguard enabled

25,048

Solution 1

Variable names will be obfuscated with proguard, leaving you with something like

private String a;

Instead of

private String descripcionCategoria;

You can add proguard rules so some classes don't get obfuscated. I got away with it using these:

-keepattributes Signature
# POJOs used with GSON
# The variable names are JSON key values and should not be obfuscated
-keepclassmembers class com.example.apps.android.Categorias { <fields>; }
# You can apply the rule to all the affected classes also
# -keepclassmembers class com.example.apps.android.model.** { <fields>; }

If your POJO class name is also used for parsing then you should also add the rule

-keep class com.example.apps.android.model.** { <fields>; }

In your case, annotations are not used, you would need this if you do

# Keep the annotations
-keepattributes *Annotation*

Another way to solve this problem is to use the SerializedName annotation and let the class get obfuscated. For this you will still need the -keepattributes *Annotation* rule.

import com.google.gson.annotations.SerializedName

@SerializedName("descripcionCategoria")
private String descripcionCategoria;

Solution 2

If you want your models still being obfuscated use annotation @SerializedName("name_of_json_field"). It will let gson know the real name of the field.

I believe you will also need

-keepattributes *Annotation*

to keep your annotations from obfuscation

Solution 3

You need to exclude obfuscating of your model classes like below where I excluded all model classes in package in.intellicode.webservices.models

-keep class in.intellicode.webservices.models.** { *; }
-keep class in.intellicode.models.** { *; }
-keep class in.intellicode.events.*{ *; }

-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }

Solution 4

When you apply proguard script to your model classes it obfuscates their names and their properties' names. So after obfuscation of String descripcionCategoria; you will have something like String aaaa;

Gson works through java reflection and it will try to use a property name while parsing data. So, after applying obfuscation to model classes you won't be able to parse your data.

So, exclude model classes from your proguard script and you will be able to parse again.

Solution 5

Use proguard-rules from default rule of Gson

# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

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

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

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

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

# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

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

Share:
25,048
Eder Ramírez Hernández
Author by

Eder Ramírez Hernández

Updated on August 28, 2021

Comments

  • Eder Ramírez Hernández
    Eder Ramírez Hernández almost 3 years

    My code works perfectly without proguard, but GSON doesn't work when proguard is enabled.

    This is the part of code where it doesn't works

    JSONArray mensaje = response.getJSONArray("categorias");
    // Parsear con Gson
    Categorias[] categorias = gson.fromJson(mensaje.toString(), Categorias[].class);
    Log.d("mainfragment","desc categoria "+categorias[0].getDescripcionCategoria());
    

    mainfragment's log prints null

    # Output
    D/Dato categorias﹕ Respuesta: {"categorias":[{"idCategoria":"22","imagenCategoria":"ic_aseguradora","descripcionCategoria":"Aseguradoras"},{"idCategoria":"24","imagenCategoria":"ic_bar","descripcionCategoria":"Bares"},{"idCategoria":"12","imagenCategoria":"ic_boutique","descripcionCategoria":"Boutiques"},{"idCategoria":"6","imagenCategoria":"ic_cafe","descripcionCategoria":"Cafeterias"},{"idCategoria":"21","imagenCategoria":"ic_ciber","descripcionCategoria":"Ciber"},{"idCategoria":"10","imagenCategoria":"ic_estetica","descripcionCategoria":"Estéticas"},{"idCategoria":"1","imagenCategoria":"ic_farmacia","descripcionCategoria":"Farmacias"},{"idCategoria":"7","imagenCategoria":"ic_ferreteria","descripcionCategoria":"Ferreterias"},{"idCategoria":"16","imagenCategoria":"ic_gas","descripcionCategoria":"Gas"},{"idCategoria":"23","imagenCategoria":"ic_gasolinera","descripcionCategoria":"Gasolineras"},{"idCategoria":"4","imagenCategoria":"ic_gym","descripcionCategoria":"Gimnasios"},{"idCategoria":"2","imagenCategoria":"ic_hotel","descripcionCategoria":"Hoteles"},{"idCategoria":"15","imagenCategoria":"ic_lavanderia","descripcionCategoria":"Lavanderias"},{"idCategoria":"19","imagenCategoria":"ic_muebleria","descripcionCategoria":"Mueblerias"},{"idCategoria":"25","imagenCategoria":"ic_optica","descripcionCategoria":"Ópticas"},{"idCategoria":"20","imagenCategoria":"ic_pasteleria","descripcionCategoria":"Pastelerias"},{"idCategoria":"17","imagenCategoria":"ic_pizza","descripcionCategoria":"Pizzerías"},{"idCategoria":"13","imagenCategoria":"ic_purificadora","descripcionCategoria":"Purificadoras de agua"},{"idCategoria":"5","imagenCategoria":"ic_restaurant","descripcionCategoria":"Restaurantes"},{"idCategoria":"11","imagenCategoria":"ic_ropa","descripcionCategoria":"Ropa"},{"idCategoria":"9","imagenCategoria":"ic_salon","descripcionCategoria":"Salones de fiestas"},{"idCategoria":"3","imagenCategoria":"ic_sonido","descripcionCategoria":"Sonidos"},{"idCategoria":"28","imagenCategoria":"ic_taqueria","descripcionCategoria":"Taquería"},{"idCategoria":"8","imagenCategoria":"ic_taxi","descripcionCategoria":"Taxis"},{"idCategoria":"14","imagenCategoria":"ic_tortilleria","descripcionCategoria":"Tortillerias"},{"idCategoria":"27","imagenCategoria":"ic_veterinaria","descripcionCategoria":"Veterinarias"},{"idCategoria":"18","imagenCategoria":"ic_vinateria","descripcionCategoria":"Vinaterías"},{"idCategoria":"26","imagenCategoria":"ic_zapateria","descripcionCategoria":"Zapaterías"}],"estado":1}
    D/mainfragment﹕ desc categoria null
    

    This are my proguard rules

    #GoogleMaps
    -keep class * extends java.util.ListResourceBundle {
        protected Object[][] getContents();
    }
    
    -keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
        public static final *** NULL;
    }
    
    -keepnames @com.google.android.gms.common.annotation.KeepName class *
    -keepclassmembernames class * {
        @ccom.google.android.gms.common.annotation.KeepName *;
    }
    
    -keepnames class * implements android.os.Parcelable {
        public static final ** CREATOR;
    }
    
    
    
    #Volley?
    
    -optimizationpasses 5
    -dontusemixedcaseclassnames
    -dontskipnonpubliclibraryclasses
    -dontpreverify
    -verbose
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    
    
    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Application
    -keep public class * extends android.app.Service
     -keep public class * extends android.content.BroadcastReceiver
     -keep public class * extends android.content.ContentProvider
     -keep public class * extends android.app.backup.BackupAgentHelper
     -keep public class * extends android.preference.Preference
     -keep public class com.android.vending.licensing.ILicensingService
    -dontnote com.android.vending.licensing.ILicensingService
    
    -keepclassmembers class * implements java.io.Serializable {
         static final long serialVersionUID;
         private static final java.io.ObjectStreamField[] serialPersistentFields;
         private void writeObject(java.io.ObjectOutputStream);
         private void readObject(java.io.ObjectInputStream);
         java.lang.Object writeReplace();
         java.lang.Object readResolve();
     }
    
    
     -keepclasseswithmembernames class * {
         native <methods>;
     }
    
    
     -keepclasseswithmembers class * {
         public <init>(android.content.Context, android.util.AttributeSet);
     }
    
    
     -keepclasseswithmembers class * {
         public <init>(android.content.Context, android.util.AttributeSet, int);
     }
    
    
    -keepclassmembers class **.R$* {
       public static <fields>;
     }
    
     -keepclassmembers class * extends android.app.Activity {
        public void *(android.view.View);
     }
    
    
     -keepclassmembers enum * {
         public static **[] values();
         public static ** valueOf(java.lang.String);
     }
    
    -keep public class * {
         public protected *;
     }
    
    
    
     -keep class * implements android.os.Parcelable {
       public static final android.os.Parcelable$Creator *;
     }
    
     -keep class android.support.v7.widget.SearchView
     -keep class android.support.v7.widget.**{*;}
     -keep class android.support.v4.app.** { *; }
     -keep interface android.support.v4.app.** { *; }
     -keep class com.actionbarsherlock.** { *; }
     -keep interface com.actionbarsherlock.** { *; }
     -keep class com.android.volley.** { *; }
     -keep interface com.android.volley.** { *; }
     -keepattributes *Annotation*
    
    
    ##---------------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
    # For using GSON @Expose annotation
    #-keepattributes *Annotation*
    -keepattributes EnclosingMethod
    
    # 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 Categorias.data.model.** { *; }
     -keep class Categorias.** { *; }
    
    # Application classes that will be serialized/deserialized over Gson
    -keep class com.google.gson.examples.android.model.** { *; }
    -keep class com.puertosoft.appcomercialdelpuerto.android.model.** { *; }
    -keep class com.puertosoft.appcomercialdelpuerto.model.** { *; }
    -keep class com.puertosoft.appcomercialdelpuerto.model.User { *; }
    
    # Add the gson class
    -keep public class com.google.gson
    
    # Add any classes the interact with gson
    -keep class com.puertosoft.appcomercialdelpuerto.models.ChatModel { *; }
    -keep class com.puertosoft.appcomercialdelpuerto.models.FeedModel { *; }
    -keep class com.puertosoft.appcomercialdelpuerto.android.models.ChatModel { *; }
    -keep class com.puertosoft.appcomercialdelpuerto.android.models.FeedModel { *; }
    
    -libraryjars /build/intermediates/pre-dexed/debug/gson-2.3-08958b96da94c86264ec30e35a9d524bac95d2df.jar
    
    
    
    
    -printmapping outputfile.txt
    -renamesourcefileattribute SourceFile
    #-keepattributes SourceFile,LineNumberTable
    

    This is the affected class

    public class Categorias {
    
        private String idCategoria;
        private String descripcionCategoria;
        private String imagenCategoria;
    
        public Categorias(String idCategoria, String descripcionCategoria, String imagenCategoria){
            this.idCategoria=idCategoria;
            this.descripcionCategoria=descripcionCategoria;
            this.imagenCategoria=imagenCategoria;
        }
    
        public String getIdCategoria(){
            return idCategoria;
        }
    
        public String getDescripcionCategoria(){
            return descripcionCategoria;
        }
    
        public String getImagenCategoria(){
            return imagenCategoria;
        }
    
    }
    
  • Sebastian
    Sebastian almost 9 years
    A similar question
  • Jemshit Iskenderov
    Jemshit Iskenderov over 5 years
    Do you know any use case where POJO class name should not be obfuscated? (other than reflection)
  • Bharadwaj Giridhar
    Bharadwaj Giridhar about 3 years
    Thank you so much, -keep class com.company.model.** { ; } -keepclassmembers class com.company.model. {<fields>;} Worked for me!