【问题标题】:GSON Custom serialization with annotations带注释的 GSON 自定义序列化
【发布时间】:2017-05-05 20:33:09
【问题描述】:

我有一个非常具体的使用 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 或对象)的字段,然后根据需要使用该标记进行序列化。我如何在general 中做到这一点,不仅适用于 Student 类,而且适用于 BaseModel 的所有子类?

我唯一的想法是使用自定义注释: 仅使用一个注释描述我想序列化为 ID 的字段,以及我想使用另一个注释将其序列化为对象的字段, 但是我找不到在 TypeAdapter 的 write 方法中检索注解的方法。

任何想法如何处理这个?

【问题讨论】:

    标签: java android reflection annotations gson


    【解决方案1】:

    我自己找到了答案。事实证明,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 将用于该字段的默认适配器,并将其传递给适配器以在反序列化该字段时使用。这样这个 Adapter 只用于序列化,而反序列化则委托给默认适配器。

    现在我只需要注释我的 Student 类中的字段,我想用这个 TypeAdapterFactory 将其序列化为 ID,如下所示:

    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 字段。这使我能够读取十六进制数字或颜色名称,而不是强制使用纯整数。
    • 很高兴我能帮上忙 :)
    猜你喜欢
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多