通過Jackson實現敏感詞過濾和型別轉換的功能
目前正在做老專案遷移重構工作(Clojure轉Java),因歷史原因專案中給到端上的Json資料中和(id/user_id/order_id)等相關的id欄位需要以string型別給到端上。
已有clojure實現
祖傳專案是通過clojure實現的,clojure是一門弱語言和JavaScript一樣任何物件都是看做一個map,所以在clojure裡面針對這個long->string的功能,實現起來很簡單;只需要遞迴遍歷map判斷key是否存在於定義的set裡面即可,如果滿足條件,直接根據是否為list進行toString的處理;
需要實現的功能
實現一個Java方法,傳入一個物件進行返回序列化的Json字串。序列化的同時如果遇到滿足條件的欄位需要對該欄位進行 toString 處理,如果是List<Objec>需要轉換為 List<String>。
如何通過Java實現?
因為專案中使用的是jackson序列化json,所以很容易想到的就是使用jackson提供的AnnotationIntrospector,在對應的欄位上新增 註解 ,然後自定義AnnotationIntrospector在匹配對應註解的時候返回自定義的Serializer。
tips:僅使用@JsonSerialize(using = ToStringSerializer.class)是不能處理 List<Long> -> List<String>這種情況的
AnnotationIntrospector 實現 long->toString 功能
擴充套件-AnnotationIntrospector 實現 欄位過濾 功能(也可以註解增加屬性,用於指定環境過濾等功能)
這裡欄位過濾其實功能只相當於 @JsonIgnore ,需要增加CustomToString的屬性,比如 env;然後在DefaultAnnotationIntrospector中根據env值再做判斷
AnnotationIntrospector實現分析
副作用
在後續開發過程中,在我們定義新的Object時,需要參照對應的field表對對應欄位增加註解。如果此時突然要對某個欄位過濾或者toString,那又得從頭挨著挨著檢查添加註解。增加開發成本和維護成本
優化升級
通過對 new ObjectMapper().writeValueAsString() 的執行流程 debug分析,發現物件的屬性都被解析成 BeanProperty了,然後會呼叫 SerializerProvider 的方法尋找合適的Serializer進行序列化
實現 long->toString 功能
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.ser.SerializerFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
/**
* @class-name: IdFieldToStringSerializerProvider
* @description:
* @author: Mr.Zeng
*/