Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

[Dúvida] Serializacao para Json

Durante minha tentativa, não havia me atentado que, quando vamos serializar um objeto para Json, temos de passar um objeto e não uma classe, como acontece quando tentamos desserializar. Por conta disso, me deparei com o seguinte erro:

"Exception in thread "main" java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: com.company.app.domain.People. Forgot to register a type adapter? See"

Fiquei sem entender, então fui ler o stacktrace, que mostrava "Forgot to register a type adapter", e fiquei sem saber o que fazer. Resolvi então consultar a documentação JsonAdapter para tentar solucionar. Nesse processo, percebi que teria de criar uma classe inteira apenas para dizer como minha classe People deveria ser serializada e desserializada.

Tudo isso para descobrir, depois, que bastava apenas alterar uma única palavra na minha linha de código na classe PeopleService para resolver o problema, trocando Class<T> por T. Mas isso não foi totalmente ruim: com esse erro, aprendi um pouco sobre como customizar minhas classes ao serializá-las para JSON e vice-versa. Assim ficou meu codigo:

package com.company.app;

import com.company.app.domain.People;
import com.company.app.service.PeopleService;

public class Main {
    public static void main(String[] args) {
        String json = """
                {
                    "name": "Rick",
                    "age": 22,
                    "city": "Quixada"
                }
                """;

        PeopleService peopleService = new PeopleService();

        // Desserializa JSON -> objeto
        People people = peopleService.fromJson(json, People.class);

        // Serializa objeto -> JSON
        String json2 = peopleService.toJson(people);

        System.out.println(people);
        System.out.println(json2);
    }
}
package com.company.app.util;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Contract;
import com.google.gson.GsonBuilder;
import com.google.gson.Gson;

@lombok.experimental.UtilityClass
public class GsonProvider {

    @lombok.Getter
    private final Gson gson = build();

    @Contract(" -> new")
    private static @NotNull Gson build() {
        return new GsonBuilder().serializeNulls().create();
    }
}
package com.company.app.service;

import com.company.app.util.GsonProvider;
import org.jetbrains.annotations.NotNull;

public class PeopleService {

    public <T> T fromJson(@NotNull String json, @NotNull Class<T> classOfT) {
        return GsonProvider.getGson().fromJson(json, classOfT);
    }

    public <T> String toJson(@NotNull T object) {
        return GsonProvider.getGson().toJson(object);
    }

}
package com.company.app.domain;

import com.google.gson.annotations.JsonAdapter;

@JsonAdapter(PeopleJsonAdapter.class)
public record People(String name, int age, String city) {
}

Class extra que criei por conta do erro que comentei:

package com.company.app.domain;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;


public class PeopleJsonAdapter extends TypeAdapter<People> {

    @Override
    public void write(JsonWriter out, People people) throws IOException {
        if (people == null) {
            out.nullValue();
            return;
        }
        out.beginObject();

        out.name("name").value(people.name());
        out.name("age").value(people.age());
        out.name("city").value(people.city());

        out.endObject();
    }

    @Override
    public People read(@NotNull JsonReader in) throws IOException {
        String name = null;
        int age = 0;
        String city = null;

        in.beginObject();
        while (in.hasNext()) {
            String nextName = in.nextName();

            switch (nextName) {
                case "name" -> name = in.nextString();
                case "age" -> age = in.nextInt();
                case "city" -> city = in.nextString();
                default -> in.skipValue();
            }
        }
        in.endObject();

        return new People(name, age, city);
    }
}
3 respostas

Gostaria ate de saber se tipo, em empresas e muito comum usar este sistema de TypeAdapter<...>? Porque achei um pouco confuso, talvez por ser a primeira vez mexendo com isso. Ate onde entendi, isso serve como uma forma de manipulacao do Json, como a soma de valores numa so, remover dados que nao sejam uteis na aplicacao dentre outras mais.

solução!

Oi, Rick! Como vai?

Sobre sua dúvida, o uso de TypeAdapter realmente é comum em projetos maiores, mas só quando há necessidade de customizar a serialização ou desserialização. Em muitos casos, usar apenas o Gson padrão já resolve. O TypeAdapter entra em cena quando você precisa, por exemplo:

  • Renomear atributos sem usar anotações.
  • Ignorar ou transformar campos durante a conversão.
  • Tratar formatos específicos de data/hora.
  • Combinar ou separar atributos no JSON de forma personalizada.

Veja este exemplo simples de quando o TypeAdapter se torna útil:


public class DateAdapter extends TypeAdapter<LocalDate> {
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");

    @Override
    public void write(JsonWriter out, LocalDate date) throws IOException {
        out.value(date.format(formatter));
    }

    @Override
    public LocalDate read(JsonReader in) throws IOException {
        return LocalDate.parse(in.nextString(), formatter);
    }
}

Assim, se sua aplicação precisa de datas no formato "20-08-2025" ao invés do ISO padrão, você registra o adapter e resolve o problema.

Ou seja, em empresas o uso existe, mas não é para todo caso: apenas quando o Gson sozinho não atende. No seu exemplo do People, não era necessário, porque o Gson já sabe lidar com objetos simples sem precisar de adapter.

Espero ter esclarecido e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Obrigado pela explicacao, ajudou a sanar esta minha duvida. De qualquer forma, o erro que eu comete valeu de algo e, eu meio que fui forcado a aprender o uso do Adapter.