Gson add field during serialization

后端 未结 2 1920
一整个雨季
一整个雨季 2020-12-23 11:36

I can\'t find a simple way to add a custom field during serialization in Gson and I was hoping someone else may be able to help.

Here is a sample class to show my is

相关标签:
2条回答
  • 2020-12-23 12:27

    Use Gson.toJsonTree to get a JsonElement, with which you can interact dynamically.

    A a = getYourAInstanceHere();
    Gson gson = new Gson();
    JsonElement jsonElement = gson.toJsonTree(a);
    jsonElement.getAsJsonObject().addProperty("url_to_user", url);
    return gson.toJson(jsonElement);
    
    0 讨论(0)
  • 2020-12-23 12:34

    Well, the top rated answer is quite a quick one and not essentially bad when you are lacking much time but here is the problem: There is no proper separation of concern

    You are modifying the serialized JSON at the same place where you are writing your business logic. You should be doing all the serialization inside of a TypeAdapter or a JsonSerializer.

    How can we maintain a proper separation of concern?

    The answer wraps around a bit of additional complexity but the architecture demands it. Here we go(taken from my other answer):

    First, we would be using a custom serializer for the type. Second, we would have to create a copy constructor inside the base class and a wrapper subclass as follows:

    Note: The custom serializer might seem like an overkill but trust me, it pays off in long run for maintainability. .

    // Lets say the base class is named Cat
    public class Cat {
    
        public String name;
    
        public Cat(String name) {
            super();
            this.name = name;
        }
        // COPY CONSTRUCTOR
        public Cat(Cat cat) {
            this.name = cat.name;
        }
    
        @Override
        public String sound() {
            return name + " : \"meaow\"";
        };
    }
    
    
    
        // The wrapper subclass for serialization
    public class CatWrapper extends Cat{
    
    
        public CatWrapper(String name) {
            super(name);
        }
    
        public CatWrapper(Cat cat) {
            super(cat);
        }
    }
    

    And the serializer for the type Cat:

    public class CatSerializer implements JsonSerializer<Cat> {
    
        @Override
        public JsonElement serialize(Cat src, Type typeOfSrc, JsonSerializationContext context) {
    
            // Essentially the same as the type Cat
            JsonElement catWrapped = context.serialize(new CatWrapper(src));
    
            // Here, we can customize the generated JSON from the wrapper as we want.
            // We can add a field, remove a field, etc.
    
            // The main logic from the top rated answer now here instead of *spilling* around(Kindly ignore the cat having a url for the sake of example)
            return catWrapped.getAsJsonObject().addProperty("url_to_user", url);
        }
    }
    

    So, why a copy constructor?

    Well, once you define the copy constructor, no matter how much the base class changes, your wrapper will continue with the same role. Secondly, if we don't define a copy constructor and simply subclass the base class then we would have to "talk" in terms of the extended class, i.e, CatWrapper. It is quite possible that your components talk in terms of the base class and not the wrapper type.

    0 讨论(0)
提交回复
热议问题