基于注解实现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的更多相关文章

  1. springAOP实现基于注解的数据源动态切换

    需求 代码实现读写数据库分离 武器 spring3.0以上版本 实现思路 1.继承org.springframework.jdbc.datasource.lookup.AbstractRoutingD ...

  2. SPRINGAOP实现基于注解的数据源动态切换(转)

    需求 代码实现读写数据库分离 武器 spring3.0以上版本 实现思路 1.继承org.springframework.jdbc.datasource.lookup.AbstractRoutingD ...

  3. spring boot整合mybatis基于注解开发以及动态sql的使用

    让我们回忆一下上篇博客中mybatis是怎样发挥它的作用的,主要是三类文件,第一mapper接口,第二xml文件,第三全局配置文件(application.properties),而今天我们就是来简化 ...

  4. spring中实现基于注解实现动态的接口限流防刷

    本文将介绍在spring项目中自定义注解,借助redis实现接口的限流 自定义注解类 import java.lang.annotation.ElementType; import java.lang ...

  5. Struts2基于注解的Action配置

    使用注解来配置Action的最大好处就是可以实现零配置,但是事务都是有利有弊的,使用方便,维护起来就没那么方便了. 要使用注解方式,我们必须添加一个额外包:struts2-convention-plu ...

  6. 基于注解的Spring AOP的配置和使用

    摘要: 基于注解的Spring AOP的配置和使用 AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不 ...

  7. SpringMVC框架搭建 基于注解

    本文将以一个很简单的案例实现 Springmvc框架的基于注解搭建,一下全为个人总结 ,如有错请大家指教!!!!!!!!! 第一步:创建一个动态web工程(在创建时 记得选上自动生成 web.xml ...

  8. Spring AOP:面向切面编程,AspectJ,是基于注解的方法

    面向切面编程的术语: 切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象 通知(Advice): 切面必须要完成的工作 目标(Target): 被通知的对象 代理(Pr ...

  9. Spring基础知识之基于注解的AOP

    背景概念: 1)横切关注点:散布在应用中多处的功能称为横切关注点 2)通知(Advice):切面完成的工作.通知定了了切面是什么及何时调用. 5中可以应用的通知: 前置通知(Before):在目标方法 ...

随机推荐

  1. [源码解析] 深度学习流水线并行之PopeDream(1)--- Profile阶段

    [源码解析] 深度学习流水线并行之PopeDream(1)--- Profile阶段 目录 [源码解析] 深度学习流水线并行之PopeDream(1)--- Profile阶段 0x00 摘要 0x0 ...

  2. 剖析虚幻渲染体系(11)- RDG

    目录 11.1 本篇概述 11.2 RDG基础 11.2.1 RDG基础类型 11.2.2 RDG资源 11.2.3 RDG Pass 11.2.4 FRDGBuilder 11.3 RDG机制 11 ...

  3. 使用Keepalived实现Nginx的双机主备高可用

    1.概述 前面我们聊过使用 Nginx 为 后端Tomcat 做负载均衡.高可用,但是这时Nginx又成了单点,如果Nginx不幸挂掉,整个网站便无法访问. 此时我们就会用到另一个软件 -- Keep ...

  4. 性能测试工具JMeter 基础(三)—— 创建测试计划

    如何创建一个完整的测试计划? 安装好JMeter后,通过根目录下的bin目录中的jmeter.bat启动JMeter 添加线程组(Thread Group) 在 Test Plan 鼠标右键 Add- ...

  5. Eclipse开发Java的简单配置

    目录 Eclipse配置Java开发环境 1.配置JDK 2.切换项目的JDK版本 3.配置maven 4.配置lombok Eclipse配置Java开发环境 时隔N年重新使用Eclipse,对一些 ...

  6. Python习题集(十五)

    每天一习题,提升Python不是问题!!有更简洁的写法请评论告知我! https://www.cnblogs.com/poloyy/category/1676599.html 题目 请写一个函数,该函 ...

  7. VMware NAT模式,虚机访问公网

    1)  确认VMnet8实际获取的IP是否与VMware中配置相同,不同则禁用启用该虚拟网卡 2)确认/etc/sysconfig/network-scripts/ifcfg-ens33 中的配置,G ...

  8. RDS导入注意事项

    1)导入文件大小不超过100M,支持格式有CSV.SQL.ZIP 2)sql文件需注释如下内容: SET @@SESSION.SQL_LOG_BIN=0 ; SET @@GLOBAL.GTID_PUR ...

  9. 了解HTTP基本知识板块

    一.HTTP 协议概述 HTTP协议采用了请求/响座模型. 客户端向服务器发送-个请求,请求头包含请求的方法.URT..协议版本.以以 及包含请求修饰符.客户信息和内容的类似于MIME的消息结构. 服 ...

  10. Oracle列值拼接

    最近在学习的过程中,发现一个挺有意思的函数,它可实现对列值的拼接.下面我们来看看其具体用法. 用法: 对其作用,官方文档的解释如下: For a specified measure, LISTAGG  ...