Gson反序列化其类实现的接口 [英] Gson deserialize interface to its Class implementation

查看:250
本文介绍了Gson反序列化其类实现的接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Retrofit 2.1.0 converter-gson:2.1.0 ,并分别使用 gson:2.6.2 序列化/反序列化。问题是我的POJO应该隐藏在接口后面,我想告诉gson哪个类应该是反序列化的接口。而反序列化/序列化改造应该能够返回接口。如果我可以利用泛型并很容易地创建一种方法来告诉Gson或Retrofit将FooInterface序列化或反序列化为FooClass,那将是一件好事。 解决方案

我假设你想为所有的接口和它们各自的实现创建一个单一的反序列化器。请按照以下步骤操作:

1. 创建一个基本界面,该界面将通过其他应用界面进行扩展。需要为所有接口和实现类创建单个解串器。

  public interface Convertable {
String getClassName();

2。创建您的功能界面和实施类。作为一个例子,让我们将它们命名为FooInterface和FooClass。 FooInterface应该扩展Convertable接口。



FooInterface

  public interface FooInterface extends Convertable {

}

FooClass

$ b

  public class FooClass implements FooInterface {

// DISCRIMINATOR FIELD
private final String className;

private String field1;

private String field2;

public FooClass(){
this.className = getClass()。getName();
}

public String getClassName(){
return className;
}

public String getField1(){
return field1;
}

public void setField1(String field1){
this.field1 = field1;
}

public String getField2(){
return field2;
}

public void setField2(String field2){
this.field2 = field2;
}

}

请注意getClassName ()用作鉴别器字段,将用于Gson解串器(下一步)初始化可返回实例。 我假设您的序列化器和反序列化器类将驻留在同一个包中,即使它们位于不同的客户端和服务器应用程序中。如果不是,则需要更改getClassInstance()实现,但会这非常简单。



3。为您的所有应用程序实现定制的Gson序列化程序

  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.JsonPrimitive;

公共类ConvertableDeserializer< T extends Convertable>实现JsonDeserializer< T> {

private static final String CLASSNAME =className;

public T deserialize(final JsonElement jsonElement,final Type类型,
final JsonDeserializationContext deserializationContext
)throws JsonParseException {

final JsonObject jsonObject = jsonElement.getAsJsonObject ();
final JsonPrimitive prim =(JsonPrimitive)jsonObject.get(CLASSNAME);
final String className = prim.getAsString();
final Class< T> clazz = getClassInstance(className);
return deserializationContext.deserialize(jsonObject,clazz);
}

@SuppressWarnings(unchecked)
public Class< T> getClassInstance(String className){
try {
return(Class< T>)Class.forName(className);
catch(ClassNotFoundException cnfe){
throw new JsonParseException(cnfe.getMessage());





$ b

4。使用Gson注册反序列化器并初始化改造

  private static GsonConverterFactory buildGsonConverter(){

final GsonBuilder builder = new GsonBuilder();

//添加自定义反序列化器
builder.registerTypeAdapter(FooInterface.class,
new ConvertableDeserializer< FooInterface>());
final Gson gson = builder.create();

return GsonConverterFactory.create(myGson);


$ b public void initRetrofit(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(REST_ENDPOINT)
.addConverterFactory(buildGsonConverter())
.client(httpClient)
.build();



$ b

如果需要,您可以为所有实现注册适配器,方法是:

  builder.registerTypeAdapter(Convertable.class,new ConvertableDeserializer< Convertable>()); 


I am using Retrofit 2.1.0 with converter-gson:2.1.0 and separately gson:2.6.2 in order to customize the serialization/deserialization. The problem is that my POJOs should be hidden behind interfaces and I want to tell gson which class should be the deserialized interface. And after the deserialization/ serialization retrofit should be able to return the interface. It would be good if I can take advantage of Generics and easily create a way to tell Gson or Retrofit to serialize/deserialize FooInterface to FooClass.

解决方案

I am assuming that you want to create a single deserializer for all of your interfaces and their respective implementations. Follow these steps please:

1. Create a base interface that will be extended by your other app interfaces. It is required to create a single deserializer for all of your interfaces and implementation classes.

public interface Convertable {
     String getClassName();
}

2. Create your feature interface and implementation class. As an example, lets name them FooInterface and FooClass. FooInterface should extend Convertable interface.

FooInterface

public interface FooInterface extends Convertable {

}

FooClass

public class FooClass implements FooInterface {

    // DISCRIMINATOR FIELD
    private final String className;

    private String field1;

    private String field2;

    public FooClass() {
        this.className = getClass().getName();
    }

    public String getClassName() {
        return className;
    }

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public String getField2() {
        return field2;
    }

    public void setField2(String field2) {
        this.field2 = field2;
    }

}

Note that the value returned by getClassName() is used as discriminator field that will be used in Gson Deserializer (next step) to initialize returnable instance. I am assuming that your serializer and deserializer class will reside in the same package even if they are in different client and server applications. If not, then you will need to change getClassInstance() implementation, but would be pretty simple to do so.

3. Implement a custom Gson Serializer for all of your application

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.JsonPrimitive;

public class ConvertableDeserializer<T extends Convertable> implements JsonDeserializer<T> {

    private static final String CLASSNAME = "className";

    public T deserialize(final JsonElement jsonElement, final Type type,
                         final JsonDeserializationContext deserializationContext
                        ) throws JsonParseException {

        final JsonObject jsonObject = jsonElement.getAsJsonObject();
        final JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME);
        final String className = prim.getAsString();
        final Class<T> clazz = getClassInstance(className);
        return deserializationContext.deserialize(jsonObject, clazz);
    }

    @SuppressWarnings("unchecked")
    public Class<T> getClassInstance(String className) {
        try {
            return (Class<T>) Class.forName(className);
        } catch (ClassNotFoundException cnfe) {
            throw new JsonParseException(cnfe.getMessage());
        }
    }

}

4. Register Deserializer with Gson and initialize retrofit

 private static GsonConverterFactory buildGsonConverter() {

        final GsonBuilder builder = new GsonBuilder();

        // Adding custom deserializers
        builder.registerTypeAdapter(FooInterface.class, 
                                    new ConvertableDeserializer<FooInterface>());
        final Gson gson = builder.create();

        return GsonConverterFactory.create(myGson);
    }


    public void initRetrofit() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("REST_ENDPOINT")
                .addConverterFactory(buildGsonConverter())
                .client(httpClient)
                .build();
    }

You may register the adapter for all of your implementations if you want, using:

builder.registerTypeAdapter(Convertable.class, new ConvertableDeserializer<Convertable>());

这篇关于Gson反序列化其类实现的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆