Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
192 views
in Technique[技术] by (71.8m points)

java - Using Gson and Abstract Classes

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:

The class Message is this one:


public class Mensagem
{
    private TipoMensagem    type;

    private Conteudo        conteudo;

    private Cliente         autor;
    private Cliente         destino;    // null -> to all(broadcast)
}

And Content is this one:

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

And an example of a extend class from conteudo is this one:

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...