0.复杂对象解析思路
复杂的json对象的解析思路,就是一层一层的解析出JSONObject,再从JSONObject中解析出JSONObject,直到能取到需要字段为止
1. Fastjson API ParseProcess简介
ParseProcess是编程扩展定制反序列化的接口。fastjson支持如下ParseProcess:
- 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,用于不同场景的定制序列化。
- PropertyPreFilter 根据PropertyName判断是否序列化
- PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
- NameFilter 修改Key,如果需要修改Key,process返回值则可
- ValueFilter 修改Value
- BeforeFilter 序列化时在最前添加内容
- AfterFilter 序列化时在最后添加内容
PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
public interface PropertyFilter extends SerializeFilter {
boolean apply(Object object, String propertyName, Object propertyValue);
}
可以通过扩展实现根据object或者属性名称或者属性值进行判断是否需要序列化。例如:
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调用可能存在的异常。
public interface PropertyPreFilter extends SerializeFilter {
boolean apply(JSONSerializer serializer, Object object, String name);
}
NameFilter 序列化时修改Key
如果需要修改Key,process返回值则可
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 添加内容
public abstract class BeforeFilter implements SerializeFilter {
protected final void writeKeyValue(String key, Object value) { ... }
// 需要实现的抽象方法,在实现中调用writeKeyValue添加内容
public abstract void writeBefore(Object object);
}
AfterFilter 序列化时在最后添加内容
在序列化对象的所有属性之后执行某些操作,例如调用 writeKeyValue 添加内容
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。
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