GSON带注释的自定义序列化 [英] GSON Custom serialization with annotations

查看:448
本文介绍了GSON带注释的自定义序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



假设我有一个类:

  public class Student extends BaseModel {
private int id;
私人字符串名称;
私人学生goodFriend;
私人学生最好的朋友;
}

BaseModel只是我所有模型类的基类。



当我简单地做

$ $ p $ g code> gson.toJson(student / *一些学生实例* /);

我会举例:

 {
id:1,
name:Jack,
goodFriend:{id:2,name:Matt},
bestFriend:{id:3,nameTom}
}

这很好,但我需要的是:

  {
id:1,
name:Jack,
goodFriend:2,//这个字段只有一个ID
bestFriend:{id:3,nameTom} //这个字段的整个对象
//两个字段都是相同的类型,所以我不能使用TypeAdapterFactory这个
}

我需要某种方式用序列化类型(id或object)标记字段,然后根据需要使用该标记进行序列化。我如何在 general 中做到这一点,不仅仅是为了一个Student类,而是为了BaseModel的所有子类?



我唯一的想法是使用自定义注释
描述了我想要序列化为只有一个注释的ID的字段,和字段,我想序列化为另一个注释对象,
,但我找不到方法来检索TypeAdapter的写入方法中的注释。



任何想法如何处理这个?

解决方案

我自己找到了答案。事实证明,GSON中已经有这种情况的注释。它叫做@JsonAdapter。



首先,我必须创建一个TypeAdapterFactory:

  public class BaseModelForeignKeyTypeAdapterFactory implements TypeAdapterFactory {

@Override
public< T> TypeAdapter< T> create(Gson gson,TypeToken< T> type){
if(!BaseModel.class.isAssignableFrom(type.getRawType())){
return null;
}

TypeAdapter defaultAdapter = gson.getAdapter(type);

// noinspection unchecked
return(TypeAdapter< T>)new Adapter(defaultAdapter);
}

private static class Adapter< T extends BaseModel>扩展TypeAdapter< T> {

private final TypeAdapter< T> defaultAdapter;

Adapter(TypeAdapter< T> defaultAdapter){
this.defaultAdapter = defaultAdapter;
}

@Override
public void write(JsonWriter out,T value)throws IOException {
out.value(value.getId());
}

@Override
public T read(JsonReader in)throws IOException {
return defaultAdapter.read(in);


$ b

创建()方法我检索Gson用于此字段的默认适配器,并将它传递给适配器以供反序列化字段时使用。这种方式这个适配器只用于序列化,而反序列化是委托给默认的适配器。



现在我只需要注释我的 Student class,我想以这种TypeAdapterFactory的形式序列化为ID:

  public class Student extends BaseModel {
private int id;
私人字符串名称;

@JsonAdapter(BaseModelForeignKeyTypeAdapterFactory.class)
私人学生goodFriend;

私人学生bestfriend;
}

这就是全部,现在 gson.toJson学生)会输出:

  {
id:1,
name :Jack,
goodFriend:2,//使用ForeignKeyTypeAdapter
bestFriend:{id:3,nameTom} //使用默认的TypeAdapter
}

我希望这可以帮助别人!


I have a very specific case of custom serialization with GSON:

Let's say I have a following class:

public class Student extends BaseModel{
    private int id;
    private String name;
    private Student goodFriend;
    private Student bestFriend;
}

BaseModel is just a base class for all my model classes.

When I simply do

gson.toJson(student /* Some Student instance */);

I will get for example:

{
 id: 1, 
 name: "Jack", 
 goodFriend: {id: 2, name: "Matt"}, 
 bestFriend: {id: 3, name "Tom"}
}

It's fine, but what I need is this:

{
 id: 1, 
 name: "Jack", 
 goodFriend: 2, // only an ID for this field
 bestFriend: {id: 3, name "Tom"} // whole object for this field
 // both fields are of the same Type, so I can't use TypeAdapterFactory for this
}

I need some way of marking the fields with serialization type (id or object) and then using that marking to serialize as needed. How do I do that in general, not just for a Student class, but for all subclasses of BaseModel?

My only idea was to use custom annotations: describing the fields that I want to serialize as ID only with one annotation, and fields that I want to serialize as objects with another annotation, but I couldn't find a way to retrieve the annotations in TypeAdapter's write method.

Any ideas how to handle this?

解决方案

I found an answer myself. It turns out there already is an annotation for this kind of case in GSON. It's called @JsonAdapter.

First I had to create a TypeAdapterFactory:

public class BaseModelForeignKeyTypeAdapterFactory implements TypeAdapterFactory {

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (!BaseModel.class.isAssignableFrom(type.getRawType())) {
            return null;
        }

        TypeAdapter defaultAdapter = gson.getAdapter(type);

        //noinspection unchecked
        return (TypeAdapter<T>) new Adapter(defaultAdapter);
    }

    private static class Adapter<T extends BaseModel> extends TypeAdapter<T> {

        private final TypeAdapter<T> defaultAdapter;

        Adapter(TypeAdapter<T> defaultAdapter) {
            this.defaultAdapter = defaultAdapter;
        }

        @Override
        public void write(JsonWriter out, T value) throws IOException {
            out.value(value.getId());
        }

        @Override
        public T read(JsonReader in) throws IOException {
            return defaultAdapter.read(in);
        }
    }
}

In the create() method I retrieve the default adapter Gson would use for this field and pass it to the Adapter for use when deserializing the field. This way this Adapter is only used for serialization, while deserialization is delegated to the default adapter.

Now I just need to annotate the fields in my Student class, which I want to be serialized as IDs with this TypeAdapterFactory like this:

public class Student extends BaseModel{
    private int id;
    private String name;

    @JsonAdapter(BaseModelForeignKeyTypeAdapterFactory.class)
    private Student goodFriend;

    private Student bestFriend;
}

And this is all, now gson.toJson(student) will output:

{
 id: 1, 
 name: "Jack", 
 goodFriend: 2, // using "ForeignKey" TypeAdapter
 bestFriend: {id: 3, name "Tom"} // using default TypeAdapter
}

I hope this helps someone!

这篇关于GSON带注释的自定义序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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