基于注解实现jackson动态JsonProperty
基于注解实现jackson动态JsonProperty
@JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,但是值是固定的,(不贴代码,可以看其他博客)
目前跟某公司做接口对接时数据格式是这样的:
接口A: 接口B:

映射实体对象 :(这里用到lombok工具)



报文第三个字段与具体的pojo类有关,@JsonProperty在这里显然无法实现;
这里写两种序列化方式:
第一种 : 注解@JsonAnyGetter (自己了解下这个注解,这里变相使用了下)
映射实体对象类做下调整

测试代码(注意测试时每个类里加些属性,否则抛异常):

第二种 : 自定义注解来实现(我不想做pojo类的变动,感觉Map怪怪的,因为这里接口对接这里是一个对象)
先贴测试代码:


这里@DynamicJsonProperty为自定义的注解,(不了解自定义注解的可以先百度下"jackson自定义序列化注解实现自己的序列逻辑")
下面是该注解相应的代码:
1 import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
2 import com.fasterxml.jackson.core.JsonGenerator;
3 import com.fasterxml.jackson.core.json.UTF8JsonGenerator;
4 import com.fasterxml.jackson.core.json.WriterBasedJsonGenerator;
5 import com.fasterxml.jackson.databind.BeanProperty;
6 import com.fasterxml.jackson.databind.JsonMappingException;
7 import com.fasterxml.jackson.databind.JsonSerializer;
8 import com.fasterxml.jackson.databind.SerializerProvider;
9 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
10 import com.fasterxml.jackson.databind.ser.ContextualSerializer;
11 import com.sinosoft.ehs.utils.Reflector;
12 import com.sinosoft.ehs.utils.Strings;
13
14 import java.io.IOException;
15 import java.lang.annotation.*;
16 import java.util.function.Function;
17
18 @Documented
19 @Retention(RetentionPolicy.RUNTIME)
20 @Target({ElementType.FIELD,ElementType.METHOD})
21 @JacksonAnnotationsInside
22 @JsonSerialize(using = DynamicJsonProperty.DynamicJsonPropertySerializer.class)
23 public @interface DynamicJsonProperty {
24
25 AS[] value() default {};
26
27 Strategy strategy() default Strategy.CLASS_SIMPLE_NAME_LOWERCASE;
28
29
30 @interface AS{
31
32 String name();
33
34 Class<?> value();
35 }
36
37 @Retention(RetentionPolicy.RUNTIME)
38 @interface Name{
39 String value();
40 }
41
42 interface KeyName{
43 String jsonPropertyName();
44 }
45
46
47 enum Strategy{
48
49 CLASS_NAME(object -> object.getClass().getName()),
50 CLASS_SIMPLE_NAME(object -> object.getClass().getSimpleName()),
51 CLASS_SIMPLE_NAME_LOWERCASE(object -> object.getClass().getSimpleName().toLowerCase()),
52 CLASS_SIMPLE_NAME_UPPERCASE(object -> object.getClass().getSimpleName().toUpperCase());
53
54 private Function<Object,String> function;
55
56 Strategy(Function<Object,String> function){
57 this.function = function;
58 }
59
60 public String getName(Object object){
61 if(object==null)
62 return null;
63 return function.apply(object);
64 }
65
66 }
67
68 class DynamicJsonPropertySerializer extends JsonSerializer<Object> implements ContextualSerializer {
69 /**key值是否重置*/
70 private boolean gotName;
71 private DynamicJsonProperty annotation;
72 /**原先的key值*/
73 private String originalName;
74
75
76 @Override
77 public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
78 if(value != null && !gotName){
79 String name = getKeyName(value);
80 if(jsonGenerator instanceof WriterBasedJsonGenerator){
81 char[] _outputBuffer = Reflector.getFieldValue(jsonGenerator,"_outputBuffer",char[].class);
82 char _quoteChar = Reflector.getFieldValue(jsonGenerator,"_quoteChar",char.class);
83 int start = String.valueOf(_outputBuffer).lastIndexOf(originalName);
84 int end = start+name.length()+1;
85 Reflector.setFieldValue(jsonGenerator,"_outputTail",end);
86
87 for(int i=0;i<name.length();i++){
88 _outputBuffer[start+i] = name.charAt(i);
89 }
90 _outputBuffer[start+name.length()] = _quoteChar;
91 }
92
93 if(jsonGenerator instanceof UTF8JsonGenerator){
94 byte[] _outputBuffer = Reflector.getFieldValue(jsonGenerator,"_outputBuffer",byte[].class);
95 int _outputTail = Reflector.getFieldValue(jsonGenerator,"_outputTail",int.class);
96
97 byte _quoteChar = Reflector.getFieldValue(jsonGenerator,"_quoteChar",byte.class);
98 System.err.println(new String(_outputBuffer,"UTF-8"));
99 int startIndex = getStartIndex(_outputBuffer, _outputTail, 1)+1;
100 byte[] nameBytes = name.getBytes("UTF-8");
101 int end = startIndex+nameBytes.length+1;
102 Reflector.setFieldValue(jsonGenerator,"_outputTail",end);
103
104 for(int i=0;i<nameBytes.length;i++){
105 _outputBuffer[startIndex+i] = nameBytes[i];
106 }
107 _outputBuffer[startIndex+nameBytes.length] = _quoteChar;
108
109
110 }
111 }
112 jsonGenerator.writeObject(value);
113 }
114
115
116 @Override
117 public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
118 annotation = beanProperty.getAnnotation(DynamicJsonProperty.class);
119 /**
120 * PropertyName fullName = beanProperty.getFullName();
121 * PropertyName._simpleName 字段即为key健的值,反射直接赋值即可实现,
122 * 不过这里未获取操作的Object对象,只能获取Field或者Method
123 * createContextual优先执行,serialize之后执行,这里顺序问题也不能操作
124 * 之后在细看程序研究,或者有大牛能解决的联系学习下
125 */
126 originalName = beanProperty.getName();
127 return this;
128 }
129
130 private String getKeyName(Object value){
131 Class<?> valueType = value.getClass();
132 AS[] asAnnotations = annotation.value();
133 for(int i=0;i<asAnnotations.length;i++){
134 if(asAnnotations[i].value() == valueType)
135 return asAnnotations[i].name();
136 }
137
138 Annotation[] annotations = valueType.getAnnotations();
139
140 Name nameAnnotation = valueType.getAnnotation(DynamicJsonProperty.Name.class);
141 if(nameAnnotation!=null)
142 return nameAnnotation.value();
143
144 if(value instanceof DynamicJsonProperty.KeyName){
145 String name = ((DynamicJsonProperty.KeyName)value).jsonPropertyName();
146 if(!Strings.isBlank(name))
147 return name;
148 }
149
150 return annotation.strategy().getName(value);
151 }
152
153 private int getStartIndex(byte[] _outputBuffer,int _outputTail,int index){
154 int currentIndex = 0;
155 for(int i=_outputTail;i>=0;i--){
156 if(_outputBuffer[i] == 34){
157 if(currentIndex == index)
158 return i;
159 currentIndex++;
160 }
161 }
162 return -1;
163 }
164
165 }
166
167
168 }
四种写法实例:





注意 : 以上四种方法字段data均需加注解@DynamicJsonProperty
反序列话直接加set方法即可

这里是通过反射重新赋值来实现,不同版本可能存在差异或者异常,测试用maven依赖

附反射代码:
public static Field getField(Class<?> formType,String fieldName) throws NoSuchFieldException{
if(formType == Object.class)
throw new NoSuchFieldException();
Field[] fields = formType.getDeclaredFields();
for(int i=0;i<fields.length;i++){
if(fields[i].getName().equals(fieldName))
return fields[i];
}
return getField(formType.getSuperclass(),fieldName);
}
@SuppressWarnings("unchecked")
public static <T> T getFieldValue(Object srcObject,String fieldName,Class<T> fieldType){
try {
Field field = getField(srcObject.getClass(),fieldName);
field.setAccessible(true);
return (T) field.get(srcObject);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void setFieldValue(Object srcObject,String fieldName,Object fieldValue){
try {
Field field = getField(srcObject.getClass(),fieldName);
field.setAccessible(true);
field.set(srcObject, fieldValue);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
最后这个问题如能解决,麻烦留言下解决的代码

基于注解实现jackson动态JsonProperty的更多相关文章
- springAOP实现基于注解的数据源动态切换
需求 代码实现读写数据库分离 武器 spring3.0以上版本 实现思路 1.继承org.springframework.jdbc.datasource.lookup.AbstractRoutingD ...
- SPRINGAOP实现基于注解的数据源动态切换(转)
需求 代码实现读写数据库分离 武器 spring3.0以上版本 实现思路 1.继承org.springframework.jdbc.datasource.lookup.AbstractRoutingD ...
- spring boot整合mybatis基于注解开发以及动态sql的使用
让我们回忆一下上篇博客中mybatis是怎样发挥它的作用的,主要是三类文件,第一mapper接口,第二xml文件,第三全局配置文件(application.properties),而今天我们就是来简化 ...
- spring中实现基于注解实现动态的接口限流防刷
本文将介绍在spring项目中自定义注解,借助redis实现接口的限流 自定义注解类 import java.lang.annotation.ElementType; import java.lang ...
- Struts2基于注解的Action配置
使用注解来配置Action的最大好处就是可以实现零配置,但是事务都是有利有弊的,使用方便,维护起来就没那么方便了. 要使用注解方式,我们必须添加一个额外包:struts2-convention-plu ...
- 基于注解的Spring AOP的配置和使用
摘要: 基于注解的Spring AOP的配置和使用 AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不 ...
- SpringMVC框架搭建 基于注解
本文将以一个很简单的案例实现 Springmvc框架的基于注解搭建,一下全为个人总结 ,如有错请大家指教!!!!!!!!! 第一步:创建一个动态web工程(在创建时 记得选上自动生成 web.xml ...
- Spring AOP:面向切面编程,AspectJ,是基于注解的方法
面向切面编程的术语: 切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象 通知(Advice): 切面必须要完成的工作 目标(Target): 被通知的对象 代理(Pr ...
- Spring基础知识之基于注解的AOP
背景概念: 1)横切关注点:散布在应用中多处的功能称为横切关注点 2)通知(Advice):切面完成的工作.通知定了了切面是什么及何时调用. 5中可以应用的通知: 前置通知(Before):在目标方法 ...
随机推荐
- 刷题-力扣-LCP 07. 传递信息
LCP 07. 传递信息 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/chuan-di-xin-xi 著作权归领扣网络所有.商业转 ...
- vue组件里不用的css还在搜索过滤来删除?试一下vue-clearcss吧!
这篇文章其实是推广介绍我个人的npm工具库,但你不会后悔点进来的(应该吧...)vue-clearcss 为什么要用它? 一个vue文件在长期迭代中css会越来越冗余,它不像html和js那么好删除, ...
- pgsql基本介绍
join on 与数学原理 pgsql切换数据库 直接输入 \C youdatabasename 即可 \d 表名 -- 得到表结构 select * from tablename查看表的数据 相信有 ...
- Docker之Alpine制作jre镜像(瘦身)+自定义镜像上传阿里云
alpine制作jdk镜像 alpine Linux简介 1.Alpine Linux是一个轻型Linux发行版,它不同于通常的Linux发行版,Alpine采用了musl libc 和 BusyBo ...
- ubantu虚拟机搭建xl2tp服务
在编译成功源码,安装完毕xl2tpd后,便可以配置xl2tpd服务.基本配置过程主要涉及两个配置文件:一个用来配置xl2tpd, 一个用来配置ppp协议.下面分别对这两个文件进行说明,最后添加xl2t ...
- word文档转成图片
1:先把word文档转成pdf格式 这个是在word中转成pdf格式,保存好 2:再把pdf格式转成图片 在这个链接中打开https://smallpdf.com/cn/pdf-converter, ...
- 海量列式非关系数据库HBase 架构,shell与API
HBase的特点: 海量存储: 底层基于HDFS存储海量数据 列式存储:HBase表的数据是基于列族进行存储的,一个列族包含若干列 极易扩展:底层依赖HDFS,当磁盘空间不足的时候,只需要动态增加Da ...
- project read error(项目读取错误)
maven的pom文件出现project read error 1,打开电脑cmd操作界面,在cmd界面找到打开出错项目的文件夹; 比如我的项目文件夹在D:\>eclipse-jee-file\ ...
- vue2.0 前端框架
在正式开始先复习一下js基础.因为vue最通终也要操作这些元素,vue和以前学的js并不挂勾,他和传统的jquert 设计理念相反 ## js 数据类型 1 基本类型 number string ...
- JavaScript进行表单提交
表单结构,设置form表单的id属性,method="post/get","action"要跳转的页面(jsp或servlet) <form name=& ...