1. 程式人生 > 其它 >基於註解實現jackson動態JsonProperty

基於註解實現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);
        }
    }

最後這個問題如能解決,麻煩留言下解決的程式碼