Background
I want to serialize an interface into a JSON object. For instance, say I have the following interface:
public interface Person {
String getName();
int getAge();
}
Which is implemented by the class PersonImpl:
public class PersonImpl implements Person {
private String name;
private int age;
public PersonImpl(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String getName() {
return name;
}
@Override
public int getAge() {
return age;
}
}
PersonSerializer.java is used to serialize the interface using GSON:
public class PersonSerializer implements JsonSerializer<Person> {
@Override
public JsonElement serialize(Person src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject person = new JsonObject();
person.addProperty("name", src.getName());
person.addProperty("age", src.getAge());
return person; // Breakpoint BP1
}
}
I then use a GsonBuilder to serialize the interface:
Person person = new PersonImpl("Bob", 42);
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Person.class, new PersonSerializer());
Gson gson = builder.create();
String personAsJsonString = gson.toJson(person); // Breakpoint BP2
Issue
The problem is the Person class is being serialized as follows:
// Not what I want
{
"person": {
"name": "Bob",
"age": 42
}
}
However, I only want the data within person:
// What I want
{
"name": "Bob",
"age": 42
}
Troubleshooting & Debugging
At Breakpoint BP1 (noted via the comment), the String value of person is exactly what I want. However, by Breakpoint BP2, after GSON completes serialization of the interface (i.e. personAsJsonString), it is the undesired result.
How can I get GSON to serialize a custom interface without encapsulating the result in a JSON Object?
Edit (root cause found)
I completely failed to mention that I was using the Decorator Pattern, which happened to be the root cause of the issue.
public abstract class PersonDecorator implements Person {
protected Person person;
public PersonDecorator(Person person) {
this.person = person;
}
@Override
public String getName() {
return person.getName();
}
@Override
public int getAge() {
return person.getAge();
}
}
Below is an example Decorator:
public class MrPersonDecorator extends PersonDecorator {
public MrPersonDecorator(Person person) {
super(person);
}
@Override
public String getName() {
return "Mr. " + person.getName();
}
}
So the issue happened when creating a Person instance via a decorator:
Person person = new MrPersonDecorator(new PersonImpl("Bob", 42));
In this case, I was not getting a reference to the interface itself, but rather the decorator, which also contains an instance of the interface along with implementing it.