Gson, JSON и тонкости LinkedTreeMap

Я недавно начал играть с JSON строки, и было сказано, что собственная библиотека Google,Gson, это новый и хип-способ борьбы с этими.

насколько я понял, это JSON строка по существу является картой. Где каждая переменная указывает на значение в строке.

например:

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

пока все хорошо. Информация, например, когда это JSON строка была создана, может быть назначена переменной с следующий код:

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");

это почти художественно в простой красоте. Но здесь красота заканчивается, и начинается мое замешательство.

следующее является расширением выше JSON строка

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

мой вопрос в том, как эти "скобки в скобках" работа для на JSON?

как я могу присвоить значения, указанные в этих внутренних скобок к переменным?

может кто-нибудь объяснить мне, или покажите мне в коде как Gson обрабатывает такие вещи, и как я могу его использовать?

короче, Почему...

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);

... распечатать null?

5 ответов


забудьте о Java. Вы должны сначала понять формат JSON. Это в основном это

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

ваш второй JSON String (у которого отсутствует ") следующее (используйте jsonlint.com форматировать)

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

JSON-это объект, внешний {}, который содержит три пары, created_at который является строкой JSON,id который также является строкой JSON и user который является объектом JSON. Этот объект JSON содержит еще три пары все строки JSON.

Вы спрашивали

как я могу присвоить значения, указанные в этих внутренних скобках переменные?

большинство продвинутых библиотек JSON-анализа/генерации предназначены для преобразования JSON в Pojos и обратно.

таким образом, вы можете сопоставить формат JSON с классами Java.

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

Примечание @SerializedName чтобы вы могли продолжать использовать Соглашения об именах Java для вашего поля.

теперь вы можете десериализовать JSON в код

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

печати

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

показывает, что все поля были правильно установлены.

может ли кто-нибудь объяснить мне или показать мне в коде, как Gson обрабатывает такие вещи, и как я могу их использовать?

исходный код Gson находится в свободном доступе. Вы можете найти его в интернете. Это сложно, и объяснение исходного кода здесь не подходит. Проще говоря, он использует Class объект, который вы предоставляете, чтобы определить, как он будет отображать пары JSON. Он смотрит на поля соответствующего класса. Если эти поля являются другими классами, то он повторяется, пока не построит карту всего, что ему нужно десериализовать.


короче, Почему...распечатать значение null?

потому что ваш корневой объект JSON не имеет пары с именем name. Вместо использования Map используйте Дсын это JsonObject тип.

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);

, который печатает

somethingClever

вышеуказанный класс метода мог бы создать ряд исключений, если бы они не были правильным типом. Если бы, например, мы сделали

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

это не так user не является массивом JSON. В частности, он будет бросать

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)

так JsonElement class (который является родительским классом JsonObject, JsonArray и несколько других) предоставляет методы для проверки того, что это такое. Увидеть документация Javadoc.


строка JSON имеет следующую структуру:

{
    created_at: "",
    id: "",
    user: {
            id_str: "",
            name: "",
            screen_name: ""
    }
 }

когда вы помещаете значения в карту, используя код:

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

он имеет следующие основные значения:

created_at
id
user

и поэтому вы можете использовать map.get("created_at").

теперь, поскольку вы хотите получить имя пользователя, вам нужно получить карту пользователя:

LinkedTreeMap<String, Object> userMap = (LinkedTreeMap<String, Object>) map.get("user");

на userMap, вы получите следующие ключевые значения:

id_str
name
screen_name

теперь, вы можете получить name на user

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

для людей, которые приходят сюда в поисках пути к преобразовать LinkedTreeMap в object:

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

Это было полезно для меня, когда мне нужно было разобрать общий объект, такой как:

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

но я не знаю, какой объект сервер собирался отправить. ObjectFull станет LinkedTreeMap


user это :

JsonObject user = map.get("user");

Ok. Прежде всего, JSON является сокращением от "JavaScript Object Notation", поэтому ваше утверждение о том, что "строка JSON по существу является картой" неверно. Блок JSON-это объектный граф, описываемый с помощью синтаксиса языка JavaScript. Поскольку вы пытаетесь принудить граф объектов к отображению пар значений String, Sting kay, это будет работать только в тех случаях, когда любой данный граф объектов JSON по существу является именно этим (так что не очень часто). Более успешной была бы стратегия gson.fromJson() Что будет преобразуйте JSON в правильный график объектов Java.