Гсон: Мой папа — Google.

Java задняя часть
Гсон: Мой папа — Google.

01. Прошлая и настоящая жизнь

Меня зовут Gson, это библиотека Java с открытым исходным кодом, основной целью которой является сериализация объектов Java в строки JSON или десериализация строк JSON в объекты Java. Из моего имени вы можете увидеть некоторые подсказки. Я не неизвестный человек. Я из знатной семьи. Мой отец Google.

Конечно, как умный человек, я осознаю себя, в глазах папы я не самая яркая звезда.

Я попал в этот мир чисто случайно.Во всяком случае,об этом мне рассказывал мой папа.Он всегда говорил,что я подобрала его с реки,хотя я никогда в это не верила. За это я подтвердил маме, а она расхохоталась от уха до уха, сказав, что я слишком наивен.

Когда я вырос, мне нравилось путешествовать, поэтому я встретил много коллег, в том числеJacksonиFastjson.

Говоря о Джексоне, я всегда могу думать о Майкле Джексоне, короле поп-музыки, которого забрал Бог. У Джексона 6,1 тысячи звезд на GitHub, хотя у него не так много поклонников, как у меня, я очень уважаю его как парсер JSON по умолчанию в Spring Boot.

Fastjson родом с загадочного Востока.Хотя были обнаружены некоторые серьезные уязвимости, это не мешает ему стать самым популярным парсером JSON.У него больше поклонников, чем у меня, хотя у меня уже более 18К звезд.

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

У каждого из нас есть свои сильные стороны, Джексон использует меньше памяти во время выполнения, Fastjson работает быстрее, а я могу обрабатывать произвольные объекты Java даже без исходного кода. Кроме того, моя поддержка дженериков также более дружелюбна.

02. Добавьте зависимости

Прежде чем использовать мой API, мне нужно сначала добавить себя в проект.Рекомендуются Maven и Gradle.

Мейвен:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

Грейдл:

dependencies {
  implementation 'com.google.code.gson:gson:2.8.6'
}

PS: Gradle — это инструмент построения автоматизации проектов, основанный на концепциях Apache Ant и Apache Maven. Сценарии сборки Gradle написаны на доменном языке Groovy или Kotlin, а не на традиционном XML.

03. Производительность

Это не то, что я думаю, это правда, с помощью множества тестов я доказал, что производительность по-прежнему очень хороша при работе с JSON.

Тестовая среда: двухъядерный процессор, 8 ГБ памяти, 64-битная операционная система Ubuntu (дистрибутив Linux на основе настольных приложений)

Результаты теста:

1) Не было проблем с десериализацией строк выше 25M.

2) Коллекция из 1,4 миллиона объектов может быть сериализована.

3) Коллекция, содержащая 87000 объектов, может быть десериализована.

4) Увеличьте предел десериализации для байтовых массивов и коллекций с 80K до более чем 11M.

Я написал для вас тестовый пример и выложил его на GitHub, если не верите, можете проверить.

GitHub.com/Google/ Скажи, о, ты…

04. Руководство пользователя

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

У меня есть девушка, которую зовут так же, как и меня.Gson, мои основные функции обеспечиваются ею. ты можешь пройтиnew Gson()Это простой и грубый способ ее создания, вы также можете позвонить боссу по имени GsonBuilder и попросить его отправить копию по почте, правда, я не буду вам врать.

Давайте сначала рассмотрим пример сериализации.

Gson gson = new Gson();
System.out.println(gson.toJson(18));
System.out.println(gson.toJson("沉默"));
System.out.println(gson.toJson(new Integer(18)));
int[] values = { 18,20 };
System.out.println(gson.toJson(values));

С помощью моей подруги вы можете передать в качестве параметров примитивный тип данных int, строковый тип String, тип оболочки Integer, массив int и т. д.toJson()метод, который вернет строку в формате JSON.

Взгляните на вывод:

18
"沉默"
18
[18,20]

Давайте снова посмотрим на пример десериализации.

Gson gson = new Gson();
int one = gson.fromJson("1", int.class);
Integer two = gson.fromJson("2", Integer.class);
Boolean false1 = gson.fromJson("false", Boolean.class);
String str = gson.fromJson("\"王二\"", String.class);
String[] anotherStr = gson.fromJson("[\"沉默\",\"王二\"]", String[].class);

System.out.println(one);
System.out.println(two);
System.out.println(false1);
System.out.println(str);
System.out.println(Arrays.toString(anotherStr));

toJson()метод сериализации, соответствующий,fromJson()способ десериализации. Однако вам необходимо указать тип параметра при десериализации, будь то int или Integer, Boolean или String или массив String.

Взгляните на вывод:

1
2
false
王二
[沉默, 王二]

Приведенные выше примеры относительно просты и не отражают моей силы.

Далее, давайте определим класс:

public class Writer {
    private int age = 18;
    private String name = "王二";
    private transient int sex = 1;
}

Затем давайте сериализуем его:

Writer writer = new Writer();
Gson gson = new Gson();
String json = gson.toJson(writer);
System.out.println(json);

Использование так же просто, как и раньше, взгляните на результат:

{"age":18,"name":"王二"}

Точно так же результат можно десериализовать:

Writer writer1 = gson.fromJson(json, Writer.class);

Вот несколько предостережений, о которых я должен вам напомнить.

1) Рекомендуется использоватьprivateИзмененные поля.

2) Нет необходимости использовать какие-либо аннотации, чтобы указать, какие поля нужно сериализовать, а какие поля не нужно сериализовать. По умолчанию включаются все поля, а также поля, унаследованные от родительских классов.

3) Если полеtransientЕсли ключевое слово изменено, оно не будет участвовать в сериализации.

4) Если значение поля равно null, оно не будет отображаться в сериализованном результате.

5) Отсутствующие поля в JSON будут установлены в значения по умолчанию после десериализации, значение по умолчанию для ссылочных типов данных — null, значение по умолчанию для числовых типов — 0, а значение по умолчанию для логических значений — false.

Далее рассмотрим пример сериализации коллекции.

List<String> list =new ArrayList<>();
list.add("好好学习");
list.add("天天向上");
String json = gson.toJson(list);

Результат выглядит следующим образом:

["好好学习","天天向上"]

При десериализации это также очень просто.

List<String> listResult = gson.fromJson(json,List.class);

Результат выглядит следующим образом:

[好好学习, 天天向上]

Моя девушка очень внимательный и заботливый человек, когда звонишьtoJson()Когда метод будет сериализован, она сначала оценит значение null, чтобы предотвратить генерацию NPE, а затем передастgetClass()Получите тип параметра, затем сериализуйте его.

public String toJson(Object src) {
    if (src == null) {
        return toJson(JsonNull.INSTANCE);
    }
    return toJson(src, src.getClass());
}

но? Для дженериков,getClass()Параметризованный тип отбрасывается. Взгляните на пример ниже.

public class Foo<T> {
    T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

    public static void main(String[] args) {
        Gson gson = new Gson();
        Foo<Bar> foo = new Foo<Bar>();
        Bar bar = new Bar();
        foo.set(bar);

        String json = gson.toJson(foo);
    }
}

class Bar{
    private int age = 10;
    private String name = "图灵";
}

Если вы отлаживаете, перейдите кtoJson()Внутри метода это можно наблюдать.

Фактический тип fooFoo<Bar>, но моя девушка звонитfoo.getClass(), получает только Foo , что означает, что она не знает фактический тип foo .

При сериализации все нормально, но при десериализации делать нечего.

Foo<Bar> foo1 = gson.fromJson(json, foo.getClass());
Bar bar1 = foo1.get();

Этот код выдает ошибку при запуске.

Exception in thread "main" java.lang.ClassCastException: class com.google.gson.internal.LinkedTreeMap cannot be cast to class com.itwanger.gson.Bar (com.google.gson.internal.LinkedTreeMap and com.itwanger.gson.Bar are in unnamed module of loader 'app')
	at com.itwanger.gson.Foo.main(Foo.java:36)

По умолчанию тип параметра универсального типа будет преобразован в LinkedTreeMap, что явно не является тем Bar, которого мы ожидали, и подруга очень беспомощна в этом.

Как сын Гугла, слово "благородный" течет в моей крови, как я могу вынести одиночество своей девушки, когда она беспомощна.

Итак, я внедрил в тело своей девушки два других метода с параметрами Type:

toJson(Object src, Type typeOfSrc);
<T> T fromJson(String json, Type typeOfT);

Таким образом, вы можете указать параметризованный тип универсального типа при сериализации и десериализации универсального типа.

Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
String json = gson.toJson(foo,fooType);
Foo<Bar> foo1 = gson.fromJson(json, fooType);
Bar bar1 = foo1.get();

запись отладкиtoJson()Если вы заглянете внутрь метода, то увидите настоящий тип foo.

fromJson()Аналогично этому при десериализации.

В этом случае бар1 может пройтиfoo1.get()прибыть.

Смотри, какой я задумчивый, моя девушка не может не сделать мне комплимент!

05. Работайте со смешанными типами

Вы знаете, Java не рекомендует использовать смешанные типы, как в случае ниже.

List list = new ArrayList();
list.add("沉默王二");
list.add(18);
list.add(new Event("gson", "google"));

Определение события выглядит так:

class Event {
    private String name;
    private String source;
    Event(String name, String source) {
        this.name = name;
        this.source = source;
    }
}

Поскольку список не определяет конкретный тип, в нем могут храниться различные типы данных. Хотя это избавляет от проблем, у моей подруги нет проблем с сериализацией, но с десериализацией будет больше проблем.

Gson gson = new Gson();
String json = gson.toJson(list);
System.out.println(json);

Результат выглядит следующим образом:

["沉默王二",18,{"name":"gson","source":"google"}]

При десериализации нужно подумать, чтобы получить объект Event.

JsonParser parser = new JsonParser();
JsonArray array = parser.parse(json).getAsJsonArray();
String message = gson.fromJson(array.get(0), String.class);
int number = gson.fromJson(array.get(1), int.class);
Event event = gson.fromJson(array.get(2), Event.class);

Признайтесь, JsonParser — мой предшественник. Надеюсь, ты не назовешь меня отморозком, это не потому, что я беспокоюсь, это потому, что мы немного не подходим друг другу. Но мы все равно остаемся друзьями, потому что никто из нас не прав, просто код более стандартизирован, и мало кто из разработчиков уже использует смешанные типы.

06. Индивидуальная настройка

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

Что мне нравится, так это мое стремление к совершенству; что я ненавижу, так это то, что она иногда перегружена и не может помочь.

использоватьtoJson()При сериализации объекта Java возвращаемая строка JSON не содержит пробелов и является компактной. Если вы хотите напечатать более приятный формат JSON, вам нужно позвонить боссу по имени GsonBuilder и попросить его сделать некоторые настройки, а затем отправить вам переделку по почте, как я сделал вруководство пользователякак указано в.

public class Writer {
    private int age = 18;
    private String name = "沉默王二";

    public static void main(String[] args) {
        Writer writer = new Writer();
        Gson gson = new Gson();
        String json = gson.toJson(writer);
        System.out.println(json);

        Gson gson1 = new GsonBuilder().setPrettyPrinting().create();
        String jsonOutput = gson1.toJson(writer);
        System.out.println(jsonOutput);
    }
}

Давайте сравним вывод:

{"age":18,"name":"沉默王二"}
{
  "age": 18,
  "name": "沉默王二"
}

пройти черезsetPrettyPrinting()После настройки выходной формат становится более иерархическим и трехмерным, с пробелами между полями и значениями и разрывами строк между разными полями.

Как было сказано ранее, моя подруга по умолчанию игнорирует поля с нулевыми значениями при сериализации.Если вы этого не хотите, вы также можете вызвать GsonBuilder.

public class Writer {
    private int age = 18;
    private String name = null;

    public static void main(String[] args) {
        Writer writer = new Writer();
        Gson gson = new Gson();
        String json = gson.toJson(writer);
        System.out.println(json);

        Gson gson2 = new GsonBuilder().serializeNulls().create();
        String jsonOutput2 = gson2.toJson(writer);
        System.out.println(jsonOutput2);
    }
}

Давайте сравним вывод:

{"age":18}
{"age":18,"name":null}

пройти черезserializeNulls()После настройки поля с нулевыми значениями больше не будут игнорироваться при сериализации.

Возможно, вы хотите фильтровать какие-то поля при сериализации и десериализации, я тоже учёл это требование и специально для вас подготовил несколько решений, вы можете выбрать то, которое подходит вам по своему вкусу.

Первый, через модификатор Java.

Вы видели это раньше, используйтеtransientПоля с измененным ключевым словом не будут участвовать в сериализации и десериализации. такой же,staticТак же как и поля, украшенные ключевыми словами. Если вы хотите сохранить эти поля, украшенные ключевыми словами, вы можете это сделать.

Держите один вид.

Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).create();

Держите разнообразие.

Gson gson = new GsonBuilder()
    .excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT, Modifier.VOLATILE)
    .create();

Во-вторых, через@Exposeаннотация.

нужно использовать@Exposeаннотация, вам нужно сделать это в первую очередь:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

Добавьте к полям, которые необходимо сериализовать и десериализовать@ExposeАннотация, если не добавить, это поле будет проигнорировано.

@Expose
private int age = 18;

07. Голос

Если вы хотите узнать больше, посетите мою страницу GitHub:

github.com/google/gson

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

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

Рекомендуемое чтение:

Программист третьего уровня 2020, ни скромный, ни высокомерный | Ежегодное эссе Nuggets

Потрясающие, более 115 000 руководств по Java на GitHub!