【工具类】JacksonUtils

发布时间 2023-08-18 13:39:35作者: 日月星宿

 

package com.ryxx.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

@SuppressWarnings("unused")
@Slf4j
public final class JacksonUtils {


    private static final String pattern = "yyyy-MM-dd HH:mm:ss.SSS";

    private static final String timeZoneString = "Asia/Shanghai";

    private static final ObjectMapper MAPPER = new ObjectMapper();

    private static final String SERIALIZATION_ERROR_MESSAGE = JacksonUtils.class.getName() + ": Serialize error.";

    private static final String DESERIALIZATION_ERROR_MESSAGE = JacksonUtils.class.getName() + ": Deserialize error.";


    static {
        // POJO对象的属性值不论是什么,序列化时都显示
        MAPPER.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 设置在反序列化时忽略在JSON字符串中存在,而在Java中不存在的属性
        MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 设置序列化时间类型不使用时间戳形式(jackson时间类型默认都是序列化为时间戳形式的)
        MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        // 为了处理JSON中的日期字符串并正确转换为 LocalDate,我们需要注册在 ObjectMapper 实例中注册 JavaTimeModule 模块。
        // 还需要禁止把日期转换为时间戳字符串的动作
        JavaTimeModule javaTimeModule = new JavaTimeModule();

        // Date类型序列化、反序列化全局配置-方式1
//        MAPPER.setDateFormat(new SimpleDateFormat(pattern));

        // Date类型序列化、反序列化全局配置-方式2
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZoneString));
        javaTimeModule.addSerializer(Date.class, new DateSerializer(false, simpleDateFormat));
        javaTimeModule.addDeserializer(Date.class, new DateDeserializer());

        // LocalDateTime类型序列化、反序列化全局配置
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern)));

        MAPPER.registerModule(javaTimeModule);

    }

    /**
     * Object to json string.
     *
     * @param obj obj
     * @return json string
     */
    public static String toJson(Object obj) {
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(SERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Object to json string byte array.
     *
     * @param obj obj
     * @return json string byte array
     */
    public static byte[] toJsonBytes(Object obj) {
        try {
            return MAPPER.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(SERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param json json string
     * @param cls  class of object
     * @param <T>  General type
     * @return object
     */
    public static <T> T toObj(byte[] json, Class<T> cls) {
        try {
            return MAPPER.readValue(json, cls);
        } catch (Exception e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param json json string
     * @param cls  {@link Type} of object
     * @param <T>  General type
     * @return object
     */
    public static <T> T toObj(byte[] json, Type cls) {
        try {
            return MAPPER.readValue(json, constructJavaType(cls));
        } catch (Exception e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param inputStream json string input stream
     * @param cls         class of object
     * @param <T>         General type
     * @return object
     */
    public static <T> T toObj(InputStream inputStream, Class<T> cls) {
        try {
            return MAPPER.readValue(inputStream, cls);
        } catch (IOException e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param json          json string byte array
     * @param typeReference {@link TypeReference} of object
     * @param <T>           General type
     * @return object
     */
    public static <T> T toObj(byte[] json, TypeReference<T> typeReference) {
        try {
            return MAPPER.readValue(json, typeReference);
        } catch (Exception e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param json json string
     * @param cls  class of object
     * @param <T>  General type
     * @return object
     */
    public static <T> T toObj(String json, Class<T> cls) {
        try {
            return MAPPER.readValue(json, cls);
        } catch (IOException e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param json json string
     * @param type {@link Type} of object
     * @param <T>  General type
     * @return object
     */
    public static <T> T toObj(String json, Type type) {
        try {
            return MAPPER.readValue(json, MAPPER.constructType(type));
        } catch (IOException e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param json          json string
     * @param typeReference {@link TypeReference} of object
     * @param <T>           General type
     * @return object
     */
    public static <T> T toObj(String json, TypeReference<T> typeReference) {
        try {
            return MAPPER.readValue(json, typeReference);
        } catch (IOException e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Object.
     *
     * @param inputStream json string input stream
     * @param type        {@link Type} of object
     * @param <T>         General type
     * @return object
     */
    public static <T> T toObj(InputStream inputStream, Type type) {
        try {
            return MAPPER.readValue(inputStream, MAPPER.constructType(type));
        } catch (IOException e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Json string deserialize to Jackson {@link JsonNode}.
     *
     * @param json json string
     * @return {@link JsonNode}
     */
    public static JsonNode readTree(String json) {
        try {
            return MAPPER.readTree(json);
        } catch (IOException e) {
            throw new RuntimeException(DESERIALIZATION_ERROR_MESSAGE, e);
        }
    }

    /**
     * Register subtype for child class.
     *
     * @param clz  child class
     * @param type type name of child class
     */
    public static void registerSubtype(Class<?> clz, String type) {
        MAPPER.registerSubtypes(new NamedType(clz, type));
    }

    /**
     * Create a new empty Jackson {@link ObjectNode}.
     *
     * @return {@link ObjectNode}
     */
    public static ObjectNode createEmptyJsonNode() {
        return new ObjectNode(MAPPER.getNodeFactory());
    }

    /**
     * Create a new empty Jackson {@link ArrayNode}.
     *
     * @return {@link ArrayNode}
     */
    public static ArrayNode createEmptyArrayNode() {
        return new ArrayNode(MAPPER.getNodeFactory());
    }

    /**
     * Parse object(usually a bean) to Jackson {@link JsonNode}.
     *
     * @param obj object
     * @return {@link JsonNode}
     */
    public static JsonNode transferToJsonNode(Object obj) {
        return MAPPER.valueToTree(obj);
    }

    /**
     * construct java type -> Jackson Java Type.
     *
     * @param type java type
     * @return JavaType {@link JavaType}
     */
    public static JavaType constructJavaType(Type type) {
        return MAPPER.constructType(type);
    }

    public static ObjectMapper getObjectMapper() {
        return MAPPER;
    }


    /**
     * Date类型反序列化定制
     */
    public static class DateDeserializer extends JsonDeserializer<Date> {

        private static final List<String> patternList = new ArrayList<String>(4);

        static {
            patternList.add("yyyy-MM");
            patternList.add("yyyy-MM-dd");
            patternList.add("yyyy-MM-dd hh:mm");
            patternList.add("yyyy-MM-dd hh:mm:ss");
            patternList.add("yyyy-MM-dd hh:mm:ss.SSS");
        }

        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            String source = p.getText().trim();
            if ("".equals(source)) {
                return null;
            }

            if (source.matches("^\\d{4}-\\d{1,2}$")) {
                return parseDate(source, patternList.get(0));
            } else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
                return parseDate(source, patternList.get(1));
            } else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$")) {
                return parseDate(source, patternList.get(2));
            } else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$")) {
                return parseDate(source, patternList.get(3));
            } else if (source.matches("^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}.\\d{1,3}$")) {
                return parseDate(source, patternList.get(4));
            } else if (source.matches("^\\d{13}$")) {//毫秒
                return new Date(Long.parseLong(source));
            } else if (source.matches("^\\d{10}$")) {//
                return new Date(Long.parseLong(source) * 1000);
            } else {
                throw new IllegalArgumentException("Invalid Date value '" + source + "'");
            }

        }

        /**
         * 功能描述:格式化日期
         *
         * @param dateStr String 字符型日期
         * @param format  String 格式
         * @return Date 日期
         */
        private Date parseDate(String dateStr, String format) {
            Date date = null;
            try {
                DateFormat dateFormat = new SimpleDateFormat(format);
                date = dateFormat.parse(dateStr);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return date;
        }

    }

}