【问题标题】:Using Gson and Abstract Classes使用 Gson 和抽象类
【发布时间】:2013-04-14 14:30:54
【问题描述】:

我正在尝试使用 GSON 在客户端和服务器之间交换消息。

问题如下:

我有这个结构:

public class Message 
{
    private TypeOfContent type; //  It's a enum 
    private Content       content;
    ....
}

那么对象内容可以是各种类的集合。

我找到了 2 个教程 herehere,但都没有解决问题。

编辑1:

Message 类是这个:


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

conteudo 的扩展类的一个例子是这个:

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

最后我所做的是:“String strObject = new Gson().toJson(mensage);”哪个有效,但在反序列化时无效,因为它始终假定它来自 Content 类

【问题讨论】:

  • 您是否在序列化、反序列化方面都有问题?
  • 两者。当我尝试序列化它时,它会进入一个循环,并且出现“堆栈溢出”错误。问题是抽象类是内容而不是消息
  • Gson 无法根据 JSON 字符串神奇地找出未知的子类类型。您将不得不编写一个自定义序列化程序来查看您的 TypeOfContent 枚举并采取适当的行动。

标签: java object gson abstract-class


【解决方案1】:

我终于解决了!

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

注意:“registerTypeAdapter(AbstractClass.class, new InterfaceAdapter());”

AbstractClass.class 我的意思是在我的例子中你正在实现的类是 Conteúdo,它可能是 ConteudoTweet 或 ConteudoUserSystem 等等......

InterfaceAdapter的实现是:

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

}

而且这个 InterfaceAdapter 是通用的,所以它应该可以正常工作...

就是这样!

【讨论】:

  • 这对我有用——你应该接受你自己的答案。我的问题出在我的 JsonDeserializer 中,我正在创建一个新的 GSON 实例并使用 gson.fromJson() 而不是 context.deserialize()。
  • 这只是这里另一个答案的副本:stackoverflow.com/a/9550086/795673
【解决方案2】:

您应该看看我在这里回答的类似问题: https://stackoverflow.com/a/22081826/3315914

你需要使用Gson's RuntimeTypeAdapterFactory

并注册基类和所有子类以使其工作。

【讨论】:

    【解决方案3】:

    这是我对 Sub 类型序列化的看法。 (github repo here)

    // GsonSerializer.java
    package com.rathnas.main;
    
    import java.lang.reflect.Type;
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    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;
    import com.rathnas.vo.Thing;
    import com.rathnas.vo.sub.Animal;
    import com.rathnas.vo.sub.Bird;
    import com.rathnas.vo.sub.nested.Barking;
    import com.rathnas.vo.sub.nested.Chirping;
    import com.rathnas.vo.sub.nested.NoiseType;
    
    public class GsonSerializer {
        public static void main(String[] args) {
            GsonBuilder builder = new GsonBuilder().registerTypeAdapter(Thing.class, new ThingSerializer<Thing>()).registerTypeAdapter(NoiseType.class, new ThingSerializer<NoiseType>());
            builder.setPrettyPrinting();
            Gson gson = builder.create();
            Animal thing = God.createDog();
            String tmp = gson.toJson(thing, Thing.class); // Note: StackoverflowError, if you do gson.toJson(thing)
            System.out.println("Ser Dog: " + tmp);
            System.out.println("Des Dog: " + gson.fromJson(tmp, Thing.class));
            Bird thing2 = God.createBird();
            tmp = gson.toJson(thing2, Thing.class);
            System.out.println("\n\n\nSer Bird: " + tmp);
            System.out.println("Des Bird: " + gson.fromJson(tmp, Thing.class));
        }
    }
    
    class ThingSerializer<T> implements JsonSerializer<T>, JsonDeserializer<T> {
        private static final String TYPE = "type";
    
        public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            JsonObject jsonObj = json.getAsJsonObject();
            String className = jsonObj.get(TYPE).getAsString();
            try {
                return context.deserialize(json, Class.forName(className));
            } catch (ClassNotFoundException e) {
                throw new JsonParseException(e);
            }
        }
        public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
            JsonElement jsonEle = context.serialize(src, src.getClass());
            jsonEle.getAsJsonObject().addProperty(TYPE, src.getClass().getCanonicalName());
            return jsonEle;
        }
    }
    
    class God {
        public static Animal createDog() {
            Animal thing = new Animal();
            thing.setName("Dog");
            thing.setLegs(4);
            thing.setWings(0);
            thing.setNoise(new Barking());
            return thing;
        }
        public static Bird createBird() {
            Bird thing = new Bird();
            thing.setName("Bird");
            thing.setLegs(1);
            thing.setWings(2);
            thing.setNoise(new Chirping());
            return thing;
        }
    }
    // Thing.java
    public abstract class Thing {
        private String name;
        private NoiseType noise;
        ..
    }
    
    // Animal.java
    public class Animal extends Thing implements iThing {
        private Integer legs;
        private Integer wings;
        ..
    }
    // Bird.java
    public class Bird extends Thing implements iThing {
        private Integer legs;
        private Integer wings;
        ..
    }
    // NoiseType.java
    public abstract class NoiseType {..}
    // Chirping.java
    public class Chirping extends NoiseType {..}
    // Barking.java
    public class Barking extends NoiseType {..}
    

    输出

    Ser Dog: {
      "legs": 4,
      "wings": 0,
      "name": "Dog",
      "noise": {
        "noise": "barking",
        "type": "com.rathnas.vo.sub.nested.Barking"
      },
      "type": "com.rathnas.vo.sub.Animal"
    }
    Des Dog: Animal [legs=4, wings=0, noise=NestedAbstractClass [noise=barking]]
    
    Ser Bird: {
      "legs": 1,
      "wings": 2,
      "name": "Bird",
      "noise": {
        "noise": "chirping",
        "type": "com.rathnas.vo.sub.nested.Chirping"
      },
      "type": "com.rathnas.vo.sub.Bird"
    }
    Des Bird: Bird [legs=1, wings=2, noise=NestedAbstractClass [noise=chirping]]
    

    【讨论】:

      猜你喜欢
      • 2015-09-27
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      • 2016-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多