引言
浏览网上关于动态序列化的文章,都不太能满足我想实现的功能,所以在实现该功能后,想分享下。
编写目的
分享一个基于Jackson实现的动态序列化、反序列化的功能,可以理解为一个增强版的@JsonProperty()。
和JsonProperty的区别在于JsonProperty是静态实现,在编码阶段即已经定义好序列化的名字。 而该功能可以在程序运行中实时调整,对key的修改,隐藏等。功能效果
背景
ToB产品,在对接多个上游系统的时候,字段命名差异化怎么解决?比如商品编码:我们使用skuCode,上游使用pluCode,skuId等
于是老大提出一个需求,能不能实现一个对现有系统无侵入,动态序列化反序列化的功能。
功能展示
//举例:一个对象 正常序列化后
{ "id":1, "name":"auto" }
//A项目中修改配置将name->newName,再次序列化后
{ "id":1, "newName":"auto" }
//B项目中修改配置将name->myName,再次序列化后
{ "id":1, "myName":"auto" }
解决方案
定义需要动态调整的对象
如果你的Api返回下面的Car对象,那么就可以实现上面功能展示的效果,如果需要动态修改的字段使用范围很广,字段抽取为抽象类,让需要动态修改的类继承使用
/**
* 标记需要做实体字段配置的类
*
* <p>该注解支持继承,子类也可以使用</p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Inherited
public @interface Metadata {
String value() default "";
}
//标记要动态序列化的类
@Metadata()
@Data
public class Car {
private Long id;
private String name;
}
捕捉动态调整对象并修改key信息
需要继承BeanDeserializerModifier和BeanSerializerModifier做自定义配置处理,下面只展示反序列化的配置定义
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.google.common.collect.Maps;
import com.megvii.lbg.wes.engine.common.annotation.EntityName;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class MyDeserializerModifier extends BeanDeserializerModifier {
private final Map<String,String> cacheMap = Maps.newHashMap();
public void addOrUpdateCache(String key, String value) {
cacheMap.put(key, value);
}
@Override
public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) {
Metadata metadata = beanDesc.getBeanClass().getAnnotation(Metadata.class);
if (metadata == null) {
return propDefs;
}
return propDefs.stream()
.map(p -> {
String fieldName = cacheMap.get(p.getName());
return p.withSimpleName(fieldName == null ? p.getName() : fieldName);
})
.collect(Collectors.toList());
}
}
实时修改后,清空Jackson缓存
注意,如果调用上面的addOrUpdateCache方法,Jackson加载数据信息后会缓存,如果在运行中修改,需要删除缓存
SerializerProvider serializerProvider = objectMapper.getSerializerProvider();
if (serializerProvider instanceof DefaultSerializerProvider) {
//清空缓存,json重命名才能生效
((DefaultSerializerProvider) serializerProvider).flushCachedSerializers();
}
参考信息
结束语
这是掘金发表的第一篇分享文章,如果看完觉得有了解到新知识,麻烦点个赞,如果后续万一用得到,可以收藏下,谢谢啦