GSON 2.0+ - Deserialize and parse arbitrary fields - java

I am pulling a JSON string from a web service, that is styled in the version below. The JSON strings fields for the id's displayed would be arbitrary depending on what was sent in the get. I have followed some examples with gson where they talk about taking the json and running it into an object to handle the arbitrary field values.
How to decode JSON with unknown field using Gson? and Dealing with randomly generated and inconsistent JSON field/key names using GSON
My question is, what do I do with the object once I create it to pull out specific fields. I had a custom class to pull the values from the inside of the object (id, name, profile) etc, but I'm lost in how I would be able to reference the two, or how I would extract the information from the object into an arraylist or something of the sort.
{
"415943": {
"id": 415943,
"name": "Zoro Roronoa",
"profileIconId": 580,
"revisionDate": 1390848107000,
"summonerLevel": 30
},
"19758386": {
"id": 19758386,
"name": "Zoro",
"profileIconId": 535,
"revisionDate": 1390855130000,
"summonerLevel": 30
}
}
Main.java
Gson gson = new Gson();
Object o = gson.fromJson(jsonStatsString, Object.class);

You can use your custom object that contains the mapped fields in the JSON, and have them converted to a List for you:
List<MyObject> items =
gson.fromJson(json, new TypeToken<List<MyObject>>() { }.getType());

Related

How to create POJOs for JSON response consisting of ordered pair with date and data?

This is what my JSON looks like:
{
"Meta Data":{
"1: Symbol":"MSFT",
"2: Indicator":"Moving Average Convergence/Divergence (MACD)",
"3: Last Refreshed":"2019-03-08",
"4: Interval":"daily",
"5.1: Fast Period":12,
"5.2: Slow Period":26,
"5.3: Signal Period":9,
"6: Series Type":"open",
"7: Time Zone":"US/Eastern"
},
"Technical Analysis: MACD":{
"2019-03-08":{
"MACD":"1.5751",
"MACD_Signal":"1.6779",
"MACD_Hist":"-0.1028"
},
"2019-03-07":{
"MACD":"1.8551",
"MACD_Signal":"1.7036",
"MACD_Hist":"0.1515"
},
"2019-03-06":{
"MACD":"1.9574",
"MACD_Signal":"1.6657",
"MACD_Hist":"0.2918"
}
}
}
I tried generating POJOs through online tools, however, it generates a different POJO for each data. Since my data could potentially be of a hundred dates. I want a generic POJO setup that would allow me to store this data with the dates, something like a 2D array or a HashMap.
Edit: I am developing an Android app using Retrofit, Gson.
When the keys are fixed (e.g. "Meta Data", "MACD", ...), you map the JSON Object to a POJO class.
When the keys are dynamic (e.g. "1: Symbol", "2019-03-08", ...), you map the JSON Object to a Map.
E.g. if using Gson:
class Root {
#SerializedName("Meta Data")
Map<String, String> metaData;
#SerializedName("Technical Analysis: MACD")
Map<String, Analysis> analysis;
}
class Analysis {
#SerializedName("MACD")
String macd;
#SerializedName("MACD_Signal")
String macdSignal;
#SerializedName("MACD_Hist")
String macdHist;
}

Converting DynamoDB JSON document to JSON object in Java

I am reading the backup DynamoDB S3 bucket which has format for DynamoDB JSON.
I am trying to convert it into a normal JSON without the AttributeValue.
Original String
{
"id": {
"s": "someString"
},
"name": {
"b": "someByteBuffer"
},
"anotherId": {
"s": "someAnotherString"
},
"version": {
"n": "1"
}
}
Trying to convert to
{
"id": "someString",
"name": "someByteBuffer",
"anotherId": "someAnotherString",
"version": "1"
}
There are many answers which I referred to, but it doesn't convert into normal JSON, it gives me back the same JSON.
Here is what I tried:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(inputJsonString);
final JacksonConverter converter = new JacksonConverterImpl();
Map<String, AttributeValue> map = converter.jsonObjectToMap(jsonNode);
Item item = ItemUtils.toItem(map);
Gson gson = new Gson();
System.out.println(gson.toJson(item.asMap()));
Also, when I was debugging, I wasn't able to create the Map properly. Map would contain key as "id", value as AttributeValue, but the AttributeValue would contain the string inside its own Map<String, AttributeValue> instead of inside String s
I feel I am missing something while creating the Map. Any pointers?
References on Stackoverflow:
Link 1
Link 2
What you're describing as the result sounds correct. If you look at the original JSON string, you have a list of key:value pairs where each value is another list of key:value pairs (length 1, but still a list).
To convert this to a single list of key:value pairs you need to write a map-reduce type of loop. Basically iterate the first map, take the key, then, from the second map (which is the value for the key you just recorded), just take the first entry's value (AttributeValue) and add that key:value pair into a new map (Map<String, AttributeValue>, which you define before the loop). That map you can then convert to JSON and it will result in the JSON string that you were expecting.
Hope that helps!

Java Jackson Serialize JSON to HashTable

I am trying to serialize a list of JSON blobs and put certain keys into a HashTable during the serialization. Here is an example of my JSON:
[
{
"name": "sally",
"id": 1,
"eye_color": "green"
},
{
"name": "jack",
"id": 2,
"eye_color": "blue"
},
{
"name": "jane",
"id": 3,
"eye_color": "brown"
}
]
What I am looking for specifically is a POJO (or set of POJOs) which can serialize the above JSON like so with Jackson assuming the above JSON is in a file called above_json.json:
MyPOJO pojo = objectMapper.readValue(new File("above_json.json"), MyPOJO.class);
I want the result of the serialization to give me a HashTable (or an Object which encapsulates the HashTable) where the HashTable key is the value of name and the Hashtable value is the value of the corresponding id above.
Assuming we serialized the above JSON in this fashion, I would want to access the HashTable like so:
myTable.get("jane")
result: 3
myTable.get("jack")
result: 2
myTable.get("Jill")
result: null
I know how to serialize basic JSON with Jackson. I have an example like below:
JSON Input:
"Parameter":{
"Name":"Parameter-Name",
"Value":"Parameter-Value"
}
POJO to serialize above simple JSON:
public class Parameter {
#JsonProperty("Name")
public String name;
#JsonProperty("Value")
public String value;
}
But obviously this type of setup does not put the results into a HashTable. I need a POJO like what I have in this example which will serialize JSON directly into a HashTable
I don't think that is possible.
You serialize this json into a list of pojos, and have a utility function to generate the hashtable in the way you desire from the list of pojos.
Create a POJO for holding the properties you are interested in.
#JsonIgnoreProperties(ignoreUnknown = true)
private static class MyPOJO {
#JsonProperty("name")
private String name;
#JsonProperty("id")
private Integer id;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
}
Deserialize the contents of the file into List<MyPOJO>
List<MyPOJO> myPOJO = mapper.readValue(new File(".."), new TypeReference<List<MyPOJO>>(){});
Stream the contents of the map to construct a map whose key is the name and value is the id.
Map<String, Integer> map = myPOJO.stream()
.collect(Collectors.toMap(MyPOJO::getName, MyPOJO::getId));
First of all, you probably don't want to use a HashTable, as it's considered to be an obsolete type (see here).
Either use a HashMap or if you want thread safety, a ConcurrentHashMap or a thread-unsafe Map backed by Collections.synchronized[...] and referenced to within synchronized statements.
Secondly, you can use a TypeReference to de-serialize as your desired type.
Finally, your JSON's syntax is incorrect: it starts with a square bracket ([) and ends with a curly bracket (}), which is technically unparseable.
Assuming you want an array of Maps here (e.g. HashMap<String, String>[]), here is some suitable code, provided you replace the last curly bracket with a square one:
// the map array
Map<String, String>[] map = null;
map = om.readValue(yourFile, new TypeReference<HashMap<String, String>[]>() {});
// prints the de-serialized contents
System.out.println(Arrays.toString(map));
Edit
Since you have now edited your JSON to remove the first square bracket and replace it with a curly bracket, no you can't parse as a Map as is.
Edit 2
Since you have now re-edited your JSON to feature square brackets once again instead of curly brackets in the wrapping object, you can once again de-serialize as a Map[]. Until the next edit, I guess...

Parse json use JsonOjbect vs map into entity with GSon

I'm looking for the right way to parse json use GSon library. Up to now, I have known 2 ways to do this:
Assume I have a json string like this:
{
'Events' : [{
'name' : 'exp',
'date' : '10-10-2010',
'tags' : ["tag 1", "tag2", "tag3"]
},...more events...],
'Contacts' : [{
'name' : 'John Smith',
'date' : '10-10-2010',
'tags' : ["tag 1", "tag2", "tag3"]
},...more contacts...],
}
Use JSonOjbect to get field by its name:
JsonElement jelement = new JsonParser().parse(jsonLine);
JsonObject jobject = jelement.getAsJsonObject();
jobject = jobject.getAsJsonArray("Events");
JsonArray jarray = jobject.getAsJsonArray("Contacts");
jobject = jarray.get(0).getAsJsonObject();
Use GSon to map into entity
public class Container{
List<Event> Events;
List<Contact> Contacts;
}
Container c = new GSon().fromJSon(jsonString,Container.class);
Could you tell me when I should use the first way or the second?
I have a web service could return many kinds of complex json string, and I need get data from this. What should I do?
According to the benchmarks, the first approach (GSON_DOM) is faster. This is likely because with the DOM approach you are only deserializing part of the JSON string. If you wanted even more performance you could switch to the GSON_STREAM approach which seems to do best in the benchmarks.
Practically, the second approach makes for simpler code. I would use probably use that approach first and then switch to one of the other methods if I find that JSON deserialization is taking a significant amount of time.

How can i sort Nested JSON Array?

How can i sort Nested JSON Array? Like for a JSON below...
{
"id":"rtmc05.lax.someabc.net",
"name":"rtmc05.lax.someabc.net",
"tenants":[{
"id":"rtmc",
"name":"rtmc"
},{
"id":"hrs",
"name":"hrs"
},{
"id":"amotelbe1",
"name":"amotelbe"
},{
"id":"cds",
"name":"cds"
},{
"id":"idx-server",
"name":"idx-server",
"tenants":[{
"id":"amotelbe",
"name":"amotelbe",
"tenants":[{
"id":"amotelui",
"name":"amotelui"
}]
}]
}]
}
There's a few parts implicit to your question, and it's not clear where you're having trouble:
How do you take a JSON string and make usable Java objects out of it. (I'm assuming Java, not JavaScript, since you've tagged your question with "java".)
How do you sort those objects after they're made?
How do you handle sorting the nested parts? (In your example, "idx-server" has sub-tenants.)
Not sure exactly which parts of this you're having trouble with, so here's some notes for all three.
Part 1: Getting Java objects
I agree with the other guy that Jackson is a good JSON parser to use. Here's a couple lines of code you could use to parse some JSON:
String jsonString = "..."; // Load this in whatever way makes sense for you
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> parsedJson = mapper.readValue(jsonString, Map.class);
If your JSON string is really huge, then there are other readValue overloads that you can use to avoid reading the whole String into memory.
Part 2: Sorting Java objects
Once you've got the parsed JSON, sorting is just a matter of calling Collections.sort(...), passing in the tenants array. Plus you'll need to write a Comparator that defines the ordering that you want. For example, here's a comparator that sorts by name:
public class NameComparator implements Comparator<Map<String,Object>> {
public int compare(Map<String,Object> o1, Map<String,Object> o2) {
String name1 = (String) o1.get("name");
String name2 = (String) o2.get("name");
return name1.compareTo(name2);
}
}
Then you get the tenants array out (Jackson makes them into ArrayList objects) and call Collections.sort(...). For example,
List<Map<String,Object>> tenants =
(List<Map<String,Object>>) parsedJson.get("tenants");
Collections.sort(tenants, new NameComparator());
Part 3: Handling the nesting
The clearest way to do this is to add some extra code to walk through your JSON looking for any object with a tenants array, and sort it. For example, here's a recursive function that should do it:
public static void recursiveSortTenants(Map<String,Object> jsonObject) {
List<Map<String,Object>> tenants =
(List<Map<String,Object>>) jsonObject.get("tenants");
if (tenants != null) {
Collections.sort(tenants, new NameComparator());
// For each tenant, see if it has sub-tenants. If so,
// call this function again to sort them.
for (Map<String,Object> tenant : tenants) {
if (tenants.containsKey("tenants")) {
recursiveSortTenants(tenant);
}
}
}
}
Hope this helps!
Parse it into (javascript) objects then write a sort function that sorts an array of such javascript objects.
Deserialize it to POJOs(with Gson or Jackson), and write a Comparator for that POJOs.

Categories

Resources