skip to Main Content

I have 2 class

class X {
  public String name;
  public int age;
}
class Y {
  public float score;
}

The json is like this

{
  "type": "X",
  "data": {
    "name": "myname",
    "age": 20
  }
}

or

{
  "type": "Y",
  "data": {
    "score": 10
  }
}

How to parse the json with gson but if the type field is X then the data will be X class instance

3

Answers


  1. Chosen as BEST ANSWER

    I found how after some questions to google bard...

    public static class CustomTypeAdapter extends TypeAdapter<Object> {
        @Override
        public void write(JsonWriter out, Object value) {
    
        }
    
        @Override
        public Object read(JsonReader reader) {
            JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject();
    
            String type = jsonObject.get("type").getAsString();
    
            System.out.println(type);
    
            return switch (type) {
                case "X" -> new Gson().fromJson(jsonObject.get("data"), X.class);
                case "Y" -> new Gson().fromJson(jsonObject.get("data"), Y.class);
                default -> throw new JsonParseException("Unknown type: " + type);
            };
        }
    }
    

    Then I use it like this

    JsonReader reader = new Gson().newJsonReader(new StringReader("{"type":"X","data":{"name":"Name","age":10}}"));
    
    Object output = new CustomTypeAdapter().read(reader);
    
    System.out.println(((X) output).name);
    

    But with this i dont know why i extend the TypeAdapter<Object>.. i dont think i need it.


  2. You want to deserialize the JSON according to the value of the type element. So you parse the JSON and extract the value of the type element. Then you extract the data element and use Gson to deserialize it to a Java object.

    import com.google.gson.Gson;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    
    public class GsonTest {
    
        public static void main(String[] args) {
            String json = """
    {
      "type": "X",
      "data": {
        "name": "myname",
        "age": 20
      }
    }
    """;
            JsonElement root = JsonParser.parseString(json);
            JsonObject obj = root.getAsJsonObject();
            JsonElement typeElem = obj.get("type");
            String type = typeElem.getAsString();
            JsonElement dataElem = obj.get("data");
            Gson gson = new Gson();
            Class<?> theClass;
            if ("X".equals(type)) {
                theClass = X.class;
            }
            else if ("Y".equals(type)) {
                theClass = Y.class;
            }
            else {
                theClass = null;
            }
            if (theClass != null) {
                Object result = gson.fromJson(dataElem, theClass);
                System.out.println(result);
            }
        }
    }
    

    The above code uses text blocks that were added in Java 15.

    I added a toString method to class X:

    public String toString() {
        return String.format("%s:%d", name, age);
    }
    

    When I run the above code, I get the following:

    myname:20
    

    Note that one would usually make class X and class Y JavaBeans, i.e. you need to add "getters" and "setters".

    Here is a complete code:

    import com.google.gson.Gson;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.google.gson.JsonParser;
    
    public class GsonTest {
    
        public static void main(String[] args) {
            String json = """
    {
      "type": "Y",
      "data": {
        "score": 10
      }
    }
    """;
            JsonElement root = JsonParser.parseString(json);
            JsonObject obj = root.getAsJsonObject();
            JsonElement typeElem = obj.get("type");
            String type = typeElem.getAsString();
            JsonElement dataElem = obj.get("data");
            Gson gson = new Gson();
            Class<?> theClass;
            if ("X".equals(type)) {
                theClass = X.class;
            }
            else if ("Y".equals(type)) {
                theClass = Y.class;
            }
            else {
                theClass = null;
            }
            if (theClass != null) {
                Object result = gson.fromJson(dataElem, theClass);
                System.out.println(result);
            }
        }
    }
    
    class X {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString() {
            return String.format("%s:%d", name, age);
        }
    }
    
    class Y {
        private float score;
    
        public float getScore() {
            return score;
        }
    
        public void setScore(float score) {
            this.score = score;
        }
    
        public String toString() {
            return Float.toString(score);
        }
    }
    

    Refer to Gson User Guide

    Login or Signup to reply.
  3. var m = new TreeMap();
    m.put("type", X.class.getSimpleName());
    m.put("data", new X("myname", 20));
    
    var gson = new Gson();
    var json = gson.toJson(m);
    

    if you don’t want to create custom adapter then try using map!
    it could be one of the most simple solution

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search