如何解决:无法为类X调用no-args构造函数:使用Gson为这种类型注册InstanceCreator可能会解决此问题

时间:2019-07-08 19:56:16

标签: java android abstract parcelable

我试图列出所有属于抽象类的对象的列表,但是每个对象都有自己的类。该列表需要持久化,因此我认为自从过去以来我就实现了可打包。只能在不同的类中使用所有抽象类。

我尝试仅使抽象类可拆分,但是不能拥有我习惯的创建者,因为(当然)您不能创建它的实例(因为它是抽象的)。到处阅读我注意到人们说您不需要在抽象类中的构造函数,只需在子类中。

AbstractFocusPower类

public abstract class AbstractFocusPower implements Parcelable {

    private transient AppExtension app;
    private ImplementSchool school;
    private String name;
    private int duration;
    private int cost;
    private int altCost;
    private int requiredLevel;
    private boolean isSelected;
    private boolean isResonant;
    private int nofSpirtBonusUsed;

    /**
     * Constructor for Focus Power with no alternative cost
     */
    public AbstractFocusPower(AppExtension app, ImplementSchool school, String name, int requiredLevel, int duration, int cost, boolean isSelected) {
        this.app = app;
        this.school = school;
        this.name = name;
        this.requiredLevel = requiredLevel;
        this.duration = duration;
        this.cost = cost;
        this.altCost = -1;
        this.isSelected = isSelected;
        this.isResonant = false;
    }

    // I cut out the other constructors

    public abstract AbstractFocusPower makeCopy();

    public abstract String getDescription();

    // I cut out the getters and setters

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.school == null ? -1 : this.school.ordinal());
        dest.writeString(this.name);
        dest.writeInt(this.duration);
        dest.writeInt(this.cost);
        dest.writeInt(this.altCost);
        dest.writeInt(this.requiredLevel);
        dest.writeByte(this.isSelected ? (byte) 1 : (byte) 0);
        dest.writeByte(this.isResonant ? (byte) 1 : (byte) 0);
        dest.writeInt(this.nofSpirtBonusUsed);
    }

    protected AbstractFocusPower(Parcel in) {
        int tmpSchool = in.readInt();
        this.school = tmpSchool == -1 ? null : ImplementSchool.values()[tmpSchool];
        this.name = in.readString();
        this.duration = in.readInt();
        this.cost = in.readInt();
        this.altCost = in.readInt();
        this.requiredLevel = in.readInt();
        this.isSelected = in.readByte() != 0;
        this.isResonant = in.readByte() != 0;
        this.nofSpirtBonusUsed = in.readInt();
    }

样本子类

public class AegisFocusPower extends AbstractFocusPower {

    public AegisFocusPower(AppExtension app) {
        super(app, ImplementSchool.ABJURATION, app.getString(R.string.focus_power_name_aegis), 0, 1, 1, false);
    }

    @Override
    public String getDescription() {
        return getApp().getString(R.string.focus_power_desc_aegis, (1+((int) Math.floor(getApp().getCurrentCharacter().getOccultistLevel()/6.0))));
    }

    @Override
    public AegisFocusPower makeCopy() {
        return new AegisFocusPower(getApp());
    }

    public AegisFocusPower(Parcel in) {
        super(in);
    }

    public static final Parcelable.Creator<AegisFocusPower> CREATOR = new Parcelable.Creator<AegisFocusPower>() {
        public AegisFocusPower createFromParcel(Parcel in) {
            return new AegisFocusPower (in);
        }

        public AegisFocusPower [] newArray(int size) {
            return new AegisFocusPower[size];
        }
    };
}

我在哪里使用的代码

Gson gsonFocusPowers = new Gson();
        String jsonFocusPowers = sharedPreferences.getString(FOCUS_POWERS_GSON, null);
        Type typeFocusPower = new TypeToken<ArrayList<AbstractFocusPower>>() {
        }.getType();
        ArrayList<AbstractFocusPower> focusPowers;
        focusPowers = gsonFocusPowers.fromJson(jsonFocusPowers, typeFocusPower);
        if (focusPowers != null) {
            this.focusPowers.addAll(checkForNewFocusPowers(focusPowers));
        } else {
            this.focusPowers = getNewFocusPowerList();
        }

不幸的是,这给了我一个我不知道如何解决的错误。

java.lang.RuntimeException: Unable to create application nl.rekijan.occultistmentalfocushelper.AppExtension: java.lang.RuntimeException: Unable to invoke no-args constructor for class nl.rekijan.occultistmentalfocushelper.mvc.focuspowers.AbstractFocusPower. Registering an InstanceCreator with Gson for this type may fix this problem.

编辑:不确定为什么该帖子重复。对于初学者,它没有可接受的答案。答案需要一个第三方图书馆。问题不在于单个摘要下的多个子类。

1 个答案:

答案 0 :(得分:0)

您是否尝试过注册类型适配器,例如Using Gson and Abstract Classes?我总是为特定格式(用于日期,大十进制,通常需要非常特定格式的任何内容)添加适配器,还为子类添加适配器。

但是,在这种情况下,不需要适配器,这是..直接吗?

[
  {
    "_id": "abcd",
    "userID": "1",
    "noteID": "1",
    "text": "123"
  },
  {
    "_id": "efgh",
    "userID": "1",
    "noteID": "2",
    "text": "456"
  },
  {
    "_id": "ijkl",
    "userID": "1",
    "noteID": "3",
    "text": "789"
  },
  {
    "_id": "mnop",
    "userID": "2",
    "noteID": "1",
    "text": "123"
  },
  {
    "_id": "wxyz",
    "userID": "2",
    "noteID": "2",
    "text": "123"
  }
]

然后是impl(是的,我以我希望它们出现在域对象中的方式添加到toString(),hashCode()和equals()。):

public abstract class AbstractFocusPower implements Parcelable {

    // just some property needed to be pushed through a constructor
    protected final String myString;

    protected AbstractFocusPower(String myString) {
        this.myString = myString;
    }
}

然后我可以运行以下junit:

public class AegisFocusPower extends AbstractFocusPower {

    boolean imParcelled;

    public AegisFocusPower(String myString) {
        super(myString);
    }

    @Override //yup the interface impl
    public void parcelMe() {
        imParcelled = true;
    }

    @Override
    public String toString() {
        return new StringBuilder("{ imParcelled : ").append(imParcelled).append(", myString : ").append(myString).append(" }").toString();
    }

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

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other == null || !(other instanceof AegisFocusPower)) {
            return false;
        } else {
            return other.hashCode() == hashCode();
        }
    }
}

而GSON的初始化就像

@Test
public void AegisFocusPowerToJsonAndBack(){

    // single instance
    AegisFocusPower ea = new AegisFocusPower("apa");
    String json = GSON.toJson(ea);
    assertEquals("{\"imParcelled\":\"false\",\"myString\":\"apa\"}", json);
    AegisFocusPower backAtYa = (AegisFocusPower) GSON.fromJson(json, AegisFocusPower.class);
    assertEquals(backAtYa, ea);

    // A list
    AegisFocusPower ea2 = new AegisFocusPower("bepa");
    AegisFocusPower ea3 = new AegisFocusPower("cepa");
    List<AegisFocusPower> powerList = new ArrayList<>();
    powerList.add(ea2);
    powerList.add(ea3);
    String jsonList = GSON.toJson(powerList);
    assertEquals("[{\"imParcelled\":\"false\",\"myString\":\"bepa\"},{\"imParcelled\":\"false\",\"myString\":\"cepa\"}]", jsonList);
    List<AegisFocusPower> backAtYaz = Arrays.asList(GSON.fromJson(jsonList,AegisFocusPower[].class));
    assertEquals(backAtYaz.get(0), ea2);
    assertEquals(backAtYaz.get(1), ea3);
}

和我使用的为布尔值注册的类型适配器与您的问题无关。

这很简单,对您也有用吗?