美文网首页
【常用】Jackson针对泛型的序列化的工具方法

【常用】Jackson针对泛型的序列化的工具方法

作者: 小胖学编程 | 来源:发表于2022-03-02 16:24 被阅读0次

如何对带有返回的对象进行输出,可以凝练出下面的工具类。

import static com.fasterxml.jackson.core.JsonFactory.Feature.INTERN_FIELD_NAMES;
import static com.fasterxml.jackson.databind.type.TypeFactory.defaultInstance;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Map;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ObjectMapperUtils {

    private static final String EMPTY_JSON = "{}";
    private static final String EMPTY_ARRAY_JSON = "[]";
    //解决jackson2.9.x版本内存泄露的问题,详见[2] Jackson2.x中内存泄露的风险点—封装的intern逻辑
    private static final ObjectMapper MAPPER = new ObjectMapper(new JsonFactory().disable(INTERN_FIELD_NAMES));


    public static String toJSON(@Nullable Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 实现类型的强转。能实现【父类-->子类】的强转。
     * 这一点在{@code (父类)子类}是实现不了的。
     */
    public static <T> T value(Object rawValue, Class<T> type) {
        return MAPPER.convertValue(rawValue, type);
    }

    /**
     * 注意,一般情况不推荐使用本方法,因为开销还是略大,可以选择的几个方式是:
     * <p>
     * 1. 直接 {@link #fromJSON} 解析,适用于本身也是要解析JSON并生成DTO,并且是主要分支的场景
     * 2. 自己编写一个方法,只检查第一个字符,适合内部特定数据结构兼容的快速检查,并不需要完整的 JSON 检查
     */
    public static boolean isJSONWithHeavyweight(String jsonStr) {
        if (StringUtils.isBlank(jsonStr)) {
            return false;
        }
        try (JsonParser parser = new ObjectMapper().getFactory().createParser(jsonStr)) {
            while (parser.nextToken() != null) {
                // do nothing.
            }
            return true;
        } catch (IOException ioe) {
            return false;
        }
    }

    /**
     * 轻量级的校验方法
     */
    public static boolean isJSONWithLightweight(String jsonStr) {
        if (StringUtils.isBlank(jsonStr)) {
            return false;
        }
        return jsonStr.startsWith("{") || jsonStr.startsWith("[");
    }


    /**
     * 带有泛型对象的强转
     */
    public static <T> T value(Object rawValue, TypeReference<T> type) {
        return MAPPER.convertValue(rawValue, type);
    }

    public static <T> T value(Object rawValue, JavaType type) {
        return MAPPER.convertValue(rawValue, type);
    }


    /**
     * 支持带泛型的集合反序列化输出
     */
    public static <E, T extends Collection<E>> T fromJSON(String json,
            Class<? extends Collection> collectionType, Class<E> valueType) {
        if (StringUtils.isEmpty(json)) {
            json = EMPTY_ARRAY_JSON;
        }
        try {
            return MAPPER.readValue(json,
                    defaultInstance().constructCollectionType(collectionType, valueType));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 支持带有泛型的Map的输出
     */
    public static <K, V, T extends Map<K, V>> T fromJSON(String json, Class<? extends Map> mapType,
            Class<K> keyType, Class<V> valueType) {
        if (StringUtils.isEmpty(json)) {
            json = EMPTY_JSON;
        }
        try {
            return MAPPER.readValue(json,
                    defaultInstance().constructMapType(mapType, keyType, valueType));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public static <T> T fromJSON(InputStream inputStream, Class<T> type) {
        try {
            return MAPPER.readValue(inputStream, type);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 当json中只有bean部分属性时,更新一个存在的bean,只覆盖该部分的属性。
     * 当存在相同的属性时,json中属性的优先级明显会更高。
     */
    public static <T> T update(T rawValue, String jsonString) {
        try {
            return MAPPER.readerForUpdating(rawValue).readValue(jsonString);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJSON(Object value, Class<T> valueType) {
        if (value == null) {
            return null;
        } else if (value instanceof String) {
            return fromJSON((String) value, valueType);
        } else if (value instanceof byte[]) {
            return fromJSON((byte[]) value, valueType);
        } else {
            return null;
        }
    }

    public static <T> T fromJSON(@Nullable byte[] bytes, Class<T> valueType) {
        if (bytes == null) {
            return null;
        }
        try {
            return MAPPER.readValue(bytes, valueType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJSON(@Nullable String json, Class<T> valueType) {
        if (json == null) {
            return null;
        }
        try {
            return MAPPER.readValue(json, valueType);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
  
    public static <T> T parseObject(String str, TypeReference<T> type) {
        try {
            return MAPPER.readValue(str, type);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

对二级数组进行反序列化的操作?

    public static void main(String[] args) {
        List<List<Integer>> v1 = Lists.newArrayList(Lists.newArrayList(1, 2, 3), Lists.newArrayList(4, 2, 3));
        //二维数组的反序列化
        List<List<Integer>> lists = parseObject(toJSON(v1), new TypeReference<List<List<Integer>>>() {
        });
        System.out.println(lists);
    }

推荐阅读

json解析工具类

[2] Jackson2.x中内存泄露的风险点—封装的intern逻辑

相关文章

网友评论

      本文标题:【常用】Jackson针对泛型的序列化的工具方法

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