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