01, past life

I am Fastjson, a native of Hangzhou, but I always have an ambition to go to the world. My GitHub profile has been changed to English, isn’t it?

If your English proficiency is not my boss 666, I can simply translate (speak human language, not pretend to be pushy).

I am an open source JSON parsing library of Alibaba, which can serialize Java objects into JSON strings, and also deserialize JSON strings into Java objects.

  • I provided two kinds of parsing tools on the server side and android client side, and the performance was good.

  • I provide a convenient way to interchange Java objects and JSON, with the toJSONString() method for serialization and the parseObject() method for deserialization.

  • I allow conversion of pre-existing objects that cannot be modified (only class, no source code).

  • There is extensive support for Java generics.

  • I support arbitrarily complex objects (deep hierarchies of inheritance).

In 2012, I was selected as one of the most popular domestic open source software by Open Source China. After many years, my popularity has not abated, and I can say THAT I am NO. 1 in JSON because I have over 22K followers on GitHub, and NO one would dare to ignore my achievements.

02. Usage Guide

Before using my API, I need to introduce my dependencies in the POM.xml file.

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.58</version>
</dependency>
Copy the code

Let me write a simple test case, and you’ll see.

public class Test {
    public static void main(String[] args) {
        Writer writer = new Writer();
        writer.setAge(18);
        writer.setName("Silent King II."); String json = JSON.toJSONString(writer); System.out.println(json); }}class Writer {
    private int age;
    private String name;

    // getter/setter
}
Copy the code

Writer is a normal Java class with two fields, age and name, and their corresponding getter and setter methods.

The main() method creates a Writer object, and then calls a static method I provided, json.tojsonString (), to get the JSON string.

Take a look at the printed results.

{"age":18,"name":" Silent King 2 "}Copy the code

If you want to deserialize, just do the following.

Writer writer1 = JSON.parseObject(json, Writer.class);
Copy the code

Call the static method json.parseObject (), passing two arguments, a JSON string and the type of the object.

If you want to convert JSON strings into collections, you call another static method, json.parsearray ().

List<Writer> list = JSON.parseArray("[{\" age \ ": 18, \" name \ ": \" silence reigned two \ "}, {\ "age \" : 19, \ "name \" : \ "the king of silent a \"}]", Writer.class);
Copy the code

If there are no specific requirements, I can say that the above three methods should cover most of your business scenarios.

03. Use notes

Sometimes, the key in your JSON string might not match the field in your Java object, such as case; Sometimes you need to specify fields to serialize but not deserialize; Sometimes, you need the date field to be displayed in the specified format.

I have all of these special scenarios in mind for you, just add the @jsonField annotation to the corresponding field.

Let’s take a look at the definition of the @jsonField annotation.

public @interface JSONField {
    String name(a) default "";
    String format(a) default "";
    boolean serialize(a) default true;
    boolean deserialize(a) default true;
}
Copy the code

Name specifies the name of the field, format specifies the date format, and serialize and deserialize specifies whether to serialize or deserialize.

class Writer {
    private int age;
    private String name;
    private Date birthday;

    @jsonfield (format = "YYYY ")
    public Date getBirthday(a) {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @JSONField(name = "Age")
    public int getAge(a) {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @JSONField(serialize = false,deserialize = true)
    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name; }}Copy the code

I recommend using @jsonField annotations on getter fields. Take a look at the test code.

Writer writer = new Writer();
writer.setAge(18);
writer.setName("Silent King II.");
writer.setBirthday(new Date());

String json = JSON.toJSONString(writer);
System.out.println(json);
Copy the code

The output is as follows.

{"Age":18,"birthday":" 17 December 2020 "}Copy the code

The Age in the JSON string starts with an uppercase letter, birthday is in the format expected for “year month day”, and name does not appear in the result, indicating that it has not been serialized.

04. Serialization features

To meet more personalized requirements, I’ve defined a number of features in the SerializerFeature class that you can specify when calling the toJSONString() method.

  • PrettyFormat, to make the JSON format print a little bit prettier
  • WriteClassName, output class name
  • UseSingleQuotes, UseSingleQuotes for key
  • WriteNullListAsEmpty if List is empty []
  • WriteNullStringAsEmpty: if String is empty, print “”

Blah, blah, blah, more new skills, waiting for you to pick locks. I’ll write a simple demo here for your reference.

System.out.println(JSON.toJSONString(writer, 
SerializerFeature.PrettyFormat, 
SerializerFeature.UseSingleQuotes));
Copy the code

Compare the results before and after the configuration.

{"Age":18,"birthday":" 17 Dec 2020 "} {'Age':18, 'birthday':' 17 Dec 2020 '}Copy the code

05, why am I fast

As we all know, serializing Java objects into JSON strings is impossible with string concatenation because of poor performance. A better alternative to string concatenation is to use StringBuilder.

StringBuilder, as good as it is, has room for improvement in performance. “Do it yourself, make it rich,” so I created a SerializeWriter class just for serialization.

The SerializeWriter class contains a char[] buf that is allocated every time it is serialized, but I used ThreadLocal to optimize this, which effectively reduces object allocation and garbage collection to improve performance.

private final static ThreadLocal<char[]> bufLocal         = new ThreadLocal<char[] > ();public SerializeWriter(java.io.Writer writer, int defaultFeatures, SerializerFeature... features){
    this.writer = writer;

    buf = bufLocal.get();

    if(buf ! =null) {
        bufLocal.set(null);
    } else {
        buf = new char[2048]; }}Copy the code

There are many other details, such as using IdentityHashMap instead of HashMap, to avoid redundant equals operations and to avoid endless loops in multithreaded concurrency.

/**
 * for concurrent IdentityHashMap
 * 
 * @author wenshao[[email protected]]
 */
@SuppressWarnings("unchecked")
public class IdentityHashMap<K.V> {
    private final Entry<K, V>[] buckets;
    private final int           indexMask;
    public final static int DEFAULT_SIZE = 8192;
}
Copy the code

For example, use ASM technology to avoid reflection overhead.

I admit, the speed brings with it some security issues. The introduction of AutoType, in particular, has allowed hackers to take advantage.

1.2.59 release, enhanced security when AutoType is on

1.2.60 Release, added the AutoType blacklist, fixed denial of service security issues

Added the AutoType security blacklist in 1.2.61 Release

1.2.62 Release added AutoType blacklist, enhanced date deserialization and JSONPath

1.2.66 release, Bug fix security hardening, and do security hardening, add AutoType blacklist

1.2.67 release, Bug fix security hardening, added AutoType blacklist

1.2.68 release, support for GEOJSON, complement AutoType blacklist. (A safeMode configuration is introduced. After configuring safeMode, no matter the whitelist or blacklist, autoType is not supported.)

1.2.69 Release fixes the newly discovered high-risk AutoType switch to bypass security vulnerabilities and supplement the AutoType blacklist

1.2.70 release, improved compatibility, added AutoType blacklist

Lies in the hacker’s repeated contest, although I became more and more stable mature, but at the same time, let my users also paid a heavy price for this.

There are also a lot of dissonant voices on the Internet, claiming that I am one of the most rubbish domestic open source software, but with some opportunism to win the trust of domestic developers.

But more than that, you never give up on me.

The one that moved me the most was:

Almost single-handedly, Wen has built a widely used JSON library, while other libraries rely on a whole team. For this reason, Wen is worthy of being “the first generation of Ali open source who has never changed his mind”.

Loopholes are not terrible, what is terrible is not finding them, or failing to solve them.

In 1.2.68, I introduced safeMode security mode, which does not support AutoType for both whitelists and blacklists, so that attacks can be completely eliminated.

In safe mode, the checkAutoType() method throws an exception directly.

06, end

No matter how many difficulties there are in the road ahead, no matter how many rumors I have to face, I will forge ahead. For the vigorous development of domestic open source software, I am willing to be a pioneer, but also willing to be a persistent fighter.

The last article of 2020, let’s go for 2021, give it a thumbs up and hold on to this last moment.

Recommended reading:

A three wire programmer, in 2020, counted and | Denver annual essay

GitHub star 115K + Java tutorial is awesome!