What is the problem? Well, it turns out that in dealing with these services they were sending back JSON in two different forms. One of those forms was the object form of JSON, which looks like the following:
{"name":"Dustin", "userid":"WebSphereClouds"}
{"name":"Dustin", "userid":"WebSphereClouds"}
The other form that was getting sent back was the array form of JSON, which starts with a [ instead of a {:
[{"name":"Dustin", "userid":"WebSphereClouds"}]
[{"name":"Dustin", "userid":"WebSphereClouds"}]
That may not seem like a big deal, but it does in fact affect the way the data is parsed and the Java object type to which the data is converted.
For instance, consider my application which uses the IBM JSON4J library. If I were trying to convert a response input stream containing data in JSON object form, I would call JSONObject.parse(responseInputStream) and that would return a JSONObject. On the other hand, if I were converting a response input stream containing data in JSON array form I would call JSONArray.parse(responseInputStream) and that would return a JSONArray. Clearly, my application needed a way to determine what form of JSON data it was handling.
To do this, I created a simple class that encapsulates this data type determination. It contains two methods to parse a response input stream and return a JSONArtifact type which is an interface implemented by both JSONObject and JSONArray.
private enum JSONType {
ARRAY_TYPE,
REGULAR_TYPE
}
public JSONArtifact parse(InputStream is) throws IOException {
JSONArtifact parsedJSON = null;
FilterInputStream fis = new BufferedInputStream(is);
JSONType jsonType = getJSONType(fis);
if(jsonType == JSONType.ARRAY_TYPE) {
parsedJSON = JSONArray.parse(fis);
}
else {
parsedJSON = JSONObject.parse(fis);
}
return parsedJSON;
}
JSONType getJSONType(FilterInputStream fis) throws IOException {
JSONType type = null;
fis.mark(1);
byte[] bytes = new byte[1];
fis.read(bytes);
fis.reset();
String firstChar = new String(bytes);
if("[".equals(firstChar)) {
type = JSONType.ARRAY_TYPE;
}
else {
type = JSONType.REGULAR_TYPE;
}
return type;
}
The class simply reads the first byte of data from the stream, resets the stream, and then determines, based on whether the first byte is { or [, whether to parse using the JSONArray or JSONObject class.
I also want to point out what I would consider to be a best practice with respect to JSON data sent back from a RESTful service. When developing RESTful services on the server-side, I suggest sending back the object form of JSON. If necessary, you can encapsulate arrays in this object form:
{"userInfo":[{"name":"Dustin", "userid":"WebSphereClouds"}]}
{"userInfo":[{"name":"Dustin", "userid":"WebSphereClouds"}]}
This will make for simpler parsing by clients of your services, and you can easily add data to what you return by adding more entries in the JSON without regressing existing clients.