Make writing a habit together! This is the fifth day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

Introduction to the

There are many ways to transfer data between programs. Binary protocols can be used to transfer data. Popular ones are thrift or Google’s Protobuf. These binary protocols can transfer data efficiently and save data volume in binary form, which can be very effective in some cases where speed and efficiency are a priority. And if different programming languages call each other, it can also be implemented through this binary protocol.

Although binary is faster and more efficient, it is not very friendly for programmers because it is difficult for a person to read binary files directly. Although there are some textual data transmission methods, such as XML, XML’s cumbersome tags cause a lot of inconvenience in using XML. Json, a universal text file transfer format, was born.

If you’re reading this, you’ll be familiar with JSON, but there are also more concise file formats, such as YAML, for those who are interested.

Here we want to talk about netty decoding json.

Json support in Java

Our use of JSON in Java is usually to convert an object into JSON for data transmission, or to parse the received JSON and convert it into an object.

Unfortunately, the JDK does not provide a useful JSON tool, so we usually need to use a third-party JSON package to implement Object and JSON conversion work.

Common uses include Google’s GSON, Alibaba’s FastJSON and Jackson.

Here we use Google’s GSON for the introduction.

We’ll focus on converting objects to JSON in Java, so we won’t cover the more powerful features of GSON.

First we create a JAVA object. We define a Student class as follows:

static class Student { String name; String phone; Integer age; public Student(String name, String phone, Integer age) { this.name = name; this.phone = phone; this.age = age; }}Copy the code

In this class, we define several different attributes and a constructor for Student. Let’s see how we can use GSON to convert this object to JSON:

        Student obj = new Student("tina","188888888",18);
        Gson gson = new Gson();
        String json = gson.toJson(obj);
        System.out.println(json);
        Student obj2 = gson.fromJson(json, Student.class);
        System.out.println(obj2);
Copy the code

GSON is very simple to use. Once we have built a GSON object, we can directly call its toJson method to convert the object into a JSON string.

The JSON string can then be converted to an object by calling json’s fromJson method.

The above code output looks like this:

{"name":"tina","phone":"188888888","age":18}
com.flydean.JsonTest$Student@4534b60d
Copy the code

Netty decoding of JSON

Json decoder netty provides a decoder for JSON called JsonObjectDecoder.

public class JsonObjectDecoder extends ByteToMessageDecoder
Copy the code

JsonObjectDecoder inherits ByteToMessageDecoder rather than MessageToMessageDecoder, unlike the base64 byte array explained earlier.

JsonObjectDecoder is directly converted from ByteBuf to JsonObject.

We know that there is no JSON object in the JDK. All objects are imported from third-party packages. Netty does not introduce new objects, so the object parsed from JSON in Netty is still a ByteBuf object, and in this ByteBuf contains a JSON object.

JsonObjectDecoder parsing logic is what?

Let’s start with the four states defined in JsonObjectDecoder:

    private static final int ST_CORRUPTED = -1;
    private static final int ST_INIT = 0;
    private static final int ST_DECODING_NORMAL = 1;
    private static final int ST_DECODING_ARRAY_STREAM = 2;
Copy the code

ST_INIT represents the initial state of decode, and ST_CORRUPTED represents the abnormal state that occurs in decode.

ST_DECODING_NORMAL represents a normal JSON, as follows:

{
	"source": "web",
	"type": "product_info",
	"time": 1641967014440,
	"data": {
		"id": 30000084318055,
		"staging": false
	},
	"dataId": "123456"
}
Copy the code

ST_DECODING_ARRAY_STREAM represents an array. An array is also an object, so arrays can also be represented as JSON. Here is a common JSON array:

[ "Google", "Runoob", "Taobao" ]
Copy the code

JsonObjectDecoder decoding logic is relatively simple, it is mainly read ByteBuf data, by judging the read data and JSON in the special curly braces, brackets, commas and other delimiters to split and parse json objects.

Note that JsonObjectDecoder decodes ByteBuf messages in UTF-8 format.

This is because json delimiters, even in UTF-8, are stored in a single byte, so we can compare the byte values with json delimiters during data reading to determine the boundaries between different objects in JSON.

In any other encoding, delimiters in JSON might be represented by multiple bytes, which makes parsing more difficult because we need to know when delimiters start and end.

The core decoding logic is as follows, first reading a byte from ByteBuf:

byte c = in.getByte(idx);
Copy the code

Then call decodeByte(C, in, IDX); To determine whether the current position is open parentheses, closed parentheses, inside an object string, or a new object string.

First, we need to make a judgment about the current state, which calls initDecoding method:

private void initDecoding(byte openingBrace) { openBraces = 1; if (openingBrace == '[' && streamArrayElements) { state = ST_DECODING_ARRAY_STREAM; } else { state = ST_DECODING_NORMAL; }}Copy the code

If it is a normal JSON object and the object is already in the closed parentheses state, the object has been read and can be converted to output:

 if (state == ST_DECODING_NORMAL) {
                decodeByte(c, in, idx);
                if (openBraces == 0) {
                    ByteBuf json = extractObject(ctx, in, in.readerIndex(), idx + 1 - in.readerIndex());
                    if (json != null) {
                        out.add(json);
                    }
    ...
Copy the code

If state means that it is currently an array object, the array object may contain multiple objects, which are distinguished by commas. There may also be Spaces between commas, so this data requires special judgment and processing, as shown below:

else if (state == ST_DECODING_ARRAY_STREAM) {
                decodeByte(c, in, idx);

                if (!insideString && (openBraces == 1 && c == ',' || openBraces == 0 && c == ']')) {
                    for (int i = in.readerIndex(); Character.isWhitespace(in.getByte(i)); i++) {
                        in.skipBytes(1);
                    }
                    int idxNoSpaces = idx - 1;
                    while (idxNoSpaces >= in.readerIndex() && Character.isWhitespace(in.getByte(idxNoSpaces))) {
                        idxNoSpaces--;
                    }
                    ByteBuf json = extractObject(ctx, in, in.readerIndex(), idxNoSpaces + 1 - in.readerIndex());
                    if (json != null) {
                        out.add(json);
                    }
    ....
Copy the code

Finally, the parsed JSON object is put into byteBuf’s out list, and the whole parsing ends there.

conclusion

The above is the use of JSON core decoder JsonObjectDecoder in Netty. Its essence is to divide multiple JSON strings by judging the segmentation in JSON objects, and then store the segmented JSON strings in ByteBuf for output.

Decoder and Encoder decoder and Encoder decoder Why is there only a JsonObjectDecoder in Netty and not a JsonObjectEncoder?

In fact, the Json object here is just a string containing Json characters that are written to ByteBuf, so no special encoder is required here.

This article is available at www.flydean.com/14-3-netty-…

The most popular interpretation, the most profound dry goods, the most concise tutorial, many tips you didn’t know waiting for you to discover!

Welcome to pay attention to my public number: “procedures those things”, understand technology, more understand you!