fastjson 定製化解析

最近寫了一個簡單的定製解析。

fastjson 解析 Map key value時有bug.

public static class KVPair<K,V> {
        private K key;
        private V value;
        public KVPair(){}
        public KVPair(K key, V value){
            this.key = key;
            this.value = value;
        }
        public K getKey() {
            return key;
        }
        public void setKey(K key) {
            this.key = key;
        }
        public V getValue() {

            return value;
        }
        public void setValue(V value) {
            this.value = value;
        }
        
    }

這是一個簡單的 KeyValue 類。這個類被fastjson解析出來的結果是:

public static void main(String[] args) {
        KVPair<String, String> kv = new KVPair<String, String>("aaa", "bbb");
        System.out.println(JSON.toJSONString(kv));
    }


輸出結果爲:
{"key":"aaa","value":"bbb"}



在fastjson 1.1.23 版本時, 只要改動一下 setValue() 這個方法,就可以得到這樣的解析結果:

改動後的 setValue(V value) 方法爲:

public V setValue(V value) {
      this.value = value;
      return this.value;
}

輸出結果爲:
{"aaa":"bbb"}

這明顯是 fastjson的bug。所以在1.1.46版本,已經不存在這個問題了。不管如何變化 setValue()函數,最後的輸出結果仍然爲:

輸出結果:
{"key":"aaa","value":"bbb"}

現在問題來了。我更希望解析爲下面的這種。
{"aaa":"bbb"}

這樣佔用的資源更少,並且也很清楚的表達了意思。這怎麼寫?fastjson提供的specialConfig 來提供特殊的序列化配置。

首先我們先對這個class創建一個特殊的序列化方法:

public static final SerializeConfig JSON_WRITE_CONFIG = new SerializeConfig();
    static {
        JSON_WRITE_CONFIG.put(KVPair.class, new KVPairSerailzer());
    }

然後我們來構造這個特殊的序列化類:

public class KVPairSerailzer implements ObjectSerializer{

    @SuppressWarnings("rawtypes")
    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType) throws IOException {
        
        SerializeWriter out = serializer.getWriter();
        if (object ==null) {
            return ;
        }
        KVPair pair = (KVPair)object; 
        out.write("{");
        write(out,pair.getKey());
        out.write(":");
        write(out,pair.getValue());
        out.write("}");
    }
    
    public void write(SerializeWriter out, Object value) {
        if (value == null) {
            return;
        } else if (value instanceof Integer) {
            out.writeInt((Integer)value);
        } else if (value instanceof Long) {
            out.writeLong((Long)value);
        } else if (value instanceof String) {
            out.write("\"");
            out.write((String)value);
            out.write("\"");
        } else if (value instanceof Double) {
            out.write(Double.toString((Double)value));
        } else if (value instanceof Float) {
            out.write(Float.toString((Float)value));
        } else {
            throw new RuntimeException("not support value:"+value);
        }
    }

}


fastjson的邏輯是: 開始要傳入一個序列化配置。這個序列化配置中有針對各個類如何進行序列化的子類(也就是映射關係)。如果我們將JSON_WRITE_CONFIG傳入到序列化過程中,那麼針對 KVPair.class這個類,就可以使用KVPairSerialzer()進行序列化。KVPairSerialzer在這個類需要繼承ObjectSerializer, 重要的是重構這個方法:

public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType)

 這裏只要獲取serializer.getWriter(),然後將序列化後的字符串寫入到writer中就結束了。SerializerWriter 其實就是一個可變長char數組,細節沒有什麼好講的。


另外 1.1.46 之前的版本如果不希望將某些field不放在序列化後的json中,需要加入一個 實現了PropertyPreFilter的類纔行。例如下面這個類:

public class FieldJsonIgnoreFilter implements PropertyPreFilter  {
    private Set<String> excludes;

    @Override
    public boolean apply(JSONSerializer serializer, Object object, String name) {
        if(object instanceof ComputerCluster) {
            return !excludes.contains(name);
        }
        return true;
    }
    public FieldJsonIgnoreFilter() {
        this.excludes = Sets.newHashSet();
        
    }
    public void add(String excludeFieldName) {
        excludes.add(excludeFieldName);
    }
    
    public static final FieldJsonIgnoreFilter FIELD_JSON_IGNORE_FILTER = new FieldJsonIgnoreFilter();
    static {
        FIELD_JSON_IGNORE_FILTER.add("aaa");  // 如果fieldName 爲 aaa 則不進行序列化。
        FIELD_JSON_IGNORE_FILTER.add("bbb");
        FIELD_JSON_IGNORE_FILTER.add("ccc");
        
    }
}

1.1.46版本之後只需要在在field上面加入Annotation.就可以實現上面的效果。 

@JSONField(serialize=false)
private String aaa;





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章