Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson doesn't serialize fields defined in subclasses

Tags:

java

gson

For some unknown reason if I have:

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]
}

if I serialize an Object of type C I have only the fields of A in the serialized objects in the field classes (while I would expect to have the fields of B if the object is a B).

How to do that?

like image 785
gotch4 Avatar asked Nov 16 '11 14:11

gotch4


People also ask

Does Gson ignore transient fields?

By default, GSON excludes transient and static fields from the serialization/deserialization process.

Does Gson serialize private fields?

In this example you'll see how the Gson library handles the object fields. For object fields to be serialized into JSON string it doesn't need to use any annotations, it can even read private fields.

How does Gson serialize?

Serialization in the context of Gson means converting a Java object to its JSON representation. In order to do the serialization, we need to create the Gson object, which handles the conversion. Next, we need to call the function toJson() and pass the User object. Program output.

Does Gson ignore extra fields?

As you can see, Gson will ignore the unknown fields and simply match the fields that it's able to.


2 Answers

Gson 2.1 supports this out of the box:

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;
  }
}

The ouput is

{
  "classes": [
    {
      "stars": 1
    },
    {
      "sunshines": 3,
      "stars": 2
    }
  ]
}
like image 95
Guillaume Perrot Avatar answered Nov 14 '22 23:11

Guillaume Perrot


I used Ivan's answer to clue me into a slightly more elegant solution - it's not perfect, but it worked well enough for me. I created a new JsonSerializer that throws away the type of A by casting it to an Object. It seems that when given a plain Object Gson looks at the actual type of the object instead of referring from the type of the variable that's passed in.

public static class ASerializer implements JsonSerializer<A> {

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

You then pass the ASerializer to a GsonBuilder to get yourself a Gson instance to use:

GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter( A.class, new ASerializer() ); 
Gson gson = gb.create();
like image 28
Volker Neumann Avatar answered Nov 14 '22 22:11

Volker Neumann