Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default Serializer stops working when a Custom Deserializer is registered #1366

Closed
adityax10 opened this issue Aug 7, 2018 · 4 comments
Closed
Labels

Comments

@adityax10
Copy link

Walkthrough -

I created an abstract class Child with one concrete implementation Son. A reference to Child is used in Parent class as a member variable. Next we try to serialize an instance of Parent class.

Scenario 1 -
When no adapter is registered for Child class.
Output -
{"child":{"sonName":"s1","childName":"p1"}} //this is the correct, expected response

Scenario 2 -
When only a custom deserializer (which simply calls the default deserializer) adapter is registered for Child class.
Output -
{"child":{"childName":"p1"}} //Child class fields are missing in the response

Scenario 3 -
When both custom deserializer and a custom serializer are registered for Child class.
Output -
{"child":{"sonName":"s1","childName":"p1"}} //expected response

Question - Is it necessary to register a custom serializer along with a custom deserializer?

The code snippet to reproduce the above scenarios. Please register the appropriate adapters in the main method for each of the above scenarios -

`public class GsonAdapterTest {

abstract static class Child {
    protected String childName;

    public Child(String childName) {
        this.childName = childName;
    }

    public Child() {
    }

    public String getChildName() {
        return childName;
    }

    public void setChildName(String childName) {
        this.childName = childName;
    }
}

static class Son extends Child {
    public String sonName;

    public Son(String parentName, String sonName) {
        super(parentName);
        this.sonName = sonName;
    }

    public Son() {

    }

    public String getSonName() {
        return sonName;
    }

    public void setSonName(String sonName) {
        this.sonName = sonName;
    }
}

static class Parent {
    private Child child;

    public Parent(Child child) {
        this.child = child;
    }

    public Parent() {
    }

    public Child getChild() {
        return child;
    }

    public void setChild(Child child) {
        this.child = child;
    }
}

public static void main(String[] args) {
    try {
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Child.class, new ChildDeserializer())
                .create();
        Son son = new Son("p1", "s1");
        Parent parent = new Parent(son);
        System.out.println(gson.toJson(parent));

    } catch (Exception e) {
        e.printStackTrace();
    }
}

static class ChildDeserializer implements JsonDeserializer<Child> {
    @Override
    public Child deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return context.deserialize(json, typeOfT);
    }
}

static class ChildSerializer implements JsonSerializer<Child> {
    @Override
    public JsonElement serialize(Child src, Type typeOfSrc, JsonSerializationContext context) {
        return context.serialize(src);
    }
}

}`

@lyubomyr-shaydariv
Copy link
Contributor

Interesting. What if you use registerTypeHierarchyAdapter?

@anirudhramanan
Copy link
Contributor

Yes, you will need to register both serializer and deserailzer, since internally this uses SingleTypeFactory for creating the typeadapter.

screen shot 2018-08-20 at 11 26 46 am

Alternatively, you can extend the TypeAdapter, have your custom implementation in case of read/write

@Marcono1234
Copy link
Collaborator

Might be the same as #2032

@Marcono1234 Marcono1234 added the bug label Aug 5, 2022
@Marcono1234
Copy link
Collaborator

Looks like #1787 fixed this issue. The next Gson version will include that fix.

The reason why in your code using registerTypeAdapter(Child.class, new ChildSerializer()) fixed this issue is because ChildSerializer calls context.serialize(src). This will end up using the adapter for the runtime type of src. In your case that seems to be safe because Child is an abstract class. However, in general calling context.serialize(src) should be avoided because it can lead to infinite recursion (the documentation of JsonSerializer.serialize warns about this).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants