Jackson接入指南和工具类util编写

1. Why Jackson?和fastJson的差异以及优劣

  • fastJson更新迭代较快,稳定性较差,究其根本原因是底层bug较多,很可能你现在用的最新的版本,一个月之后就被标记为不安全版本了;
  • fastJson以解析json和组装json较快著称,但是,其实Jackson的性能瓶颈主要在初始化ObjectMapper上,详细初始化代码下面贴出,而在解析上,Jackson的性能是显著高于fastJson的;
  • fastJson解析json主要是用的String类substring这个方法,因为jdk1.7之前substring的实现并没有new一个新对象,申请内存次数很少。但是,在jdk1.7以上版本对string的substring方法做了改写,改成了重新new一个string的方式,于是这个“快”的优势也不存在了(因为不new的话有可能稍不注意就会出现内存泄漏);
  • 当然,fastJson也有其优势,针对于易用性来说,fastjson还是很适合的,碾压Jackson,基本可以实现零配置简单使用,具体使用什么还是根据业务场景以及个人爱好来。
public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
        this._rootDeserializers = new ConcurrentHashMap(64, 0.6F, 2);
        if (jf == null) {
            this._jsonFactory = new MappingJsonFactory(this);
        } else {
            this._jsonFactory = jf;
            if (jf.getCodec() == null) {
                this._jsonFactory.setCodec(this);
            }
        }

        this._subtypeResolver = new StdSubtypeResolver();
        RootNameLookup rootNames = new RootNameLookup();
        this._typeFactory = TypeFactory.defaultInstance();
        SimpleMixInResolver mixins = new SimpleMixInResolver((MixInResolver)null);
        this._mixIns = mixins;
        BaseSettings base = DEFAULT_BASE.withClassIntrospector(this.defaultClassIntrospector());
        this._configOverrides = new ConfigOverrides();
        this._coercionConfigs = new CoercionConfigs();
        this._serializationConfig = new SerializationConfig(base, this._subtypeResolver, mixins, rootNames, this._configOverrides);
        this._deserializationConfig = new DeserializationConfig(base, this._subtypeResolver, mixins, rootNames, this._configOverrides, this._coercionConfigs);
        boolean needOrder = this._jsonFactory.requiresPropertyOrdering();
        if (needOrder ^ this._serializationConfig.isEnabled(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)) {
            this.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, needOrder);
        }

        this._serializerProvider = (DefaultSerializerProvider)(sp == null ? new Impl() : sp);
        this._deserializationContext = (DefaultDeserializationContext)(dc == null ? new com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl(BeanDeserializerFactory.instance) : dc);
        this._serializerFactory = BeanSerializerFactory.instance;
    }

2. Jackson maven依赖

       <jackson.version>2.12.0</jackson.version>
       
        <!--jackson start -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!--jackson end -->

3. ObjectMapper初始化

public static final ObjectMapper mapper = new ObjectMapper();

static {
    // 转换为格式化的json
    mapper.enable(SerializationFeature.INDENT_OUTPUT);

    // 如果json中有新增的字段并且是实体类类中不存在的,不报错
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}

其中,mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}这个一定要加上,不然bean中字段和映射的数据流中字段有出入的时候就会报错。

3. 一些常用的方法封装

  • javaBean、列表数组转换为json字符串
    public static String objectToJson(Object data) {
        try {
            String result = MAPPER.writeValueAsString(data);
            return result;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
  • json 转JavaBean对象
public static <T> T jsonToBean(String jsonData, Class<T> beanType) {
        try {
            T result = MAPPER.readValue(jsonData, beanType);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
  • json转list
public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);

        try {
            List<T> resultList = MAPPER.readValue(jsonData, javaType);
            return resultList;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
  • json转map
public static <K, V> Map<K, V> jsonToMap(String jsonData, Class<K> keyType, Class<V> valueType) {

        JavaType javaType = MAPPER.getTypeFactory().constructMapType(Map.class, keyType, valueType);
        try {
            Map<K, V> resultMap = MAPPER.readValue(jsonData, javaType);
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
  • 按照路径取json中的数据
 /**
     * @param json 原json数据
     * @param paths 需要取的路径地址 按照层级
     * @return
     */
    public static JsonNode getJsonNodeByPath(String json, String... paths) {
        JsonNode rootNode = null;
        try {
            rootNode = MAPPER.readTree(json);

            if (paths != null && paths.length > 0) {
                //一直遍历下去
                for (int i = 0; i < paths.length; i++) {
                    String path = paths[i];
                    rootNode = rootNode.path(path);
                    //如果不存在
                    if (rootNode.isMissingNode()) {
                        return null;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return rootNode;
    }

4. 将json对象按照层级封装为map

工作中经常有场景,需要将json对象按照层级,一层层打平为键值对的形式,比如user.name,user.password这种形式,参考https://tools.ietf.org/html/rfc6901

/**
 * This class flatten a json object, the key pattern is defined at the following url:
 * https://tools.ietf.org/html/rfc6901
 *
 * @author bob
 * @since 2020-12-14
 */
public final class Rfc6901Flattener
        implements Function<JsonNode, Map<String, JsonNode>>, Serializable {

    private static final String STANDARD_SEPARATOR = ".";
    private static final int DEFAULT_EXPECT_SIZE = 15;
    private static final long serialVersionUID = 501491114373294711L;

    private final int expectSize;
    private final String prefix;
    private final String separator;

    public Rfc6901Flattener(int expectSize, @NonNull String prefix, @NonNull String separator) {
        if (expectSize <= 0 || expectSize > 1000) {
            throw new IllegalArgumentException("illegal expect size: " + expectSize);
        }
        this.expectSize = expectSize;
        this.prefix = prefix;
        this.separator = separator;
    }

    public Rfc6901Flattener() {
        this(DEFAULT_EXPECT_SIZE, "props.", STANDARD_SEPARATOR);
    }

    public static String getStandardSeparator() {
        return STANDARD_SEPARATOR;
    }

    private String generateKey(Deque<String> path, StringBuilder keyBuf) {
        if (path.size() == 1) {
            return prefix.concat(path.peek());
        }
        keyBuf.setLength(0);
        Joiner.on(separator).appendTo(keyBuf.append(prefix), path.descendingIterator());
        return keyBuf.toString();
    }

    @Override
    public Map<String, JsonNode> apply(@NonNull JsonNode jsonNode) {
        Map<String, JsonNode> result = new HashMap<>(expectSize);
        iterateOverNode(result, new ArrayDeque<>(5), new StringBuilder(16), jsonNode);
        return result;
    }

    private void iterateOverObject(
            Map<String, JsonNode> map, Deque<String> stack, StringBuilder keyBuf, JsonNode target) {
        Iterator<Map.Entry<String, JsonNode>> iterator = target.fields();
        while (iterator.hasNext()) {
            Map.Entry<String, JsonNode> entry = iterator.next();
            stack.push(entry.getKey());
            iterateOverNode(map, stack, keyBuf, entry.getValue());
            stack.pop();
        }
    }

    private void iterateOverArray(
            Map<String, JsonNode> map, Deque<String> stack, StringBuilder keyBuf, JsonNode target) {

        int size = target.size();
        for (int i = 0; i < size; ++i) {
            stack.push(Integer.toString(i));
            iterateOverNode(map, stack, keyBuf, target.get(i));
            stack.pop();
        }
    }

    private void iterateOverNode(
            Map<String, JsonNode> map, Deque<String> stack, StringBuilder keyBuf, JsonNode target) {
        if (target.isObject()) {
            iterateOverObject(map, stack, keyBuf, target);
        } else if (target.isArray()) {
            iterateOverArray(map, stack, keyBuf, target);
        } else if (target.isValueNode() && !target.isNull() && !stack.isEmpty()) {
            String key = generateKey(stack, keyBuf);
            map.put(key, target);
        }
    }
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值