最近写了一个简单的定制解析。
fastjson 解析 Map key value时有bug.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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解析出来的结果是:
1 2 3 4 5 public static void main(String[] args) { KVPair<String, String> kv = new KVPair<String, String>("aaa", "bbb"); System.out.println(JSON.toJSONString(kv)); }
1 2 3 输出结果为: {"key":"aaa","value":"bbb"}
在fastjson 1.1.23 版本时, 只要改动一下 setValue() 这个方法,就可以得到这样的解析结果:
1 2 3 4 5 6 7 8 9 10 11 改动后的 setValue(V value) 方法为: public V setValue(V value) { this.value = value; return this.value; } 输出结果为: {"aaa":"bbb"}
这明显是 fastjson的bug。所以在1.1.46版本,已经不存在这个问题了。不管如何变化 setValue()函数,最后的输出结果仍然为:
1 2 3 输出结果: {"key":"aaa","value":"bbb"}
现在问题来了。我更希望解析为下面的这种。 ```
{"aaa":"bbb"}
1 2 3 4 这样占用的资源更少,并且也很清楚的表达了意思。这怎么写?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);
}
}
}
1 2 3 4 5 fastjson的逻辑是: 开始要传入一个序列化配置。这个序列化配置中有针对各个类如何进行序列化的子类(也就是映射关系)。如果我们将JSON_WRITE_C ONFIG传入到序列化过程中,那么针对 KVPair.class这个类,就可以使用KVPairSerialzer()进行序列化。KVPairSerialze r在这个类需要继承ObjectSerializer, 重要的是重构这个方法:
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType)
1 2 3 4 5 6 7 这里只要获取 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 2 3 1.1.46版本之后只需要在在field上面加入Annotation.就可以实现上面的效果。
@JSONField(serialize=false)
private String aaa;