I'm trying to exchange messages between a client and a server using GSON.
The problem is the following:
I have this structure:
public class Message
{
private TypeOfContent type; // It's a enum
private Content content;
....
}
Then the object content can be a various set of Classes.
I found 2 tutorials here and here, but none of them solves the problem.
Edit1:
public class Mensagem
{
private TipoMensagem type;
private Conteudo conteudo;
private Cliente autor;
private Cliente destino; // null -> to all(broadcast)
}
public class Conteudo
{
protected TipoConteudo typeConteudo;
protected String texto;
protected Posicao posicao;
public Conteudo(TipoConteudo typeConteudo, String texto, Posicao posicao)
{
this.texto = texto;
this.posicao = posicao;
this.typeConteudo = typeConteudo;
}
}
public class ConteudoTweet extends Conteudo
{
protected String pathImagem;
public ConteudoTweet(TipoConteudo typeConteudo, String tweet, Posicao location, String picturePath)
{
super(typeConteudo,tweet, location);
this.pathImagem = picturePath;
}
}
Finally what I do is like : "String strObject = new Gson().toJson(mensage);" which works but on deserialization it doesn't because it assumes always that it is from Content class
GSON can use the Object definition to directly create an object of the desired type. While JSONObject needs to be parsed manually.
By default, GSON excludes transient and static fields from the serialization/deserialization process.
Gson Goals: Provide simple toJson() and fromJson() methods to convert Java objects to JSON and vice-versa. Allow pre-existing unmodifiable objects to be converted to and from JSON. Extensive support of Java Generics.
Gson requires the class to have a default no-args constructor.
I finally solved it!
// GSON
GsonBuilder gsonBilder = new GsonBuilder();
gsonBilder.registerTypeAdapter(Conteudo.class, new InterfaceAdapter<Conteudo>());
gsonBilder.setPrettyPrinting();
Gson gson =gsonBilder.create();
String str2send = gson.toJson(message);
Mensagem msg_recv = gson.fromJson(str2send,Mensagem.class);
Note that: "registerTypeAdapter(AbstractClass.class, new InterfaceAdapter());"
by AbstractClass.class i mean the class that you are implementing in my case it was Conteúdo that could be ConteudoTweet or ConteudoUserSystem and so on...
The implementation of InterfaceAdapter is :
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class InterfaceAdapter<T>
implements JsonSerializer<T>, JsonDeserializer<T> {
@Override
public final JsonElement serialize(final T object, final Type interfaceType, final JsonSerializationContext context)
{
final JsonObject member = new JsonObject();
member.addProperty("type", object.getClass().getName());
member.add("data", context.serialize(object));
return member;
}
@Override
public final T deserialize(final JsonElement elem, final Type interfaceType, final JsonDeserializationContext context)
throws JsonParseException
{
final JsonObject member = (JsonObject) elem;
final JsonElement typeString = get(member, "type");
final JsonElement data = get(member, "data");
final Type actualType = typeForName(typeString);
return context.deserialize(data, actualType);
}
private Type typeForName(final JsonElement typeElem)
{
try
{
return Class.forName(typeElem.getAsString());
}
catch (ClassNotFoundException e)
{
throw new JsonParseException(e);
}
}
private JsonElement get(final JsonObject wrapper, final String memberName)
{
final JsonElement elem = wrapper.get(memberName);
if (elem == null)
{
throw new JsonParseException(
"no '" + memberName + "' member found in json file.");
}
return elem;
}
}
And this InterfaceAdapter is generic so it should work in general...
That's it!
You should take a look on a similar question I've answered here : https://stackoverflow.com/a/22081826/3315914
You need to use Gson's RuntimeTypeAdapterFactory
And register the base class and all child classes to make it work.
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