【问题标题】:Gson doesn't serialize fields defined in subclassesGson 不序列化子类中定义的字段
【发布时间】:2011-12-30 12:21:16
【问题描述】:

如果我有一些未知的原因:

class A{
int stars;
public int getStars(){
return stars;
}

public void setStarts(int stars){
this.stars = stars;
}
}

class B extends A{
 int sunshines;

[getter and setter for sunshines]
}

class C{
 List<A> classes;
[get and set for classes]
}

如果我序列化 C 类型的对象,我在字段类的序列化对象中只有 A 的字段(而如果对象是 B,我希望有 B 的字段)。

如何做到这一点?

【问题讨论】:

标签: java gson


【解决方案1】:

Gson 2.1 开箱即用地支持这一点:

import java.util.ArrayList;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GsonInheritanceTest
{
  public static void main(String[] args)
  {
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    C c = new C();
    c.classes = new ArrayList<A>();
    c.classes.add(new A(1));
    c.classes.add(new B(2, 3));
    System.out.println(gson.toJson(c));
  }

  static class A
  {
    int stars;

    A(int stars)
    {
      this.stars = stars;
    }
  }

  static class B extends A
  {
    int sunshines;

    B(int stars, int sunshines)
    {
      super(stars);
      this.sunshines = sunshines;
    }
  }

  static class C
  {
    List<A> classes;
  }
}

输出是

{
  "classes": [
    {
      "stars": 1
    },
    {
      "sunshines": 3,
      "stars": 2
    }
  ]
}

【讨论】:

【解决方案2】:

我使用 Ivan 的回答来引导我找到一个更优雅的解决方案 - 它并不完美,但它对我来说已经足够好了。我创建了一个新的 JsonSerializer,它通过将 A 类型转换为 Object 来丢弃 A 的类型。似乎当给定一个普通的对象时,Gson 会查看对象的实际类型,而不是从传入的变量的类型中引用。

public static class ASerializer implements JsonSerializer<A> {

    @Override
    public JsonElement serialize( A in, Type type, JsonSerializationContext ctx ) {
        return ctx.serialize( (Object) in );
    }
}

然后您将ASerializer 传递给GsonBuilder 以获得一个Gson 实例以供使用:

GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter( A.class, new ASerializer() ); 
Gson gson = gb.create();

【讨论】:

    【解决方案3】:

    我已经尝试了您的示例,并在 C 类中将 List&lt;A&gt; 替换为 List&lt;Object&gt; 解决了这个问题。

    import java.util.ArrayList;
    import java.util.List;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    
    public class GsonInheritanceTest {
    public static void main(String[] args) {
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        C c = new C();
        c.classes = new ArrayList<Object>();
        c.classes.add(new A());
        c.classes.add(new B());
        System.out.println(gson.toJson(c));
    }
    
    public static class A {
        int stars;
    }
    
    public static class B extends A {
        int sunshines;
    }
    
    public static class C {
        List<Object> classes;
    }
    }
    

    生产:

    {
      "classes": [
        {
          "stars": 0
        },
        {
          "sunshines": 0,
          "stars": 0
        }
      ]
    }
    

    但是,这会阻止您使用默认的 json 反序列化...考虑重构您的 OOD 和继承关系。

    【讨论】:

    • hm...这种方式行得通,反正我的java代码不会这样运行。
    • 谢谢,但这不是一个好的解决方案 1) 使用 List&lt;Object&gt; 丢失类型 2) 使用 JSON 序列化之类的小东西影响设计,您不应该更改您认为最适合的设计您的应用程序,只是因为某些序列化库需要不同的序列化库。
    【解决方案4】:

    Gson 对多态类型处理的支持不完整。

    如果可能,我强烈建议切换到Jackson,它可以完美地处理原始问题中的序列化问题。

    如果必须使用 Gson,则需要自定义序列化处理来处理这种数据结构。幸运的是,自定义序列化程序的实现可以非常简单。例如:

    import java.lang.reflect.Type;
    import java.util.ArrayList;
    import java.util.List;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonSerializationContext;
    import com.google.gson.JsonSerializer;
    
    public class GsonFoo
    {
      public static void main(String[] args)
      {
        C c = new C();
        c.classes = new ArrayList<A>();
        c.classes.add(new A(42));
        c.classes.add(new B(8));
    
        System.out.println(new Gson().toJson(c));
        // output:
        // {"classes":[{"stars":42},{"stars":-1}]}
    
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(A.class, new ASerializer());
        Gson gson = gsonBuilder.create();
        System.out.println(gson.toJson(c));
        // output:
        // {"classes":[{"stars":42},{"sunshines":8,"stars":-1}]}
      }
    }
    
    class ASerializer implements JsonSerializer<A>
    {
      @Override
      public JsonElement serialize(A src, Type typeOfSrc, JsonSerializationContext context)
      {
        Gson gson = new Gson();
        return gson.toJsonTree(src);
      }
    }
    
    class A
    {
      public int stars;
    
      A(int s)
      {
        stars = s;
      }
    }
    
    class B extends A
    {
      public int sunshines;
    
      B(int s)
      {
        super(-1);
        sunshines = s;
      }
    }
    
    class C
    {
      public List<A> classes;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-30
      • 1970-01-01
      • 2020-07-19
      • 1970-01-01
      • 2016-01-16
      • 1970-01-01
      • 2020-01-23
      • 1970-01-01
      相关资源
      最近更新 更多