fastjson

Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。Fastjson接口简单易用,已经被广泛使用在缓存序列化、协议交互、Web输出、Android客户端等多种应用场景。

#fastjson主要的API

fastjson入口类是com.alibaba.fastjson.JSON,主要的API是JSON.toJSONString,和parseObject。

package com.alibaba.fastjson;
public abstract class JSON {
  public static final String toJSONString(Object object);
  public static final <T> T parseObject(String text, Class<T> clazz, Feature... features);
}

fastjson如何处理日期


fastjson处理日期的API很简单,例如:

JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS")

使用ISO-8601日期格式

JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);

全局修改日期格式

JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";
JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);

反序列化能够自动识别如下日期格式:

  • ISO-8601日期格式
  • yyyy-MM-dd
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss.SSS
  • 毫秒数字
  • 毫秒数字字符串
  • .NET JSON日期格式
  • new Date(198293238)

如何定制序列化?

使用SimplePropertyPreFilter过滤属性

需要根据不同的环境返回定制化返回属性时,可以使用SimplePropertyPreFilter。

SimplePropertyPreFilter接口

public class SimplePropertyPreFilter implements PropertyPreFilter {      
    public SimplePropertyPreFilter(String... properties){
          this(null, properties);
    }

    public SimplePropertyPreFilter(Class<?> clazz, String... properties){
          // ... ...
    }

    public Class<?> getClazz() {
          return clazz;
    }

    public Set<String> getIncludes();

    public Set<String> getExcludes();

    /**
     * @since 1.2.9
     */
    public int getMaxLevel();

    /**
     * @since 1.2.9
     */
    public void setMaxLevel(int maxLevel)

    //...
}

你可以配置includes、excludes。当class不为null时,针对特定类型;当class为null时,针对所有类型。

当includes的size > 0时,属性必须在includes中才会被序列化,excludes优先于includes。

Class_Level_SerializeFilter

对于框架来说,如果在toJSONString的时候,传入SerializeFilter,会导致对所有的类型做过滤,性能会受到一定影响。在1.2.10版本之后,fastjson提供类级别的SerializeFilter支持。
package com.alibaba.fastjson.serializer;

public class SerializeConfig {
    public void addFilter(Class<?> clazz, SerializeFilter filter);
}

Sample

public class ClassNameFilterTest extends TestCase {
    public void test_filter() throws Exception {
        NameFilter upcaseNameFilter = new NameFilter() {
            public String process(Object object, String name, Object value) {
                return name.toUpperCase();
            }
        };
        SerializeConfig.getGlobalInstance() //
                       .addFilter(A.class, upcaseNameFilter);

        Assert.assertEquals("{\"ID\":0}", JSON.toJSONString(new A()));
        Assert.assertEquals("{\"id\":0}", JSON.toJSONString(new B()));
    }

    public static class A {
        public int id;
    }

    public static class B {
        public int id;
    }
}

fastjson支持多种方式定制序列化。

  • 通过@JSONField定制序列化
  • 通过@JSONType定制序列化
  • 通过SerializeFilter定制序列化
  • 通过ParseProcess定制反序列化

使用@JSONField配置

可以把@JSONField配置在字段或者getter/setter方法上。例如:

public class VO {
  @JSONField(name="ID")
  private int id;
}

public class VO {
  private int id;

  @JSONField(name="ID")
  public int getId() { return id;}

  @JSONField(name="ID")
  public void setId(int value) {this.id = id;}
}

使用format配置日期格式化

 public class A {
  // 配置date序列化和反序列使用yyyyMMdd日期格式
  @JSONField(format="yyyyMMdd")
  public Date date;
}

使用serialize/deserialize指定字段不序列化

public class A {
@JSONField(serialize=false)
      public Date date;
 }

 public class A {
      @JSONField(deserialize=false)
      public Date date;
 }

使用ordinal指定字段的顺序

缺省fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。
public static class VO {
@JSONField(ordinal = 3)
private int f0;

@JSONField(ordinal = 2)
private int f1;

@JSONField(ordinal = 1)
private int f2;
}

使用serializeUsing制定属性的序列化类

在fastjson 1.2.16版本之后,JSONField支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化,比如:
public static class Model {
@JSONField(serializeUsing = ModelValueSerializer.class)
public int value;
}

public static class ModelValueSerializer implements ObjectSerializer {
    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
                      int features) throws IOException {
        Integer value = (Integer) object;
        String text = value + "元";
        serializer.write(text);
    }
}

使用@JSONType配置

和JSONField类似,但JSONType配置在类上,而不是field或者getter/setter方法上。

通过SerializeFilter定制序列化

通过SerializeFilter可以使用扩展编程的方式实现定制序列化。fastjson提供了多种SerializeFilter:

  • PropertyPreFilter 根据PropertyName判断是否序列化
  • PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
  • NameFilter 修改Key,如果需要修改Key,process返回值则可
  • ValueFilter 修改Value
  • BeforeFilter 序列化时在最前添加内容
  • AfterFilter 序列化时在最后添加内容

以上的SerializeFilter在JSON.toJSONString中可以使用。

SerializeFilter filter = ...; // 可以是上面5个SerializeFilter的任意一种。
JSON.toJSONString(obj, filter);

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);
}

通过ParseProcess定制反序列化

ParseProcess是编程扩展定制反序列化的接口。fastjson支持如下ParseProcess:

  • ExtraProcessor 用于处理多余的字段
  • ExtraTypeProvider 用于处理多余字段时提供类型信息

使用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"));

使用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 int.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类型了。

当对象存在引用时,序列化后的结果浏览器不支持,怎么办?

使用SerializerFeature.DisableCircularReferenceDetect特性关闭引用检测和生成。例如:

String  jsonString = JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);

fastjson 如何处理超大对象和超大JSON文本

当需要处理超大JSON文本时,需要Stream API,在fastjson-1.1.32版本中开始提供Stream API。

序列化

超大JSON数组序列化

如果你的JSON格式是一个巨大的JSON数组,有很多元素,则先调用startArray,然后挨个写入对象,然后调用endArray。

JSONWriter writer = new JSONWriter(new FileWriter("/tmp/huge.json"));
writer.startArray();
for (int i = 0; i < 1000 * 1000; ++i) {
    writer.writeValue(new VO());
}
writer.endArray();
writer.close();

超大JSON对象序列化

如果你的JSON格式是一个巨大的JSONObject,有很多Key/Value对,则先调用startObject,然后挨个写入Key和Value,然后调用endObject。

JSONWriter writer = new JSONWriter(new FileWriter("/tmp/huge.json"));
writer.startObject();
 for (int i = 0; i < 1000 * 1000; ++i) {
    writer.writeKey("x" + i);
    writer.writeValue(new VO());
 }
 writer.endObject();
 writer.close();

##S 反序列化

JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startArray();
while(reader.hasNext()) {
    VO vo = reader.readObject(VO.class);
    // handle vo ...
}
reader.endArray();
reader.close();

JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startObject();
while(reader.hasNext()) {
    String key = reader.readString();
    VO vo = reader.readObject(VO.class);
    // handle vo ...
}
reader.endObject();
reader.close();

将对象中的空值输出

输入输出空值

在fastjson中,缺省是不输出空值的。无论Map中的null和对象属性中的null,序列化的时候都会被忽略不输出,这样会减少产生文本的大小。但如果需要输出空值怎么做呢?

使用SerializerFeature.WriteMapNullValue

Model obj = ...;
JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue);

空值特别处理

SerializerFeature 描述

WriteNullListAsEmpty
将Collection类型字段的字段空值输出为[]

WriteNullStringAsEmpty
将字符串类型字段的空值输出为空字符串 “”

WriteNullNumberAsZero
将数值类型字段的空值输出为0

WriteNullBooleanAsFalse
将Boolean类型字段的空值输出为false

 class Model {
  public List<Objec> items;
}

Model obj = ....;

String text = JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);

ContextValueFilter

在某些场景下,对Value做过滤,需要获得所属JavaBean的信息,包括类型、字段、方法等。在fastjson-1.2.9中,提供了ContextValueFilter,类似于之前版本提供的ValueFilter,只是多了BeanContext参数可用。

package com.alibaba.fastjson.serializer;

public interface ContextValueFilter extends SerializeFilter {
    Object process(BeanContext context, 
                   Object object, 
                   String name, 
                   Object value);
}

package com.alibaba.fastjson.serializer;

public final class BeanContext {
    public Class<?> getBeanClass();

    public Method getMethod();

    public Field getField();

    public String getName();

    public String getLabel();

    public <T extends Annotation> T getAnnation(Class<T> annotationClass);
}

Sample

ContextValueFilter valueFilter = new ContextValueFilter() {
    public Object process(SerializeContext context, 
                          Object object, 
                          String name, 
                          Object value) {
        Class<?> objectClass = context.getBeanClass();
        UrlIdentify annotation = context.getAnnation(UrlIdentify.class);

        // ....

        return value;
    }
};

JSON.toJSONString(model, valueFilter);
article.share