Gson.toJson: примеры (JAVA)
Gson.toJson(Object src): StringОписание метода Gson.toJson
Метод Gson.toJson выполняет преобразование Java-объекта в строковое представление JSON. Используется при необходимости сериализации данных для передачи по сети, логирования, хранения в текстовом формате или взаимодействия с внешними API.
В библиотеке Gson присутствуют несколько перегрузок метода toJson, наиболее часто используемые:
- toJson(Object src) - принимает объект и возвращает строку JSON.
- toJson(Object src, Type typeOfSrc) - позволяет явно указать тип-источник, полезно при сериализации параметризованных типов (например, List<MyType>).
- toJson(JsonElement jsonElement) - преобразует уже сформированное дерево JsonElement в строку.
- toJson(Object src, Appendable writer) - записывает JSON напрямую в указанный Appendable (например, StringWriter, Writer), не возвращая строку.
- toJson(Object src, Type typeOfSrc, Appendable writer) - комбинация явного типа и записи в Appendable.
Возвращаемые значения и поведение:
- Версия без Appendable возвращает объект String с текстом JSON. Для null возвращается строка
"null". - Варианты с Appendable возвращают void (запись выполняется непосредственно в переданный поток), при этом возможны исключения I/O если Appendable/Writer выбрасывает ошибки.
- Передача явного Type полезна для обхода проблем с type erasure при обобщениях. Тип можно получить через
new TypeToken<List<T>>(){}.getType().
Настройка поведения сериализации осуществляется через GsonBuilder. Ключевые опции:
- serializeNulls() - включение сериализации полей со значением null (по умолчанию null-поля пропускаются).
- setDateFormat(...) - форматирование дат.
- registerTypeAdapter(...) - регистрация кастомных сериализаторов/адаптеров для конкретных типов.
- excludeFieldsWithoutExposeAnnotation() - сериализация только отмеченных полей аннотацией @Expose.
- setPrettyPrinting() - форматирование выходного JSON с отступами.
Ограничения и особенности:
- По умолчанию Gson сериализует поля (включая приватные) через рефлексию, но пропускает статические и transient-поля.
- При сериализации обобщённых типов требуется передавать Type, иначе информация о параметрах типа теряется (type erasure).
- Gson не поддерживает некоторые стандартные типы (например, java.time.LocalDateTime) без дополнительных адаптеров.
Короткие практические примеры
Ниже приведены компактные примеры с кодом и результатом.
1) Простейшая сериализация объекта
import com.google.gson.Gson;
class User {
String name;
int age;
User(String name, int age) { this.name = name; this.age = age; }
}
Gson gson = new Gson();
String json = gson.toJson(new User("Ivan", 30));
System.out.println(json);
{"name":"Ivan","age":30}
2) Сериализация списка с явным Type
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
Gson gson = new Gson();
Type listType = new TypeToken(){}.getType();
String json = gson.toJson(Arrays.asList("a","b","c"), listType);
System.out.println(json);
["a","b","c"]
3) Pretty printing
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Gson pretty = new GsonBuilder().setPrettyPrinting().create();
String json = pretty.toJson(new java.util.HashMap<String,Object>() {{ put("k",1); put("arr", new int[]{1,2}); }});
System.out.println(json);
{
"k": 1,
"arr": [
1,
2
]
}
4) Запись в Writer
import com.google.gson.Gson;
import java.io.StringWriter;
Gson gson = new Gson();
StringWriter w = new StringWriter();
gson.toJson(42, w);
System.out.println(w.toString());
42
Похожие инструменты в Java
В Java доступны альтернативы Gson с отличиями по функциональности и производительности:
- Jackson (com.fasterxml.jackson) - очень гибкая библиотека, чаще быстрее на больших объёмах, имеет расширенную поддержку Java типов, аннотаций и модулей. Предпочтительна при необходимости сложной настройки, потоковой обработки и интеграции с Spring.
- JSON-B (javax.json.bind) - стандарт Java API для биндинга JSON, использует аннотации и настроечные механизмы, удобна при желании следовать спецификации.
- org.json (JSONObject) - более простой и лёгкий инструмент для быстрых манипуляций с JSON, но менее гибкий для автоматической сериализации сложных Java-объектов.
- Moshi - компактная библиотека от Square, ориентирована на Android, имеет удобную работу с Kotlin и адаптерами для null/nullable типов.
Обобщённо: выбор между Gson и Jackson/Moshi зависит от требований к производительности, поддержке типов и интеграции с экосистемой. Jackson часто выбирают для серверных приложений с высокими нагрузками. Moshi и Gson применяются в клиентских/мобильных проектах за компактность и простоту.
Аналоги в других языках
Краткие соответствия по языкам с примерами вывода.
- JavaScript: встроенный
JSON.stringify.
const obj = {name: 'Ivan', age: 30};
console.log(JSON.stringify(obj));
{"name":"Ivan","age":30}
- Python: модуль
json.dumps.
import json
print(json.dumps({'name':'Ivan','age':30}))
{"name": "Ivan", "age": 30}
- PHP: функция
json_encode.
$a = ['name' => 'Ivan', 'age' => 30];
echo json_encode($a);
{"name":"Ivan","age":30}
- C#:
Newtonsoft.Json.JsonConvert.SerializeObjectилиSystem.Text.Json.JsonSerializer.Serialize.
using Newtonsoft.Json;
var obj = new { name = "Ivan", age = 30 };
Console.WriteLine(JsonConvert.SerializeObject(obj));
{"name":"Ivan","age":30}
- Go: пакет
encoding/json, функцияjson.Marshal.
package main
import (
"encoding/json"
"fmt"
)
func main(){
obj := map[string]interface{}{"name":"Ivan","age":30}
b,_ := json.Marshal(obj)
fmt.Println(string(b))
}
{"name":"Ivan","age":30}
- Kotlin: можно использовать Gson аналогично Java или kotlinx.serialization для сериализации с поддержкой Kotlin-модулей.
val gson = com.google.gson.Gson()
println(gson.toJson(mapOf("name" to "Ivan","age" to 30)))
{"name":"Ivan","age":30}
- Lua: библиотека cjson, функция
cjson.encode.
local cjson = require 'cjson'
print(cjson.encode({name='Ivan', age=30}))
{"name":"Ivan","age":30}
- SQL (пример в PostgreSQL): функция
to_jsonиrow_to_jsonдля конвертации строк и полей в JSON.
SELECT row_to_json((SELECT t FROM (SELECT 'Ivan' AS name, 30 AS age) t));
{"name":"Ivan","age":30}
Отличия от Java/Gson: в большинстве языков встроенные функции работают с примитивными структурами и словарями, а не с произвольными объектами через рефлексию, поэтому в языках с сильной типизацией и метаданными (C#, Kotlin) доступны более гибкие механизмы и аннотации, похожие на возможности Gson или Jackson.
Типичные ошибки при использовании
Ниже перечислены распространённые ошибки и примеры их проявления.
1) Потеря информации об обобщённом типе (type erasure)
Gson gson = new Gson();
List<String> list = Arrays.asList("a","b");
String json = gson.toJson(list); // иногда хватает
// Но при десериализации нужно указывать TypeToken
List<String> back = gson.fromJson(json, List.class);
// back будет List<Double> или List<LinkedTreeMap> - неверный тип элементов
Комментарий: при сериализации обычно проблем нет, но при обратном преобразовании требуется TypeToken.
2) Неправильная сериализация приватных/пропущенных полей
class A { transient int t = 5; static int s = 7; private int p = 3; }
Gson gson = new Gson();
System.out.println(gson.toJson(new A()));
{"p":3}
Комментарий: transient и static поля не сериализуются. Приватные поля сериализуются через рефлексию.
3) Циклические ссылки и StackOverflowError
class Node { String name; Node next; }
Node a = new Node(); a.name="a";
Node b = new Node(); b.name="b";
a.next = b; b.next = a;
Gson gson = new Gson();
System.out.println(gson.toJson(a));
// При попытке сериализовать циклическую структуру может возникнуть StackOverflowError
Комментарий: Gson не поддерживает циклы по умолчанию; для этого требуется специальная обработка (например, заменять ссылки на идентификаторы) или другой парсер.
4) Отсутствие адаптера для нестандартных типов (java.time)
Gson gson = new Gson();
java.time.LocalDateTime dt = java.time.LocalDateTime.now();
System.out.println(gson.toJson(dt));
{"error":"UnsupportedOperation"} или неожиданный результат
Комментарий: для новых типов нужна регистрация TypeAdapter/JsonSerializer.
5) Исключения при записи в Appendable
StringWriter w = null;
Gson gson = new Gson();
// gson.toJson(obj, w); // вызовет NullPointerException
// java.lang.NullPointerException
Изменения и эволюция метода
API метода toJson в библиотеке Gson исторически стабилен и не претерпевал кардинальных изменений: перегрузки для указания типа и записи в Appendable присутствуют давно. В последних релизах основное внимание уделялось исправлению ошибок, улучшению производительности и безопасности.
Дополнительно отмечается тенденция к появлению и распространению готовых адаптеров и модулей в экосистеме (включая сторонние библиотеки) для поддержки новых типов Java (java.time) и интеграции с Kotlin. В кодовой базе Gson время от времени добавляются оптимизации сериализации примитивных коллекций и улучшения при работе с потоковым выводом.
Расширенные и редкие сценарии использования
Ниже несколько подробных примеров с пояснениями.
1) Кастомный сериализатор для java.time.LocalDateTime
import com.google.gson.*;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
.create();
String json = gson.toJson(LocalDateTime.of(2021,1,2,3,4,5));
System.out.println(json);
"2021-01-02T03:04:05"
Комментарий: регистрация адаптера решает проблему отсутствия нативной поддержки.
2) Сериализация с использованием @Expose и фильтрация полей
import com.google.gson.annotations.Expose;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
class Person {
@Expose String name;
@Expose int age;
String secret;
Person(String n,int a,String s){name=n;age=a;secret=s}
}
Gson g = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
System.out.println(g.toJson(new Person("Ivan",30,"x")));
{"name":"Ivan","age":30}
Комментарий: полезно при контроле видимости полей для API.
3) TypeAdapter для оптимизированной сериализации коллекций
import com.google.gson.*;
import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.JsonReader;
import java.io.IOException;
import java.util.List;
class IntListAdapter extends TypeAdapter<List<Integer>> {
public void write(JsonWriter out, List<Integer> list) throws IOException {
out.beginArray();
for (Integer i : list) out.value(i);
out.endArray();
}
public List<Integer> read(JsonReader in) { throw new UnsupportedOperationException(); }
}
Gson gson = new GsonBuilder().registerTypeAdapter(new com.google.gson.reflect.TypeToken<List<Integer>>(){}.getType(), new IntListAdapter()).create();
System.out.println(gson.toJson(java.util.Arrays.asList(1,2,3)));
[1,2,3]
Комментарий: TypeAdapter обеспечивает контроль над форматом и производительностью.
4) Обход циклических ссылок через идентификаторы
// Подход: перед сериализацией преобразовать объекты в DTO с id-ссылками
class Node { int id; Integer nextId; }
// Построить список DTO и затем вызвать gson.toJson(dtoList)
[{"id":1,"nextId":2},{"id":2,"nextId":1}]
Комментарий: вместо прямой сериализации объектов со связями создаётся промежуточная структура без циклов.
5) Сериализация больших потоков с экономией памяти
import com.google.gson.stream.JsonWriter;
import java.io.OutputStreamWriter;
JsonWriter jw = new JsonWriter(new OutputStreamWriter(System.out));
jw.beginArray();
for (int i=0;i<3;i++) {
jw.beginObject();
jw.name("i").value(i);
jw.endObject();
}
jw.endArray();
jw.close();
[{"i":0},{"i":1},{"i":2}]
Комментарий: JsonWriter позволяет писать потоково, не создавая в памяти больших промежуточных строк.
6) Пример сочетания serializeNulls и pretty printing
Gson g = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
class A{ String a; Integer b; A(String a,Integer b){this.a=a;this.b=b}}
System.out.println(g.toJson(new A(null, 2)));
{
"a": null,
"b": 2
}
Комментарий: по умолчанию null-поля исключаются, опция serializeNulls включает их.