DeserializationFeature配置

序言

com.fasterxml.jackson.databind包中有很多属性

  • 1)映射特性:MapperFeature;
  • 2)序列化特性:SerializationFeature;
  • 3)反序列化特性:DeserializationFeature;

最近开发过程中,有同事使用了一个不太恰当的反序列化特性导致在定位问题时找了半天才发现是在某一处转换时出了问题。

【简要描述一下问题】
我们依赖的某个接口模型发生了变化,某个字段枚举值新增了某个属性值,然而在我们这一层没有感知到。在使用方处使用了新的枚举值进行接口调用,然后我们在反序列化时把该新增的枚举值转换为了默认枚举值。
原因是在反序列化时设置了属性DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE,该配置即在反序列化未知枚举值时使用默认值。

【个人建议】
中间层不建议使用该特性,如果某个属性不是关键属性,且服务提供方认为该属性不重要可做降级处理时使用该特性。

映射特性、序列化特性使用较少,一般反序列化特性较多,故下面只简单介绍反序列化的属性使用。

DeserializationFeature

com.fasterxml.jackson.databind.DeserializationFeature中的特性很多,最常用的是FAIL_ON_UNKNOWN_PROPERTIES,即遇到未知属性仍然能够反序列化非未知的属性,保证反序列化不会因为瞎填了一些多余参数而不可用。

下面使用一个demo介绍部分特性,

package com.hust.zhang.serializable;

import static com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT;
import static com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
import static com.fasterxml.jackson.databind.DeserializationFeature.READ_ENUMS_USING_TO_STRING;
import static com.fasterxml.jackson.databind.DeserializationFeature.UNWRAP_ROOT_VALUE;
import static com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS;
import static com.fasterxml.jackson.databind.DeserializationFeature.USE_BIG_INTEGER_FOR_INTS;
import static com.fasterxml.jackson.databind.DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY;
import static com.fasterxml.jackson.databind.DeserializationFeature.WRAP_EXCEPTIONS;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.text.Normalizer;
import java.util.HashMap;

@Slf4j
public class DeserializationFeatureDemo {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        /**
         * 该特性决定对于json浮点数,是否使用BigDecimal来序列化。如果不允许,则使用Double序列化。
         * 注意:该特性默认是关闭的,因为性能上来说,BigDecimal低于Double。
         */
        OBJECT_MAPPER.configure(USE_BIG_DECIMAL_FOR_FLOATS, true);

        /**
         * 该特性决定对于json整形(非浮点),是否使用BigInteger来序列化。如果不允许,则根据数值大小来确定 是使用Integer},
         * {@link Long} 或者 {@link java.math.BigInteger}
         */
        OBJECT_MAPPER.configure(USE_BIG_INTEGER_FOR_INTS, false);

        /**
         * 该特性决定JSON ARRAY是映射为Object[]还是List<Object>。如果开启,都为Object[],false时,则使用List。
         * @since 1.9
         */
        OBJECT_MAPPER.configure(USE_JAVA_ARRAY_FOR_JSON_ARRAY, false);

        /**
         * 该特性决定了使用枚举值的标准序列化机制:如果允许,则枚举假定使用Enum.toString()返回的值作为序列化结构;如果禁止, 则返回Enum.name()的值。
         * 注意:默认使用的时Enum.name()的值作为枚举序列化结果。这个的设置和WRITE_ENUMS_USING_TO_STRING需要一致。
         * For further details, check out [JACKSON-212]
         * @since 1.6
         */
        OBJECT_MAPPER.configure(READ_ENUMS_USING_TO_STRING, false);

        /**
         * 该特性决定了当遇到未知属性(没有映射到属性,没有任何setter或者任何可以处理它的handler),是否应该抛出一个
         * JsonMappingException异常。这个特性一般式所有其他处理方法对未知属性处理都无效后才被尝试,属性保留未处理状态。
         * 默认情况下,该设置是被打开的。
         * @since 1.2
         */
        OBJECT_MAPPER.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        /**
         * 该特性决定JSON 整数是否是一个有效的值,当被用来反序列化Java枚举值。如果false,数字可以接受,并且映射为枚举的值ordinal();
         * 如果true,则数字不允许并且抛出JsonMappingException异常。后面一种行为原因是因为大部分情况下,枚举被反序列化为 JSON 字符串, 从而造成从整形到枚举的意外映射关系。
         * Feature is disabled by default (to be consistent with behavior of Jackson 1.6), i.e. to allow use of JSON
         * integers for Java enums.
         * @since 1.7
         */
        OBJECT_MAPPER.configure(FAIL_ON_NULL_FOR_PRIMITIVES, false);

        /**
         * 异常封装,不封装Error,catch异常之后,抛出IOException。默认封装异常。
         * @since 1.7
         */
        OBJECT_MAPPER.configure(WRAP_EXCEPTIONS, true);

        /**
         * 该特性决定是否接受强制非数组(JSON)值到Java集合类型。如果允许,集合反序列化将尝试处理非数组值。
         * @since 1.8
         */
        OBJECT_MAPPER.configure(ACCEPT_SINGLE_VALUE_AS_ARRAY, false);

        /**
         * 该特征允许 unwrap根级别JSON 值,来匹配WRAP_ROOT_VALUE 序列化设置。
         * @since 1.9
         */
        OBJECT_MAPPER.configure(UNWRAP_ROOT_VALUE, false);

        /**
         * 该特性可以允许JSON空字符串转换为POJO对象为null。如果禁用,则标准POJO只会从JSON null或者JSON对象转换过来;
         * 如果允许,则空JSON字符串可以等价于JSON null。
         * @since 1.8
         */
        OBJECT_MAPPER.configure(ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, false);
    }

    /**
     * 注意上面的实例对象必须要有无参构造函数,否则在反序列化时创建实例对象
     * 会抛出异常com.fasterxml.jackson.databind.exc.InvalidDefinitionException
     */
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    private static class Person {
        private String name;
        private Long age;
    }

    public static void main(String[] args) {
        String jsonStr = "{\"name\":\"张三\",\"age\":18,\"sex\":\"男\"}";
        String normalizedStr = Normalizer.normalize(jsonStr, Normalizer.Form.NFKC);
        System.out.println("serialize java object to json : " + normalizedStr);
        Person A = parse(jsonStr, Person.class, false);
        System.out.println("after deserialize to object :" + JSON.toJSONString(A));
        Person B = parse(jsonStr, Person.class, true);
        System.out.println("after deserialize to object :" + JSON.toJSONString(B));
        String floatJson = "{\"key\":123.10010}";
        HashMap<String, Object> map = parse(floatJson, new TypeReference<HashMap<String, Object>>() {
        });
        System.out.println(JSON.toJSONString(map));
    }

    private static <T> T parse(String json, Class<T> tClass, boolean failOnUnknownProperties) {
        T result = null;
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, failOnUnknownProperties);
        // 忽略 transient 修饰的属性,默认不忽略
        OBJECT_MAPPER.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
        // 默认不修改序列化后日期格式
        OBJECT_MAPPER.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        try {
            result = OBJECT_MAPPER.readValue(json, tClass);
        } catch (JsonProcessingException e) {
            log.error("Failed to deserialize JSON content, json value : " + json);
        }
        return result;
    }

    private static <T> T parse(String json, TypeReference<T> typeReference) {
        T result = null;
        try {
            result = OBJECT_MAPPER.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            log.error("Failed to deserialize JSON content, json value : " + json);
        }
        return result;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 反序列化特性(DeserializationFeature)是指在将序列化后的数据转换为对象时,可以设置一些特性来控制反序列化的行为。例如,可以设置是否允许反序列化时忽略未知属性、是否允许反序列化时忽略空值等。反序列化特性可以帮助开发人员更好地控制反序列化过程,提高程序的健壮性和安全性。 ### 回答2: 反序列化是指将存储在文件中或在网络传输中的二进制数据转换为内存中的对象的过程。在计算机编程中,反序列化是常见的操作,特别是在使用网络传输数据或持久化存储数据时。 DeserializationFeature是一个用于配置反序列化过程的特性。它是在Java中的Jackson库中定义的,Jackson是一个流行的JSON库,用于在Java对象和JSON数据之间进行转换。 DeserializationFeature提供了多个选项来控制反序列化的行为。一些常见的选项包括: 1. ACCEPT_SINGLE_VALUE_AS_ARRAY:将单个数值也作为数组处理,这样可以避免在JSON中的某些情况下的类型不匹配错误。 2. FAIL_ON_UNKNOWN_PROPERTIES:如果JSON中包含未知的属性,是否抛出异常。设置为false可以忽略未知属性。 3. READ_ENUMS_USING_TO_STRING:使用枚举的字符串值来反序列化,而不是使用枚举的名称。 4. UNWRAP_ROOT_VALUE:当JSON中的根级别包装对象时,是否解包该值。 5. WRAP_EXCEPTIONS:是否将异常包装在JsonMappingException中,以提供更详细的错误信息。 通过使用DeserializationFeature,我们可以根据需要灵活地配置反序列化过程。例如,如果我们不希望在JSON中的未知属性上抛出异常,可以将FAIL_ON_UNKNOWN_PROPERTIES设置为false。这样可以确保即使JSON包含额外的属性,反序列化过程也能够成功完成。 总之,DeserializationFeature是一个重要的特性,它提供了在反序列化过程中进行配置的选项,以满足不同的需求和应用场景。 ### 回答3: DeserializationFeature是一个用于处理Java对象反序列化的特性集合。在Java编程中,对象的序列化是将对象转换为字节流的过程,而反序列化则是将字节流转换回对象的过程。 DeserializationFeature提供了许多选项,可以定制反序列化的行为。其中一些重要的特性包括: 1. ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT:允许将空数组解析为null对象。在反序列化过程中,如果遇到空数组,可以将其解析为一个null对象。 2. ACCEPT_EMPTY_STRING_AS_NULL_OBJECT:允许将空字符串解析为null对象。如果反序列化的过程中遇到空字符串,可以将其解析为null对象。 3. FAIL_ON_UNKNOWN_PROPERTIES:如果在反序列化过程中遇到未知的属性,是否抛出一个异常。如果设置为false,则会忽略未知的属性;如果设置为true,则会抛出一个异常。 4. UNWRAP_ROOT_VALUE:允许反序列化过程中取消包装根值。例如,如果一个JSON对象有一个根键值对,可以使用这个特性将根值解析为一个Java对象。 DeserializationFeature的使用可以使得反序列化过程更加灵活,能够根据需要进行定制。通过设置不同的特性,可以控制是否接受空数组或空字符串,是否忽略未知的属性等。这些特性提升了代码的可读性和可维护性,同时也提供了更多的选择和控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值