Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson, JSON and the subtleties of LinkedTreeMap

Tags:

java

json

gson

I've recently started playing around with JSON strings, and was told that Google's own library, Gson, is the new and hip way of dealing with these.

The way I've understood it, is that a JSON string is essentially a map. Where each variable points to a value in the string.

For example:

String jsonInput2 = "{\"created_at\":\"Sat Feb 08 15:37:37 +0000 2014\",\"id\":432176397474623489\"}

Thus far, all is well. Information such as when this JSON string was created, can be assigned to a variable with the following code:

Gson gson = new Gson();

Map<String, String> map = new HashMap<String, String>();

map = (Map<String, String>) gson.fromJson(jsonInput, map.getClass());

String createdAt = map.get("created_at");

It's almost artistic in in simple beauty. But this is where the beauty ends and my confusion begins.

The following is an extension of the above JSON string;

String jsonInput2 = "{\"created_at\":\"Sat Feb 08 15:37:37 +0000 2014\",\"id\":432176397474623489\",\"user\":{\"id_str\":\"366301747\",\"name\":\"somethingClever\",\"screen_name\":\"somethingCoolAndClever\"}}";

My question is how these "brackets within brackets" work for the user section of the JSON?

How could I assign the values specified within these inner-brackets to variables?

Can anyone explain to me, or show me in code, how Gson handles stuff like this, and how I can use it?

In short, why does...

String jsonInput = "{\"created_at\":\"Sat Feb 08 15:37:37 +0000 2014\",\"id\":432176397474623489\",\"user\":{\"id_str\":\"366301747\",\"name\":\"somethingClever\",\"screen_name\":\"somethingCoolAndClever\"}}";

Gson gson = new Gson();

Map<String, String> map = new HashMap<String, String>();

map = (Map<String, String>) gson.fromJson(jsonInput, map.getClass());

String name = map.get("name");

System.out.println(name);

... print out null?

like image 436
ViRALiC Avatar asked Mar 09 '14 17:03

ViRALiC


People also ask

What is difference between JSON and Gson?

GSON can use the Object definition to directly create an object of the desired type. While JSONObject needs to be parsed manually.

What is LinkedTreeMap Java?

Class LinkedTreeMap<K,V>A map of comparable keys to values. Unlike TreeMap , this class uses insertion order for iteration order. Comparison order is only used as an optimization for efficient insertion and removal. This implementation was derived from Android 4.1's TreeMap class.

What is the use of Gson fromJson?

As many of you know already Gson is a great Java library that can be used to convert Java Objects into their JSON representation. It works also in reverse order deserializing the specified JSONObject or JSONArray into an object of the specified class.


2 Answers

Forget about Java. You need to first understand the JSON format.

This is basically it

object
    {}
    { members }
members
    pair
    pair , members
pair
    string : value
array
    []
    [ elements ]
elements
    value 
    value , elements
value
    string
    number
    object
    array
    true
    false
    null

Your second JSON String (which has a missing ") is the following (use jsonlint.com to format)

{
    "created_at": "Sat Feb 08 15:37:37 +0000 2014",
    "id": "432176397474623489",
    "user": {
        "id_str": "366301747",
        "name": "somethingClever",
        "screen_name": "somethingCoolAndClever"
    }
}

The JSON is an object, outer {}, that contains three pairs, created_at which is a JSON string, id which is also a JSON string, and user which is a JSON object. That JSON object contains three more pairs which are all JSON strings.

You asked

How could I assign the values specified within these inner-brackets to variables?

Most advanced JSON parsing/generating libraries are meant to convert JSON to Pojos and back.

So you could map your JSON format to Java classes.

class Pojo {
    @SerializedName("created_at")
    private String createdAt;
    private String id;
    private User user;
}

class User {
    @SerializedName("id_str")
    private String idStr;
    private String name;
    @SerializedName("screen_name")
    private String screenName;
}

// with appropriate getters, setters, and a toString() method

Note the @SerializedName so that you can keep using Java naming conventions for your fields.

You can now deserialize your JSON

Gson gson = new Gson();
Pojo pojo = gson.fromJson(jsonInput2, Pojo.class);
System.out.println(pojo);

would print

Pojo [createdAt=Sat Feb 08 15:37:37 +0000 2014, id=432176397474623489", user=User [idStr=366301747, name=somethingClever, screenName=somethingCoolAndClever]]

showing that all the fields were set correctly.

Can anyone explain to me, or show me in code, how Gson handles stuff like this, and how I can use it?

The source code of Gson is freely available. You can find it online. It is complex and a source code explanation wouldn't fit here. Simply put, it uses the Class object you provide to determine how it will map the JSON pairs. It looks at the corresponding class's fields. If those fields are other classes, then it recurs until it has constructed a map of everything it needs to deserialize.


In short, why does...print out null?

Because your root JSON object, doesn't have a pair with name name. Instead of using Map, use Gson's JsonObject type.

JsonObject jsonObject = new Gson().fromJson(jsonInput2, JsonObject.class);

String name = jsonObject.get("user")       // get the 'user' JsonElement
                        .getAsJsonObject() // get it as a JsonObject
                        .get("name")       // get the nested 'name' JsonElement
                        .getAsString();    // get it as a String
System.out.println(name);

which prints

somethingClever

The above method class could have thrown a number of exceptions if they weren't the right type. If, for example, we had done

String name = jsonObject.get("user")       // get the 'user' JsonElement
                        .getAsJsonArray()  // get it as a JsonArray

it would fail because user is not a JSON array. Specifically, it would throw

Exception in thread "main" java.lang.IllegalStateException: This is not a JSON Array.
    at com.google.gson.JsonElement.getAsJsonArray(JsonElement.java:106)
    at com.spring.Example.main(Example.java:19)

So the JsonElement class (which is the parent class of JsonObject, JsonArray, and a few others) provides methods to check what it is. See the javadoc.

like image 185
Sotirios Delimanolis Avatar answered Sep 30 '22 04:09

Sotirios Delimanolis


For people that come here searching for a way to convert LinkedTreeMap to object:

MyClass object = new Gson().fromJson(new Gson().toJson(((LinkedTreeMap<String, Object>) theLinkedTreeMapObject)), MyClass .class)

This was usefull for me when i needed to parse an generic object like:

Class fullObject {
  private String name;
  private String objectType;
  private Object objectFull;   
}

But i don't know which object the server was going to send. The objectFull will become a LinkedTreeMap

like image 40
Renato Probst Avatar answered Sep 30 '22 06:09

Renato Probst