简体   繁体   中英

Not able to serialize complex json to an object using GSON?

Below is my JSON String which I am getting back by calling from a service API. I have shorten it down by having only three reportRecords for the understanding purpose. In general, it might have ~500 reportRecords

{
   "aggRecords": {
      "reportRecords": [
         {
            "min": 0,
            "max": 12,
            "avg": 0.3699187,
            "count": 246,
            "sumSq": 571,
            "stddev": 1.4779372,
            "median": 0,
            "percentileMap": {
               "95": 4
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "PostProcessing",
               "Type": "PostProcessing"
            },
            "value": 91
         },
         {
            "min": 0,
            "max": 23,
            "avg": 2.3991289E-4,
            "count": 1463031,
            "sumSq": 3071,
            "stddev": 0.045814946,
            "median": 0,
            "percentileMap": {
               "95": 0
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "ResourceContext",
               "Type": "ResourceContext"
            },
            "value": 351
         },
         {
            "min": 0,
            "max": 1209,
            "avg": 1.9203402,
            "count": 7344636,
            "sumSq": 71832774,
            "stddev": 2.4683187,
            "median": 2,
            "percentileMap": {
               "95": 4
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "Client::Sync",
               "Type": "Client::Sync"
            },
            "value": 14104200
         }
      ]
   },
   "minRecordsMap": {}
}

Now From the above JSON response, I need to extract reportRecords whose Name is Client::Sync . Meaning, I need to extract below reportRecords from the above JSON response only.

         {
            "min": 0,
            "max": 1209,
            "avg": 1.9203402,
            "count": 7344636,
            "sumSq": 71832774,
            "stddev": 2.4683187,
            "median": 2,
            "percentileMap": {
               "95": 4
            },
            "metricName": "TransactionDuration",
            "dimensions": {
               "env": "dev",
               "pool": "titan",
               "Name": "Client::Sync",
               "Type": "Client::Sync"
            },
            "value": 14104200
         }

And now I need to parse the above reportRecords for Client::Sync to below object -

public class DataMetrics {

    private String pool;
    private String name;
    private String type;
    private String env;
    private String metricName;
    private String percentile;
    private String median;
    private String stdDev;
    private String sumSq;
    private String count;
    private String avg;
    private String max;
    private String min;

    // getters and setters here
}

So after serializing, above object should look like this -

pool is titan
name is Client::Sync 
type is Client::Sync
env is dev
metricNname is TransactionDuration
95th  percentile is 4
median is 2
stdDev is 2.4683187 
sumSq is 71832774 
count is 7344636 
avg is 1.9203402
max is 1209
min is 0

I am using GSON library here and below is what I have tried so far -

private static RestTemplate restTemplate = new RestTemplate();

public static void main(String[] args) {

    String jsonLine = restTemplate.getForObject("some_url", String.class);
    System.out.println(jsonLine); // here jsonLine will give me above big JSON String

    JsonElement jelement = new JsonParser().parse(jsonLine);
    JsonObject  jobject = jelement.getAsJsonObject();
    jobject = jobject.getAsJsonObject("aggRecords");
    JsonArray jarray = jobject.getAsJsonArray("reportRecords");

    Type type = new TypeToken<List<DataMetrics>>() {}.getType();
    List<DataMetrics> records = gson.fromJson(jsonArrayThatYouHave, type);      

    List<DataMetrics> result = new LinkedList<>();

    for(DataMetrics record : records){
       if(record.name.equals("Client::Sync")){
          result.add(record);
       }
    }       
}

But for some reason, some fields in the DataMetrics shows me the data but some fields are coming empty so that makes me think something is wrong in my above code or my DataMetrics class is not right?

Generally, for nested objects like dimensions you'll declare another POJO for it

class DataMetrics{
  private String min;
  private String max;
  private String avg;
  /*Insert other members*/

  private Dimensions dimensions;

  public boolean isClientSync(){
    return "Client::Sync".equals(dimensions.Name);
  }
  private class Dimensions{
    private String env;
    private String pool;
    private String Name;
  }
}

Tested:

 public void test() {

 String json = "[{\"min\": 0,\"max\": 1209,\"avg\": 1.9203402,\"count\": 7344636,\"sumSq\": 71832774,  \"stddev\": 2.4683187, \"median\": 2,\"percentileMap\": {\"95\": 4},\"metricName\": \"TransactionDuration\",\"dimensions\": {\"env\": \"dev\",\"pool\": \"titan\",\"Name\": \"Client::Sync\", \"Type\": \"Client::Sync\"},\"value\": 14104200}]";

 final Gson gson = new Gson();
 final Type type = new TypeToken<List<DataMetrics>>() {}.getType();
 final List<DataMetrics> records = gson.fromJson(json, type);

 Assert.assertTrue(records.get(0).isClientSync());
}

For percentileMap you'll want an actual map

private Map<String, Integer> percentileMap;

Also note the member variable names should match the JSON property name exactly

  • stdDev => stddev
  • name => Name
  • percentile => percentileMap

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM