java.lang.ClassCastException: LinkedTreeMap cannot be cast to ProductDetails$OneTimePurchaseOfferDetails

63 Views Asked by At

I am using in-app billing (com.android.billingclient:[email protected]:2) lib for payment in Android.

Billing Library: Provides product detail information as ProductDetails in response of QueryInventory.

I am storing those product detail information in session as JSON string using Gson Lib.

JSON String

{
      "zza": "{\"productId\":\"com.abc.xyz\",\"type\":\"inapp\",\"title\":\"One-Time Purchase \",\"name\":\"One-Time Purchase\",\"description\":\"One-Time Purchase and Get premium content\",\"localizedIn\":[\"en-US\"],\"skuDetailsToken\":\"AEuhp4L1zoq6cjMTf8R2UF1nkG69D_MsfpoBqHySShV1u0cU5_NuObiMwl\",\"oneTimePurchaseOfferDetails\":{\"priceAmountMicros\":2900000000,\"priceCurrencyCode\":\"INR\",\"formattedPrice\":\"₹2,900.00\"}}",
      "zzb": {
        "nameValuePairs": {
          "productId": "com.abc.xyz",
          "type": "inapp",
          "title": "One-Time Purchase",
          "name": "One-Time Purchase",
          "description": "One-Time Purchase and Get premium content",
          "localizedIn": {
            "values": [
              "en-US"
            ]
          },
          "skuDetailsToken": "AEuhp4L1zoq6cjMTf8R2UF1nkG69D_MsfpoBqHySShV1u0cU5_NuObiMwl",
          "oneTimePurchaseOfferDetails": {
            "nameValuePairs": {
              "priceAmountMicros": 2900000000,
              "priceCurrencyCode": "INR",
              "formattedPrice": "₹2,900.00"
            }
          }
        }
      },
      "zzc": "com.abc.xyz",
      "zzd": "inapp",
      "zze": "One-Time Purchase",
      "zzf": "One-Time Purchase",
      "zzg": "One-Time Purchase and Get premium content",
      "zzh": "AEuhp4L1zoq6cjMTf8R2UF1nkG69D_MsfpoBqHySShV1u0cU5_NuObiMwl",
      "zzi": "",
      "zzj": "",
      "zzk": "",
      "zzm": [
        {
          "zza": "₹2,900.00",
          "zzb": 2900000000,
          "zzc": "INR",
          "zzd": "",
          "zze": "",
          "zzf": []
        }
      ]
    }

Now, I have created same ProductDetails object from JSON using Gsonlib.

But I am getting LinkedTreeMap casting exception while trying to get oneTimePurchaseOfferDetails info.

ProductDetails.class

package com.android.billingclient.api;

import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.internal.play_billing.zzu;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public final class ProductDetails {
    private final String zza;
    private final JSONObject zzb;
    private final String zzc;
    private final String zzd;
    private final String zze;
    private final String zzf;
    private final String zzg;
    private final String zzh;
    private final String zzi;
    private final String zzj;
    @Nullable
    private final String zzk;
    @Nullable
    private final List zzl;
    @Nullable
    private final List zzm;

    public int hashCode() {
        return this.zza.hashCode();
    }

    @Nullable
    public ProductDetails.OneTimePurchaseOfferDetails getOneTimePurchaseOfferDetails() {
        List var1 = this.zzm;
        return var1 != null && !var1.isEmpty() ? (ProductDetails.OneTimePurchaseOfferDetails)this.zzm.get(0) : null;
    }

    @NonNull
    public String getDescription() {
        return this.zzg;
    }

    @NonNull
    public String getName() {
        return this.zzf;
    }

    @NonNull
    public String getProductId() {
        return this.zzc;
    }

    @NonNull
    public String getProductType() {
        return this.zzd;
    }

    @NonNull
    public String getTitle() {
        return this.zze;
    }

    @NonNull
    public String toString() {
        String var1 = this.zza;
        String var2 = this.zzb.toString();
        String var3 = this.zzc;
        String var4 = this.zzd;
        String var5 = this.zze;
        String var6 = this.zzh;
        String var10000 = String.valueOf(this.zzl);
        StringBuilder var10001 = new StringBuilder();
        var10001.append("ProductDetails{jsonString='");
        var10001.append(var1);
        var10001.append("', parsedJson=");
        var10001.append(var2);
        var10001.append(", productId='");
        var10001.append(var3);
        var10001.append("', productType='");
        var10001.append(var4);
        var10001.append("', title='");
        var10001.append(var5);
        var10001.append("', productDetailsToken='");
        var10001.append(var6);
        var10001.append("', subscriptionOfferDetails=");
        var10001.append(var10000);
        var10001.append("}");
        return var10001.toString();
    }

    @Nullable
    public List<ProductDetails.SubscriptionOfferDetails> getSubscriptionOfferDetails() {
        return this.zzl;
    }

    ProductDetails(String var1) throws JSONException {
        this.zza = var1;
        this.zzb = new JSONObject(this.zza);
        this.zzc = this.zzb.optString("productId");
        this.zzd = this.zzb.optString("type");
        if (TextUtils.isEmpty(this.zzc)) {
            throw new IllegalArgumentException("Product id cannot be empty.");
        } else if (TextUtils.isEmpty(this.zzd)) {
            throw new IllegalArgumentException("Product type cannot be empty.");
        } else {
            this.zze = this.zzb.optString("title");
            this.zzf = this.zzb.optString("name");
            this.zzg = this.zzb.optString("description");
            this.zzi = this.zzb.optString("packageDisplayName");
            this.zzj = this.zzb.optString("iconUrl");
            this.zzh = this.zzb.optString("skuDetailsToken");
            this.zzk = this.zzb.optString("serializedDocid");
            JSONArray var2 = this.zzb.optJSONArray("subscriptionOfferDetails");
            ArrayList var3;
            int var4;
            if (var2 != null) {
                var3 = new ArrayList();

                for(var4 = 0; var4 < var2.length(); ++var4) {
                    var3.add(new ProductDetails.SubscriptionOfferDetails(var2.getJSONObject(var4)));
                }

                this.zzl = var3;
            } else {
                ArrayList var5;
                if (!this.zzd.equals("subs") && !this.zzd.equals("play_pass_subs")) {
                    var5 = null;
                } else {
                    var5 = new ArrayList();
                }

                this.zzl = var5;
            }

            JSONObject var6 = this.zzb.optJSONObject("oneTimePurchaseOfferDetails");
            var2 = this.zzb.optJSONArray("oneTimePurchaseOfferDetailsList");
            var3 = new ArrayList();
            if (var2 == null) {
                if (var6 != null) {
                    var3.add(new ProductDetails.OneTimePurchaseOfferDetails(var6));
                    this.zzm = var3;
                } else {
                    this.zzm = null;
                }
            } else {
                for(var4 = 0; var4 < var2.length(); ++var4) {
                    var3.add(new ProductDetails.OneTimePurchaseOfferDetails(var2.getJSONObject(var4)));
                }

                this.zzm = var3;
            }
        }
    }

    public boolean equals(@Nullable Object o) {
        if (this == o) {
            return true;
        } else if (!(o instanceof ProductDetails)) {
            return false;
        } else {
            ProductDetails o1 = (ProductDetails)o;
            return TextUtils.equals(this.zza, o1.zza);
        }
    }

    @NonNull
    public final String zza() {
        return this.zzb.optString("packageName");
    }

    final String zzb() {
        return this.zzh;
    }

    @Nullable
    public String zzc() {
        return this.zzk;
    }

    public static final class SubscriptionOfferDetails {
        private final String zza;
        @Nullable
        private final String zzb;
        private final String zzc;
        private final ProductDetails.PricingPhases zzd;
        private final List zze;
        @Nullable
        private final zzbf zzf;

        @NonNull
        public ProductDetails.PricingPhases getPricingPhases() {
            return this.zzd;
        }

        @NonNull
        public String getBasePlanId() {
            return this.zza;
        }

        @Nullable
        public String getOfferId() {
            return this.zzb;
        }

        @NonNull
        public String getOfferToken() {
            return this.zzc;
        }

        @NonNull
        public List<String> getOfferTags() {
            return this.zze;
        }

        SubscriptionOfferDetails(JSONObject var1) throws JSONException {
            this.zza = var1.optString("basePlanId");
            String var2 = var1.optString("offerId");
            if (var2.isEmpty()) {
                var2 = null;
            }

            this.zzb = var2;
            this.zzc = var1.getString("offerIdToken");
            var2 = "pricingPhases";
            this.zzd = new ProductDetails.PricingPhases(var1.getJSONArray(var2));
            JSONObject var5 = var1.optJSONObject("installmentPlanDetails");
            zzbf var6;
            if (var5 == null) {
                var6 = null;
            } else {
                var6 = new zzbf(var5);
            }

            this.zzf = var6;
            ArrayList var7 = new ArrayList();
            JSONArray var3 = var1.optJSONArray("offerTags");
            if (var3 != null) {
                for(int var4 = 0; var4 < var3.length(); ++var4) {
                    var7.add(var3.getString(var4));
                }
            }

            this.zze = var7;
        }
    }

    public static final class OneTimePurchaseOfferDetails {
        private final String zza;
        private final long zzb;
        private final String zzc;
        private final String zzd;
        private final String zze;
        private final zzu zzf;
        @Nullable
        private final zzbg zzg;
        @Nullable
        private final zzbi zzh;
        @Nullable
        private final zzbh zzi;

        public long getPriceAmountMicros() {
            return this.zzb;
        }

        @NonNull
        public String getFormattedPrice() {
            return this.zza;
        }

        @NonNull
        public String getPriceCurrencyCode() {
            return this.zzc;
        }

        OneTimePurchaseOfferDetails(JSONObject var1) throws JSONException {
            this.zza = var1.optString("formattedPrice");
            this.zzb = var1.optLong("priceAmountMicros");
            this.zzc = var1.optString("priceCurrencyCode");
            this.zzd = var1.optString("offerIdToken");
            this.zze = var1.optString("offerId");
            var1.optInt("offerType");
            JSONArray var3 = var1.optJSONArray("offerTags");
            ArrayList var4 = new ArrayList();
            if (var3 != null) {
                for(int var2 = 0; var2 < var3.length(); ++var2) {
                    var4.add(var3.getString(var2));
                }
            }

            this.zzf = zzu.zzj(var4);
            var1.optLong("fullPriceMicros");
            JSONObject var6 = var1.optJSONObject("discountDisplayInfo");
            zzbg var7;
            if (var6 == null) {
                var7 = null;
            } else {
                var7 = new zzbg(var6);
            }

            this.zzg = var7;
            var6 = var1.optJSONObject("validTimeWindow");
            zzbi var8;
            if (var6 == null) {
                var8 = null;
            } else {
                var8 = new zzbi(var6);
            }

            this.zzh = var8;
            var1 = var1.optJSONObject("limitedQuantityInfo");
            zzbh var5;
            if (var1 == null) {
                var5 = null;
            } else {
                var5 = new zzbh(var1);
            }

            this.zzi = var5;
        }

        @NonNull
        public final String zza() {
            return this.zzd;
        }
    }

    @Retention(RetentionPolicy.SOURCE)
    public @interface RecurrenceMode {
        int INFINITE_RECURRING = 1;
        int FINITE_RECURRING = 2;
        int NON_RECURRING = 3;
    }

    public static final class PricingPhase {
        private final String zza;
        private final long zzb;
        private final String zzc;
        private final String zzd;
        private final int zze;
        private final int zzf;

        public int getBillingCycleCount() {
            return this.zze;
        }

        public int getRecurrenceMode() {
            return this.zzf;
        }

        public long getPriceAmountMicros() {
            return this.zzb;
        }

        @NonNull
        public String getBillingPeriod() {
            return this.zzd;
        }

        @NonNull
        public String getFormattedPrice() {
            return this.zza;
        }

        @NonNull
        public String getPriceCurrencyCode() {
            return this.zzc;
        }

        PricingPhase(JSONObject var1) {
            this.zzd = var1.optString("billingPeriod");
            this.zzc = var1.optString("priceCurrencyCode");
            this.zza = var1.optString("formattedPrice");
            this.zzb = var1.optLong("priceAmountMicros");
            this.zzf = var1.optInt("recurrenceMode");
            this.zze = var1.optInt("billingCycleCount");
        }
    }

    public static class PricingPhases {
        private final List zza;

        @NonNull
        public List<ProductDetails.PricingPhase> getPricingPhaseList() {
            return this.zza;
        }

        PricingPhases(JSONArray var1) {
            ArrayList var3 = new ArrayList();
            if (var1 != null) {
                for(int var2 = 0; var2 < var1.length(); ++var2) {
                    JSONObject var4 = var1.optJSONObject(var2);
                    if (var4 != null) {
                        var3.add(new ProductDetails.PricingPhase(var4));
                    }
                }
            }

            this.zza = var3;
        }
    }
}
1

There are 1 best solutions below

2
Sujal Kumar On

What I can see so far is use of similar variable names again and again throughout the code snippet. It is making it confusing to see where the thing is going wrong but I would suggest you to make use of generics in the Lists defined if you are only going to have a single Object type inside. For example: Define zzm as

List<ProductDetails.OneTimePurchaseOfferDetails> zzm;

instead of:

List zzm;

This will make it sure that this.zzm.get(0) in the getOneTimePurchaseOfferDetails() method will fetch you an object of ProductDetails.OneTimePurchaseOfferDetails type only and if you are by any chance trying to add a different kind of object to the list, you won't be able to at all.

If it still doesn't work, please let me know.