Is there a sane way of making Gson handling nested objects differently from those at the top level? Things to be serialized are entities and they all have an id. A nested entity should be replaced by its id (to shorten the output and possibly fight endless recursion).
Let's say there's a
@AllArgsConstructor class User {
int id;
String name;
User parent;
}
and I execute
User grampa = new User(3, "Grampa", null);
User homer = new User(2, "Homer", grampa);
User bart = new User(1, "Bart", homer);
What I get when serializing bart is
{
id: 1,
name: "Bart",
father: {
id: 2,
name: "Homer",
father: {
id: 3,
name: "Grampa"
}
}
}
which is much more than I need. I actually never want to serialize nested entities, their ids are good enough.
Using a global thread-local variable hack and a TypeAdapterFactory I can get
{
id: 1,
name: "Bart",
father: 2,
}
which is nearly what I want. I'd prefer fatherId to father and I'd surely prefer something less hacky than a global variable.
I don't want to create a DAO, scan the object reflexively or alike (then I could do the whole serialization myself, couldn't I?).
The Gson documentation I think points the way to a "saner" approach. Create a TypeAdapter factory which encapsulates state and returns an inner class TypeAdapter instance referencing that state, something like this:
public class UserTypeAdapterFactory {
private Set<Integer> serializedUsers = new HashSet<>();
public JsonSerializer<User> getTypeAdapter() {
return (user, type, context) -> {
JsonObject el = new JsonObject();
el.addProperty("id", user.getId());
el.addProperty("name", user.getName());
if(user.getFather() != null) {
JsonArray els = new JsonArray();
int fatherId = user.getFather().getId();
if(!serializedUsers.contains(fatherId)) {
JsonElement father = context.serialize(user.getFather());
if (father.isJsonArray()) {
els.addAll(father.getAsJsonArray());
} else {
els.add(father);
}
serializedUsers.add(fatherId);
}
el.addProperty("fatherId", fatherId);
els.add(el);
return els;
} else {
return el;
}
};
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(
User.class,
new UserTypeAdapterFactory().getTypeAdapter())
.build();
System.out.println(gson.toJson(
new User(1, "Bart", new User(2, "Homer", new User(3, "Grampa", null)))));
Which should print:
[{"id":3,"name":"Grampa"},{"id":2,"name":"Homer","fatherId":3},{"id":1,"name":"Bart","fatherId":2}]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With