1. Introdução ao Gson
Já conhecemos o Jackson e vimos por que ele é considerado o padrão de fato para trabalhar com JSON em Java. Mas há outra biblioteca que ganhou enorme popularidade, especialmente no mundo Android — o Gson. O Gson foi criado no Google como uma solução leve e simples para serializar e desserializar objetos Java em JSON. Ele é valorizado pelo baixíssimo custo de entrada: para começar, quase nada precisa ser configurado — a maioria das tarefas funciona literalmente “pronta para uso”.
Outro ponto forte do Gson é sua leveza. A biblioteca ocupa pouco espaço e não puxa um monte de dependências, por isso é muito usada onde o tamanho do aplicativo é crítico, por exemplo, em dispositivos móveis. O Gson se tornou o padrão de fato para projetos Android — compacidade e simplicidade são decisivas nesse contexto.
Aliás, o nome Gson significa Google JSON. Às vezes, na comunidade, aparece uma interpretação bem-humorada — “Genius’ Son” (“filho do gênio”), mas isso, claro, não é oficial. Apenas um jogo de palavras.
Adicionando o Gson ao projeto
Se você usa Maven ou Gradle, basta adicionar a dependência (a versão pode variar):
Maven:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
Gradle:
implementation 'com.google.code.gson:gson:2.10.1'
Ainda não estudamos a construção de projetos, então, para começar, você pode simplesmente baixar o arquivo jar da página oficial do Gson e adicioná-lo ao projeto.
2. Operações básicas: serialização e desserialização
Vamos ver como serializar e desserializar objetos com Gson usando um exemplo de classe simples.
Exemplo: classe User
// Classe de exemplo
public class User {
private String name;
private int age;
private boolean active;
// Construtor
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
// Getters e setters (o Gson os usa quando necessário)
public String getName() { return name; }
public int getAge() { return age; }
public boolean isActive() { return active; }
}
Serialização: objeto → JSON
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
User user = new User("Alice", 25, true);
Gson gson = new Gson();
String json = gson.toJson(user);
System.out.println(json);
// {"name":"Alice","age":25,"active":true}
}
}
Atenção: os campos são serializados com seus nomes definidos na classe!
Desserialização: JSON → objeto
public class GsonExample {
public static void main(String[] args) {
String json = "{\"name\":\"Bob\",\"age\":30,\"active\":false}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class);
System.out.println(user.getName()); // Bob
System.out.println(user.getAge()); // 30
System.out.println(user.isActive());// false
}
}
Trabalhando com listas de objetos
Gson lida com coleções de forma um pouco mais trabalhosa do que o Jackson, mas é totalmente viável.
import java.util.List;
import java.util.Arrays;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
public class GsonListExample {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("Alice", 25, true),
new User("Bob", 30, false)
);
Gson gson = new Gson();
String json = gson.toJson(users);
System.out.println(json);
// [{"name":"Alice","age":25,"active":true},{"name":"Bob","age":30,"active":false}]
// Desserialização de lista
Type userListType = new TypeToken<List<User>>(){}.getType();
List<User> users2 = gson.fromJson(json, userListType);
System.out.println(users2.get(0).getName()); // Alice
}
}
Observação importante: para desserializar coleções, use TypeToken<>!
3. Configuração do Gson: GsonBuilder
O Gson oferece configuração flexível por meio da classe GsonBuilder. Com ela, você pode ativar pretty printing, serialização de null, formatação de datas e muito mais.
Exemplo: pretty printing e serialização de null
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonBuilderExample {
public static void main(String[] args) {
User user = new User("Charlie", 0, false);
Gson gson = new GsonBuilder()
.setPrettyPrinting() // Saída formatada (indentação)
.serializeNulls() // Serializar campos null
.create();
String json = gson.toJson(user);
System.out.println(json);
/*
{
"name": "Charlie",
"age": 0,
"active": false
}
*/
}
}
Formatação de datas
Se você tem campos do tipo Date, por padrão o Gson os serializa em um formato específico. É possível definir seu próprio formato:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Date;
public class DateExample {
private String event;
private Date date;
public DateExample(String event, Date date) {
this.event = event;
this.date = date;
}
}
public class Main {
public static void main(String[] args) {
DateExample meeting = new DateExample("Team Meeting", new Date());
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
String json = gson.toJson(meeting);
System.out.println(json);
// {"event":"Team Meeting","date":"2024-06-10 13:45:23"}
}
}
4. Anotações do Gson: controle da serialização
Gson oferece anotações para controle mais preciso da serialização e desserialização.
@SerializedName — renomeando campo
Se você quiser que um campo no JSON tenha outro nome, use @SerializedName:
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("full_name")
private String name;
private int age;
private boolean active;
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
}
Agora, na serialização, o campo se chamará full_name:
User user = new User("Diana", 28, true);
String json = new Gson().toJson(user);
// {"full_name":"Diana","age":28,"active":true}
@Expose — serializar apenas campos anotados
Se você deseja serializar apenas determinados campos, use @Expose e configure o Gson:
import com.google.gson.annotations.Expose;
public class User {
@Expose
private String name;
@Expose
private int age;
private boolean active; // não é serializado
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
}
Criando um Gson com suporte a @Expose:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
User user = new User("Eve", 21, false);
String json = gson.toJson(user);
// {"name":"Eve","age":21}
@Since/@Until — serialização condicional por versão
Você pode usar @Since e @Until para serializar campos apenas para determinadas versões (raramente usado na prática, mas é útil conhecer).
5. Características e limitações do Gson
Trabalhando com objetos aninhados
Gson funciona muito bem com objetos aninhados:
public class Profile {
private User user;
private String bio;
public Profile(User user, String bio) {
this.user = user;
this.bio = bio;
}
}
Profile profile = new Profile(new User("Frank", 27, true), "Java developer");
String json = new Gson().toJson(profile);
// {"user":{"name":"Frank","age":27,"active":true},"bio":"Java developer"}
Trabalhando com coleções
Serializar coleções (List, Map) não é problema, mas para desserializar use TypeToken (veja acima).
Limitações do Gson em comparação com o Jackson
- Sem suporte a classes record do Java (até versões recentes)
- Suporte limitado às APIs novas de data/hora (por exemplo, LocalDate, LocalDateTime — exigem adaptadores personalizados)
- Não funciona com as anotações do Jackson
- Sem suporte para estruturas polimórficas complexas “prontas para uso”
- Sem suporte automático a referências bidirecionais (ciclicidade)
Adaptadores personalizados (TypeAdapter)
Se os recursos padrão não forem suficientes, você pode escrever seu próprio adaptador para serializar/desserializar tipos complexos.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
public class BooleanAsIntAdapter extends TypeAdapter<Boolean> {
@Override
public void write(JsonWriter out, Boolean value) throws IOException {
out.value(value ? 1 : 0);
}
@Override
public Boolean read(JsonReader in) throws IOException {
return in.nextInt() == 1;
}
}
// Uso:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Boolean.class, new BooleanAsIntAdapter())
.create();
6. Prática: serialização e desserialização com configurações
Vamos evoluir seu aplicativo de estudos e adicionar o salvamento e o carregamento de uma lista de usuários em formato JSON.
Classe User com anotações
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
public class User {
@Expose
@SerializedName("full_name")
private String name;
@Expose
private int age;
private boolean active; // não é serializado
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
// getters, setters...
}
Salvando a lista de usuários em JSON
import java.util.List;
import java.util.Arrays;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class SaveUsers {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("Ivan", 23, true),
new User("Olga", 19, false)
);
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create();
String json = gson.toJson(users);
System.out.println(json);
/*
[
{
"full_name": "Ivan",
"age": 23
},
{
"full_name": "Olga",
"age": 19
}
]
*/
}
}
Carregando a lista de usuários a partir de JSON
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
public class LoadUsers {
public static void main(String[] args) {
String json = "[{\"full_name\":\"Ivan\",\"age\":23},{\"full_name\":\"Olga\",\"age\":19}]";
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
Type userListType = new TypeToken<List<User>>(){}.getType();
List<User> users = gson.fromJson(json, userListType);
for (User user : users) {
System.out.println(user.getName() + " (" + user.getAge() + ")");
}
// Ivan (23)
// Olga (19)
}
}
7. Comparação: Gson e Jackson
| Característica | Gson | Jackson |
|---|---|---|
| Facilidade de uso | +++++ (muito simples) | +++ (um pouco mais complexo) |
| Tamanho da biblioteca | Pequeno | Maior |
| Velocidade | Rápido, mas um pouco mais lento | Muito rápido |
| Flexibilidade | Média | Alta (mais configurações) |
| Suporte a anotações | Próprias (@SerializedName) | Próprias (@JsonProperty etc.) |
| Suporte a novos tipos | Limitado | Excelente (Java 8+, record) |
| Suporte a Android | Excelente | Bom, porém mais pesado |
| Trabalhar com datas | Somente via adaptadores | Pronto para uso |
| Polimorfismo | Limitado | Altamente configurável |
8. Erros comuns ao trabalhar com Gson
Erro nº 1: Você não usa TypeToken para coleções.
Se for desserializar uma lista ou um mapa, use obrigatoriamente TypeToken<>, caso contrário você terá erros estranhos ou coleções vazias.
Erro nº 2: Não há construtor sem parâmetros.
O Gson pode funcionar sem construtor padrão, mas às vezes, ao desserializar objetos complexos sem esse construtor, podem ocorrer erros. É melhor sempre adicionar um construtor sem parâmetros se você planeja desserializar.
Erro nº 3: Nomes de campos não correspondem.
Se no JSON o campo se chama "full_name", e na classe — "name", sem a anotação @SerializedName("full_name") o campo não será associado e o valor será null.
Erro nº 4: Problemas com campos privados.
O Gson pode serializar campos privados, mas se houver apenas campos privados e não houver getters/setters, às vezes surgem problemas na desserialização. É melhor usar getters e setters.
Erro nº 5: Trabalho com datas.
Por padrão, o Gson serializa Date em um formato pouco prático. Para LocalDate, LocalDateTime e outros tipos novos, sem adaptadores personalizados ocorrerão erros de serialização.
Erro nº 6: Você não usa @Expose, mas ativou excludeFieldsWithoutExposeAnnotation().
Se você ativou excludeFieldsWithoutExposeAnnotation(), mas não anotou os campos com @Expose, eles não serão serializados nem desserializados — o resultado será um JSON vazio ou objetos com null.
GO TO FULL VERSION