2

I'm writing a Java client to a web service and need to parse the response JSON object into a Map<String,String>.

I don't have control over the JSON format, and the client plugs into a relatively old existing app is a memory hog and has literally hundreds of other java library dependencies.

So my concerns are to make my client as free of external dependencies as possible and have a minimal memory footprint over time to avoid heavy memory usage and garbage collection.

I know I can do this with Gson or Jackson so am looking for input as to the best approach considering these runtime constraints (I've never used JSON. Simple and I didn't see on quick perusal how to handle complex types).

The JSON looks like this. I only need to concern myself with the attribute section name/value pairs. The rest I can ignore.

{
    "responseInfo": {
        "responseMsg": "Success",
        "timeStamp": "***",
        "transactionId": "***"
    },
    "callerId":  "****", 
    "locale": "en-US",
    "userId": "***",
    "attributes":[
    {
        "attributeName": "AN",
        "attributeDescription": "Account Number",
        "attributeValue": "*****"
    },
    {
        "attributeName": "EA",
        "attributeDescription": "Email Address",
        "attributeValue": "****@****"
    },
    {
        "attributeName": "SOI",
        "attributeDescription": "someotherinfo",
        "attributeValue": "****"
    }
}

Thanks for any input!

alayor
  • 4,537
  • 6
  • 27
  • 47
Richard Sand
  • 642
  • 6
  • 20
  • What if you use json.org? https://mvnrepository.com/artifact/org.json/json/20160810 – alayor Mar 03 '17 at 05:10
  • I would use JSONobject and read in the JSON and then create a DAO data access object with setters to store the information into your Java app or you could even leave it as a JSONobject. http://docs.oracle.com/javaee/7/api/javax/json/JsonObject.html you could use getJsonObject("Key") which would return you the value. – JesseBoyd Mar 03 '17 at 05:15
  • You wrote **I don't have control over the JSON format** so is it that json received can have any format and the one you placed in question as example is not the static format? – Rajen Raiyarela Mar 03 '17 at 05:24
  • Checkout this [answer](http://stackoverflow.com/a/13926850/3831557) and this [answer](http://stackoverflow.com/a/19760249/3831557), may be helpful to you – Rajen Raiyarela Mar 03 '17 at 05:29
  • There are dozens of options. Which Java version/environment are you using? What dependencies do you have already (Gson, Jackson, org.json, a JSR-374 implementation)? Would you like simple JSON trees processing or more complicated but more efficient stream reading/analyzing to probably have more efficient memory management? – Lyubomyr Shaydariv Mar 03 '17 at 08:28
  • Hi all - by "don't have control" I mean that the JSon document format (the sample snipped I provided) is what the server generates and I don't have any flexibility in rearranging the JSon. The Java version is 1.7. There is no JSon library in the application I'm plugging into, and my main concern is to add as few new dependencies as possible (I'm planning on making a shaded/uber-jar) and having as small a memory footprint as possible – Richard Sand Mar 03 '17 at 15:19
  • In other words, I'm more concerned with memory and garbage collection impacts than I am the actual time performance of the parsing – Richard Sand Mar 03 '17 at 15:20
  • @RichardSand All popular JSON libraries do not seem to have external dependencies, so adding one of them seems to mean just adding one dependency and no transitive dependencies. If the size of a particular library is too large, you can shrink it with tools like ProGuard in order to drop away the dead code your application is not supposed to ever use. – Lyubomyr Shaydariv Mar 03 '17 at 16:04
  • @RichardSand Regarding memory management: libraries like Gson deserialize using JSON stream reading (from my understanding of Gson under the hood), so creating a special class to map necessary properties only may be both efficient and simple. But no `JsonElement` and so on: they are designed to store all data in memory, even data you want to ignore (like XML DOM). If you believe it can be faster, you can write low-level parser to read JSON as tokens (similarly to SAX for XML, but "pulling"; usually not quite simple, so there should be a compromise). – Lyubomyr Shaydariv Mar 03 '17 at 16:04
  • @RichardSand In Gson, the simplest way is just creating a concrete mapping `class Mapping { List> attributes; }` and just deserializing it ignoring other fields: `Mapping mapping = gson.fromJson(..., Mapping.class);`. `System.out.println(mapping.attributes);` results as: `[{attributeName=AN, attributeDescription=Account Number, attributeValue=*****}, {attributeName=EA, attributeDescription=Email Address, attributeValue=****@****}, {attributeName=SOI, attributeDescription=someotherinfo, attributeValue=****}]` – Lyubomyr Shaydariv Mar 03 '17 at 16:05

1 Answers1

0

Thanks for your helpful responses. FYI I went with Jackson and implemented a generic parser to look for name/value pairs within a JSon block. I'm pleased with the flexibility and the short amount of code necessary. For reference this is the code I wrote:

   final ObjectMapper mapper = new ObjectMapper();
   final ArrayType type = mapper.getTypeFactory().constructArrayType(Map.class);

   try {
       if (attrBlockName == null || attrBlockName.length() == 0)
           return mapper.readValue(f, type);
       JsonNode base = new ObjectMapper().readTree(f);
       if (base == null)
           return JSonHttpClientAttributeProvider.PROVIDER_FAILED_UNKNOWN;
       JsonNode attrJson = base.get(attrBlockName);
       if (attrJson == null)
           return JSonHttpClientAttributeProvider.PROVIDER_FAILED_UNKNOWN;
       Map<String, String>[] mapArray = mapper.readValue(mapper.treeAsTokens(attrJson), type);
       for (Map<String, String> newmap : mapArray) {
           if (newmap.containsKey(attrNameField) && newmap.containsKey(attrValueField))
               map.put(newmap.get(attrNameField), newmap.get(attrValueField));
       }
       return PROVIDER_SUCCEEDED;
   } catch (IOException ioe) {
       throw new MyExceptionClass("Exception occurred during request", ioe);
   }
Richard Sand
  • 642
  • 6
  • 20