How would I decode this JSON with GSON (multi-d-array)? - java

I am using GSON to decode JSON strings that are returned from our server. I haven't had any problems, until I ran into this one particular JSON return from the API. The return is in the following format:
"success":1,"errors":[],"data":{"524":{"id":"524"}, "525":{"id":"525"}}
For the other returns I had data as an array of a class of my own creation, but for this return it says that it is an object and not an array. So how should I format my class?
***edit: What I am having trouble with is that the '524' and '525' fields are not static names. They are dependent on what the user's credentials are. There could be fields 323, 324, 325 or a single one 123. It all depends. How would I be able to handle this dynamically?
SOLVED*
What I had to was make 'data' a <String, Object> hashmap in my custom class. Then after the first decoding, I turned 'data' into an array of type Object []. Then for each Object[i], I converted it into a JSON string. After that I used gson.fromJson() to convert it into what I had originally intended for it to be.

If the API is giving inconsistent results and you can't find a reason on your end why it is doing so, one option is to parse the object into a GSON JSONObject o = gson.fromJson(String) and then convert the data to a list if it is not one already by doing o.getElement("data").isList(), etc..
When this is complete, you can then create the object via gson.fromJson(JSONObject,Class). The alternative is to have two classes, one for each instance, but this seems sloppy if this is the only reason to have two different classes.

GSON is correct. From server reply data is object with two members that are objects also. To be array data should have square brackets [] instead of curly brackets {}. More about JSON format here.
Server format was changed or you tried another API version or someone made bug on server side.

Related

Generate different Java Objects from JSON API Response using Jackson

I'm working on a project at the moment that requires me to take in a various currency pairs and generate a response object from an API call response. I'm using jackson to map the JSON response to java objects then reading data from an ArrayList generated. The problem is the JSON response can have the different currency pairing strings as a key for the list of pairing data. Here's what a typical response looks like:
{"error":[],"result":{"XXBTZUSD":[[1647062100,"39091.2","39184.9","39088.9","39139.0","39150.9","59.22447291",161],}[1647063000,"39138.9","39188.4","39138.9","39151.2","39174.2","2.92905848",126]]}
The problem arises when I try to pull data from a different currency pair as my result object is hard coded to pull the data for the JSON key XXBTZUSD. Here's what my result object looks like:
public class Result{
#JsonProperty("XXBTZUSD")
public ArrayList<ArrayList<Object>> candles;
public int last;
}
I was thinking having the #JsonProperty be variable and pass in the key from the json response to correct pull the currnecy pair I set it to, but JsonProperty needs to be a constant. The only way around this I can see is to have a ton of different classes for each currency pair but that would be inefficient and take around 15 separate classes to do. I'm not too familiar with the jackson library. If anyone has any ideas of how to solve this I would be greatly appreciative, I've been trying to figure out a way around this for awhile now. Thank you!
If keys can be different, one option is to use a Map. Your Result class won't be needed, parse the result property into Map<String, Object>. Then extract like this:
Map<String, Object> result = deserialize();
ArrayList<ArrayList<Object>> arrays = (ArrayList<ArrayList<Object>>) result.get("XXBTZUSD");
Just change property depending on which currency pair you need.
Another option is writing custom deserializer, in which to always put value in your candles field, regardless of how the property is named in json.

Gson: fields that sometimes are strings and others arrays

I'm parsing json with Gson but I'm struggling with the data I'm getting. This is part of an API out of my control (openFDA) so changing that might not be an option.
Here's the json I'm strugling with: https://api.fda.gov/device/event.json?search=device.generic_name:generator&limit=10
There are some fields that are not consistent, for example remedial_action. Sometimes it comes out like this:
"remedial_action": [
"Recall"
]
and in other results like this:
"remedial_action": ""
So it's either an array or a plain string. Is there a way to handle this? If not possible in Gson, any other json parsing library that can help?
I created my pojos here in case someone needs the code. There are a few files created from that and didn't want to spam them here. I can add them if needed.
Update: The bug has been confirmed and it's scheduled for a fix.
It is possible through GSON, by using a TypeAdapter.
Here are the initial steps I would use to do that:
Create a POJO that contains the array and the String. Let's call it RemedialAction.
In your original POJO, create an attribute of the new class.
Create a class that extends TypeAdapter<RemedialAction>.
Override the read() and write() methods and create the logic in them.
That should be a little hard to parse, though. Read this tutorial for more information.
Note: you can customize getRemedialAction() to give you only the valid return -- array or String.

Deserialise array of BSON objects as root object in Java?

My goal is to deserialise a BSON array of documents on Android. When the outer array is anonymous the deserialisation fails (trying to deserialise to CustomObject[].class). When the array is wrapped in an object with a key containing the array it works (deserialising to WrapperObject.class).
In JSON the object would look like this:
[{"id":....},{"id":....},{"id":....}....]
According to the BSON Specification the BSON array is a regular BSON document with integer values for keys. In other words the same object in BSON looks like this:
{"0":{"id":....},"1":{"id":....},"2":{"id":....}....}
I was trying to deserialise the above using bson4jackson when it threw a "Can not deserialize instance of x out of START_OBJECT token" error and in the stacktrace I noticed the unexpected token was a "0" - the BSON representation for the beginning of an array.
My solution, for now, is to wrap the array in a new root object which, in JSON, would look like this:
{"data":[{"id":....},{"id":....},{"id":....},....]}
Can you set bson4jackson, or any other deserialisation library for Java, to treat the root object as an array and deal with it as is, without wrapping?
The reason for this is that bson4jackson is a low-level library which does not know about the type of the object currently being parsed. In BSON arrays are objects and bson4jackson just assumes that every document has an object as its root.
However, there is a workaround for this. Jackson calls the low-level parser's isExpectedStartArrayToken() method whenever an array is read. So, it is possible for bson4jackson to switch to array parsing if the current object is a document, but an array is expected.
The fix has just been implemented. For further details see:
https://github.com/michel-kraemer/bson4jackson/issues/31

Does the sequence of the values matter in a JSON object?

I have a JSON object which I have constructed within my Java program.
JSONObject jObj = {"AAA:aaa","BBB:bbb","CCC:ccc"}
I am sending this object to a server in which it expects the JSON object in the following type.
{"BBB:bbb", "AAA:aaa", "CCC:ccc"}
My question is that does the order of the JSON object really matters on the server side? If yes, how can I change the order?
My question is that does the order of the JSON object really matters on the server side?
It should not matter. According to various JSON specifications, the order of the attributes is not significant. For example:
"An object is an unordered set of name/value pairs." (Source json.org)
"An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array." (Source RFC 7159)
Unfortunately, there are nitwits out there1 who ignore that aspect of the specs, and place some significance on the order of the attributes. (The mistake is usually made when there is a disconnect between the people specifying the APIs and those implementing them, and the people doing the specification work don't really understand JSON.)
Fortunately, the chances are that whoever designed / implemented the server didn't make that mistake. Most Java JSON parsers I've come across don't preserve the attribute order when parsing ... by default2. It would be hard to accidentally implement a server where the order of the JSON attributes being parsed was significant.
If yes, how can i change the order?
With difficulty, I fear:
You could generate the JSON by hand.
There is at least one JSON for java implementation3 that allows you to supply the Map object that holds a JSON object's attributes. If you use a LinkedHashMap or TreeMap, it should retain the insertion order or the lexical order of the attribute keys.
1 - For example, the nitwits that this poor developer was working for ... https://stackoverflow.com/a/4515863/139985
2 - RFC 7159 also says this: "JSON parsing libraries have been observed to differ as to whether or not they make the ordering of object members visible to calling software. Implementations whose behavior does not depend on member ordering will be interoperable in the sense that they will not be affected by these differences.". By my reading, this recommends that JSON libraries should hide any order of the pairs from application code.
3 - JSON-simple : https://code.google.com/p/json-simple/. There could be others too.
IMHO not possible.
JSON docs says
An object is an unordered set of name/value pairs
So the way is getting the values in required order,rather than ordering json
You could use list assuming your server can accept it:
{"list": [ {"AAA":"aaa"},{"BBB":"bbb"},{"CCC":"ccc"}]}
The other answers rightly point out that the order should not matter. There are circumstances were the order may matter in a specific implementation that misunderstands the unordered nature of JSON.
For example say you want take a hash of the JSON string and store the hash for comparison against future hashes. The hash would be different if the order of the fields in the JSON string is not the same the next time you create the hash (even thought the data in the JSON string is the same).
This can happen if you're working with an API or a deserializer that returns JSON strings, with the fields in an inconsistent order.
This question more thoroughly discusses that issue and provides solutions to getting a consistent order JSON order mixed up
The order of fields in a JSON object actually can matter. It depends on the serializer you are using. For example, when you serialize an inherited object you will get an extra JSON field called type=''. When you deserialize it the type field must come before any other JSON Field, otherwise it takes on the type of the parent.

Using reflection to set property values where types are unknown

I am using reflection to set value object properties at runtime. If everything were a string, I may not be asking this question, but that's not the case. I have a web service that returns json and I want to use the json returned by the service to populate the object. I have an ArrayList of strings called alphabeticalKeys that contains sorted keys in the json string. Here is the code I am using to dynamically populate the object (user):
for(String fieldName : alphabeticalKeys){
Log.d("JSON:" + fieldName, json.getString(fieldName));
Field f = userClass.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(user, jsonObject.get(fieldName));
}
In the json data set, there are strings, doubles and more. This is part of a factory class where the type of object being returned is unknown at compile time. Also, the json fields' data types may vary depending on the type of object needed.
The json output matches the field names in the returned object, so I am looking for a way to handle the different data types returned in the json output. Can somebody offer up a suggestion?
Thx! Vivian
There are libraries available to aid in setting property values using reflection, converting to the appropriate type if necessary. For example, Spring Framework's BeanWrapper and Apache Commons BeanUtils.
There are also json libraries that will handle mapping json to/from java objects. For example, Gson and Jackson. This may make it easier, especially if the json structure closely matches the java object structure.

Categories