Search code examples
jsongsondeserializationjson-deserialization

How to parse multiple fields into one sub-object in GSON?


I'm trying to parse some json data that looks like this:

{
  "store_name": "Coffee Co",
  "location": "New York",
  "supplier_name": "Cups Corps",
  "supplier_id": 12312521,
  "supplier_email": "[email protected]"
}

And here's my Java POJOs

class Store {
    @com.google.gson.annotations.SerializedName("store_name")
    String storeName;
    String location;
    Supplier supplier;
}

class Supplier {
    String id;
    String name;
    String email;
}

//Getters and setters omitted

The issue I'm having is that the fields for the Supplier are flattened directly into the Store record. I tried adding a TypeAdapter to my Gson object for Supplier but it doesn't get triggered because there's no field named supplier on the incoming json object. I also can't use an alternate name for supplier because it needs information from all three of the fields in order to be created.

What is the best way to parse this data so that the nested Supplier field can also be populated?


Solution

  • What you could do is use a custom deserializer:

    class StoreDeserializer implements JsonDeserializer<Store> {
    
        @Override
        public Store deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            JsonObject jsonObject = jsonElement.getAsJsonObject();
    
            Supplier supplier = new Supplier(
                    jsonObject.get("supplier_id").getAsInt(),
                    jsonObject.get("supplier_name").getAsString(),
                    jsonObject.get("supplier_email").getAsString()
            );
    
            return new Store(
                    jsonObject.get("store_name").getAsString(),
                    jsonObject.get("location").getAsString(),
                    supplier
            );
        }
    }
    

    You can then deserialize by registering the deserializer:

    String json = "{\"store_name\":\"Coffee Co\",\"location\":\"New York\",\"supplier_name\":\"Cups Corps\",\"supplier_id\":12312521,\"supplier_email\":\"[email protected]\"}";
    Gson gson = new GsonBuilder().registerTypeAdapter(Store.class, new StoreDeserializer()).create();
    Store store = gson.fromJson(json, Store.class);
    

    Note that I changed the type of Supplier#id to int, since it is numeric in your JSON:

    class Supplier {
        int id;
        String name, email;
    
        Supplier(int id, String name, String email) {
            this.id = id;
            this.name = name;
            this.email = email;
        }
    }
    
    class Store {
        String storeName, location;
        Supplier supplier;
    
        Store(String storeName, String location, Supplier supplier) {
            this.storeName = storeName;
            this.location = location;
            this.supplier = supplier;
        }
    }