jackson序列化反序列化报错处理

Jackson 默认支持多种基本数据类型和复杂数据类型的序列化和反序列化。例如常见的布尔类型、字符串类型、集合、数组、枚举等,但某些特定类型(如 Java 8 的 LocalDateTime、LocalDate、LocalTime 等)需要额外的模块支持。需要进行如下配置:

1、你需要添加 jackson-datatype-jsr310 模块。

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.3</version> <!-- 请根据你的Jackson版本选择合适的版本 -->
</dependency>

2、同时封装如下的公共对象,轻松实现java对象、json对象、json字符串之间的相互转化:

package xxxxxx;

import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer;
import xxxxxxxxx.JSONConvertException;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.OffsetDateTimeSerializer;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.Predicate;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.Type;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xxxx
 */
@Slf4j
public class JsonUtils {
    private static final ObjectMapper objectMapper;
    private static final ObjectMapper rawObjectMapper;

    private static final ObjectMapper snakeCaseMapper;

    private static final Gson GSON = new Gson();

    static {
        JavaTimeModule javaTimeModule = new JavaTimeModule();

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(TimeUtils.DATETIME_FORMAT_PATTERN);
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(dateTimeFormatter));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(dateTimeFormatter));

        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(TimeUtils.DATE_FORMAT_PATTERN);
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter));
        javaTimeModule.addSerializer(Instant.class, InstantSerializer.INSTANCE);
        javaTimeModule.addDeserializer(Instant.class, InstantDeserializer.INSTANT);
        javaTimeModule.addSerializer(OffsetDateTime.class, OffsetDateTimeSerializer.INSTANCE);
        objectMapper = new ObjectMapper()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
                .registerModule(javaTimeModule);

        rawObjectMapper = new ObjectMapper()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL);

        snakeCaseMapper = new ObjectMapper()
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                .setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
                .registerModule(javaTimeModule)
                .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

    }

    /**
     * json元素到对象
     * @param json
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T fromJson(JsonElement json, Class<T> classOfT) {
        if (json == null) {
            return null;
        }
        return GSON.fromJson(json, classOfT);
    }

    /**
     * 字符串转换成对象
     * @param json
     * @param typeOfT
     * @param <T>
     * @return
     */
    public static <T> T fromJson(String json, Type typeOfT) {
        return GSON.fromJson(json, typeOfT);
    }

    /**
     * 对象 to 字符串
     * @param src
     * @return
     */
    public static String toJson(Object src) {
        return GSON.toJson(src);
    }

    /**
     * 字符串解析成 JsonObject
     * @param json
     * @return
     */
    public static JsonObject parserJsonObject(String json) {
        return JsonParser.parseString(json).getAsJsonObject();
    }


    public static ObjectMapper defaultObjectMapper(){
        return objectMapper;
    }

    /**
     * 任意对转换为JSON字符串
     *
     * @param obj
     * @return
     */
    public static String object2JsonString(Object obj) {
        objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        String jsonString = null;
        try {
            jsonString = objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Json转换异常");
        }
        return jsonString;
    }

    public static ObjectNode createObjectNode() {
        return objectMapper.createObjectNode();
    }

    public static ObjectNode createObjectNode(String key, String value) {
        ObjectNode node = createObjectNode();
        node.put("key", key);
        node.put("value", value);
        return node;
    }

    public static ArrayNode createArrayNode() {
        return objectMapper.createArrayNode();
    }

    /**
     * 任意对象转为ObjectNode
     *
     * @param o
     * @return
     */
    public static ObjectNode object2ObjectNode(Object o) {
        return objectMapper.convertValue(o, ObjectNode.class);
    }

    public static ObjectNode object2ObjectNodeSnakeCase(Object o){
        return snakeCaseMapper.convertValue(o, ObjectNode.class);
    }


    /**
     * 任意对象转为ArrayNode
     *
     * @param o
     * @return
     */
    public static ArrayNode objectToArrayNode(Object o) {
        return objectMapper.convertValue(o, new TypeReference<ArrayNode>() {
        });
    }

    /**
     * Convert object to json
     *
     * @param fromValue the pojo class
     * @param <T>       Json node
     * @return
     */
    public static <T extends JsonNode> T object2Json(Object fromValue) {
        return objectMapper.valueToTree(fromValue);
    }

    /**
     * Convert object to json string
     *
     * @param fromValue the pojo class
     * @return string in json format
     */
    public static String object2JsonStr(Object fromValue) {
        String jsonString = null;
        try {
            jsonString = objectMapper.writeValueAsString(fromValue);
        } catch (JsonProcessingException e) {
            throw new JSONConvertException("convert json string error");
        }
        return jsonString;
    }

    /**
     * Convert json string to java pojo
     *
     * @param jsonStr the string in json format
     * @param type    the java class type
     * @param <T>     the class type
     * @return the instance of class type
     */
    public static <T> T jsonStr2Object(String jsonStr, Class<T> type) {
        T obj;
        try {
            obj = objectMapper.readValue(jsonStr, type);
        } catch (Exception e) {
            throw new JSONConvertException(e);
        }
        return obj;
    }

    /**
     * Convert json to java pojo
     *
     * @param jsonNode the json object
     * @param type     the java class type
     * @param <T>      the class type
     * @return the instance of class type
     */
    public static <T> T json2Object(JsonNode jsonNode, Class<T> type) {
        T obj;
        try {
            obj = objectMapper.convertValue(jsonNode, type);
        } catch (Exception e) {
            throw new JSONConvertException(e);
        }
        return obj;
    }


    /**
     * 获得json path对象,json path对象是使用json path库的基础
     *
     * @param bluePrintStr String in json format
     * @return json path object
     */
    public static Object toJsonPath(String bluePrintStr) {
        return Configuration.defaultConfiguration().jsonProvider().parse(bluePrintStr);
    }

    public static <T> T silentReadJsonPath(Object json, String jsonPath, Predicate... filters) {
        try {
            return readJsonPath(json, jsonPath, filters);
        } catch (PathNotFoundException e) {
            //keep silent
        }
        return null;
    }

    public static <T> T readJsonPath(Object json, String jsonPath, Predicate... filters) {
        return JsonPath.read(json, jsonPath, filters);
    }

    public static <T> T fromJson(String content, Class<T> valueType) {
        try {
            return objectMapper.readValue(content, valueType);
        } catch (IOException ioException) {
            throw new RuntimeException(ioException);
        }
    }

    public static String toJsonString(Object value) {
        try {
            return objectMapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> List<T> arrayNodeToList(ArrayNode node, Class<T> clazz) {
        List<T> list = new ArrayList<>();
        node.forEach(n1 -> {
            list.add(fromJson(toJsonString(n1), clazz));
        });
        return list;
    }

}

package xxxx.common.exception

public class JSONConvertException extends ProcessException {

    public JSONConvertException(String msg, Throwable original) {
        super(msg, original);
    }
    public JSONConvertException(Throwable original) {
        super(original);
    }
    public JSONConvertException(String msg) {
        super(msg);
    }
}
package xxxxx.common.exception;

import lombok.Getter;

@Getter
public class ProcessException extends RuntimeException{
    protected String msg = null;

    protected Throwable original = null;

    public ProcessException(String msg, Throwable original){
        this.msg = msg;
        this.original = original;
    }
    public ProcessException(Throwable original){
        this.original = original;
    }
    public ProcessException(String msg){
        this.msg = msg;
    }

    public static ProcessException create(Throwable original){
        return new ProcessException(original.getMessage(),original);
    }

    public static ProcessException create(String msg){
        return new ProcessException(msg);
    }
}

### 关于 FastJSON RedisSerializer 反序列化错误解决方案 当使用 FastJSON 作为 `RedisTemplate` 的序列化器时,可能会遇到反序列化的异常情况。这通常是因为对象在存储到 Redis 中之前未按照预期的方式进行序列化,或者读取的对象类型与实际存储的数据类型不符。 为了处理此类问题,可以采取以下措施: #### 修改配置类以适配FastJSON序列化方式 确保应用程序上下文中定义了正确的序列化策略。下面是一个基于 Spring Boot 应用程序的例子,在其中指定了如何自定义 `StringRedisTemplate` 通用类型的 `RedisTemplate` 使用 FastJSON 进行序列化/反序列化操作[^1]。 ```java import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 设置键(key)的序列化采用 StringRedisSerializer 方式 template.setKeySerializer(new StringRedisSerializer()); // 设置值(value)的序列化采用 FastJsonRedisSerializer 方式 FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); template.afterPropertiesSet(); return template; } } ``` #### 处理特定实体类的字段映射关系 对于某些复杂场景下可能出现的特殊字符转义等问题,则可以通过调整 JSON 转换规则来规避潜在风险。例如设置日期格式、忽略空属性等参数选项,从而提高兼容性稳定性[^2]。 ```properties # application.properties 或者 yml 文件中添加如下配置项 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.time-zone=GMT+8 spring.jackson.default-property-inclusion=non_null ``` 另外值得注意的是,虽然上述方法能够有效缓解大部分情况下由于序列化引起的异常现象,但在生产环境中仍需谨慎评估业务需求并选择合适的消息中间件产品,因为像 Kafka、RabbitMQ 等专门设计用于消息传递的服务往往具备更完善的功能特性以及更高的可靠性保障[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值