基于注解实现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); } }
最后这个问题如能解决,麻烦留言下解决的代码