Jackson

作者: 十二找十三 | 来源:发表于2022-06-20 11:42 被阅读0次

    基础

    1.jackson的github地址:https://github.com/FasterXML/jackson
    2.jackson共有1.x和2.x两个版本系列, 其中1.x已废弃不再有版本发布, 2.x是活跃版本, 1.x和2.x并不兼容但也不冲突可以同时使用    
    3.jackson有三个核心模块
        jackson-core -> 低阶API库,提供流式解析工具JsonParser,流式生成工具JsonGenerator
        jackson-annotations -> jackson注解
        jackson-databind -> 基于java对象的序列化, 反序列化能力, 需要前面两个模块的支持才能实现
    
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.3</version>
    </dependency>
    
    spring boot 已经自动集成 如果是Spring 项目根本不需要引依赖
    

    jackson-core 相关知识

    相关核心API
        private static JsonFactory jsonFactory = new JsonFactory(); // 线程安全的 可以全局公用一个
    
        /**
         * jsonStr to Object
         * 反序列化测试(JSON STR -> Object),入参是JSON字符串
         */
        private static Object deserializeJSONByStr(String jsonString) {
            JsonParser jsonParser = null;
    
            Object object = new Object(); // 可以声明自己想要的对象类型 然后返回 就是转换成指定类型
    
            try {
                jsonParser = jsonFactory.createParser(jsonString);
    
                if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
                    jsonParser.close();
                    throw new IOException("起始位置没有大括号{");
                }
    
                while ( jsonParser.nextToken() != JsonToken.END_OBJECT) {
    
                    String fieldName = jsonParser.getCurrentName(); // 当前正在解析字段
                    jsonParser.nextToken(); // * next 解析下一个
    
    
                    /**
                     * 可以获取多种类型
                     * jsonParser.getLongValue()
                     * jsonParser.getText()
                     * jsonParser.getIntValue()
                     * jsonParser.getBooleanValue()
                     */
                    String fieldValue = jsonParser.getValueAsString();
    
                    System.out.println(fieldName + "->" + fieldValue);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return object;
        }
    
    
        /**
         * 序列化测试(Object -> JSON)
         *
         * @return 由对象序列化得到的JSON字符串
         */
        public static String serialize(Map<String, Object> obj) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    
            try (JsonGenerator jsonGenerator = jsonFactory.createGenerator(byteArrayOutputStream, JsonEncoding.UTF8)) {
    
                jsonGenerator.useDefaultPrettyPrinter();
    
                jsonGenerator.writeStartObject();
                jsonGenerator.writeNumberField("id", (int) obj.get("id"));
                jsonGenerator.writeStringField("str", (String) obj.get("str"));
                jsonGenerator.writeEndObject();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            return byteArrayOutputStream.toString();
        }
    
    
    
    -------------------------------------------------------------------测试类---------------------------------------------
    
    package com.study.other;
    
    import com.fasterxml.jackson.core.*;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    public class JacksonCoreTest {
    
        public static void main(String[] args) {
            String str = "{\"aaa\":\"1\", \"bbb\":2}";
            System.out.println(deserializeJSONByStr(str));
    
            Map<String, Object> obj = new HashMap<>();
            obj.put("id", 1);
            obj.put("str", "2");
            System.out.println(serialize(obj));
        }
    
        private static JsonFactory jsonFactory = new JsonFactory();
    
        /**
         * 序列化测试(Object -> JSON)
         *
         * @return 由对象序列化得到的JSON字符串
         */
        public static String serialize(Map<String, Object> obj) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    
            try (JsonGenerator jsonGenerator = jsonFactory.createGenerator(byteArrayOutputStream, JsonEncoding.UTF8)) {
    
                jsonGenerator.useDefaultPrettyPrinter();
    
                jsonGenerator.writeStartObject();
                jsonGenerator.writeNumberField("id", (int) obj.get("id"));
                jsonGenerator.writeStringField("str", (String) obj.get("str"));
                jsonGenerator.writeEndObject();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return byteArrayOutputStream.toString();
        }
    
    
        // jsonStr to Object
        private static Object deserializeJSONByStr(String jsonString) {
            JsonParser jsonParser = null;
    
            Object object = new Object(); // 可以声明自己想要的对象类型 然后返回 就是转换成指定类型
    
            try {
                jsonParser = jsonFactory.createParser(jsonString);
    
                if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
                    jsonParser.close();
                    throw new IOException("起始位置没有大括号{");
                }
    
                while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
    
                    String fieldName = jsonParser.getCurrentName(); // 当前正在解析字段
                    jsonParser.nextToken(); // * next 解析下一个
    
    
                    /**
                     * 可以获取多种类型
                     * jsonParser.getLongValue()
                     * jsonParser.getText()
                     * jsonParser.getIntValue()
                     * jsonParser.getBooleanValue()
                     */
                    String fieldValue = jsonParser.getValueAsString();
    
                    System.out.println(fieldName + "->" + fieldValue);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return object;
        }
    
    }
    

    常用相关API

    package com.study.other;
    
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    import java.util.*;
    
    public class JacksonAPIDemo {
        public static void main(String[] args) throws Exception {
            ObjectMapper mapper = new ObjectMapper();
    
            TestVO testVO = new TestVO();
            testVO.setId(1);
            testVO.setAaa("aaa");
            testVO.setBbb(new Date());
    
            TestVO testVO2 = new TestVO();
            testVO2.setId(2);
            testVO2.setAaa("bbb");
            testVO2.setBbb(new Date());
    
            String jsonStr = mapper.writeValueAsString(testVO);
            System.out.println("对象序列化成字符串-->" + jsonStr);
    
            String testVOJsonStr = "{\"id\":2," +
                    "\"aaa\":\"bbb\"," +
                    "\"bbb\":1655513110837}";
    
            // 字符串 -> 对象
            TestVO testVOR1 = mapper.readValue(jsonStr, TestVO.class);
            System.out.println("反序列化--->" + testVOR1);
    
            // 对象 -> 文件
    //        mapper.writeValue(new File("testVO.json"), testVOR1);
            // 文件 -> 对象
    //        TestVO testVO2 = mapper.readValue(new File("testVO.json"), TestVO.class);
    //        System.out.println(testVO2);
    
            // 对象 -> byte数组
    //        byte[] array = mapper.writeValueAsBytes(testVOR1);
    //        System.out.println("111->" + Arrays.toString(array));
    
            // byte数组 -> 对象
    //        TestVO testVO3 = mapper.readValue(array, TestVO.class);
            // 字符串网络地址 -> 对象
    //        mapper.readValue(new URL(jsonDataUrl), TestVO.class);
    
    
            System.out.println("-------------------------------------------------集合序列化相关API----------------------------------------------------");
    
            Map<String, Object> root = new HashMap<>(8);
            root.put("id", 1);
            root.put("aaa", "s1");
    
            Map<String, String> child = new HashMap<>();
            child.put("a","a");
            child.put("b", "b");
    
            root.put("child", child);
    
            String mapTestJsonStr = mapper.writeValueAsString(root);
            System.out.println("HashMap序列化的字符串---->" + mapTestJsonStr);
    
            Map<String, Object> mapFromStr = mapper.readValue(mapTestJsonStr, new TypeReference<Map<String, Object>>() {});
            System.out.println("HashMap反序列化---->" + mapFromStr);
    
            // JsonNode类型操作
            JsonNode jsonNode = mapper.readTree(mapTestJsonStr);
            System.out.println(jsonNode.get("child").get("a").asText());
    
    
            List<TestVO> list = new ArrayList<>(2);
            list.add(testVO);
            list.add(testVO2);
    
            String listStr = mapper.writeValueAsString(list);
    
            System.out.println("listStr->" + listStr);
    
            // json数组 -> 对象数组
            TestVO[] testVOArray = mapper.readValue(listStr, TestVO[].class);
            System.out.println("testVOArray--->" + Arrays.toString(testVOArray));
    
            // json数组 -> 对象集合
            List<TestVO> testVOList = mapper.readValue(listStr, new TypeReference<List<TestVO>>() {});
            System.out.println("testVOList--->" + testVOList);
        }
    }
    
    
    平时可能用到的自定义配置项说明:
    1.反序列化时,遇到未知属性不要抛出异常:
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    
    2.空对象不要抛出异常:
    mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    
    3反序列化时,空字符串对于的实例属性为null:
    mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    
    4.序列化结果格式化:
    mapper.enable(SerializationFeature.INDENT_OUTPUT);
    
    5.Date、Calendar等序列化为时间格式的字符串(如果不执行以下设置,就会序列化成时间戳格式):
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    
    6.允许C和C++样式注释:
    mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
    
    7.允许字段名没有引号(可以进一步减小json体积):
    mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
    
    8.允许单引号:
    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
    
    9. 配合@JsonRootName(value = "xxx")注解使用 外层增加JSON嵌套注解
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE); // 用于序列化 没有JsonRootName注解 有默认值Order1
    mapper.enable(SerializationFeature.UNWRAP_ROOT_VALUE); // 用于反序列化 反序列化必须JsonRootName必须存在
    
    

    实际工作相关

    package com.study.other;
    
    import com.fasterxml.jackson.annotation.JsonFilter;
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.ser.BeanPropertyFilter;
    import com.fasterxml.jackson.databind.ser.FilterProvider;
    import com.fasterxml.jackson.databind.ser.PropertyFilter;
    import com.fasterxml.jackson.databind.ser.PropertyWriter;
    import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
    
    import java.util.*;
    
    public class JacksonWorkTest {
        static class DTO {
            private int id;
            private String aaa;
            private String bbb;
            private DTO1 ccc;
    
            public int getId() {
                return id;
            }
    
            public void setId(int id) {
                this.id = id;
            }
    
            public String getAaa() {
                return aaa;
            }
    
            public void setAaa(String aaa) {
                this.aaa = aaa;
            }
    
            public String getBbb() {
                return bbb;
            }
    
            public void setBbb(String bbb) {
                this.bbb = bbb;
            }
    
            public DTO1 getCcc() {
                return ccc;
            }
    
            public void setCcc(DTO1 ccc) {
                this.ccc = ccc;
            }
    
            @Override
            public String toString() {
                return "DTO{" +
                        "id=" + id +
                        ", aaa='" + aaa + '\'' +
                        ", bbb='" + bbb + '\'' +
                        ", ccc='" + ccc + '\'' +
                        '}';
            }
        }
    
        static class DTO1 {
            private int id1;
            private String aaa1;
            private String bbb1;
    
            public int getId1() {
                return id1;
            }
    
            public void setId1(int id1) {
                this.id1 = id1;
            }
    
            public String getAaa1() {
                return aaa1;
            }
    
            public void setAaa1(String aaa1) {
                this.aaa1 = aaa1;
            }
    
            public String getBbb1() {
                return bbb1;
            }
    
            public void setBbb1(String bbb1) {
                this.bbb1 = bbb1;
            }
    
            @Override
            public String toString() {
                return "DTO1{" +
                        "id1=" + id1 +
                        ", aaa1='" + aaa1 + '\'' +
                        ", bbb1='" + bbb1 + '\'' +
                        '}';
            }
        }
    
        @JsonFilter("JsonFilterUtilByCm")
        static class JsonFilterUtilByCm extends FilterProvider {
            Map<Class<?>, Set<String>> includeMap = new HashMap<>();
            Map<Class<?>, Set<String>> filterMap = new HashMap<>();
    
            public void include(Class<?> type, String[] fields) {
                addToMap(includeMap, type, fields);
            }
    
            public void filter(Class<?> type, String[] fields) {
                addToMap(filterMap, type, fields);
            }
    
            private void addToMap(Map<Class<?>, Set<String>> map, Class<?> type, String[] fields) {
                Set<String> fieldSet = map.getOrDefault(type, new HashSet<>());
                fieldSet.addAll(Arrays.asList(fields));
                map.put(type, fieldSet);
            }
    
            @Override
            public BeanPropertyFilter findFilter(Object filterId) {
                throw new UnsupportedOperationException("Access to deprecated filters not supported");
            }
    
            @Override
            public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {
                return new SimpleBeanPropertyFilter() {
                    @Override
                    public void serializeAsField(Object pojo, JsonGenerator jsonGenerator, SerializerProvider provider, PropertyWriter writer)
                            throws Exception {
                        if (apply(pojo.getClass(), writer.getName())) {
                            writer.serializeAsField(pojo, jsonGenerator, provider);
                        } else if (!jsonGenerator.canOmitFields()) {
                            writer.serializeAsOmittedField(pojo, jsonGenerator, provider);
                        }
                    }
                };
            }
    
            public boolean apply(Class<?> type, String name) {
                Set<String> includeFields = includeMap.get(type);
                Set<String> filterFields = filterMap.get(type);
                if (includeFields != null && includeFields.contains(name)) {
                    return true;
                } else if (filterFields != null && !filterFields.contains(name)) {
                    return true;
                } else if (includeFields == null && filterFields == null) {
                    return true;
                }
                return false;
            }
    
        }
    
    
        // 测试实际工作中的序列化问题
        private static void test1() {
            ObjectMapper objectMapper = new ObjectMapper();
            DTO1 ccc = new DTO1();
            ccc.setId1(2);
    
            DTO dto = new DTO();
            dto.setId(1);
            dto.setBbb("bbb");
            dto.setCcc(ccc);
    
            JsonFilterUtilByCm jacksonFilterUtil = new JsonFilterUtilByCm();
            jacksonFilterUtil.include(dto.getClass(), new String[]{"id", "aaa", "ccc"});
            jacksonFilterUtil.include(ccc.getClass(), new String[]{"id", "aaa1"});
            objectMapper.setFilterProvider(jacksonFilterUtil);
            objectMapper.addMixIn(DTO.class, JsonFilterUtilByCm.class);
            objectMapper.addMixIn(DTO1.class, JsonFilterUtilByCm.class);
            try {
                System.out.println(objectMapper.writeValueAsString(dto));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    
    
        // 测试实际工作中的反序列化问题
        private static void test2() {
            String str = "{\"id\":1,\"aaa\":null,\"ccc\":{\"aaa1\":null}}";
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                DTO obj = objectMapper.readValue(str, DTO.class);
                System.out.println(obj);
                System.out.println(obj.getAaa());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    
    
        public static void main(String[] args) {
    //        test1();
            test2();
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Jackson

          本文链接:https://www.haomeiwen.com/subject/mifjvrtx.html