3

I have an app that uses retrofit for api calls. I'm trying to add pro guard, but it keeps failing with one of the responses.

FATAL EXCEPTION: main Process: com.karriapps.smartsiddurlite, PID: 13387
  java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
       at com.karriapps.smartsiddur.util.b$3.a(SourceFile:255)
       at com.karriapps.smartsiddur.util.b$3.success(SourceFile:252)
       at retrofit.CallbackRunnable$1.run(SourceFile:45)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:135)
       at android.app.ActivityThread.main(ActivityThread.java:5431)
       at java.lang.reflect.Method.invoke(Native Method)
       at java.lang.reflect.Method.invoke(Method.java:372)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:914)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)

I know for a fact that the response contains the data, it just doesn't appear to be able to deserialize it

Here is the code that failing

mElavationService.getElevation(new ElavationService.LatLng(mLocation.getLatitude(), mLocation.getLongitude()),
            BING_KEY,
            new Callback<BingElevationResponse>() {
                @Override
                public void success(BingElevationResponse bingElevationResponse, Response response) {
                    double elavation = bingElevationResponse.getResourceSets().get(0)
                            .getResources().get(0).getOffsets().get(0);
                    if (elavation > 0) {
                        mLocation.setElevation(elavation);
                    } else {
                        mLocation.setElevation(0);
                    }
                    responsesCount++;
                    if (requestsCount == responsesCount) {
                        setZmanimToLocation(mLocation);
                    }
                }

                @Override
                public void failure(RetrofitError error) {
                    Log.e(TAG, error.toString(), error.fillInStackTrace());
                    mLocation.setElevation(0);
                    responsesCount++;
                    if (requestsCount == responsesCount) {
                        setZmanimToLocation(mLocation);
                    }
                }
            });

And my pro guard file

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/orel/Android/Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Proguard Configuration for Realm (http://realm.io)
# For detailed discussion see: https://groups.google.com/forum/#!topic/realm-java/umqKCc50JGU
# Additionally you need to keep your Realm Model classes as well
# For example:
# -keep class com.yourcompany.realm.** { *; }

-keep class io.realm.annotations.RealmModule
-keep @io.realm.annotations.RealmModule class *
-keep class io.realm.internal.Keep
-keep @io.realm.internal.Keep class *
-keepnames public class * extends io.realm.RealmObject
-dontwarn javax.**
-dontwarn io.realm.**

-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose

# Allow obfuscation of android.support.v7.internal.view.menu.**
# to avoid problem on Samsung 4.2.2 devices with appcompat v21
# see https://code.google.com/p/android/issues/detail?id=78377
-keep class !android.support.v7.internal.view.menu.**,android.support.** {*;}


# Crashlytics 2.+

-keep class com.crashlytics.** { *; }
-keep class com.crashlytics.android.**
-keepattributes SourceFile, LineNumberTable, *Annotation*

# If you are using custom exceptions, add this line so that custom exception types are skipped during obfuscation:
-keep public class * extends java.lang.Exception

# In App Billing
-keep class com.android.vending.billing.**

## Google Play Services 4.3.23 specific rules ##
## https://developer.android.com/google/play-services/setup.html#Proguard ##

-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 * {
    @com.google.android.gms.common.annotation.KeepName *;
}

-keepnames class * implements android.os.Parcelable {
    public static final ** CREATOR;
}

## GSON 2.2.4 specific rules ##

# 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.** { *; }

## Joda Time 2.3

-dontwarn org.joda.convert.**
-dontwarn org.joda.time.**
-keep class org.joda.time.** { *; }
-keep interface org.joda.time.** { *; }

# OkHttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**

# Retrofit 1.X

-keep class retrofit.** { *; }
-keep class retrofit.http.** { *; }
-keep class retrofit.client.** { *; }
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }

-dontwarn com.squareup.okhttp.**
-dontwarn okio.**
-dontwarn retrofit.**
-dontwarn rx.**

-keepclasseswithmembers class * {
    @retrofit.http.* <methods>;
}

# If in your rest service interface you use methods with Callback argument.
-keepattributes Exceptions

#support design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }

# http://stackoverflow.com/questions/29679177/cardview-shadow-not-appearing-in-lollipop-after-obfuscate-with-proguard/29698051
-keep class android.support.v7.widget.RoundRectDrawable { *; }

# mixpanel
-dontwarn com.mixpanel.**

# for play services
-dontwarn org.apache.http.**
-dontwarn android.net.http.AndroidHttpClient
-dontwarn com.google.android.gms.**

##---------------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*

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.karriapps.smartsiddur.model.response.** { *; }
-keepnames public class com.karriapps.smartsiddur.model.response.**

# debug
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

Edit: I added the pojo class itself

public class BingElevationResponse {

    private List<ResourceSet> resourceSets;

    public List<ResourceSet> getResourceSets() {
        return resourceSets;
    }

    public class ResourceSet {
        private List<Resource> resources;

        public List<Resource> getResources() {
            return resources;
        }
    }

    public class Resource {
        private List<Integer> elevations;

        public List<Integer> getOffsets() {
            return elevations;
        }
    }
}

It's path is

com.karriapps.smartsiddur.model.response.BingElevationResponse

I would deeply appreciate ant help Thanks

orelzion
  • 2,452
  • 4
  • 30
  • 46
  • you say its failing with one of the responses can u give the full name of the class used for json parsing of that response? and try keeping that class and its fields explicitly or better yet use annotations(@Serializedname for gson) to match names with json reponse field names – Bhargav Feb 02 '16 at 07:44
  • Using annotations is better? I'll try that – orelzion Feb 02 '16 at 07:54
  • 1
    yes of course then gson doesnt have to reflect to get the field names that way when field names are obfuscated it doesnt affect the json field names used for psrsing as gson will be using the names in the annotation – Bhargav Feb 02 '16 at 07:59
  • Well, that didn't help. I added annotations but it still crashes with the same exception – orelzion Feb 02 '16 at 10:00
  • ah this because of inner classes try refactorin the Resource class to a separate class file or you need to add it to keep like this `-keep class com.karriapps.smartsiddur.model.response. BingElevationResponse$Resource` I would recommend refactoring into an proper class file – Bhargav Feb 02 '16 at 10:34
  • if you solved it can you tell which of the solutions I gave actually fixed your problem I'll add it to my answer, to help future readers – Bhargav Feb 03 '16 at 09:08
  • Sure, I used annotations as you suggested, the reason it didn't help me at first, is because I was hitting run after changing only the pro guard file, o it didn't actually rebuilt the app. After I realized that, I ran a rebuild and it worked – orelzion Feb 03 '16 at 12:37

1 Answers1

3

If you are using gson jackson or any such json parser libraries (I think retrofit uses one internally I'm not sure) You need to -keep any and all Pojo classes AND its FIELDS and its NAMES !

EDIT

Adding @SerializedName (in case of gson) annotations to the java pojo class fields also helps as then gson doesn't have to reflect and get the field names(which proguard changes and therefore gson will use wrong json field names to parse json). Also in order for annotation to work you need to also add -keepattributes *Annotation* to your proguard rules.

Bhargav
  • 8,118
  • 6
  • 40
  • 63
  • Thank you. If you can please see the bottom of my pro guard file, I have tried to include it -keep class com.karriapps.smartsiddur.model.response.** { *; } -keepnames public class com.karriapps.smartsiddur.model.response.** – orelzion Feb 02 '16 at 06:38