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;
}
}
}