'Deserialise object into a subtype dynamically using gson

I have a base class

public class Box<T> {
    private T entity;

    public T getEntity() {
        return entity;
    }

    void setEntity(T entity) {
        this.entity = entity;
    }
}

It has 2 implementations.

// Class Person
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
// Class Machine
public class Machine {
    private String macAddress;
    private String type;

    public Machine(String macAddress, String type) {
        this.macAddress = macAddress;
        this.type = type;
    }
}

If I want to serialise either of classA or class B objects, I will do it like this

Type typeTokenPerson = new TypeToken< Box <Person>>() {}.getType();
String userJson = gson.toJson(boxWithPersonObject, typeTokenPerson);

But the problem here is I need to know the type at compile time. I have a use case where I don't know this at compile-time, in other words, I have a json which I want to deserialize into either Person or Animal and I want to do this at runtime based on some condition. Is there a way to do this usig Gson ?

Example: Lets say we have a json like this

{
  "entity": {
    "name": "ABC",
    "age": 10
  }
}

This is of type Person. I want to deserialise this into an object of type Box<Person>



Solution 1:[1]

Gson can do it like this.

package com.example.demo;

import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Type;
import java.time.Duration;
import java.time.LocalDateTime;

public class GsonDemo {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private <T> Box<T> parseResponse(String responseData) {

        Gson gson = new Gson();
        Type jsonType = new TypeToken<Box<T>>() {
        }.getType();
        Box<T> result = gson.fromJson(responseData, jsonType);

        return result;
    }

    @Test
    public void test() {
        LocalDateTime start = LocalDateTime.now();
        try {
            String json = "{  \"entity\": {  \"name\": \"ABC\",    \"age\": 10 }}";
            Box<Person> objectBox = parseResponse(json);
            System.out.println(objectBox);
            String json2 = "{\n  \"entity\": {  \"macAddress\": \"DEF\",   \"type\": \"def\" }}";
            Box<Machine> objectBox2 = parseResponse(json2);
            System.out.println(objectBox2);
        } catch (Exception e) {
            logger.error("Error", e);
        }
        LocalDateTime end = LocalDateTime.now();
        logger.info("Cost time {}", Duration.between(start, end).toMillis() + "ms");
    }

    public class Box<T> {
        private T entity;

        public T getEntity() {
            return entity;
        }

        void setEntity(T entity) {
            this.entity = entity;
        }

        @Override
        public String toString() {
            return "Box{" + "entity=" + entity + '}';
        }
    }

    public class Person {
        private String name;
        private Integer age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }


        @Override
        public String toString() {
            return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
        }
    }

    public class Machine {
        private String macAddress;
        private String type;

        public Machine(String macAddress, String type) {
            this.macAddress = macAddress;
            this.type = type;
        }

        public String getMacAddress() {
            return macAddress;
        }

        public void setMacAddress(String macAddress) {
            this.macAddress = macAddress;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        @Override
        public String toString() {
            return "Machine{" + "macAddress='" + macAddress + '\'' + ", type='" + type + '\'' + '}';
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1