RedisTemplate配置的jackson.ObjectMapper里的一個enableDefaultTyping方法過期解決


起因是使用 objectMapper.enableDefaultTyping()方法是發現被棄用。

建議使用 objectMapper.activateDefaultTyping()方法替代它。

 

1、前言

最近升級SpringBoot,從2.1.6版本升級到2.4.1版本,發現enableDefaultTyping方法過期過期了。

該方法是指定序列化輸入的類型,就是將數據庫里的數據安裝一定類型存儲到redis緩存中。

2、為什么要指定序列化輸入類型

2.1、沒有指定序列化輸入類型

如果注釋掉enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL),那存儲到redis里的數據將是沒有類型的純json,我們調用redis API獲取到數據后,java解析將是一個LinkHashMap類型的key-value的數據結構,我們需要使用的話就要自行解析,這樣增加了編程的復雜度。

[{"id":72,"uuid":"c4d7fc52-4096-4c79-81ef-32cb1b87fd28","type":2}]

2.2、指定序列化輸入類型

指定enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)的話,存儲到redis里的數據將是有類型的json數據,例如:

["java.util.ArrayList",[{"@class":"com.model.app","id":72,"uuid":"c4d7fc52-4096-4c79-81ef-32cb1b87fd28","type":2}]]

這樣java獲取到數據后,將會將數據自動轉化為java.util.ArrayList和com.model.app,方便直接使用。

3、enableDefaultTyping過期怎么解決

3.1 查找函數接口

查看enableDefaultTyping內部實現

/** @deprecated */
@Deprecated
public ObjectMapper enableDefaultTyping(ObjectMapper.DefaultTyping dti) {
    return this.enableDefaultTyping(dti, As.WRAPPER_ARRAY);
}

查看enableDefaultTyping內部實現

/** @deprecated */
@Deprecated
public ObjectMapper enableDefaultTyping(ObjectMapper.DefaultTyping applicability, As includeAs) {
    return this.activateDefaultTyping(this.getPolymorphicTypeValidator(), applicability, includeAs);
}

查看activateDefaultTyping內部實現

public ObjectMapper activateDefaultTyping(PolymorphicTypeValidator ptv, ObjectMapper.DefaultTyping applicability, As includeAs) {
    if (includeAs == As.EXTERNAL_PROPERTY) {
        throw new IllegalArgumentException("Cannot use includeAs of " + includeAs);
    } else {
        TypeResolverBuilder<?> typer = this._constructDefaultTypeResolverBuilder(applicability, ptv);
        typer = typer.init(Id.CLASS, (TypeIdResolver)null);
        typer = typer.inclusion(includeAs);
        return this.setDefaultTyping(typer);
    }
}

這里我們可以直接調用activateDefaultTyping方法了,從而不用調用過期的enableDefaultTyping方法。

再看activateDefaultTyping的參數默認是哪些呢?代碼里有這樣一個靜態初始化:

static {
    DEFAULT_BASE = new BaseSettings((ClassIntrospector)null, DEFAULT_ANNOTATION_INTROSPECTOR, (PropertyNamingStrategy)null, TypeFactory.defaultInstance(), (TypeResolverBuilder)null, StdDateFormat.instance, (HandlerInstantiator)null, Locale.getDefault(), (TimeZone)null, Base64Variants.getDefaultVariant(), LaissezFaireSubTypeValidator.instance);
}

3.2 解決

從而我們知道,默認的參數有哪些,

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.activateDefaultTyping(

     LaissezFaireSubTypeValidator.instance , 
    ObjectMapper.DefaultTyping.NON_FINAL,

     JsonTypeInfo.As.WRAPPER_ARRAY);

jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

 

4 DefaultTyping 類型定義

如果想知道詳細的說明,大家google去吧:

public static enum DefaultTyping {
    JAVA_LANG_OBJECT,
    OBJECT_AND_NON_CONCRETE,
    NON_CONCRETE_AND_ARRAYS,
    NON_FINAL,
    EVERYTHING;
    private DefaultTyping() {
    }
}

 DefaultTyping有四個選項:

JAVA_LANG_OBJECT: 當對象屬性類型為Object時生效;

OBJECT_AND_NON_CONCRETE: 當對象屬性類型為Object或者非具體類型(抽象類和接口)時生效;

NON_CONCRETE_AND+_ARRAYS: 同上, 另外所有的數組元素的類型都是非具體類型或者對象類型;

NON_FINAL: 對所有非final類型或者非final類型元素的數組。

因此,當開啟DefaultTyping后,會開發者在反序列化時指定要還原的類,過程中調用其構造方法setter方法或某些特殊的getter方法,當這些方法中存在一些危險操作時就造成了代碼執行。

具體參考鏈接

https://blog.csdn.net/panda1103/article/details/106021599/?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-0.control&spm=1001.2101.3001.4242

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM