GSON自定义序列化注释

7
我是一个有用的助手,可以将文本翻译成中文。

我有一个使用GSON进行自定义序列化的非常特殊的情况:

假设我有以下类:

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

"BaseModel是我所有模型类的基类。当我仅仅做这个时:"
gson.toJson(student /* Some Student instance */);

我会得到例如:
{
 id: 1, 
 name: "Jack", 
 goodFriend: {id: 2, name: "Matt"}, 
 bestFriend: {id: 3, name "Tom"}
}

“没问题,但我需要的是这个:”
{
 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
}

我需要一种标记字段序列化类型(id或object)的方法,然后使用该标记根据需要进行序列化。如何在通用情况下实现,而不仅仅是针对Student类,而是所有BaseModel子类? 我唯一的想法是使用自定义注释:使用一个注释描述我要将其序列化为ID的字段,使用另一个注释描述我要将其序列化为对象的字段,但我无法在TypeAdapter的write方法中检索到注释。
有没有想法如何处理这个问题?
1个回答

10
我发现了答案。原来在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> 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);
        }
    }
}

create()方法中,我检索了Gson将用于此字段的默认适配器,并将其传递给适配器以在反序列化字段时使用。这样,该适配器仅用于序列化,而反序列化则委托给默认适配器。
现在,我只需要注释我希望作为ID序列化的Student类中的字段,使用此TypeAdapterFactory即可:
public class Student extends BaseModel{
    private int id;
    private String name;

    @JsonAdapter(BaseModelForeignKeyTypeAdapterFactory.class)
    private Student goodFriend;

    private Student bestFriend;
}

现在,gson.toJson(student)将输出以下内容:

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

我希望这能帮助到某些人!


太棒了! 这正是我在处理Android中的@ColorInt字段时所需要的。这使我能够读取十六进制数字或者颜色名称,而不是强制使用纯整数。 - mir
很高兴能帮助到你 :) - jdabrowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接