Why Google Gson.toJson loses data

hasanghaforian

I have five classes:

Comment,Paper,WoundPaper,Document,WoundDoc.

Comment is a holder for text.
Paper is empty and abstract class.
WoundPaper extends Paper and stores a String and an ArrayList of Comments.
Document is abstract class and stores ArrayList of <? extends Paper>.
WoundDoc extends Document.

You can see those classes below:

Comment class:

public class Comment {

    private final String text;

    public static class Builder {
        private final String text;

        public Builder(String text) {
            this.text = text;
        }

        public Comment build(){
            return new Comment(this);
        }

    }

    private Comment(Builder builder) {
        this.text = builder.text;
    }

    public String getText() {
        return text;
    }

}

Paper class:

public abstract class Paper {

    protected Paper(ArrayList<Comment> commentList) {
    }

}

WoundPaper class:

public class WoundPaper extends Paper {

    private final String imageUri;
    private final ArrayList<Comment> commentList;

    public static class Builder {
        private final String imageUri;
        private final ArrayList<Comment> commentList;

        public Builder(String imageUri, ArrayList<Comment> commentList) {
            this.imageUri = imageUri;
            this.commentList = commentList;
        }

        public WoundPaper build() {
            return new WoundPaper(this);
        }

    }

    private WoundPaper(Builder builder) {
        super(builder.commentList);
        this.imageUri = builder.imageUri;
        this.commentList = builder.commentList;
    }

}

Document class:

public abstract class Document {
    private final ArrayList<? extends Paper> paperList;


    protected Document(ArrayList<? extends Paper> paperList) {
        this.paperList = paperList;
    }

}

WoundDoc class:

public class WoundDoc extends Document {

    public static class Builder {
        private final ArrayList<WoundPaper> paperList;

        public Builder(ArrayList<WoundPaper> paperList) {
            this.paperList = paperList;
        }

        public WoundDoc build() {
            return new WoundDoc(this);
        }

    }

    private WoundDoc(Builder builder) {
        super(builder.paperList);
    }

}

Now I have to create an instance of WoundDoc and convert it to JSON string by Gson.This is a sample code to do that:

        Comment comment = new Comment.Builder("comment").build();
        ArrayList<Comment> commentList = new ArrayList<Comment>();
        commentList.add(comment);
        commentList.add(comment);

        WoundPaper woundPaper = new WoundPaper.Builder("some Uri", commentList).build();
        ArrayList<WoundPaper> woundPaperList = new ArrayList<WoundPaper>();
        woundPaperList.add(woundPaper);
        woundPaperList.add(woundPaper);

        WoundDoc woundDoc = new WoundDoc.Builder(woundPaperList).build();

        System.out.println("woundDoc to JSON >> " + gson.toJson(woundDoc));

But output is strange:

woundDoc to JSON >> {"paperList":[{},{}]}

As I displayed before,WoundDoc stores list of WoundPaper and each WoundPaper stores list of comments.But why there is no comment in output?

beresfordt

When gson goes to serialise the WoundDoc all it can tell is that there is a List of two objects of type something which extends Paper (List<? extends Paper>); the specific type is unknown. As Paper has no fields for gson to work with it can only say that there are two entries within that list, but as they are the type Paper, which has no fields, there is no way to work out how to serialize those objects.

A way to resolve this is to pass type from your implementations to the abstract classes so that when gson inspects them it can see which class the objects it encounters are instances of, and so work out how to serialise them.

Update Document to take a type parameter:

public abstract class Document<T extends Paper> {
    private final ArrayList<T> paperList;


    protected Document(ArrayList<T> paperList) {
        this.paperList = paperList;
    }
}

Update WoundDoc to pass type to Document:

public class WoundDoc extends Document<WoundPaper> {

Another way to resolve it if you are unable to make the above changes would be to write a custom serializer for WoundDoc

Personally I'd use the first solution and pass type, because I'm lazy and writing a custom serializer is more effort

edit: Minor shout out to jackson which will throw an exception if you try to serialise something and it cannot work out how to do it.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related