2016-09-15 64 views
1

我现在面临一个尴尬的问题就在这里,我想有层次parcelable类,但我得到这个奇怪的错误:无法实例抽象类“base.CreditCard”

java.lang.InstantiationException: Can't instantiate abstract class br.com.dinda.models.credit_cards.base.CreditCard 
    at java.lang.reflect.Constructor.newInstance()(Constructor.java:-2) 
    at com.google.gson.internal.ConstructorConstructor$3.construct()(ConstructorConstructor.java:104) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read()(ReflectiveTypeAdapterFactory.java:186) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read()(ReflectiveTypeAdapterFactory.java:103) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read()(ReflectiveTypeAdapterFactory.java:196) 
    at com.google.gson.Gson.fromJson()(Gson.java:810) 
    at com.google.gson.Gson.fromJson()(Gson.java:775) 
    at com.google.gson.Gson.fromJson()(Gson.java:724) 
    at com.google.gson.Gson.fromJson()(Gson.java:696) 
    at com.newrelic.agent.android.instrumentation.GsonInstrumentation.fromJson()(GsonInstrumentation.java:90) 
    at br.com.dinda.models.CheckoutData.fromJson()(CheckoutData.java:38) 
    at br.com.dinda.repositories.CheckoutRepository.getPersistedCheckout()(CheckoutRepository.java:46) 
    at br.com.dinda.repositories.CheckoutRepository.getCheckout()(CheckoutRepository.java:28) 
    at br.com.dinda.presenters.CheckoutStep2Presenter.onCreate()(CheckoutStep2Presenter.java:43) 
    at br.com.dinda.views.fragments.CheckoutStep2Fragment.onCreateView()(CheckoutStep2Fragment.java:183) 
    at android.support.v4.app.Fragment.performCreateView()(Fragment.java:1789) 
    at android.support.v4.app.FragmentManagerImpl.moveToState()(FragmentManager.java:955) 
    at android.support.v4.app.FragmentManagerImpl.moveToState()(FragmentManager.java:1138) 
    at android.support.v4.app.FragmentManagerImpl.moveToState()(FragmentManager.java:1120) 
    at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated()(FragmentManager.java:1929) 
    at android.support.v4.app.FragmentActivity.onStart()(FragmentActivity.java:547) 
    at android.support.v7.app.AppCompatActivity.onStart()(AppCompatActivity.java:-1) 
    at br.com.dinda.views.activities.BaseActivity.onStart()(BaseActivity.java:49) 
    at android.app.Instrumentation.callActivityOnStart()(Instrumentation.java:1238) 
    at android.app.Activity.performStart()(Activity.java:6288) 
    at android.app.ActivityThread.performLaunchActivity()(ActivityThread.java:2397) 
    at android.app.ActivityThread.handleLaunchActivity()(ActivityThread.java:2494) 
    at android.app.ActivityThread.access$900()(ActivityThread.java:157) 
    at android.app.ActivityThread$H.handleMessage()(ActivityThread.java:1356) 
    at android.os.Handler.dispatchMessage()(Handler.java:102) 
    at android.os.Looper.loop()(Looper.java:148) 
    at android.app.ActivityThread.main()(ActivityThread.java:5530) 
    at java.lang.reflect.Method.invoke()(Method.java:-2) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run()(ZygoteInit.java:733) 
    at com.android.internal.os.ZygoteInit.main()(ZygoteInit.java:623) 

我的代码是:

@Parcel(converter = CreditCard.CreditCardConverter.class) 
public abstract class CreditCard { 

    public static final String CREDIT_CARD_MASK = "**** **** **** ####"; 
    public static ImmutableList<CreditCard> CREDIT_CARD_OPERATORS; 

    static { 
     CREDIT_CARD_OPERATORS = ImmutableList.of(
       new EloCreditCard(), 
       new VisaCreditCard(), 
       new MastercardCreditCard(), 
       new HipercardCreditCard() 
     ); 
    } 

    @SerializedName("credit_card_id") 
    Integer id; 

    @SerializedName("credit_card_name") 
    String name; 

    @SerializedName("credit_card_number") 
    String number; 

    @SerializedName("credit_card_month") 
    Integer month; 

    @SerializedName("credit_card_year") 
    Integer year; 

    @SerializedName("credit_card_operator") 
    String operator; 

    String securityCode; 

    boolean saveCreditCard; 

    /** 
    * Funcao para retornar o nome da operadora do cartao 
    * eg. visa ou mastercard 
    * @return nome da operadora 
    */ 
    @NonNull 
    public abstract String getCreditCardOperatorName(); 

    /** 
    * Funcao que retorna o regex para verificar a validade da operadora do cartao (nums sao validos para a bandeira especificada) 
    * eg. visa = Pattern.compile("^4[0-9]{15}$"), 
    * @return @Pattern para a operadora especificada 
    */ 
    public abstract Pattern creditCardRegex(); 

    /** 
    * Funcao que retorna o Regex parcial para identificar a operadora do cartao 
    * * eg. visa = Pattern.compile("^4[0-9]*$") 
    * @return @Pattern para a verificacao parcial da operadora do cartao 
    */ 
    public abstract Pattern partialCreditCardRegex(); 

    /** 
    * Funcao que retorna o logo da bandeira da operadaora do cartao quando o msm esta selecionado 
    * @return Drawable do logo 
    */ 
    @DrawableRes 
    public abstract int operatorLogoRes(); 

    /** 
    * Funcao que retorna o logo da bandeira da operadaora do cartao quando o msm <b>nao</b> esta selecionado 
    * @return Drawable do logo desmarcado (cinza) 
    */ 
    @DrawableRes 
    public abstract int operatorLogoDisabledRes(); 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (!(o instanceof CreditCard)) return false; 

     CreditCard card = (CreditCard) o; 

     return getCreditCardOperatorName().equals(card.getCreditCardOperatorName()); 

    } 

    @Override 
    public int hashCode() { 
     return getCreditCardOperatorName().hashCode(); 
    } 

    public static class CreditCardConverter implements ParcelConverter<CreditCard> { 

     @Override 
     public void toParcel(CreditCard input, android.os.Parcel parcel) { 
      parcel.writeParcelable(Parcels.wrap(input), 0); 
     } 

     @Override 
     public CreditCard fromParcel(android.os.Parcel parcel) { 
      return Parcels.unwrap(parcel.readParcelable(CreditCard.class.getClassLoader())); 
     } 
    } 
} 

和子类:

@Parcel 
public class HipercardCreditCard extends CreditCard { 

    @Override 
    public String getCreditCardOperatorName() { 
     return "hipercard"; 
    } 

    @Override 
    public Pattern creditCardRegex() { 
     return Pattern.compile("^606282[0-9]{10}$"); 
    } 

    @Override 
    public Pattern partialCreditCardRegex() { 
     return Pattern.compile("^(?:6|60|606|6062|60628|606282[0-9]{0,10})$"); 
    } 

    @Override 
    public int operatorLogoRes() { 
     return R.drawable.ic_credit_card_hipercard_on; 
    } 

    @Override 
    public int operatorLogoDisabledRes() { 
     return R.drawable.ic_credit_card_hipercard_off; 
    } 
} 

我把他们标注为@Parcel的照顾,但我似乎无法对网络找出发生了什么事。

Parceler 1.1.5版本发生此问题。

谢谢。

+0

一般而言,您不能实例化抽象类,也无法实例化接口。你必须扩展抽象类。 – baudo2048

+0

这是关键,我没有实例化抽象类,我不明白为什么Parceler调用基类,而不是孩子。 – Leonardo

+0

提供的堆栈跟踪似乎指向Gson在实例化抽象类时遇到了问题。在Github上也有回答:https://github.com/johncarl81/parceler/issues/237 –

回答

1

其实我忘了在我的串行的CustomTypeAdapter添加,

if (json != null) { 
      Gson gson = new Gson(); 
      return gson.fromJson(json, CheckoutData.class); 

应该是:

if (json != null) { 
      Gson gson = new GsonBuilder().registerTypeAdapter(CreditCard.class, new CreditCardTypeAdapter()).create(); 
      return gson.fromJson(json, CheckoutData.class); 

很抱歉打扰,并希望它可以帮助别人!

0

我相信你遇到了这样的问题:

Polymorphism

Note that Parceler does not unwrap inheritance hierarchies, so any polymorphic fields will be unwrapped as instances of the base class. This is because Parceler opts for performance rather than checking .getClass() for every piece of data.

@Parcel public class Example { 
    public Parent p; 
    @ParcelConstructor Example(Parent p) { this.p = p; } } 

@Parcel public class Parent {} @Parcel public class Child extends 
Parent {} Example example = new Example(new Child()); 
System.out.println("%b", example.p instanceof Child); // true example 
= Parcels.unwrap(Parcels.wrap(example)); System.out.println("%b", example.p instanceof Child); // false 

Refer to the Custom Serialization section for an example of working with polymorphic fields.

所以,你应该能够使用自定义序列化来解决这个问题。

https://github.com/johncarl81/parceler#custom-serialization