Jackson 类路径变更后的反序列化

2021-08-27  本文已影响0人  蓝笔头

需引入 Jackson 依赖,可参考 Jackson 使用简介

@JsonTypeInfo 序列化

1)定义序列化结构

@Data
public class LiveLesson {
    public static final TypeReference<Container> ITEMS_TYPE = new TypeReference<Container>() {
    };

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Container {
        private List<Item> items;
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
    public interface Item {
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Item1 implements Item {
        private long id;
        private String item1Name;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Item2 implements Item {
        private long id;
        private String item2Name;
    }
}

2)测试代码

public class TestMain {
    public static void main(String[] args) {
        List<LiveLesson.Item> items = new ArrayList<>();

        items.add(new LiveLesson.Item1(1, "Item1"));
        items.add(new LiveLesson.Item2(2, "Item2"));

        LiveLesson.Container container = new LiveLesson.Container(items);

        System.out.println(serialize(items));
        System.out.println(serialize(container));

    }

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @SneakyThrows
    public static String serialize(Object obj) {
        return objectMapper.writeValueAsString(obj);
    }
}

控制台输出:

[{"id":1,"item1Name":"Item1"},{"id":2,"item2Name":"Item2"}]
{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}

可以发现不通过类进行包裹的话,序列化后不会出现 @c 字段。

@JsonTypeInfo 反序列化

public class TestMain {
    public static void main(String[] args) {
        List<LiveLesson.Item> items = new ArrayList<>();

        items.add(new LiveLesson.Item1(1, "Item1"));
        items.add(new LiveLesson.Item2(2, "Item2"));

        LiveLesson.Container container = new LiveLesson.Container(items);
        String serialize = serialize(container);
        System.out.println(serialize);

        LiveLesson.Container newContainer = deserialize(serialize, LiveLesson.ITEMS_TYPE);
        System.out.println(serialize(newContainer));
    }

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @SneakyThrows
    public static String serialize(Object obj) {
        return objectMapper.writeValueAsString(obj);
    }

    @SneakyThrows
    public static <T> T deserialize(String json, TypeReference<T> valueTypeRef) {
        return objectMapper.readValue(json, valueTypeRef);
    }
}

控制台输出:

{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}
{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}

变更路径后的反序列化

1)定义反序列化结构

除了 LiveLesson 变更为 LiveLessonInfo,其他的结构和上面的一样。

@Data
public class LiveLessonInfo {
    public static final TypeReference<Container> ITEMS_TYPE = new TypeReference<Container>() {
    };

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Container {
        private List<Item> items;
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
    public interface Item {
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Item1 implements Item {
        private long id;
        private String item1Name;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Item2 implements Item {
        private long id;
        private String item2Name;
    }
}

2)测试代码

    public static void main(String[] args) {
        List<LiveLesson.Item> items = new ArrayList<>();

        items.add(new LiveLesson.Item1(1, "Item1"));
        items.add(new LiveLesson.Item2(2, "Item2"));

        LiveLesson.Container container = new LiveLesson.Container(items);
        String serialize = serialize(container);
        System.out.println(serialize);

        // LiveLesson.ITEMS_TYPE 修改为 LiveLessonInfo.ITEMS_TYPE
        LiveLesson.Container newContainer = deserialize(serialize, LiveLesson.ITEMS_TYPE);
        System.out.println(serialize(newContainer));
    }

控制台输出:

{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'org.company.jackson.LiveLesson$Item1' as a subtype of `org.company.jackson.LiveLessonInfo$Item`: Not a subtype
 at [Source: (String)"{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}"; line: 1, column: 17] (through reference chain: org.company.jackson.LiveLessonInfo$Container["items"]->java.util.ArrayList[0])

3)使用 JsonTypeInfo.Id.NAME 替换 JsonTypeInfo.Id.MINIMAL_CLASS,新增 @JsonSubTypes 注解。

    @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
    public interface Item {
    }
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "@c")
    @JsonSubTypes({
        @JsonSubTypes.Type(value = Item1.class, name = ".LiveLesson$Item1"),
        @JsonSubTypes.Type(value = Item2.class, name = ".LiveLesson$Item2")
    })
    public interface Item {
    }

执行测试代码,控制台输出:

{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}
{"items":[{"@c":".LiveLesson$Item1","id":1,"item1Name":"Item1"},{"@c":".LiveLesson$Item2","id":2,"item2Name":"Item2"}]}

参考

上一篇下一篇

猜你喜欢

热点阅读