2

Overview, I have an abstract class from which three concrete classes inherit.

public abstract class A {}

public class B extends A {}

public class C extends A {}

public class D extends A {
   private List<A> children;
 }

Main point is that concrete class D has a list that could contain objects of concrete class B, C or D.

My challenge is how to serialize D given that its children could be of three different types; itself or the two other concrete classes. I have a working custom serializer that works if all the children are of the same type. Not looking for a full blown solution, a high level approach or strategy will be fine. Thanks.

user3146617
  • 101
  • 1
  • 1
  • 3
  • Do you mean **de**serialize? As-is Gson has no problem serializing that to JSON correctly automatically. – Brian Roach Dec 31 '13 at 18:16
  • I do mean serialize ie. Write to json. Ordinarily yes, but in the case of the scenario above no, it does not. It does not include fields in the abstract class when it serializes its subclasses. It appears to be treating classes A, B, C and D as separate concrete classes completely ignoring the inheritance relationship. – user3146617 Jan 01 '14 at 23:53
  • Then you're using an ancient version of Gson. The current version (2.2.4) works as you want / expect. – Brian Roach Jan 02 '14 at 00:09
  • It's not a version of Gson issue. Your code will break if you add an object of type D to the list in D. As I mentioned in the original question "Main point is that concrete class D has a list that could contain objects of concrete class B, C or D." – user3146617 Jan 02 '14 at 13:43

2 Answers2

1

Take a look to https://stackoverflow.com/a/22081826/3315914. There's a working example of it. All you need is Gson's RuntimeTypeAdapterFactory. A simple example could be:

RuntimeTypeAdapter<Shape> shapeAdapter = RuntimeTypeAdapterFactory.of(Shape.class)
        .registerSubtype(Rectangle.class)
        .registerSubtype(Circle.class)
        .registerSubtype(Diamond.class);

And then,

Gson gson = new GsonBuilder()
       .registerTypeAdapter(Shape.class, shapeAdapter)
       .create();

Also, here you can also find a similar answer.

I hope it helps.

Marquee
  • 1,776
  • 20
  • 21
rpax
  • 4,468
  • 7
  • 33
  • 57
  • 1
    Note that you have to copy the Google code into your own repo, it is not available in Maven Central and they do not plan to ever make it generally available. Basically, it is not officially supported so they do not make it easily accessible. But it works!! – Marquee Jan 26 '19 at 01:08
0

I highly suspect you are using some ancient version of Gson or you're not explaining exactly what the problem is. Using v2.2.4 of Gson:

public class App
{
    public static void main(String[] args) 
    {          
        D d = new D();
        D d2 = new D();
        d.list.add(d2);
        System.out.println(new Gson().toJson(d));
    }
}

abstract class A
{
    private int a = 5;
}

class B extends A
{
    private int b = 6;
}

class C extends A
{
    private int c = 7;
}

class D extends A
{
    List<A> list = new ArrayList<A>();

    public D()
    {
        list.add(new B());
        list.add(new C());
    }
}

Output:

{"list":[{"b":6,"a":5},{"c":7,"a":5},{"list":[{"b":6,"a":5},{"c":7,"a":5}],"a":5}],"a":5}

As you can see, the inherited private field a from the abstract A is serialized correctly when B,C, and D are serialized.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161