基于注解实现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. win修改host问及那

  2. git《一》

    org.eclipse.jgit.api.errors.TransportException: https://gitee.com/wbweb/springboot_vue.git: Authenti ...

  3. C#·好文分享

    时间:2018-11-14 记录:byzqy 好文收藏,集中分享! 标题:C#接口<通俗解释> 地址:https://www.cnblogs.com/hamburger/p/4681681 ...

  4. Nginx配置文件详解与优化建议

    1.概述 今天来详解一下Nginx的配置文件,以及给出一些配置建议,希望能对大家有所帮助. 2.nginx.conf 1)配置文件位置 nginx 安装目录的 conf 文件夹下,例如:/usr/lo ...

  5. grpc基础

    RPC 框架原理 RPC 框架的目标就是让远程服务调用更加简单.透明,RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP).序列化方式(XML/Json/ 二进制)和通信细节.服务调用者可以像调 ...

  6. Jenkins 使用PowerShell插件部署Net5项目

    Jenkins安装 PowerShell plugin 插件 新建自由项目 拖到 构建 处,添加 PowerShell 构建 贴入下方脚本即可 # 变量 $ProjectPath = "E: ...

  7. java 线程基础篇,看这一篇就够了。

    前言: Java三大基础框架:集合,线程,io基本是开发必用,面试必问的核心内容,今天我们讲讲线程. 想要把线程理解透彻,这需要具备很多方面的知识和经验,本篇主要是关于线程基础包括线程状态和常用方法. ...

  8. docker日常使用指南

    docker日常使用指南 目录 docker日常使用指南 前言 1.基础知识 1.1 docker是什么 1.2 与虚拟机(VM)的区别 1.3 镜像与容器 2.安装 2.1 在线安装 2.2 离线安 ...

  9. java 集合特性面试必备

    collection 集合体系 数据结构栈和队列栈结构 :先进后出队列结构 :先进先出 数据结构之数组和链表数组结构:查询快.增删慢队列结构 :查询慢.增删快 List集合概述有序集合(也称为序列), ...

  10. jq 追加元素的几种方法

    jQuery添加插入元素技巧: jquery添加分为在指定元素的里面添加和外面添加两种: 里面添加使用(append 和prepend) 里面添加又分为在里面的前面添加和后面添加 里面的前面添加使用 ...