java - GSON:对对象映射进行编码并在解码时保留类型

标签 java json gson deserialization json-deserialization

我有一个类:

public class MyClass {
    private final Map<Property, Object> properties;
} 

其中Property是一个enum
假设属性包含 2 个元素,一个元素的值为 Double,另一个元素的值为仅具有一个名为 ownerName 的属性的类实例。当我序列化此类时,我得到以下字符串:

{"properties":{"NAME":{"ownerName":"MyBucket"},"DIVISOR":33.0}}

问题是,当我尝试从上面的字符串获取 MyClass 实例时,NAME 属性的值将是 Map而不是具有 ownerName 属性的类的实例。我尝试编写自定义序列化器/反序列化器,但我无法仅针对NAME属性执行此操作。有什么想法吗?

最佳答案

您需要为整个Map编写自定义反序列化器。自定义反序列化器可能如下所示:

class PropertyJsonDeserializer implements JsonDeserializer<Map<Property, Object>>, JsonSerializer<Map<Property, Object>> {

    @Override
    public Map<Property, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (!json.isJsonObject()) {
            return Collections.emptyMap();
        }

        JsonObject root = json.getAsJsonObject();
        Map<Property, Object> result = new LinkedHashMap<>();
        root.entrySet().forEach(entry -> {
            Property property = Property.valueOf(entry.getKey());
            switch (property) {
                case DIVISOR:
                    result.put(property, entry.getValue().getAsDouble());
                    break;
                case NAME:
                    Object owner = context.deserialize(entry.getValue(), Owner.class);
                    result.put(property, owner);
            }
        });
        return result;
    }

    @Override
    public JsonElement serialize(Map<Property, Object> src, Type typeOfSrc, JsonSerializationContext context) {
        return context.serialize(src, Map.class);
    }
}

使用示例:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
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.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.annotations.JsonAdapter;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.EnumMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class GsonApp {

    public static void main(String[] args) throws Exception {
        Map<Property, Object> properties = new EnumMap<>(Property.class);
        properties.put(Property.DIVISOR, new BigDecimal("33.0"));
        properties.put(Property.NAME, new Owner());

        MyClass myClass = new MyClass(properties);

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String json = gson.toJson(myClass);
        System.out.println(json);

        myClass = gson.fromJson(json, MyClass.class);
        System.out.println(myClass);
    }
}

class MyClass {

    @JsonAdapter(PropertyJsonDeserializer.class)
    private final Map<Property, Object> properties;

    public MyClass(Map<Property, Object> properties) {
        this.properties = properties;
    }

    // getters, setters, toString
}

class Owner {
    private String ownerName = "MyBucket";

    // getters, setters, toString
}

enum Property {
    NAME, DIVISOR
}

上面的代码打印:

{
  "properties": {
    "NAME": {
      "ownerName": "MyBucket"
    },
    "DIVISOR": 33.0
  }
}

MyClass{properties={NAME=Owner{ownerName='MyBucket'}, DIVISOR=33.0}}

关于java - GSON:对对象映射进行编码并在解码时保留类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56340896/

相关文章:

java - 在java中使用递归循环复制树结构数据并创建相同的树结构数据

ios - 如何使用 Swift 从 JSON 字符串中获取时间?

java - gson 在自定义反序列化器中调用标准反序列化

java - GSON 的自定义打印格式

java - 为主方法编写公共(public)类有什么好处吗?

java - 更紧凑的 Eclipse 自动完成代码

c++ - 在运行时组装自己的对象

java - Gson并且只专注于内部对象

java - 我的 (AspectJ) jar 无法识别联合剪切

c - 如何从 json 字符串中获取值?