Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/190.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Gson将基类列表反序列化为派生类_Java_Android_Serialization - Fatal编程技术网

Java 使用Gson将基类列表反序列化为派生类

Java 使用Gson将基类列表反序列化为派生类,java,android,serialization,Java,Android,Serialization,我正在构建一个Android应用程序,它使用JSON与C#服务器进行通信 我有一个要序列化的数据类(实际上是将接收到的数据反序列化为),它包含派生类的列表字段,但将它们存储为它们的基类: public class ToSerializeClass{ @SerializedName("TestString") private String testString = "TestStringValue"; @SerializedName("DerivedClasses")

我正在构建一个Android应用程序,它使用JSON与C#服务器进行通信

我有一个要序列化的数据类(实际上是将接收到的数据反序列化为),它包含派生类的列表字段,但将它们存储为它们的基类:

public class ToSerializeClass{
    @SerializedName("TestString")
    private String testString = "TestStringValue";

    @SerializedName("DerivedClasses")
    private List<BaseClass> derivedClasses;

    public List<BaseClass> getDerivedClasses() {
        return derivedClasses;
    }

    public ToSerializeClass(List<BaseClass> derivedClasses){
        this.derivedClasses= derivedClasses;
    }
}
JSON字符串的“_type”:“SimpleClassName”字段显示序列化类的简单名称。这些是由C#side的序列化程序添加的。 如果有必要,我可以让这些字段消失,但这是C#端同样问题的解决方案。 如果没有这些类型,它将如下所示:

{"DerivedClasses":[{"FieldA":"This is a derived class."},{"FieldB":"This is ANOTHER derived class.", "IntValue":10}],"TestString":"TestStringValue"}
问题是,当我尝试将JSON字符串反序列化到ToSerializeClass的实例时:

我有一个反序列化类,它是一个ToSerializeClass实例,但是derivedClasses列表是基类的集合,而不是派生类,并且所有派生信息都丢失了

如何将字符串反序列化为ToSerializeClass实例以获得派生类列表

我完全可以控制源代码,所以我可以修改我的数据类,在必要时使用不同的集合,创建一些包装器,修改JSON字符串,但是如果可能的话,我想使用Gson解决它,并且可以在不需要太多开销的情况下完成

谢谢

编辑:例如DerivedClassA和DerivedClassB:

使用这个类

import com.google.gson.annotations.SerializedName;

public class DerivedClass {

    @SerializedName("__type")
    private String __type;

    @SerializedName("FieldA")
    private String fieldA;

    @SerializedName("FieldB")
    private String fieldB;

    public String get__type() {
        return __type;
    }

    public void set__type(String __type) {
        this.__type = __type;
    }

    public String getFieldA() {
        return fieldA;
    }

    public void setFieldA(String fieldA) {
        this.fieldA = fieldA;
    }

    public String getFieldB() {
        return fieldB;
    }

    public void setFieldB(String fieldB) {
        this.fieldB = fieldB;
    }
}
做出
Response.java
谁将获得
JSON
数据

import java.util.ArrayList;

import com.google.gson.annotations.SerializedName;

public class Response {

    @SerializedName("__type")
    private String __type;

    @SerializedName("DerivedClasses")
    private ArrayList<DerivedClass> derivedClasses;

    @SerializedName("TestString")
    private String testString;

    public String get__type() {
        return __type;
    }

    public void set__type(String __type) {
        this.__type = __type;
    }

    public ArrayList<DerivedClass> getDerivedClasses() {
        return derivedClasses;
    }

    public void setDerivedClasses(ArrayList<DerivedClass> derivedClasses) {
        this.derivedClasses = derivedClasses;
    }

    public String getTestString() {
        return testString;
    }

    public void setTestString(String testString) {
        this.testString = testString;
    }
}

我已经创建了一个快速解决方案,它与我正在寻找的解决方案非常接近(我不是Java爱好者,所以如果它伤害了你的大脑,我很抱歉,请随意评论)

数据类:

public class BaseClass {
    @SerializedName("Method")
    private String method;

    public void setMethod(String method){
        this.method = method;
    }

    public String getMethod(){
        return method;
    }

    public BaseClass(String method){
        this.method = method;
    }
}

public class DerivedClassA extends BaseClass{
    @SerializedName("FieldA")
    private String fieldA = "This is a derived class.";

    public DerivedClassA(){
        super("ClassA");
    }
}

public class DerivedClassB extends BaseClass{
    @SerializedName("FieldB")
    private String fieldB = "This is ANOTHER derived class.";

    @SerializedName("IntValue")
    private int intValue = 10;

    public DerivedClassB(){
        super("ClassB");
    }
}

public class ToSerializeClass{
    @SerializedName("TestString")
    private String testString = "TestStringValue";

    @SerializedName("DerivedClasses")
    private List<BaseClass> derivedClasses;

    public ToSerializeClass(List<BaseClass> derivedClasses){
        this.derivedClasses= derivedClasses;
    }
}
公共类基类{
@SerializedName(“方法”)
私有字符串方法;
公共void集合方法(字符串方法){
这个方法=方法;
}
公共字符串getMethod(){
返回法;
}
公共基类(字符串方法){
这个方法=方法;
}
}
公共类DerivedClassA扩展了基类{
@SerializedName(“FieldA”)
私有字符串fieldA=“这是一个派生类。”;
公共衍生类别a(){
超级(“A类”);
}
}
公共类DerivedClassB扩展了基类{
@序列化名称(“字段B”)
private String fieldB=“这是另一个派生类。”;
@SerializedName(“IntValue”)
私有int值=10;
公共衍生类别B(){
超级(“B类”);
}
}
公共类到序列化类{
@SerializedName(“TestString”)
私有字符串testString=“TestStringValue”;
@SerializedName(“派生类”)
私人课程列表;
公共ToSerializeClass(列出派生类){
this.derivedClasses=derivedClasses;
}
}
解决方案:ClassDeserializerAdapter实现:

public class ClassDeserializerAdapter implements JsonDeserializer<BaseClass>
{
    private String typeName;
    private Gson gson;
    private Map<String, Class<? extends BaseClass>> classTypeRegistry;

    ClassDeserializerAdapter(String typeName)
    {
        this.typeName = typeName;
        gson = new Gson();
        classTypeRegistry = new HashMap<>();
    }

    void registerClassType(String classTypeName, Class<? extends BaseClass> classType)
    {
        // registering Types to Strings
        classTypeRegistry.put(classTypeName, classType);
    }

    @Override
    public BaseClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
        throws JsonParseException
    {
        JsonObject jsonObject = json.getAsJsonObject();
        JsonElement typeElement = jsonObject.get(typeName);
        String method = typeElement.getAsString();
        Class<? extends BaseClass> classType = classTypeRegistry.get(method);
        BaseClass result = gson.fromJson(json, classType);
        return result;
    }
}
公共类ClassDeserializerAdapter实现JsonDeserializer
{
私有字符串类型名;
私人Gson;

private Map感谢您的回答,但是这个解决方案看起来必须将所有派生类的属性/字段存储到一个响应类中。因为有很多不同的派生类,所以它将是一个巨大的“数据类”(有时具有字段名等价性)。如果可能的话,我更喜欢将数据反序列化/反映到原始派生类的方式。(我知道,我可以在从响应类获取必要的值后创建派生类,但是..那不好。):)如果我对你的例子有错误,请随时纠正我。@KAI,你肯定会让我想起BayBlade的。你的派生类将嵌套在json列表中,这样你就不必担心Respose类的大小不会增加。关于派生类,实际上可以在你尝试为它们创建模型类时进行子类化如果您知道从服务器获得的JSON的结构,那么使用起来很方便
import com.google.gson.annotations.SerializedName;

public class DerivedClass {

    @SerializedName("__type")
    private String __type;

    @SerializedName("FieldA")
    private String fieldA;

    @SerializedName("FieldB")
    private String fieldB;

    public String get__type() {
        return __type;
    }

    public void set__type(String __type) {
        this.__type = __type;
    }

    public String getFieldA() {
        return fieldA;
    }

    public void setFieldA(String fieldA) {
        this.fieldA = fieldA;
    }

    public String getFieldB() {
        return fieldB;
    }

    public void setFieldB(String fieldB) {
        this.fieldB = fieldB;
    }
}
import java.util.ArrayList;

import com.google.gson.annotations.SerializedName;

public class Response {

    @SerializedName("__type")
    private String __type;

    @SerializedName("DerivedClasses")
    private ArrayList<DerivedClass> derivedClasses;

    @SerializedName("TestString")
    private String testString;

    public String get__type() {
        return __type;
    }

    public void set__type(String __type) {
        this.__type = __type;
    }

    public ArrayList<DerivedClass> getDerivedClasses() {
        return derivedClasses;
    }

    public void setDerivedClasses(ArrayList<DerivedClass> derivedClasses) {
        this.derivedClasses = derivedClasses;
    }

    public String getTestString() {
        return testString;
    }

    public void setTestString(String testString) {
        this.testString = testString;
    }
}
    Response response = (new Gson()).fromJson("your_JSON", Response.class);
public class BaseClass {
    @SerializedName("Method")
    private String method;

    public void setMethod(String method){
        this.method = method;
    }

    public String getMethod(){
        return method;
    }

    public BaseClass(String method){
        this.method = method;
    }
}

public class DerivedClassA extends BaseClass{
    @SerializedName("FieldA")
    private String fieldA = "This is a derived class.";

    public DerivedClassA(){
        super("ClassA");
    }
}

public class DerivedClassB extends BaseClass{
    @SerializedName("FieldB")
    private String fieldB = "This is ANOTHER derived class.";

    @SerializedName("IntValue")
    private int intValue = 10;

    public DerivedClassB(){
        super("ClassB");
    }
}

public class ToSerializeClass{
    @SerializedName("TestString")
    private String testString = "TestStringValue";

    @SerializedName("DerivedClasses")
    private List<BaseClass> derivedClasses;

    public ToSerializeClass(List<BaseClass> derivedClasses){
        this.derivedClasses= derivedClasses;
    }
}
public class ClassDeserializerAdapter implements JsonDeserializer<BaseClass>
{
    private String typeName;
    private Gson gson;
    private Map<String, Class<? extends BaseClass>> classTypeRegistry;

    ClassDeserializerAdapter(String typeName)
    {
        this.typeName = typeName;
        gson = new Gson();
        classTypeRegistry = new HashMap<>();
    }

    void registerClassType(String classTypeName, Class<? extends BaseClass> classType)
    {
        // registering Types to Strings
        classTypeRegistry.put(classTypeName, classType);
    }

    @Override
    public BaseClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 
        throws JsonParseException
    {
        JsonObject jsonObject = json.getAsJsonObject();
        JsonElement typeElement = jsonObject.get(typeName);
        String method = typeElement.getAsString();
        Class<? extends BaseClass> classType = classTypeRegistry.get(method);
        BaseClass result = gson.fromJson(json, classType);
        return result;
    }
}
// **SERIALIZATION PART** (nothing special, simple Gson serialization)
// Creating a list to pass as parameter to the container class
List<BaseClass> derivedClasses = new ArrayList<>();
derivedClasses.add(new DerivedClassA());
derivedClasses.add(new DerivedClassB());
// Creating the container class to be serialized
ToSerializeClass serializeClass = new ToSerializeClass(derivedClasses);

Gson gson = new Gson();

String json = gson.toJson(serializeClass);
// json = {"TestString":"TestStringValue","DerivedClasses":[{"FieldA":"This is a derived class.","Method":"ClassA"},{"FieldB":"This is ANOTHER derived class.","IntValue":10,"Method":"ClassB"}]}


// **DESERIALIZATION PART** (with custom deserializer)
// creating the custom deserializer, which will find the derived class' type as the class' "Method" field value. With that value, it can resolve the type.. see below
ClassDeserializerAdapter deserializer = new ClassDeserializerAdapter("Method");
// registering each Type into the Deserializer's HashMap (key-value pair), where the key (String) must be carried by the object (you can find it in the BaseClass, called "Method")
deserializer.registerClassType("ClassA", DerivedClassA.class);
deserializer.registerClassType("ClassB", DerivedClassB.class);
Gson gsonB = new GsonBuilder().registerTypeAdapter(BaseClass.class, deserializer).create();

// deserializing
ToSerializeClass deserialized = gsonB.fromJson(json, ToSerializeClass.class); // CORRECT!