基于注解实现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);
        }
    }

最后这个问题如能解决,麻烦留言下解决的代码

 

 

 

 

 

 

 

     

 

posted @ 2021-10-15 09:35  似水了流年  阅读(1254)  评论(0编辑  收藏  举报