記錄一次源碼擴展案列——FastJson自定義反序列化ValueMutator
背景:曾經遇到一個很麻煩的事情,就是一個json串中有很多佔位符,需要替換成特定文案。如果將json轉換成對象後,在一個一個屬性去轉換的話就出出現很多冗餘程式碼,不美觀也不是很實用。
而且也不能提前在json串中替換,因為替換的文案會因為某些變數發生改變。就比如國際化,在中文的時候應該是”你好”,而在英文的時候要出現”Hello”。
所以我想到一個方法,為什麼不能再json反序列化的時候,把這些都做好呢?
以下的程式碼介紹的是,我自己擴展的一點點fastjson程式碼,增加了在反序列化的時候可以對所有的值進行修改的方案。
注意:這個方案會對fastjson反序列化的速度有一定的影響,我只是用來做配置的反序列化,完成後將反序列化的東西快取起來使用。
使用方式有兩種
一種是直接通過 @JsonDeserializer 註解的valueMutators屬性注入這種方式有個缺陷,你的修改器必須有無參構造函數的
@JsonDeserializer(valueMutators = {CoustomizeValueMutator.class})
@Getter
@Setter
public class User {
private String name;
...
}
第二種方式是通過直接創建的方式,使用反序列化工具,這種方式支援有參構造函數。
CoustomizeValueMutator zhCoustomizeValueMutator = new CoustomizeValueMutator(zh);
User user = CustomizeJSON.parseObject(userStr, User.class, zhCoustomizeValueMutator);
下面先展示一下使用效果,測試程式碼如下:
import com.alibaba.fastjson.parser.deserializer.CustomizeJSON;
import com.raiden.model.*;
import org.junit.jupiter.api.Test;
import java.util.*;
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 22:39 2020/1/28
* @Modified By:
*/
public class AppTest {
@Test
public void testFastJosn() throws Throwable {
String userStr = "{\n" +
"\t\"id\":\"I18nKey:20200411001\",\n" +
"\t\"a\":\"I18nKey:張三\",\n" +
"\t\"student\":\"I18nKey:高三三班\",\n" +
"\t\"contents\":[\"I18nKey:1\",\"I18nKey:2\"]\n" +
"}";
Map<String, String> en = new HashMap<>();
en.put("3", "zhangsan");
en.put("4", "20200411001");
en.put("5", "Class three in grade three");
en.put("1", "Hello");
en.put("2", "Welcome home");
Map<String, String> zh = new HashMap<>();
zh.put("3", "張三");
zh.put("4", "20200411001");
zh.put("5", "高三三班");
zh.put("1", "你好");
zh.put("2", "歡迎回家");
CoustomizeValueMutator zhCoustomizeValueMutator = new CoustomizeValueMutator(zh);
User user = CustomizeJSON.parseObject(userStr, User.class, zhCoustomizeValueMutator);
System.err.println(user);
String string = "{\n" +
"\t\"users\": [{\n" +
"\t\t\"id\": \"I18nKey:4\",\n" +
"\t\t\"a\": \"I18nKey:3\",\n" +
"\t\t\"student\": \"I18nKey:5\",\n" +
"\t\t\"url\": \"www.baidu.com\",\n" +
"\t\t\"contents\": [\"I18nKey:1\", \"I18nKey:2\"]\n" +
"\t}],\n" +
"\t\"memberId\":\"2020\"\n" +
"}";
CoustomizeValueMutator enCoustomizeValueMutator = new CoustomizeValueMutator(en);
Administration administration = CustomizeJSON.parseObject(string, Administration.class, enCoustomizeValueMutator);
System.err.println(administration);
}
}
運行效果:
下面是測試模型程式碼:
import com.alibaba.fastjson.parser.deserializer.JsonDeserializer;
import com.raiden.CoustomizeValueMutator;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 23:56 2020/4/17
* @Modified By:
*/
@JsonDeserializer
@Getter
@Setter
public class Administration {
private List<User> users;
private String memberId;
@Override
public String toString() {
return "Administration{" +
"users=" + users +
", memberId='" + memberId + '\'' +
'}';
}
}
import com.alibaba.fastjson.parser.deserializer.JsonDeserializer;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 15:53 2020/3/21
* @Modified By:
*/
@JsonDeserializer
@Getter
@Setter
public class User {
private String name;
private String id;
private String student;
private List<String> contents;
private String url;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", student='" + student + '\'' +
", contents='" + contents.toString() + '\'' +
", url='" + url + '\'' +
'}';
}
}
自定義的反序列化值修改器:
import com.alibaba.fastjson.parser.deserializer.DeserializerValueMutator;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 22:15 2020/5/1
* @Modified By:
*/
public class CoustomizeValueMutator implements DeserializerValueMutator {
private Map<String, String> dataSource;
public CoustomizeValueMutator(Map<String, String> dataSource){
this.dataSource = dataSource;
}
@Override
public Object process(Object object, Annotation[] annotations, String name, Object value) {
if (value instanceof List){
List list = new ArrayList();
for (Object o : (List) value){
if (!(o instanceof String)){
return value;
}
list.add(DeserializerUtils.deserializer(o, dataSource));
}
return list;
}
return DeserializerUtils.deserializer(value, dataSource);
}
}
一些工具類和靜態資源類:
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 23:00 2020/4/17
* @Modified By:
*/
public class CustomizeStaticConfig {
public static final String I18N_KEY = "I18nKey:";
}
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 0:15 2020/4/18
* @Modified By:
*/
public final class DeserializerUtils {
public static final Object deserializer(Object value, Map<String, String> languageConfig){
String result = null;
if (value.getClass() == String.class && StringUtils.contains((result = ((String) value).trim()), CustomizeStaticConfig.I18N_KEY)){
int indexOf = result.indexOf(CustomizeStaticConfig.I18N_KEY) + CustomizeStaticConfig.I18N_KEY.length();
String key = StringUtils.substring(result, indexOf);
return languageConfig.getOrDefault(key, result);
}
return value;
}
}
下面給出的是擴展的關鍵程式碼。
首先是自定義解析配置類,這個類是核心。這個類繼承了 com.alibaba.fastjson.parser.ParserConfig 類。覆寫了其兩個核心方法。
方法一:
createFieldDeserializer(ParserConfig mapping, JavaBeanInfo beanInfo, FieldInfo fieldInfo) 創建一個屬性反序列化處理類
該方法的修改,是將源碼中的 ArrayListTypeFieldDeserializer 替換成 我們自定義的 CustomizeArrayListTypeFieldDeserializer 處理器。
將源碼中的 DefaultFieldDeserializer 替換成 我們自定義的 CustomizeDefaultFieldDeserializer 處理器
方法二:
createJavaBeanDeserializer(Class<?> clazz, Type type) 創建一個 JavaBean 反序列化處理器
新增判斷邏輯,如果要反序列化的類上存在 @JsonDeserializer 標識註解,返回包含自定義配置類的 JavaBeanDeserializer。
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.FieldInfo;
import com.alibaba.fastjson.util.JavaBeanInfo;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* @創建人:Raiden
* @Descriotion:
* @Date:Created in 21:52 2020/4/17
* @Modified By: 自定義fastjson 解析配置類 這個類是核心
*/
public class CustomizeParserConfig extends ParserConfig {
/**
* 值修改器數組 可以將類修改器放入其中使用
*/
private DeserializerValueMutator[] valueMutators;
public CustomizeParserConfig(){
}
/**
* 有參構造方法 可以通過該方法 將類修改器放入其中
* @param valueMutators
*/
public CustomizeParserConfig(DeserializerValueMutator... valueMutators){
super();
this.valueMutators = valueMutators;
}
/**
* 創建一個屬性反序列化處理類
* @param mapping
* @param beanInfo
* @param fieldInfo
* @return
*/
@Override
public FieldDeserializer createFieldDeserializer(ParserConfig mapping, //
JavaBeanInfo beanInfo, //
FieldInfo fieldInfo) {
//獲取要反序列化的model 的class
Class<?> clazz = beanInfo.clazz;
//獲取要反序列化屬性的 class
Class<?> fieldClass = fieldInfo.fieldClass;
Class<?> deserializeUsing = null;
JSONField annotation = fieldInfo.getAnnotation();
if (annotation != null) {
deserializeUsing = annotation.deserializeUsing();
if (deserializeUsing == Void.class) {
deserializeUsing = null;
}
}
if (deserializeUsing == null && (fieldClass == List.class || fieldClass == ArrayList.class)) {
//將源碼中的 ArrayListTypeFieldDeserializer 替換成 我們自定義的 CustomizeArrayListTypeFieldDeserializer 處理器
return new CustomizeArrayListTypeFieldDeserializer(clazz, fieldInfo, valueMutators);
}
//將源碼中的 DefaultFieldDeserializer 替換成 我們自定義的 CustomizeDefaultFieldDeserializer 處理器
return new CustomizeDefaultFieldDeserializer(mapping, clazz, fieldInfo, valueMutators);
}
/**
* 創建一個 javaBean 反序列化處理器
* @param clazz
* @param type
* @return
*/
@Override
public ObjectDeserializer createJavaBeanDeserializer(Class<?> clazz, Type type) {
//獲取要反序列化類上的標識註解
JsonDeserializer jsonDeserializer = clazz.getAnnotation(JsonDeserializer.class);
//如果不存在就走原邏輯
if (jsonDeserializer != null){
//獲取註解中的反序列化值處理器
Class<? extends DeserializerValueMutator>[] classes = jsonDeserializer.valueMutators();
if (classes != null && classes.length > 0){
DeserializerValueMutator[] mutators = new DeserializerValueMutator[classes.length];
int size = 0;
for (Class<? extends DeserializerValueMutator> c : classes) {
try {
DeserializerValueMutator mutator = c.newInstance();
mutators[size] = mutator;
size++;
} catch (Exception e) {
//如果創建失敗了就忽略掉這次錯誤
}
}
if (size > 0){
//判斷原來是否有值 如果有 就合併成一組
if (valueMutators != null){
DeserializerValueMutator[] newValueMutators = new DeserializerValueMutator[size + valueMutators.length];
System.arraycopy(valueMutators, 0, newValueMutators, 0, valueMutators.length);
System.arraycopy(mutators, 0, newValueMutators, valueMutators.length, size);
this.valueMutators = newValueMutators;
}else {
this.valueMutators = new DeserializerValueMutator[size];
System.arraycopy(mutators, 0, valueMutators, 0, size);
}
}
}
if (valueMutators != null){
return new JavaBeanDeserializer(this, clazz);
}
}
return super.createJavaBeanDeserializer(clazz, type);
}
}
CustomizeDefaultFieldDeserializer 類繼承了 DefaultFieldDeserializer 類在構造方法中新增了參數 valueMutators(值修改器數組)
並在 public void setValue(Object object, Object value) 方法中新增了邏輯如果值修改器數組中存在值修改器,就遍歷所有的修改器,
依次調用修改器的 process方法修改值。
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.util.FieldInfo; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * @創建人:Raiden * @Descriotion: * @Date:Created in 0:13 2020/4/18 * @Modified By: 替代fastjson中 對象反序列化處理類 */ public class CustomizeDefaultFieldDeserializer extends DefaultFieldDeserializer { private DeserializerValueMutator[] valueMutators; public CustomizeDefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo,DeserializerValueMutator[] valueMutators) { super(config, clazz, fieldInfo); this.valueMutators = valueMutators; } public void setValue(Object object, Object value) { if (value == null // && fieldInfo.fieldClass.isPrimitive()) { return; } else if (fieldInfo.fieldClass == String.class && fieldInfo.format != null && fieldInfo.format.equals("trim")){ value = ((String) value).trim(); } try { /** * 如果值修改器數組中存在值修改器實例,就遍歷該數組,依次調用所有的修改器的 process方法 */ if (valueMutators != null && valueMutators.length > 0){ for (DeserializerValueMutator mutator : valueMutators){ value = mutator.process(object,fieldInfo.field.getAnnotations(), fieldInfo.name, value); } } Method method = fieldInfo.method; if (method != null) { if (fieldInfo.getOnly) { if (fieldInfo.fieldClass == AtomicInteger.class) { AtomicInteger atomic = (AtomicInteger) method.invoke(object); if (atomic != null) { atomic.set(((AtomicInteger) value).get()); } } else if (fieldInfo.fieldClass == AtomicLong.class) { AtomicLong atomic = (AtomicLong) method.invoke(object); if (atomic != null) { atomic.set(((AtomicLong) value).get()); } } else if (fieldInfo.fieldClass == AtomicBoolean.class) { AtomicBoolean atomic = (AtomicBoolean) method.invoke(object); if (atomic != null) { atomic.set(((AtomicBoolean) value).get()); } } else if (Map.class.isAssignableFrom(method.getReturnType())) { Map map = (Map) method.invoke(object); if (map != null) { if (map == Collections.emptyMap() || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } map.putAll((Map) value); } } else { Collection collection = (Collection) method.invoke(object); if (collection != null && value != null) { if (collection == Collections.emptySet() || collection == Collections.emptyList() || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } collection.clear(); collection.addAll((Collection) value); } } } else { method.invoke(object, value); } } else { final Field field = fieldInfo.field; if (fieldInfo.getOnly) { if (fieldInfo.fieldClass == AtomicInteger.class) { AtomicInteger atomic = (AtomicInteger) field.get(object); if (atomic != null) { atomic.set(((AtomicInteger) value).get()); } } else if (fieldInfo.fieldClass == AtomicLong.class) { AtomicLong atomic = (AtomicLong) field.get(object); if (atomic != null) { atomic.set(((AtomicLong) value).get()); } } else if (fieldInfo.fieldClass == AtomicBoolean.class) { AtomicBoolean atomic = (AtomicBoolean) field.get(object); if (atomic != null) { atomic.set(((AtomicBoolean) value).get()); } } else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) { Map map = (Map) field.get(object); if (map != null) { if (map == Collections.emptyMap() || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } map.putAll((Map) value); } } else { Collection collection = (Collection) field.get(object); if (collection != null && value != null) { if (collection == Collections.emptySet() || collection == Collections.emptyList() || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } collection.clear(); collection.addAll((Collection) value); } } } else { if (field != null) { field.set(object, value); } } } } catch (Exception e) { throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e); } } }
類CustomizeArrayListTypeFieldDeserializer 和 類CustomizeDefaultFieldDeserializer 改動類似。
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.util.FieldInfo; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * @創建人:Raiden * @Descriotion: * @Date:Created in 0:13 2020/4/18 * @Modified By: 替代fastjson中 對象反序列化處理類 */ public class CustomizeDefaultFieldDeserializer extends DefaultFieldDeserializer { private DeserializerValueMutator[] valueMutators; public CustomizeDefaultFieldDeserializer(ParserConfig config, Class<?> clazz, FieldInfo fieldInfo,DeserializerValueMutator[] valueMutators) { super(config, clazz, fieldInfo); this.valueMutators = valueMutators; } public void setValue(Object object, Object value) { if (value == null // && fieldInfo.fieldClass.isPrimitive()) { return; } else if (fieldInfo.fieldClass == String.class && fieldInfo.format != null && fieldInfo.format.equals("trim")){ value = ((String) value).trim(); } try { /** * 如果值修改器數組中存在值修改器實例,就遍歷該數組,依次調用所有的修改器的 process方法 */ if (valueMutators != null && valueMutators.length > 0){ for (DeserializerValueMutator mutator : valueMutators){ value = mutator.process(object,fieldInfo.field.getAnnotations(), fieldInfo.name, value); } } Method method = fieldInfo.method; if (method != null) { if (fieldInfo.getOnly) { if (fieldInfo.fieldClass == AtomicInteger.class) { AtomicInteger atomic = (AtomicInteger) method.invoke(object); if (atomic != null) { atomic.set(((AtomicInteger) value).get()); } } else if (fieldInfo.fieldClass == AtomicLong.class) { AtomicLong atomic = (AtomicLong) method.invoke(object); if (atomic != null) { atomic.set(((AtomicLong) value).get()); } } else if (fieldInfo.fieldClass == AtomicBoolean.class) { AtomicBoolean atomic = (AtomicBoolean) method.invoke(object); if (atomic != null) { atomic.set(((AtomicBoolean) value).get()); } } else if (Map.class.isAssignableFrom(method.getReturnType())) { Map map = (Map) method.invoke(object); if (map != null) { if (map == Collections.emptyMap() || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } map.putAll((Map) value); } } else { Collection collection = (Collection) method.invoke(object); if (collection != null && value != null) { if (collection == Collections.emptySet() || collection == Collections.emptyList() || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } collection.clear(); collection.addAll((Collection) value); } } } else { method.invoke(object, value); } } else { final Field field = fieldInfo.field; if (fieldInfo.getOnly) { if (fieldInfo.fieldClass == AtomicInteger.class) { AtomicInteger atomic = (AtomicInteger) field.get(object); if (atomic != null) { atomic.set(((AtomicInteger) value).get()); } } else if (fieldInfo.fieldClass == AtomicLong.class) { AtomicLong atomic = (AtomicLong) field.get(object); if (atomic != null) { atomic.set(((AtomicLong) value).get()); } } else if (fieldInfo.fieldClass == AtomicBoolean.class) { AtomicBoolean atomic = (AtomicBoolean) field.get(object); if (atomic != null) { atomic.set(((AtomicBoolean) value).get()); } } else if (Map.class.isAssignableFrom(fieldInfo.fieldClass)) { Map map = (Map) field.get(object); if (map != null) { if (map == Collections.emptyMap() || map.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } map.putAll((Map) value); } } else { Collection collection = (Collection) field.get(object); if (collection != null && value != null) { if (collection == Collections.emptySet() || collection == Collections.emptyList() || collection.getClass().getName().startsWith("java.util.Collections$Unmodifiable")) { // skip return; } collection.clear(); collection.addAll((Collection) value); } } } else { if (field != null) { field.set(object, value); } } } } catch (Exception e) { throw new JSONException("set property error, " + clazz.getName() + "#" + fieldInfo.name, e); } } }
下面是值修改器介面定義:
import java.lang.annotation.Annotation; /** * @創建人:Raiden * @Descriotion: * @Date:Created in 22:01 2020/5/1 * @Modified By: 反序列化值修改器介面 */ public interface DeserializerValueMutator { Object process(Object object, Annotation[] annotations, String name, Object value); }
反序列化標識註解,只有用這個註解注釋的類才會執行拓展的方法。
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @創建人:Raiden * @Descriotion: * @Date:Created in 22:25 2020/4/17 * @Modified By: 反序列化值修改標識註解 */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) public @interface JsonDeserializer { /** * 注意這裡只能放無參構造函數的修改器 否則會創建失敗 * @return */ Class<? extends DeserializerValueMutator>[] valueMutators() default {}; }
強化的JSON序列化工具類:
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.Feature; import java.lang.reflect.Type; /** * @創建人:Raiden * @Descriotion: * @Date:Created in 22:12 2020/5/1 * @Modified By: 反序列化工具類 */ public final class CustomizeJSON { public static <T> T parseObject(String input,Type clazz,DeserializerValueMutator... valueMutators) { return JSON.parseObject(input, clazz, new CustomizeParserConfig(valueMutators)); } public static <T> T parseObject(String json, Type type,DeserializerValueMutator[] valueMutators, Feature... features) { return JSON.parseObject(json, type, new CustomizeParserConfig(valueMutators), features); } public static <T> T parseObject(String json, Type type,Feature... features) { return JSON.parseObject(json, type, new CustomizeParserConfig(), features); } public static <T> T parseObject(String json, Type type) { return JSON.parseObject(json, type, new CustomizeParserConfig()); } }
以上程式碼都可以在我的git中下載://github.com/RaidenXin/fastjson-deserializer.git
創作不易,如果轉載請註明出處,小編在此感謝各位看官。
如果覺得有用,請看官們點個贊,謝謝。
如果有想學Redis的可以關注我的Redis文章系列:
小白也能看懂的REDIS教學基礎篇——REDIS基礎數據結構
小白也能看懂的REDIS教學基礎篇——朋友面試被SKIPLIST跳躍表攔住了