Jackson 2.x 系列【16】反序列化器 JsonDeserializer

312 阅读7分钟

有道无术,术尚可求,有术无道,止于术。

本系列Jackson 版本 2.17.0

源码地址:https://gitee.com/pearl-organization/study-jaskson-demo

1. 概述

JsonDeserializer是一个用于将JSON反序列化为任意类型的对象的抽象类,是Jackson中的重要组件之一。

2. 方法

JsonDeserializer声明了很多方法。

2.1 构造

Fluent风格的工厂方法用于构建经过装饰或增强的对象(和JsonSerializer类似)。

public JsonDeserializer<T> unwrappingDeserializer(NameTransformer unwrapper) {
        return this;
    }
    
public JsonDeserializer<?> replaceDelegatee(JsonDeserializer<?> delegatee) {
        throw new UnsupportedOperationException();
    }

2.2 反序列化

声明了核心的反序列化方法:

    /**
     * 反序列化
     *
     * @param p    Json解析器
     * @param ctxt 反序列化上下文
     * @return 反序列化后的对象
     */
    public abstract T deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException, JacksonException;

    /**
     * 反序列化
     *
     * @param p    Json解析器
     * @param ctxt 反序列化上下文
     * @param intoValue 已经初始化的值实例
     * @return 反序列化后的对象
     */
    public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue)
            throws IOException, JacksonException {
        ctxt.handleBadMerge(this);
        return deserialize(p, ctxt);
    }

    /**
     * 反序列化
     *
     * @param p    Json解析器
     * @param ctxt 反序列化上下文
     * @param typeDeserializer 反序列化类型
     * @return 反序列化后的对象
     */
    public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
                                      TypeDeserializer typeDeserializer)
            throws IOException, JacksonException {
        // We could try calling
        return typeDeserializer.deserializeTypedFromAny(p, ctxt);
    }

    /**
     * 反序列化
     *
     * @param p    Json解析器
     * @param ctxt 反序列化上下文
     * @param typeDeserializer 反序列化类型
     * @param intoValue 已经初始化的值实例                 
     * @return 反序列化后的对象
     */
    public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
                                      TypeDeserializer typeDeserializer, T intoValue)
            throws IOException, JacksonException {
        ctxt.handleBadMerge(this);
        return deserializeWithType(p, ctxt, typeDeserializer);
    }

2.3 null 处理

JSON中的null值在反序列时,需要一种可控和可预测的方式确定应该使用什么值来表示这个null,对于引用类型(如对象或数组),通常直接使用Javanull。但对于原始数据类型(如intdouble等),Java没有null的概念,因此需要一个特殊的策略来处理这种情况。

JsonDeserializer声明了处理null的方法:

    /**
     * 处理null,默认返回null
     */
    @Override
    public T getNullValue(DeserializationContext ctxt) throws JsonMappingException {
        // Change the direction in 2.7
        return getNullValue(); // 返回null
    }

    /**
     * 处理null,getNullValue(DeserializationContext)方法的优化版
     * 当getNullValue返回的值是静态的时,反序列化器可以缓存这个值,避免在每次需要时都重新计算。
     */
    @Override
    public AccessPattern getNullAccessPattern() {
        // Default implementation assumes that the null value does not vary, which
        // is usually the case for most implementations. But it is not necessarily
        // `null`; so sub-classes may want to refine further.
        return AccessPattern.CONSTANT;
    }

    /**
     * 确定在没有从输入中获得值但需要传递值时所使用的占位符值。
     * 目的:该方法用于处理一种特定情况,即当创建者(Creator)方法需要为每个参数传递一个值,但输入中并没有提供值时,我们需要提供一个占位符值。
     * 常见情况:创建者方法通常指的是构造函数、工厂方法或其他用于创建对象实例的方法。这些方法可能要求为所有参数提供值,即使某些值在输入数据中并不存在。
     * 占位符值:占位符值用于替代缺失的输入值。它通常与getNullValue方法返回的值相同(这通常就是Java的null),但对于特定类型,可能需要使用不同的“默认值”。
     * 特定类型:对于某些类型(特别是原始数据类型或不能设置为null的类型),使用null作为占位符值是不合适的。因此,对于这些类型,可能需要重写此方法以提供适当的默认值(例如,对于整数类型,可能是0;对于布尔类型,可能是false等)。
     * 调用频率:该方法每次需要确定占位符值时都会被调用。这意味着,在创建对象实例时,对于每个缺失的输入值,都可能调用此方法。
     * 默认实现:该方法的默认实现是简单地调用getNullValue方法并返回其结果。这意味着,在大多数情况下,占位符值将与null值相同,除非特定类型重写了此方法。
     *
     * @since 2.13
     */
    @Override
    public Object getAbsentValue(DeserializationContext ctxt) throws JsonMappingException {
        return getNullValue(ctxt);
    }

2.4 空值

    /**
     * 空值处理
     */
    public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
        return getNullValue(ctxt);
    }

    /**
     * 检查是否需要仅调用一次(静态值),或者每次需要空值时都调用。
     *
     * @since 2.9
     */
    public AccessPattern getEmptyAccessPattern() {
        return AccessPattern.DYNAMIC;
    }

2.5 其他

    /**
     * 获取处理类型
     *
     * @since 2.3
     */
    public Class<?> handledType() {
        return null;
    }

    /**
     * 获取生成值的逻辑类型
     */
    public LogicalType logicalType() {
        return null;
    }

    /**
     * 检查反序列化器实例是否可缓存,并可用于相同类型(创建实例的类型)的其他属性
     */
    public boolean isCachable() {
        return false;
    }

    /**
     * 获取代理的反序列化器
     *
     * @since 2.1
     */
    public JsonDeserializer<?> getDelegatee() {
        return null;
    }

    /**
     * 获取属性名称,仅用于错误报告和诊断目的
     *
     * @since 2.0
     */
    public Collection<Object> getKnownPropertyNames() {
        return null;
    }


    /**
     * 获取对象标识符值,将其解析为实际的对象实例,并返回为反序列化值。
     * @since 2.0
     */
    public ObjectIdReader getObjectIdReader() {
        return null;
    }

    /**
     * 供 BeanDeserializerFactory 用于处理循环引用问题
     */
    public SettableBeanProperty findBackReference(String refName) {
        throw new IllegalArgumentException("Cannot handle managed/back reference '" + refName
                + "': type: value deserializer of type " + getClass().getName() + " does not support them");
    }

    /**
     * 查看反序列化器是否支持现有值的更新(也称为“合并”)功能(@JavaMerge)
     *
     * @since 2.9
     */
    public Boolean supportsUpdate(DeserializationConfig config) {
        return null;
    }

3. 实现类

JsonDeserializer有很多的实现类,用于处理各种数据类型。 image.png

3.1 StdDeserializer

StdDeserializer即标准的反序列化器,也是一个抽象类,是在JsonDeserializer的基础上封装了一些通用方法,实现反序列化器时,应该继承该类,而不是JsonDeserializer

3.1.1 成员属性

掩码(Bitmask)是一种位操作技术,它允许通过单个整数值来同时设置、检查或清除多个标志位。Jackson允许使用掩码在单个操作中检查多个特性,从而提高性能。

F_MASK_INT_COERCIONS声明的掩码用于于覆盖两个特定的反序列化特性:USE_BIG_INTEGER_FOR_INTSUSE_LONG_FOR_INTS

    protected final static int F_MASK_INT_COERCIONS =
            DeserializationFeature.USE_BIG_INTEGER_FOR_INTS.getMask()
            | DeserializationFeature.USE_LONG_FOR_INTS.getMask();

StdDeserializer还提供了两个成员属性,描述当前处理的值类型和Java对象的类型,便于正确地将JSON数据转换为Java对象:

    // 反序列化器处理的值类型
    final protected Class<?> _valueClass;
    
    // Java对象的类型信息
    final protected JavaType _valueType;

3.1.2 构造

StdDeserializer构造函数则比较简单,主要是对成员属性进行赋值:

    protected StdDeserializer(Class<?> vc) {
        _valueClass = vc;
        _valueType = null;
    }

    protected StdDeserializer(JavaType valueType) {
        // 26-Sep-2017, tatu: [databind#1764] need to add null-check back until 3.x
        _valueClass = (valueType == null) ? Object.class : valueType.getRawClass();
        _valueType = valueType;
    }

    protected StdDeserializer(StdDeserializer<?> src) {
        _valueClass = src._valueClass;
        _valueType = src._valueType;
    }

3.1.3 反序列化

StdDeserializer提供了一个不特定的类型反序列化方法,子类需要处理类型信息时,需要重写该方法:

    @Override
    public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
            TypeDeserializer typeDeserializer) throws IOException {
        return typeDeserializer.deserializeTypedFromAny(p, ctxt);
    }

此外还提供了很多特定类型的反序列化方法:

     protected T _deserializeFromArray(JsonParser p, DeserializationContext ctxt)
     protected T _deserializeFromString(JsonParser p, DeserializationContext ctxt)
     protected T _deserializeFromString(JsonParser p, DeserializationContext ctxt)
     protected T _deserializeWrappedValue(JsonParser p, DeserializationContext ctxt) 
     protected final boolean _parseBooleanPrimitive(DeserializationContext ctxt, JsonParser p, Class<?> targetType) 
     protected final Boolean _parseBoolean(JsonParser p, DeserializationContext ctxt, Class<?> targetType)
     protected final short _parseShortPrimitive(JsonParser p, DeserializationContext ctxt)
     protected final int _parseIntPrimitive(JsonParser p, DeserializationContext ctxt)
     protected final int _parseIntPrimitive(DeserializationContext ctxt, String text) 
     protected final int _parseIntPrimitive(DeserializationContext ctxt, String text) 
     protected final Integer _parseInteger(JsonParser p, DeserializationContext ctxt,Class<?> targetType)
     protected final Integer _parseInteger(DeserializationContext ctxt, String text)
     protected final long _parseLongPrimitive(JsonParser p, DeserializationContext ctxt)
     protected final long _parseLongPrimitive(DeserializationContext ctxt, String text) 
     protected final Long _parseLong(JsonParser p, DeserializationContext ctxt, Class<?> targetType)
     protected final Long _parseLong(DeserializationContext ctxt, String text) 
     //......................

3.1.4 辅助方法

检查特殊字符串的相关方法:

    // 字符串值 "null",并且进一步确定是否应将其强制转换为 null
    protected boolean _hasTextualNull(String value) {
        return "null".equals(value);
    }
    protected final boolean _isNegInf(String text) {
        return "-Infinity".equals(text) || "-INF".equals(text);
    }
    protected final boolean _isPosInf(String text) {
        return "Infinity".equals(text) || "INF".equals(text);
    }
    protected final boolean _isNaN(String text) {
        return "NaN".equals(text);
    }

也提供了很多辅助方法,用于校验、查询、判断等,供子类直接调用(太多,这里只列举几个):

    protected Object _coerceIntegral(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS)) {
            return p.getBigIntegerValue();
        } else {
            return ctxt.isEnabled(DeserializationFeature.USE_LONG_FOR_INTS) ? p.getLongValue() : p.getNumberValue();
        }
    }

    protected final void _verifyNullForPrimitive(DeserializationContext ctxt) throws JsonMappingException {
        if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)) {
            ctxt.reportInputMismatch(this, "Cannot coerce `null` to %s (disable `DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES` to allow)", new Object[]{this._coercedTypeDesc()});
        }

    }

3.1.5 实现类

StdDeserializer也包含了多个子实现类,和JsonSerializer类似,只不过是用于反序列化,这里就不再详细解析每个子类了:

image.png

3.2 None

JsonSerializer.None作用一样,是@JsonDeserializer的标记类

3.3 TypeWrappedDeserializer

TypeWrappedSerializer一样,基于包装模式实现。

3.4 AbstractDeserializer

AbstractDeserializer是一个仅用于处理处理反序列化过程中的多态类型的抽象类。

3.5 ErrorThrowingDeserializer

ErrorThrowingDeserializer用于存储在构建反序列化器过程中捕获的 {@link Error},该错误需要被延迟处理,直到实际尝试反序列化给定类型的值时。