具有不同类型的多态列表的对象的序列化

时间:2019-07-06 12:45:41

标签: java android json serialization gson

我正在尝试构建一个自定义应用程序,以利用Tasmota固件和MQTT控制智能家居设备。目前主要是智能灯。因此,根据设备的类型,我有一个Device类的孩子。每个设备都存储一个DeviceState,由于通过该应用程序进行的任何更改而被更新。因此DeviceState始终是设备的当前状态。根据设备的不同,我需要不同的DeviceState,因此又有一个超类和子类。 现在,我想存储带有DeviceStates的ArrayList的场景以首先存储,而不是重新创建某些明亮的气氛。因此,有一个名为Scene的类,它包含基本信息和所描述的ArrayList。 为了存储这些列表,我正在使用Android中的Gson库。现在我的问题是如何能够保存带有多态列表的场景对象。

我已遵循以下stackoverflow帖子:Gson serialize a list of polymorphic objects使用Gson库和自定义序列化器/反序列化器将设备另存为Json String。但是现在DeviceState不会扩展场景,所以我不能使用一个序列化程序从Scene对象中创建String。而且,如果我将DeviceState扩展到Scene,则DeviceState类将声明具有相同名称的多个JSON字段,因为我使用“ typeName”来区分这些类。

所以基本上我得到了错误,DeviceState没有扩展Scene或DeviceState声明了多个名为“ typeName”的JSON字段。

public class Scene{

        private ArrayList<DeviceState> states;
        private String name;
        private String room;
        private String typeName;

        public ArrayList<Scene> sceneList = new ArrayList<>();

        public Scene(){


        }

        public Scene(String pName, String pRoom) {
            name = pName;
            room = pRoom;

            states = new ArrayList<>();

            typeName = "Scene";
        }

        public String getName() {
            return name;
        }

        public String getRoom() {
            return room;
        }

        public void addDevice(Device d) {
            states.add(d.getState());
        }

        public void execute() {
            System.out.println(states.size());
        }

        public String getTypeName(){
            return typeName;
        }
    }
public class DeviceState {

    private String typeName;
    private String deviceTopic;

    public static final String RGBWLightState = "RGBWLightState";
    public static final String Default = "DeviceState";

    public DeviceState(String pTypeName, String pDeviceTopic){
        typeName = pTypeName;
        deviceTopic = pDeviceTopic;
    }

    public DeviceState(){
        typeName = Default;
    }


    public String getTypeName() {
        return typeName;
    }
}
public class CustomSceneSerializer implements JsonSerializer<ArrayList<Scene>> {

    private static Map<String, Class> map = new TreeMap<>();

    static {
        map.put(DeviceState.RGBWLightState, RGBWLightState.class);
        map.put(DeviceState.Default, DeviceState.class);
        map.put("Scene", Scene.class);
    }

    @Override
    public JsonElement serialize(ArrayList<Scene> src, Type typeOfSrc, JsonSerializationContext context) {

        if(src == null) {
            return null;
        }else{
            JsonArray ja = new JsonArray();
            for(Scene s : src){
                Class c = map.get(s.getTypeName());
                if(c == null){
                    throw new RuntimeException("Unkown class: " + s.getTypeName());
                }
                    ja.add(context.serialize(s, c));
            }
            return ja;
        }
    }

}
public class CustomSceneDeserializer implements JsonDeserializer<List<Scene>> {

    private static Map<String, Class> map = new TreeMap<>();


    static {
        map.put(DeviceState.RGBWLightState, RGBWLightState.class);
        map.put(DeviceState.Default, DeviceState.class);
        map.put("Scene", Scene.class);
    }


    @Override
    public List<Scene> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        ArrayList list = new ArrayList<Scene>();
        JsonArray ja = json.getAsJsonArray();

        for (JsonElement je : ja) {

            String type = je.getAsJsonObject().get("typeName").getAsString();
            Class c = map.get(type);
            if (c == null)
                throw new RuntimeException("Unknow class: " + type);
            list.add(context.deserialize(je, c));
        }

        return list;
    }


}

要保存包含我正在使用的那些对象的列表的对象,请执行以下操作:

String json = preferences.getString("scene_holder", "");

GsonBuilder gb = new GsonBuilder();

List<Scene> al = new ArrayList<>();

gb.registerTypeAdapter(al.getClass(), new CustomSceneDeserializer());
gb.registerTypeAdapter(al.getClass(), new CustomSceneSerializer());
Gson gson = gb.create();

System.out.println(list.size());
list.get(0).execute();
System.out.println(json);

if (!(json.equals(""))) {

    Scene result = gson.fromJson(json, Scene.class);

    System.out.println(result.sceneList.size());

    result.sceneList = list;

    System.out.println(result.sceneList.size());

    editor.putString("scene_holder", gson.toJson(result)).commit();
} else {
    Scene scene = new Scene();

    scene.sceneList = list;

    editor.putString("scene_holder", gson.toJson(scene)).commit();
}

0 个答案:

没有答案