Json study concluded (5) - Alibaba open source library Fastjson Comments

I. Introduction

JSON, full name: JavaScript Object Notation, as a common lightweight data-interchange format, should a programmer's career development is regular contact. Simple and clear hierarchy make JSON an ideal data-interchange language. Easy to read and write, but also easy for machines to parse and generate, and effectively improve the efficiency of network transmission. Java is an object-oriented language, so we have more forms in the project are the object of the processing business, but when we have to transport convert an object to JSON format to facilitate the transfer, but JSON format can generally be resolved by most the object format, but not with the programming language. Now the mainstream JSON object system conversion tool for many, we introduce today's hero, Ali Baba open source library - Fastjson. Fastjson is a Java library that can be used to convert a Java object representation for JSON. It is also used JSON string into the equivalent Java objects. Fastjson can handle arbitrary Java objects including pre-existing objects you do not have the source code.

Second, what is Fastjson?

Ali gave the official definition is, fastjson Alibaba open source JSON parsing library that can parse JSON-formatted string, will support Java Bean is serialized to JSON string, you can deserialize from JSON string to the JavaBean.

Three, Fastjson advantages

Speed : fastjson characteristics relative to other fast JSON library from version 1.1.x release after 2011, its performance has never been surpassed other JSON library implemented in Java.

Widely used : fastjson large-scale use in Alibaba, deployed on tens of thousands of servers, fastjson been widely accepted in the industry. It was named one of the most popular open-source Chinese-made open-source software in 2012.

Test complete : fastjson have a lot of testcase, in 1.2.11 version, testcase over 3321. Each release will conduct regression testing to ensure quality and stability.

Simple to use : fastjson the API is very simple.

Fully functional : support for generics, support for streaming large text, enumeration support, support serialization and de-serialization of the extension.

Fourth, how to get Fastjson

You can download fastjson through the following places:

maven central warehouse: http://central.maven.org/maven2/com/alibaba/fastjson/

Sourceforge.net : https://sourceforge.net/projects/fastjson/files/

In the configuration file directly pom maven project fastjson dependent, fastjson latest version will be released to the maven central repository, you can directly dependent.

<dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>fastjson</artifactId>
 <version>x.x.x</version>
</dependency>

Where xxx is the version number, use a specific version required, it is recommended to use the latest version.

Five, Fastjson major API

Fastjson entry class is com.alibaba.fastjson.JSON, and the main API is JSON.toJSONString parseObject.

package com.alibaba.fastjson;
public abstract class JSON {
 // Java对象转换为JSON字符串
 public static final String toJSONString(Object object);
 //JSON字符串转换为Java对象
 public static final <T> T parseObject(String text, Class<T> clazz, Feature... features);
}

Serialization:

String jsonString = JSON.toJSONString(obj);

Deserialization:

VO vo = JSON.parseObject("...", VO.class);

Generic deserialized:

import com.alibaba.fastjson.TypeReference;
List<VO> list = JSON.parseObject("...", new TypeReference<List<VO>>() {});

Six, Fastjson performance

fastjson is currently the fastest java language json library, claiming faster than the fastest speed jackson, independent third-party test results to see here: https: //github.com/eishay/jvm-serializers/wiki. Themselves do performance testing, to be closed circular reference feature detection.

JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect)
VO vo = JSON.parseObject("...", VO.class, Feature.DisableCircularReferenceDetect)

Further, Fastjson about 6 times faster than Gson, the test results can be seen here:

Checking correctness…
[done]
Pre-warmup… java-built-in hessian kryo protostuff-runtime avro-generic msgpack json/jackson/databind json/jackson/databind-strings json/jackson/db-afterburner json/google-gson/databind json/svenson-databind json/flexjson/databind json/fastjson/databind smile/jackson/databind smile/jackson/db-afterburner smile/protostuff-runtime bson/jackson/databind xml/xstream+c xml/jackson/databind-aalto
[done]
pre. create ser deser shal +deep total size +dfl
java-built-in 63 5523 27765 28084 28162 33686 889 514
hessian 64 3776 6459 6505 6690 10466 501 313
kryo 63 809 962 937 1001 1810 214 133
protostuff-runtime 62 671 903 920 957 1627 241 151
avro-generic 436 1234 1122 1416 1760 2994 221 133
msgpack 61 789 1369 1385 1449 2238 233 146
json/jackson/databind 60 1772 3089 3113 3246 5018 485 261
json/jackson/databind-strings 64 2346 3739 3791 3921 6267 485 261
json/jackson/db-afterburner 64 1482 2220 2233 2323 3805 485 261
json/google-gson/databind 64 7076 4894 4962 5000 12076 486 259
json/svenson-databind 64 5422 12387 12569 12468 17890 495 266
json/flexjson/databind 62 20923 26853 26873 27272 48195 503 273
json/fastjson/databind 63 1250 1208 1206 1247 2497 486 262
smile/jackson/databind 60 1697 2117 2290 2298 3996 338 241
smile/jackson/db-afterburner 60 1300 1614 1648 1703 3003 352 252
smile/protostuff-runtime 61 1275 1612 1638 1685 2961 335 235
bson/jackson/databind 63 5151 6729 6977 6918 12069 506 286
xml/xstreamc 62 6358 13208 13319 13516 19874 487 244
xml/jackson/databind-aalto 62 2955 5332 5465 5584 8539 683 286

Seven, Fastjson use examples

We create a class of objects, and a student objects as follows:

Class Object

public class Grade {
 private Long id;
 private String name;
 private List<Student> users = new ArrayList<Student>();
 // 省略 setter、getter
 public void addStudent(Student student) {
 users.add(student);
 }
 @Override
 public String toString() {
 return "Grade{" +
 "id=" + id +
 ", name='" + name + ''' +
 ", users=" + users +
 '}';
 }
}

Students Object

public class Student {
 private Long id;
 private String name;
 // 省略 setter、getter
 @Override
 public String toString() {
 return "Student{" +
 "id=" + id +
 ", name='" + name + ''' +
 '}';
 }
}

Main function running

public class MainTest {
 public static void main(String[] args) {
 Grade group = new Grade();
 group.setId(0L);
 group.setName("admin");
 Student student = new Student();
 student.setId(2L);
 student.setName("guest");
 Student rootUser = new Student();
 rootUser.setId(3L);
 rootUser.setName("root");
 group.addStudent(student);
 group.addStudent(rootUser);
 // 转换为 JSON
 String jsonString = JSON.toJSONString(group);
 System.out.println("JSON字符串:" + jsonString);
 // 转换为 对象BEAN
 Grade grade = JSON.parseObject(jsonString, Grade.class);
 System.out.println("JavaBean对象:" + grade);
 }
}

The final results are as follows:

JSON字符串:
{"id":0,"name":"admin","users":[{"id":2,"name":"guest"},{"id":3,"name":"root"}]}
JavaBean对象:
Grade{id=0, name='admin', users=[Student{id=2, name='guest'}, Student{id=3, name='root'}]}

Eight, the object null output

In fastjson, the default output is not null. Regardless of null null Map and object properties, the sequence of the time will be ignored output, this will reduce the size of the generated text. But if you need NULL values ​​are output how to do it? If you need to output a null value, requires the use of SerializerFeature.WriteMapNullValue

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

Some special handling null:

                  SerializerFeature description

                  WriteNullListAsEmpty a field null for the output type field Collection []

                  WriteNullStringAsEmpty nulls the output string type field empty string ""

                  WriteNullNumberAsZero the value type field null output 0

                  WriteNullBolleanAsFalse null value output type field to false Bollean

 

Specific reference to the following examples, can select a plurality of simultaneously:

class Model {
 public List<Objec> items;
}
Model obj = ....;
String text = JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty);

Nine, Fastjson processing date

API Fastjson processing date is very simple, such as:

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

The ISO-8601日期格式

JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);

Global change the date format

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

Deserialization can automatically identify the following Date format:

  • ISO-8601日期格式
  • yyyy-MM-dd
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss.SSS
  • Ms Digital
  • Ms numeric string
  • .NET JSON date format
  • new Date(198293238)

While the above process configuration of a single type of date and global date format type, but sometimes we need a target date of individual types of differentiation, not necessarily the same format. How then to handle it? Next comes the custom serialization Fastjson.

Ten, Fastjson custom serialization

10.1 Introduction

fastjson support a variety of ways to customize serialization.

  • By @JSONField custom serialization
  • By @JSONType custom serialization
  • By SerializeFilter custom serialization
  • By ParseProcess custom deserialization

10.2, using @JSONField configuration

1, JSONField notes Introduction

package com.alibaba.fastjson.annotation;
public @interface JSONField {
 // 配置序列化和反序列化的顺序,1.1.42版本之后才支持
 int ordinal() default 0;
 // 指定字段的名称
 String name() default "";
 // 指定字段的格式,对日期格式有用
 String format() default "";
 // 是否序列化
 boolean serialize() default true;
 // 是否反序列化
 boolean deserialize() default true;
}

2, JSONField configuration

@JSONField can be disposed on the field or getter / setter methods, for example:

Configured on the field

public class VO {
 @JSONField(name="ID")
 private int id;
 @JSONField(name="birthday",format="yyyy-MM-dd")
 public Date date;
}

Disposed Getter / Setter on

public class VO {
 private int id;
 @JSONField(name="ID")
 public int getId() { return id;}
 @JSONField(name="ID")
 public void setId(int id) {this.id = id;}
}

Note: If the property is private, must have set * methods. Otherwise it can not be deserialized.

3, the date format using the format configuration

You can be custom configured to format each date field

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

4, using serialize / deserialize serialized field is not specified

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

5, the specified field sequential use ordinal

The default serialization Fastjson a java bean, is serialized, you can specify the order of the fields by the ordinal alphabetical order fieldName. This feature requires 1.1.42 or later.

public static class VO {
 @JSONField(ordinal = 3)
 private int f0;
 @JSONField(ordinal = 2)
 private int f1;
 @JSONField(ordinal = 1)
 private int f2;
}

6, the sequence used to develop serializeUsing class attributes

After fastjson 1.2.16 version, JSONField support the new customized configuration serializeUsing, can be individually customized serialization on an attribute of a particular class, such as:

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

Test code

Model model = new Model();
model.value = 100;
String json = JSON.toJSONString(model);
Assert.assertEquals("{"value":"100元"}", json);

10.3, using @JSONType configuration

And JSONField similar, but JSONType disposed on the class, not the field or getter / setter methods.

10.4, by custom serialization SerializeFilter

1 Introduction

SerializeFilter custom serialization by programming extensions. fastjson supports six SerializeFilter, used to customize the sequence of different scenes.

  • The PropertyName is determined whether PropertyPreFilter serialized
  • PropertyFilter PropertyValue The PropertyName and to determine whether a sequence of
  • NameFilter modify Key, if you need to modify Key, process the return value can be
  • ValueFilter modify Value
  • BeforeFilter when serializing add content on Top
  • In the last AfterFilter add content serialization

2, PropertyFilter determines whether PropertyValue The PropertyName and serialized

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

It can determine whether to serialize object according achieved by extending or attribute name or attribute value. E.g:

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

3, PropertyPreFilter The PropertyName is determined whether serialized

And PropertyFilter only be judged according to different object and name, before calling getter, thus avoiding abnormal getter calls may exist.

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

4, NameFilter modify Key serializing

If you need to modify the Key, process the return value can be

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

fastjson built a PascalNameFilter, for outputting the first character capitalized Pascal style. E.g:

import com.alibaba.fastjson.serializer.PascalNameFilter;
Object obj = ...;
String jsonStr = JSON.toJSONString(obj, new PascalNameFilter());

5, ValueFilter modify serialization Value

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

6, BeforeFilter sequence of adding content on Top

Perform certain operations until all the attributes of a serialized object, such as adding the contents of call writeKeyValue

public abstract class BeforeFilter implements SerializeFilter {
 protected final void writeKeyValue(String key, Object value) { ... }
 // 需要实现的抽象方法,在实现中调用writeKeyValue添加内容
 public abstract void writeBefore(Object object);
}

7, when AfterFilter serialized in the last add content

After all perform certain operations serialized object attributes, such as calling writeKeyValue add content

public abstract class AfterFilter implements SerializeFilter {
 protected final void writeKeyValue(String key, Object value) { ... }
 // 需要实现的抽象方法,在实现中调用writeKeyValue添加内容
 public abstract void writeAfter(Object object);
}

10.5, by ParseProcess custom deserialization

1 Introduction

ParseProcess programming extensions to customize deserialization interface. fastjson supports the following ParseProcess:

  • ExtraProcessor extra fields for processing
  • Type information provides extra fields for processing ExtraTypeProvider

2, the processing using the extra fields 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, for the type using ExtraTypeProvider provide extra fields

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类型了。

XI, integrated Fastjson in the Spring MVC

If you use Spring MVC to build Web applications and higher performance requirements, you can replace the default Spring MVC HttpMessageConverter to improve @RestController @ResponseBody @RequestBody annotated using JSON serialization speed FastJsonHttpMessageConverter Fastjson provided. The following configuration is very simple.

XML style

If you are using XML configuration Spring MVC way, then just add the following in Spring MVC XML configuration file to configure

<mvc:annotation-driven>
 <mvc:message-converters>
 <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/> 
 </mvc:message-converters>
</mvc:annotation-driven>

Usually the default configuration already meet most usage scenarios, if you want to customize it to the configuration, you can add FastJsonConfig Bean.

<mvc:annotation-driven>
 <mvc:message-converters>
 <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
 <property name="fastJsonConfig" ref="fastJsonConfig"/>
 </bean>
 </mvc:message-converters>
</mvc:annotation-driven>
<bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
 <!-- 自定义配置... -->
</bean>

Programmatic

If you are using a programmed manner (usually based on Spring Boot project) to configure Spring MVC, then simply extend WebMvcConfigurerAdapter can override configureMessageConverters method, like this below.

@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
 @Override
 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
 FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
 //自定义配置...
 //FastJsonConfig config = new FastJsonConfig();
 //config.set ...
 //converter.setFastJsonConfig(config);
 converters.add(0, converter);
 }
}

note:

1, if Fastjson version you are using less than 1.2.36, then (strongly recommend using the latest version), use FastJsonHttpMessageConverter4 when integrating with Spring MVC 4.X version.

2, SpringBoot 2.0.1 version WebMvcConfigurer loaded sequentially change occurs, it is required to use converters.add (0, converter); FastJsonHttpMessageConverter specified order within the converters, or preferably used in a version 2.0.1 and later SpringBoot Jackson processing.

XII integrated Fastjson in the Spring Data Redis

Usually we use RedisTemplate Redis is provided by Spring Data Redis carried out in the Spring, if you intend to use as a JSON object serialization / de-serialization of way and speed serialization have higher requirements, it is recommended to use Fastjson provided GenericFastJsonRedisSerializer or FastJsonRedisSerializer as RedisSerializer RedisTemplate of. The following configuration is very simple.

XML style

If you are using XML configuration Spring Data Redis way, then, simply RedisTemplate the Serializer replaced GenericFastJsonRedisSerializer can.

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
 <property name="connectionFactory" ref="jedisConnectionFactory"/>
 <property name="defaultSerializer">
 <bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
 </property>
</bean>

Here is the complete integration of Spring Redis configuration for reference.

<!-- Redis 连接池配置(可选) -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
 <property name="maxTotal" value="${redis.pool.maxActive}"/>
 <property name="maxIdle" value="${redis.pool.maxIdle}"/>
 <property name="maxWaitMillis" value="${redis.pool.maxWait}"/>
 <property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
 <!-- 更多连接池配置...-->
</bean>
<!-- Redis 连接工厂配置 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
 <!--设置连接池配置,不设置的话会使用默认的连接池配置,若想禁用连接池可设置 usePool = false --> 
 <property name="poolConfig" ref="jedisPoolConfig" /> 
 <property name="hostName" value="${host}"/>
 <property name="port" value="${port}"/>
 <property name="password" value="${password}"/>
 <property name="database" value="${database}"/>
 <!-- 更多连接工厂配置...-->
</bean>
<!-- RedisTemplate 配置 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
 <!-- 设置 Redis 连接工厂-->
 <property name="connectionFactory" ref="jedisConnectionFactory"/>
 <!-- 设置默认 Serializer ,包含 keySerializer & valueSerializer -->
 <property name="defaultSerializer">
 <bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
 </property>
 <!-- 单独设置 keySerializer -->
 <property name="keySerializer">
 <bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
 </property>
 <!-- 单独设置 valueSerializer -->
 <property name="valueSerializer">
 <bean class="com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer"/>
 </property>
</bean>

Programmatic

If you are using a programmed manner (usually based on Spring Boot project), then simply configure RedisTemplate (@Configuration be annotated modified class) in your configuration class explicitly create RedisTemplate Bean, you can set the Serializer.

@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
 RedisTemplate redisTemplate = new RedisTemplate();
 redisTemplate.setConnectionFactory(redisConnectionFactory);
 GenericFastJsonRedisSerializer fastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
 redisTemplate.setDefaultSerializer(fastJsonRedisSerializer);//设置默认的Serialize,包含 keySerializer & valueSerializer
 //redisTemplate.setKeySerializer(fastJsonRedisSerializer);//单独设置keySerializer
 //redisTemplate.setValueSerializer(fastJsonRedisSerializer);//单独设置valueSerializer
 return redisTemplate;
}

GenericFastJsonRedisSerializer most commonly used to meet the scene, if you want to define specific types of dedicated RedisTemplate can use FastJsonRedisSerializer instead GenericFastJsonRedisSerializer, the configuration is similar.

Guess you like

Origin blog.csdn.net/u012562943/article/details/95045389