fastjson快速上手(4)

0.複雜對象解析思路

複雜的json對象的解析思路,就是一層一層的解析出JSONObject,再從JSONObject中解析出JSONObject,直到能取到須要字段爲止html

1. Fastjson API ParseProcess簡介

ParseProcess是編程擴展定製反序列化的接口。fastjson支持以下ParseProcess:java

  • ExtraProcessor 用於處理多餘的字段
  • ExtraTypeProvider 用於處理多餘字段時提供類型信息

2. 使用ExtraProcessor 處理多餘字段

public static class VO {
    private int id;
    private Map<String, Object> attributes = new HashMap<String, Object>();
    public int getId() { return id; }
    public void setId(int id) { this.id = id;}
    public Map<String, Object> getAttributes() { return attributes;}
}

ExtraProcessor processor = new ExtraProcessor() {
    public void processExtra(Object object, String key, Object value) {
        VO vo = (VO) object;
        vo.getAttributes().put(key, value);
    }
};

VO vo = JSON.parseObject("{\"id\":123,\"name\":\"abc\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals("abc", vo.getAttributes().get("name"));

3. 使用ExtraTypeProvider 爲多餘的字段提供類型

public static class VO {
        private int id;
        private Map<String, Object> attributes = new HashMap<String, Object>();

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public Map<String, Object> getAttributes() {
            return attributes;
        }
    }

    class MyExtraProcessor implements ExtraProcessor, ExtraTypeProvider {
        public void processExtra(Object object, String key, Object value) {
            VO vo = (VO) object;
            vo.getAttributes().put(key, value);
        }

        public Type getExtraType(Object object, String key) {
            if ("value".equals(key)) {
                return Integer.class;
            }
            return null;
        }
    }

    
    ExtraProcessor processor = new MyExtraProcessor();

    VO vo = JSON.parseObject("{\"id\":123,\"value\":\"123456\"}", VO.class, processor);
    Assert.assertEquals(123,vo.getId());
    Assert.assertEquals(123456,vo.getAttributes().get("value"));
    // value本應該是字符串類型的,經過getExtraType的處理變成Integer類型了。

Fastjson API SerializeFilter

SerializeFilter是經過編程擴展的方式定製序列化。fastjson支持6種SerializeFilter,用於不一樣場景的定製序列化。編程

  1. PropertyPreFilter 根據PropertyName判斷是否序列化
  2. PropertyFilter 根據PropertyName和PropertyValue來判斷是否序列化
  3. NameFilter 修改Key,若是須要修改Key,process返回值則可
  4. ValueFilter 修改Value
  5. BeforeFilter 序列化時在最前添加內容
  6. AfterFilter 序列化時在最後添加內容

PropertyFilter 根據PropertyName和PropertyValue來判斷是否序列化

public interface PropertyFilter extends SerializeFilter {
      boolean apply(Object object, String propertyName, Object propertyValue);
  }

能夠經過擴展實現根據object或者屬性名稱或者屬性值進行判斷是否須要序列化。例如:json

PropertyFilter filter = new PropertyFilter() {

        public boolean apply(Object source, String name, Object value) {
            if ("id".equals(name)) {
                int id = ((Integer) value).intValue();
                return id >= 100;
            }
            return false;
        }
    };

    JSON.toJSONString(obj, filter); // 序列化的時候傳入filter

PropertyPreFilter 根據PropertyName判斷是否序列化

和PropertyFilter不一樣只根據object和name進行判斷,在調用getter以前,這樣避免了getter調用可能存在的異常。app

public interface PropertyPreFilter extends SerializeFilter {
      boolean apply(JSONSerializer serializer, Object object, String name);
  }

NameFilter 序列化時修改Key

若是須要修改Key,process返回值則可ide

public interface NameFilter extends SerializeFilter {
    String process(Object object, String propertyName, Object propertyValue);
}

fastjson內置一個PascalNameFilter,用於輸出將首字符大寫的Pascal風格。 例如:性能

import com.alibaba.fastjson.serializer.PascalNameFilter;

Object obj = ...;
String jsonStr = JSON.toJSONString(obj, new PascalNameFilter());

ValueFilter 序列化是修改Value

public interface ValueFilter extends SerializeFilter {
      Object process(Object object, String propertyName, Object propertyValue);
  }

BeforeFilter 序列化時在最前添加內容

在序列化對象的全部屬性以前執行某些操做,例如調用 writeKeyValue 添加內容this

public abstract class BeforeFilter implements SerializeFilter {
      protected final void writeKeyValue(String key, Object value) { ... }
      // 須要實現的抽象方法,在實現中調用writeKeyValue添加內容
      public abstract void writeBefore(Object object);
  }

AfterFilter 序列化時在最後添加內容

在序列化對象的全部屬性以後執行某些操做,例如調用 writeKeyValue 添加內容spa

public abstract class AfterFilter implements SerializeFilter {
      protected final void writeKeyValue(String key, Object value) { ... }
      // 須要實現的抽象方法,在實現中調用writeKeyValue添加內容
      public abstract void writeAfter(Object object);
  }

 

Fastjson BeanToArray

在fastjson中,支持一種叫作BeanToArray的映射模式。普通模式下,JavaBean映射成json object,BeanToArray模式映射爲json array。3d

Sample 1

class Mode {
   public int id;
   public String name;
}

Model model = new Model();
model.id = 1001;
model.name = "gaotie";

// {"id":1001,"name":"gaotie"}
String text_normal = JSON.toJSONString(model); 

// [1001,"gaotie"]
String text_beanToArray = JSON.toJSONString(model, SerializerFeature.BeanToArray); 

// support beanToArray & normal mode
JSON.parseObject(text_beanToArray, Feature.SupportArrayToBean);

上面的例子中,BeanToArray模式下,少了Key的輸出,節省了空間,json字符串較小,性能也會更好。

Sample 2

BeanToArray能夠局部使用,好比:

class Company {
     public int code;
     public List<Department> departments = new ArrayList<Department>();
}

@JSONType(serialzeFeatures=SerializerFeature.BeanToArray, parseFeatures=Feature.SupportArrayToBean)
class Department {
     public int id;
     public Stirng name;
     public Department() {}
     public Department(int id, String name) {this.id = id; this.name = name;}
}


Company company = new Company();
company.code = 100;
company.departments.add(new Department(1001, "Sales"));
company.departments.add(new Department(1002, "Financial"));

// {"code":10,"departments":[[1001,"Sales"],[1002,"Financial"]]}
String text = JSON.toJSONString(commpany);

在這個例子中,若是Company的屬性departments元素不少,局部採用BeanToArray就能夠得到很好的性能,而總體又可以得到較好的可讀性。

Sample 3

上一個例子也能夠這樣寫(推薦):

class Company {
     public int code;

     @JSONField(serialzeFeatures=SerializerFeature.BeanToArray, parseFeatures=Feature.SupportArrayToBean)
     public List<Department> departments = new ArrayList<Department>();
}

性能

使用BeanToArray模式,能夠得到媲美protobuf的性能。

create     ser   deser   total   size  +dfl
protobuf                              244    2297    1296    3593    239   149
json/fastjson_array/databind          123    1289    1567    2856    281   163
msgpack/databind                      122    1525    2180    3705    233   146
json/fastjson/databind                120    2019    2610    4629    486   262
json/jackson+afterburner/databind     118    2142    3147    5289    485   261
json/jackson/databind                 124    2914    4411    7326    485   261

這裏的json/fastjson_array/databind就是fastjson啓用BeanToArray模式,total性能比protobuf好,請看fastjson Benchmark

相關文章
相關標籤/搜索