In my app I have search functionality, when ever user searches for something I make a network call fetch suggestions. When user clicks on any of the suggestion I am storing that POJO into shared preferences using Gson and when the screen loads fist I am fetching the stored data from the preferences and deserializing using Gson. It all worked fine but recently I have added ProductTier object to the search item, it never crashed during testing. But it started crashing after the release. I understood that the gson is throwing error while deserializing but I can't think of any scenario where I am passing an int instead of boolean.
public class SearchItem implements Parcelable {
private static final int ITEM_KEY_WORD = 0;
private static final int ITEM_PRODUCT = 1;
@SerializedName("name")
private String name;
@SerializedName("itemKeyword")
private String itemKeyWord;
@SerializedName("productId")
private String productId;
@SerializedName("productTier")
private ProductTier productTier;
private int itemType;
private boolean isHeader = false;
private boolean isPopular = false;
public SearchItem(String name, String productId){
this.name = name;
this.productId = productId;
}
public SearchItem(String name, String itemKeyWord, String productId, int itemType,
boolean isHeader, boolean isPopular) {
this.name = name;
this.itemKeyWord = itemKeyWord;
this.productId = productId;
this.itemType = itemType;
this.isHeader = isHeader;
this.isPopular = isPopular;
}
private SearchItem(Parcel in) {
this.name = in.readString();
this.itemKeyWord = in.readString();
this.productId = in.readString();
itemType = TextUtils.isEmpty(itemKeyWord) ? ITEM_PRODUCT : ITEM_KEY_WORD;
productTier = in.readParcelable(ProductTier.class.getClassLoader());
}
public static final Creator<SearchItem> CREATOR = new Creator<SearchItem>() {
@Override
public SearchItem createFromParcel(Parcel in) {
return new SearchItem(in);
}
@Override
public SearchItem[] newArray(int size) {
return new SearchItem[size];
}
};
public String getItemKeyWord() {
return itemKeyWord;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProductId() {
return productId;
}
public int getItemType() {
return itemType;
}
public void setItemType(int itemType) {
this.itemType = itemType;
}
public boolean isHeader() {
return isHeader;
}
public void setHeader(boolean header) {
isHeader = header;
}
public boolean isPopular() {
return isPopular;
}
public void setPopular(boolean popular) {
isPopular = popular;
}
public ProductTier getProductTier() {
return productTier;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(itemKeyWord);
dest.writeString(productId);
dest.writeParcelable(productTier, flags);
}
@Override
public boolean equals(@Nullable Object obj) {
SearchItem that = (SearchItem) obj;
if (that == null) return false;
return this.name.equals(that.name);
}
}
//
public class ProductTier implements Parcelable {
@SerializedName("categoryId")
private String categoryId;
@SerializedName("liquorTypeId")
private String liquorTypeId;
@SerializedName("subCategoryId")
private String subCategoryId;
protected ProductTier(Parcel in) {
categoryId = in.readString();
liquorTypeId = in.readString();
subCategoryId = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(categoryId);
dest.writeString(liquorTypeId);
dest.writeString(subCategoryId);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ProductTier> CREATOR = new Creator<ProductTier>() {
@Override
public ProductTier createFromParcel(Parcel in) {
return new ProductTier(in);
}
@Override
public ProductTier[] newArray(int size) {
return new ProductTier[size];
}
};
public String getCategoryId() {
return categoryId;
}
public String getLiquorTypeId() {
return liquorTypeId;
}
public String getSubCategoryId() {
return subCategoryId;
}
}
class Utils {
public static ArrayList<SearchItem> getRecentSearches(Context context) {
ArrayList<SearchItem> searchItems = new ArrayList<>();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String list = preferences.getString(Constants.RECENT_SEARCHES, "");
try {
JSONArray jsonArray = new JSONArray(list);
if (jsonArray.length() > 0) {
Gson gsonVal = new Gson();
int i = 0;
while (i < jsonArray.length()) {
searchItems.add(gsonVal.fromJson(jsonArray.getJSONObject(i).toString(), SearchItem.class));
i++;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return searchItems;
}
public static void storeSearchItemToRecentSearches(Context context, SearchItem searchItem) {
if (searchItem == null) return;
searchItem.setPopular(false);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
String list = preferences.getString(Constants.RECENT_SEARCHES, "");
ArrayList<SearchItem> previousResults = new ArrayList<>();
try {
JSONArray jsonArray = new JSONArray(list);
if (jsonArray.length() > 0) {
Gson gsonVal = new Gson();
int i = 0;
while (i < jsonArray.length()) {
previousResults.add(gsonVal.fromJson(jsonArray.getJSONObject(i).toString(), SearchItem.class));
i++;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
if (previousResults.size() == 5) {
previousResults.remove(previousResults.size() - 1);
previousResults.add(0, searchItem);
}else {
previousResults.add(0, searchItem);
}
Gson gson = new Gson();
String val = gson.toJson(previousResults);
editor.putString(Constants.RECENT_SEARCHES, val);
editor.apply();
}
}
the crash is at this line searchItems.add(gsonVal.fromJson(jsonArray.getJSONObject(i).toString(), SearchItem.class)); in the getRecentSearches method.
In my app I have search functionality, when ever user searches for something I make a network call fetch suggestions. When user clicks on any of the suggestion I am storing that POJO into shared preferences using Gson and when the screen loads fist I am fetching the stored data from the preferences and deserializing using Gson. It all worked fine but recently I have added ProductTier object to the search item, it never crashed during testing. But it started crashing after the release. I understood that the gson is throwing error while deserializing but I can't think of any scenario where I am passing an int instead of boolean.
the crash is at this line searchItems.add(gsonVal.fromJson(jsonArray.getJSONObject(i).toString(), SearchItem.class)); in the getRecentSearches method.