java - 如何使用 Gson 只存储非默认值

标签 java serialization gson deserialization

我制作了一个小型序列化系统,它使用Gson并且仅影响具有特定注释Fields

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Store  {
    String valueName() default "";
    boolean throwIfDefault() default false;
}

throwIfDefault() 确定如果 Field 的值等于默认值,是否应将其保存到文件中(我通过将字段的值与相同的字段,但在类的静态实例中)。

它工作得很好,但我想要实现的是,对于 MapArraySet 对象也同样有效:

只有当这些对象的条目未包含在该特定字段的默认实例中时,才应保存它们。

它还必须适用于反序列化:

加载的对象中尚未存在的默认值应在反序列化期间添加,或者首先加载默认的对象,然后使用加载的条目进行修改对象

是否可以通过为这些对象创建自定义Json(De)Serializer来实现这一点,或者您将如何做到这一点?

这是反序列化部分:

public void Load() throws FileNotFoundException {
    Type typeOfHashMap = new TypeToken<LinkedHashMap<String, Object>>(){}.getType();
    FileReader reader = new FileReader(file);
    HashMap<String, Object> loadedMap = mainGson.fromJson(reader,typeOfHashMap);
    for(Field f: this.getClass().getDeclaredFields()) {
        if (!f.isAnnotationPresent(Store.class)) {
            continue;
        }
        try {
            f.setAccessible(true);
            Store annotation = f.getAnnotation(Store.class);
            Object defaultValue = DefaultRegistrator.getDefault(this.getClass(),f);
            if (!loadedMap.containsKey(annotation.valueName())) {
                f.set(this, defaultValue);
                continue;
            }
            Object loadedValue = mainGson.fromJson(
                loadedMap.get(annotation.valueName()).toString(), f.getType()
            );
            f.set(this, loadedValue);
        } catch(IllegalAccessException e) {

        } 
    }
}

最佳答案

假设您的 JSON 对象是

{"defParam1": 999,
 "defParam2": 999,
 "defParam3": 999,
 "param4": 999,
 "param5": 999,
 "param6": 999}

参数defParam1、defParam2、defParam3不会被设置。

使用默认参数将 JSON 对象解析为特定对象

默认参数在构造函数中设置,因此不需要使用注释

您的 Java 对象是:

public class ObjStore {
    public ObjStore(){
        this(false);
    }
    // Load default parameters directly into the constructor
    public ObjStore(boolean loadDefault){
        if( loadDefault ){
            defParam1 = 123; // (int) DefaultRegistrator.getDefault("ObjStore", "defParam1");
            defParam2 = 123; // (int) DefaultRegistrator.getDefault("ObjStore", "defParam2");
            defParam3 = 123; // (int) DefaultRegistrator.getDefault("ObjStore", "defParam3");
        }
    }
    public int getDefParam1() {
        return defParam1;
    }

    public int getDefParam2() {
        return defParam2;
    }

    public int getDefParam3() {
        return defParam3;
    }

    public int getParam4() {
        return param4;
    }

    public void setParam4(int param4) {
        this.param4 = param4;
    }

    public int getParam5() {
        return param5;
    }

    public void setParam5(int param5) {
        this.param5 = param5;
    }

    public int getParam6() {
        return param6;
    }

    public void setParam6(int param6) {
        this.param6 = param6;
    }

    private int defParam1;
    private int defParam2;
    private int defParam3;
    private int param4;
    private int param5;
    private int param6;
}

对于反序列化,您需要以这种方式注册新的自定义 typeAdapter:

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(ObjStore.class, new JsonDeserializer<ObjStore>() {
    public ObjStore deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        ObjStore objStore = new ObjStore(true);
        JsonObject jo = json.getAsJsonObject();
        objStore.setParam4( jo.get("param4").getAsInt() );
        objStore.setParam5(jo.get("param5").getAsInt());
        objStore.setParam6(jo.get("param6").getAsInt());
        return objStore;
    }
});

Gson gson = gsonBuilder.create();

您可以使用以下方法解析 JSON 对象:

ObjStore objStore = gson.fromJson("{\"defParam1\": 999,\"defParam2\": 999,\"defParam3\": 999,\"param4\": 999,\"param5\": 999,\"param6\": 999}", ObjStore.class);

使用默认参数将 JSON 对象解析为 Map 对象

默认参数在构造函数中设置,因此不需要使用注释。

定义包装您的 Map 对象的类

public class ObjMapStore {
    public ObjMapStore(){
        this(true);
    }
    public ObjMapStore(boolean loadDefault){
        map = new HashMap<>();
        if(loadDefault){
            map.put("defParam1", 123); // (int) DefaultRegistrator.getDefault("ObjMapStore", "defParam1");
            map.put("defParam2", 123); // (int) DefaultRegistrator.getDefault("ObjMapStore", "defParam2");
            map.put("defParam3", 123); // (int) DefaultRegistrator.getDefault("ObjMapStore", "defParam3");
        }
    }

    public void put(String key, Object value){
        map.put(key, value);
    }

    public Map<String, Object> getMap(){
        return map;
    }
    private Map<String, Object> map;
}

同样,为了反序列化,您需要以这种方式注册新的自定义 typeAdapter:

GsonBuilder gsonBuilder = new GsonBuilder();

gsonBuilder.registerTypeAdapter(ObjMapStore.class, new JsonDeserializer<ObjMapStore>() {
    public ObjMapStore deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        ObjMapStore objMapStore = new ObjMapStore();
        JsonObject jo = json.getAsJsonObject();
        objMapStore.put("param4", jo.get("param4").getAsInt());
        objMapStore.put("param5", jo.get("param5").getAsInt());
        objMapStore.put("param6", jo.get("param6").getAsInt());
        return objMapStore;
    }
});

Gson gson = gsonBuilder.create();

就像在使用以下方法获取 map 对象之前所做的那样:

Map<String, Object> objMapStore = gson.fromJson("{\"defParam1\": 999,\"defParam2\": 999,\"defParam3\": 999,\"param4\": 999,\"param5\": 999,\"param6\": 999}", ObjMapStore.class).getMap();

对这个调用保持警惕 .getMap(); 因为允许您获取定义到 ObjMapStore 返回的对象中的 Map

很高兴为您提供帮助,如有任何问题请发表评论。请记得投票并检查回复是否有帮助。再见

关于java - 如何使用 Gson 只存储非默认值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35106032/

相关文章:

java - 在 Java 8 中,它显示为默认情况下没有选择可用的 4 个收集器 (GC)

java - Java单例类中final关键字是必须的吗?

c++ - boost序列化库中的<<和&有什么区别?

java - 使用Gson解析以下字符串

java - 是否可以使用单斜杠将字符串序列化为 json?

java - 如何使用 GSON 比较两个 JSON 字符串是否相等?

java - 在类路径上使用 (SAXON-HE) 进行 JAXB 解码非常慢

java - 使用 TestNG(或任何其他框架)在测试方法级别定义共享或新夹具

json - 我可以用 TJSONMarshal 序列化接口(interface)(_recordset)吗?

c# - JavaScriptSerializer 可以排除具有空值/默认值的属性吗?