Retrofit: app crashing on a request being made after uploading apk to google play

Created on 18 Dec 2016  Â·  7Comments  Â·  Source: square/retrofit

java.lang.IllegalArgumentException: Unable to create converter for com.smsgh.hubtelpos_android.i.a
for method a.a
at f.n$a.a(Unknown Source)
at f.n$a.c(Unknown Source)
at f.n$a.a(Unknown Source)
at f.m.a(Unknown Source)
at f.m$1.invoke(Unknown Source)
at java.lang.reflect.Proxy.invoke(Proxy.java:813)
at $Proxy0.a(Unknown Source)
at com.smsgh.hubtelpos_android.Activities.LoginActivity$1.onClick(Unknown Source)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.IllegalArgumentException: class com.smsgh.hubtelpos_android.e.v declares multiple JSON fields named b
at com.google.a.b.a.i.a(Unknown Source)
at com.google.a.b.a.i.a(Unknown Source)
at com.google.a.e.a(Unknown Source)
at com.google.a.b.a.i.a(Unknown Source)
at com.google.a.b.a.i.a(Unknown Source)
at com.google.a.b.a.i.a(Unknown Source)
at com.google.a.e.a(Unknown Source)
at f.a.a.a.a(Unknown Source)
at f.m.a(Unknown Source)
at f.m.b(Unknown Source)

Most helpful comment

Disable ProGuard or exclude your model classes from obfuscation.

On Sun, Dec 18, 2016, 8:33 PM samdanTetteh notifications@github.com wrote:

@JakeWharton https://github.com/JakeWharton so please any idea on how
to solve this?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/square/retrofit/issues/2128#issuecomment-267863416,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEcPSsgtJhxhRIOklIODfMj4JokWoks5rJd7ugaJpZM4LQEsY
.

All 7 comments

Gradle file
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'

compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup:otto:1.3.5'
compile 'com.squareup.okhttp:okhttp:2.7.4'
compile 'com.squareup.okhttp:okhttp-ws:2.7.4'
compile 'com.parse.bolts:bolts-android:1.2.1'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.4'

The exception message indicates the problem. Your obfuscated object defines
multiple fields named 'b' and Gson doesn't allow that.

On Sun, Dec 18, 2016, 2:57 AM samdanTetteh notifications@github.com wrote:

Gradle file
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'

compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup:otto:1.3.5'
compile 'com.squareup.okhttp:okhttp:2.7.4'
compile 'com.squareup.okhttp:okhttp-ws:2.7.4'
compile 'com.parse.bolts:bolts-android:1.2.1'
compile 'com.fasterxml.jackson.core:jackson-databind:2.4.4'

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/square/retrofit/issues/2128#issuecomment-267808606,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEX77zT61RXg2SF5OkkCT-cUngeXqks5rJOd1gaJpZM4LQEsY
.

Thanks @JakeWharton but my object does not have any field named 'b'... please find below my object and interface method and my retrofit declaration.
And why does Gson only complain when apk us pushed to google play but works fine on debug version.

Thank you.

@FormUrlEncoded
@POST("cashiers/login/")
Call> getCashier2(@Field("phoneNumber") String phoneNumber, @Field("pin") String pin);

public class ApiResponse{
public int statusCode;

public String code = "";
public T data;


public List<Error> errors;

}

public class User extends Obj{

public static User instance;

private int id;
private int branchId;
private String name= "";
private String hubtelPosBusinessId = "";
private String phoneNumber = "";
private String pin = "";
private String status = "";
private Boolean hasChangedPassword;
private Boolean isLoggedIn;
private String location = "";
private String confirmationCode = "";

// private String address = "";

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public int getBranchId() {
    return branchId;
}

public void setBranchId(int branchId) {
    this.branchId = branchId;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getHubtelPosBusinessId() {
    if (hubtelPosBusinessId.isEmpty())
        hubtelPosBusinessId = "0";

    return hubtelPosBusinessId;
}

public void setHubtelPosBusinessId(String hubtelPosBusinessId) {
    this.hubtelPosBusinessId = hubtelPosBusinessId;
}

public String getPhoneNumber() {
    return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
    this.phoneNumber = phoneNumber;
}

public String getPin() {
    return pin;
}

public void setPin(String pin) {
    this.pin = pin;
}

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}


public Boolean getLoggedIn() {
    return isLoggedIn;
}

public void setLoggedIn(Boolean loggedIn) {
    isLoggedIn = loggedIn;
}

public String getLocation() {
    return location;
}

public void setLocation(String location) {
    this.location = location;
}

public String getConfirmationCode() {
    return confirmationCode;
}

public void setConfirmationCode(String confirmationCode) {
    this.confirmationCode = confirmationCode;
}

public Boolean getHasChangedPassword() {
    return hasChangedPassword;
}

public void setHasChangedPassword(Boolean hasChangedPassword) {
    this.hasChangedPassword = hasChangedPassword;
}


public static void initialise(InputStream inputStream){
        if (inputStream == null) {
            instance = new User();
        } else {
            try {
                instance = (User) new ObjectInputStream(inputStream).readObject();
            } catch (Exception e) {
                instance = new User();
                Utils.LogException(User.class, "Failed to retrieve User Data", e);
            }finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    Utils.LogException(User.class, "Failed to close input stream.", e);
                }
            }

        }


}





public static User getInstance(){
    if (instance == null) {
        throw new RuntimeException(("User has not been initialized"));
    }

    return instance;
}

public static void setInstance(User instance) {
    User.instance = instance;
}

public static void saveUserInfo(OutputStream outputStream) throws IOException{
    ObjectOutputStream out  = new ObjectOutputStream(outputStream);
    out.writeObject(getInstance());
    out.flush();
    out.close();
}

}

public class Obj implements Serializable {

private String statusCode = "";
private String longitude = "";
private String latitude = "";
private String createdAt = "";
private String updatedAt = "";
private Boolean isCompleted;
private String completedAt = "";
private int code;


public Obj(){


}


public String getStatusCode() {
    return statusCode;
}

public void setStatusCode(String statusCode) {
    this.statusCode = statusCode;
}

public String getLongitude() {
    return longitude;
}

public void setLongitude(String longitude) {
    this.longitude = longitude;
}

public String getLatitude() {
    return latitude;
}

public void setLatitude(String latitude) {
    this.latitude = latitude;
}

public String getCreatedAt() {
    return createdAt;
}

public void setCreatedAt(String createdAt) {
    this.createdAt = createdAt;
}

public String getUpdatedAt() {
    return updatedAt;
}

public void setUpdatedAt(String updatedAt) {
    this.updatedAt = updatedAt;
}

public int getCode() {
    return code;
}

public void setCode(int code) {
    this.code = code;
}


public Boolean getCompleted() {
    return isCompleted;
}

public void setCompleted(Boolean completed) {
    isCompleted = completed;
}

public String getCompletedAt() {
    return completedAt;
}

public void setCompletedAt(String completedAt) {
    this.completedAt = completedAt;
}

}

//FIXME:this should be more generic
public static boolean isNetworkAvailable(Context context) {
Boolean hasConnection = true;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();

    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}



public static Retrofit getHttpRequestClient(Context context){
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();


    // set your desired log level
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    httpClient.readTimeout(60, TimeUnit.SECONDS);
    httpClient.connectTimeout(60, TimeUnit.SECONDS);
    // add your other interceptors …



    // add logging as last interceptor
    httpClient.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original  = chain.request();

            Request.Builder requestBuilder = original.newBuilder()
                    .addHeader("Authorization", "Basic ZjRmN2JjMDctMjBkNC00NjFlOmIyZjgtZDNjOTBjMmRlOWQz")
                    .addHeader("X-HPOS-BUSINESS-ID", String.valueOf(HubtelPosBusiness.getInstance().getActiveBusineess().getId()))
                    .addHeader("X-LATITUDE", latitude)
                    .addHeader("X-LONGITUDE", longitude);


            Request request = requestBuilder.build();

            return chain.proceed(request);
        }
    });

    httpClient.addInterceptor(logging);

     Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(context.getResources().getString(R.string.api_base_url))
            .addConverterFactory(GsonConverterFactory.create())
            .client(httpClient.build())
            .build();


    return retrofit;
}

It's because ProGuard is obfuscating your app.

On Sun, Dec 18, 2016, 4:14 AM samdanTetteh notifications@github.com wrote:

Thanks @JakeWharton https://github.com/JakeWharton but my object does
not have any field named 'b'... please find below my object and interface
method and my retrofit declaration.
And why does Gson only complain when apk us pushed to google play but
works fine on debug version.

Thank you.

@FormUrlEncoded
@POST https://github.com/POST("cashiers/login/")
Call getCashier2(@Field https://github.com/Field("phoneNumber")
String phoneNumber, @Field https://github.com/Field("pin") String pin);

public class ApiResponse{
public int statusCode;

public String code = "";
public T data;

public List errors;

}

public class User extends Obj{

public static User instance;

private int id;
private int branchId;
private String name= "";
private String hubtelPosBusinessId = "";
private String phoneNumber = "";
private String pin = "";
private String status = "";
private Boolean hasChangedPassword;
private Boolean isLoggedIn;
private String location = "";
private String confirmationCode = "";

// private String address = "";

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public int getBranchId() {
return branchId;
}

public void setBranchId(int branchId) {
this.branchId = branchId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getHubtelPosBusinessId() {
if (hubtelPosBusinessId.isEmpty())
hubtelPosBusinessId = "0";

return hubtelPosBusinessId;

}

public void setHubtelPosBusinessId(String hubtelPosBusinessId) {
this.hubtelPosBusinessId = hubtelPosBusinessId;
}

public String getPhoneNumber() {
return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}

public String getPin() {
return pin;
}

public void setPin(String pin) {
this.pin = pin;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Boolean getLoggedIn() {
return isLoggedIn;
}

public void setLoggedIn(Boolean loggedIn) {
isLoggedIn = loggedIn;
}

public String getLocation() {
return location;
}

public void setLocation(String location) {
this.location = location;
}

public String getConfirmationCode() {
return confirmationCode;
}

public void setConfirmationCode(String confirmationCode) {
this.confirmationCode = confirmationCode;
}

public Boolean getHasChangedPassword() {
return hasChangedPassword;
}

public void setHasChangedPassword(Boolean hasChangedPassword) {
this.hasChangedPassword = hasChangedPassword;
}

public static void initialise(InputStream inputStream){
if (inputStream == null) {
instance = new User();
} else {
try {
instance = (User) new ObjectInputStream(inputStream).readObject();
} catch (Exception e) {
instance = new User();
Utils.LogException(User.class, "Failed to retrieve User Data", e);
}finally {
try {
inputStream.close();
} catch (IOException e) {
Utils.LogException(User.class, "Failed to close input stream.", e);
}
}

    }

}

public static User getInstance(){
if (instance == null) {
throw new RuntimeException(("User has not been initialized"));
}

return instance;

}

public static void setInstance(User instance) {
User.instance = instance;
}

public static void saveUserInfo(OutputStream outputStream) throws IOException{
ObjectOutputStream out = new ObjectOutputStream(outputStream);
out.writeObject(getInstance());
out.flush();
out.close();
}

}

public class Obj implements Serializable {

private String statusCode = "";
private String longitude = "";
private String latitude = "";
private String createdAt = "";
private String updatedAt = "";
private Boolean isCompleted;
private String completedAt = "";
private int code;

public Obj(){

}

public String getStatusCode() {
return statusCode;
}

public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}

public String getLongitude() {
return longitude;
}

public void setLongitude(String longitude) {
this.longitude = longitude;
}

public String getLatitude() {
return latitude;
}

public void setLatitude(String latitude) {
this.latitude = latitude;
}

public String getCreatedAt() {
return createdAt;
}

public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}

public String getUpdatedAt() {
return updatedAt;
}

public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}

public int getCode() {
return code;
}

public void setCode(int code) {
this.code = code;
}

public Boolean getCompleted() {
return isCompleted;
}

public void setCompleted(Boolean completed) {
isCompleted = completed;
}

public String getCompletedAt() {
return completedAt;
}

public void setCompletedAt(String completedAt) {
this.completedAt = completedAt;
}

}

//FIXME:this should be more generic
public static boolean isNetworkAvailable(Context context) {
Boolean hasConnection = true;
ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();

return activeNetworkInfo != null && activeNetworkInfo.isConnected();

}

public static Retrofit getHttpRequestClient(Context context){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.readTimeout(60, TimeUnit.SECONDS);
httpClient.connectTimeout(60, TimeUnit.SECONDS);
// add your other interceptors …



// add logging as last interceptor
httpClient.addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original  = chain.request();

        Request.Builder requestBuilder = original.newBuilder()
                .addHeader("Authorization", "Basic ZjRmN2JjMDctMjBkNC00NjFlOmIyZjgtZDNjOTBjMmRlOWQz")
                .addHeader("X-HPOS-BUSINESS-ID", String.valueOf(HubtelPosBusiness.getInstance().getActiveBusineess().getId()))
                .addHeader("X-LATITUDE", latitude)
                .addHeader("X-LONGITUDE", longitude);


        Request request = requestBuilder.build();

        return chain.proceed(request);
    }
});

httpClient.addInterceptor(logging);

 Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(context.getResources().getString(R.string.api_base_url))
        .addConverterFactory(GsonConverterFactory.create())
        .client(httpClient.build())
        .build();


return retrofit;

}

—
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/square/retrofit/issues/2128#issuecomment-267811021,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEcC9svFhjdXkUwCqQQPkQOajPdapks5rJPmBgaJpZM4LQEsY
.

@JakeWharton so please any idea on how to solve this?

Disable ProGuard or exclude your model classes from obfuscation.

On Sun, Dec 18, 2016, 8:33 PM samdanTetteh notifications@github.com wrote:

@JakeWharton https://github.com/JakeWharton so please any idea on how
to solve this?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/square/retrofit/issues/2128#issuecomment-267863416,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEcPSsgtJhxhRIOklIODfMj4JokWoks5rJd7ugaJpZM4LQEsY
.

@JakeWharton ok so that worked!! Yaaay now can meet my dead line. Almost rewrote some parts of my entire code...hmm
Moving forward ProGaurd really helped in shrinking my apk to almost half the size. I will work on enabling it again and find a way remove retrofit2 from obfuscation.

But enabling proGaurd also did not allow me to build a signed apk until i added the below snippet to my proGuard rules file.

Maybe you can look into why proGaurd complains about retrofit2.

Thanks again.

Add project specific ProGuard rules here.

By default, the flags in this file are appended to flags specified

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 businessName to the JavaScript interface

class:

-keepclassmembers class fqcn.of.javascript.interface.for.webview {

public *;

}

-dontwarn okio.*
-dontwarn com.fasterxml.
*
-dontwarn io.mpos.*
-dontwarn jp.wasabeef.
*
-dontwarn org.simpleframework.xml.*
-dontwarn retrofit2.
*

Was this page helpful?
0 / 5 - 0 ratings