Reputation: 1421
I have created a REST web service using SSL, i.e., https://api.bmcstudios.org
The endpoint that I am trying to hit is:
GET https://api.bmcstudios.org/member
The expected response is
{
"members": [
{
"memberId": "5c4e448d46e0fb0001656a46",
"email": "[email protected]",
"displayName": "username",
"firstName": "First",
"lastName": "Last",
"address": {
"street_1": "Street Address 1",
"street_2": "",
"city": "City",
"state": "ST",
"zipCode": 55555,
"country": "US"
},
"phone": "123-456-7890",
"roles": [
{
"id": "5c47fe53473d4ad05bdf99f5",
"role": "ROLE_MEMBER"
}
]
}
]
}
I receive this response when I use Postman, and when I run the Android emulator Pixel 2 XL API 28
.
When I deploy my build via the Android App Bundle in the latest version of Android Studio 3.3 to the google play store, via the Internal Test Track
as well as Production Track
I am able to reach my web service. But the response that I am returned is empty!
Here are what my logs show as the response:
I/System.out: appWebservice.getMemberDetails(): {"members":[{},{},{}]}
The structure is present, but the Member object within the array does not show up. Here is my Java code below:
Retrofit2 Interface
public interface AppWebservice {
String API_URL = "https://api.bmcstudios.org/";
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
Retrofit RETROFIT = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
// MEMBER
@GET("member")
Call<MemberResponse> getMemberDetails(
@HeaderMap Map<String, String> headers);
}
Member Response Object
@Getter
@Setter
@NoArgsConstructor
public class MemberResponse implements Serializable {
@SerializedName("members")
@Expose
private List<Member> members;
@Getter
@Setter
@NoArgsConstructor
public class Member implements Serializable {
@SerializedName("memberId")
@Expose
private String memberId;
@SerializedName("email")
@Expose
private String email;
@SerializedName("displayName")
@Expose
private String displayName;
@SerializedName("firstName")
@Expose
private String firstName;
@SerializedName("lastName")
@Expose
private String lastName;
@SerializedName("picture")
@Expose
private String picture;
@SerializedName("address")
@Expose
private Address address;
@SerializedName("phone")
@Expose
private String phone;
@SerializedName("roles")
@Expose
private List<Role> roles;
@Getter
@Setter
@NoArgsConstructor
public class Address implements Serializable {
@SerializedName("street_1")
@Expose
private String street1;
@SerializedName("street_2")
@Expose
private String street2;
@SerializedName("city")
@Expose
private String city;
@SerializedName("state")
@Expose
private String state;
@SerializedName("zipCode")
@Expose
private Integer zipCode;
@SerializedName("country")
@Expose
private String country;
}
@Getter
@Setter
@NoArgsConstructor
public class Role implements Serializable {
@SerializedName("id")
@Expose
private String id;
@SerializedName("role")
@Expose
private String role;
}
}
}
Making the service call within the app:
public void getMemberDetails() {
if (getIdToken().getValue() == null) {
updateIdToken();
} else {
Map<String, String> headers = new HashMap<>();
headers.put("Content-type", "application/json");
headers.put(FIREBASE_AUTH_HEADER, getIdToken().getValue());
appWebservice.getMemberDetails(headers)
.enqueue(new Callback<MemberResponse>() {
@Override
public void onResponse(
@NonNull Call<MemberResponse> call,
@NonNull retrofit2.Response<MemberResponse> response) {
if (response.body() != null) {
System.out.println("appWebservice.getMemberDetails(): " + new Gson().toJson(response.body()));
for (MemberResponse.Member member : response.body().getMembers()) {
MemberEntity memberEntity =
toEntity(new Gson().toJson(member));
if (isNotBlank(memberEntity.getMemberId())) {
repository.storeMemberDetails(memberEntity);
}
}
}
}
@Override
public void onFailure(
@NonNull Call<MemberResponse> call, @NonNull Throwable t) {
System.err.println("appWebservice.getMemberDetails(): " + t.getMessage());
}
});
}
}
I am not reaching the onFailure
call because the service call is successful. I receive a json response, yet it doesn't seem to be parsing correctly, i.e., the data is missing from the objects within the array.
This issue only occurs when I deploy my .apk through the google play store.
Please help me resolve this issue! Thank you
Upvotes: 2
Views: 1483
Reputation: 31
This issue was answered here Gson Not mapping data in Production Mode APK Android
add this to your proguard 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
# 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.example.YourPackage.** { *; }
Upvotes: 1
Reputation: 1421
I was able to solve this problem using the Gson object called JsonElement
https://google.github.io/gson/apidocs/com/google/gson/JsonElement.html
I swapped out the MemberResponse
object for the JsonElement
object and then manually parsed my data via JsonObject
and JsonArray
. It worked out perfectly.
Here are the updated files.
public interface AppWebservice {
String API_URL = "https://api.bmcstudios.org/";
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
Retrofit RETROFIT = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
// MEMBER
@GET("member")
Call<JsonElement> getMemberDetails(
@HeaderMap Map<String, String> headers);
}
public void getMemberDetails() {
if (getIdToken().getValue() == null) {
updateIdToken();
} else {
Map<String, String> headers = new HashMap<>();
headers.put("Content-type", "application/json");
headers.put(FIREBASE_AUTH_HEADER, getIdToken().getValue());
appWebservice.getMemberDetails(headers)
.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(
@NonNull Call<JsonElement> call,
@NonNull retrofit2.Response<JsonElement> response) {
if (response.body() != null) {
System.out.println("appWebservice.putMemberDetails(): " + new Gson().toJson(response.body()));
JsonObject jsonObject = response.body().getAsJsonObject();
if (jsonObject.has("members")) {
JsonArray members = jsonObject.getAsJsonArray("members");
for (JsonElement memberElement : members) {
MemberEntity memberEntity =
toEntity(new Gson().toJson(memberElement));
if (isNotBlank(memberEntity.getMemberId())) {
repository.storeMemberDetails(memberEntity);
member.postValue(Member.toMember(memberEntity));
}
}
}
}
}
@Override
public void onFailure(
@NonNull Call<JsonElement> call, @NonNull Throwable t) {
System.err.println("appWebservice.getMemberDetails(): " + t.getMessage());
}
});
}
}
Upvotes: 0