Java tips: a flexible JSON building tool

1. Problem scenario

In fact, there are very mature and convenient schemes for the construction of JSON data in network transmission, but it is inevitable to encounter some non-standard special situations in practical work, such as:

  1. Similar data, the same field has different meanings in different interfaces and different value ranges;
  2. The same business entity has different number of fields in different interface interactions. For example, some require A field, while some do not.

These problems make it not very flexible to construct JSON by using the functions of framework and library. This article introduces a tool class for building JSON flexibly - JsonBuilder. (see last for complete code)

2. Common JSON construction methods

First, let's take a look at the possible JSON data construction methods, and analyze their advantages and disadvantages.

2.1 use the API of JSON third-party library directly

This method refers to the direct use of API s provided by popular JSON libraries such as gson and fastjason. For example, the following code uses gson:

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", 1);
jsonObject.addProperty("name", "test name");
String json = jsonObject.toString();

Advantages: flexible (all JSON can be built directly), and no additional classes will be generated for temporary data

Disadvantages: inconvenient, difficult to read and maintain (especially when there are many fields and complex structures)

2.2 class object mapping

This method refers to the method of directly converting the object of a class into JSON string. It is also the most commonly used method. It can be integrated into the framework. In the case of project specification, it should be the most perfect way. For example, the following code uses gson:

Gson gson = new Gson();
User user = new User();
user.setId(1);
user.setName("test name");
String json = gson.toJson(user);

Advantages: convenient (more suitable for integration into the framework), easy to read and low maintenance cost (in the case of project specifications)

Disadvantages: not particularly flexible (constructing temporary data will lead to a pile of temporary classes)

2.3 write JSON strings directly

Basically no one uses it. I don't need to explain much and I don't need to explain

String json = "{\"id\":1,\"name\":\"test name\"}";

Advantages: none (I won't say if there is)

Disadvantages: not easy to maintain, easy to cause problems, etc.

3. Use examples

  1. Building JSON objects
String json = JsonBuilder.forObject()
        .with("id", 1)
        .with("name", "test name")
        .build();
  1. Building nested JSON objects
//Object nested object
String json = JsonBuilder.forObject()
        .with("id", 1)
        .with("name", "test name")
        .with("role", JsonBuilder.forObject()
                .with("id", 11)
                .with("name", "student")
                .toJsonObject())
        .build();//{"id":1,"name":"test name","role":{"id":11,"name":"student"}}
  1. Building JSON arrays
String json = JsonBuilder.forArray()
        .add(1)
        .add(2)
        .build();//[1,2]
  1. Building objects that contain arrays
json = JsonBuilder.forObject()
        .with("id", 1)
        .with("array", JsonBuilder.forArray()
                .add(1)
                .add(2)
                .toJsonArray())
        .build();//{"id":1,"array":[1,2]}
  1. Building an array containing arrays
json = JsonBuilder.forArray()
        .add(1)
        .add(JsonBuilder.forArray()
                .add("s1")
                .add("s2")
                .toJsonArray())
        .build();//[1,["s1","s2"]]
  1. Building an array containing objects
json = JsonBuilder.forArray()
        .add(JsonBuilder.forObject()
                .with("id", 1)
                .with("name", "xiao ming")
                .toJsonObject())
        .add(JsonBuilder.forObject()
                .with("id", 2)
                .with("name", "ding ding")
                .toJsonObject())
        .build();//[{"id":1,"name":"xiao ming"},{"id":2,"name":"ding ding"}]
  1. Building objects based on existing JSON
String json = "{\"id\":1,\"name\":\"test name\"}";
json = JsonBuilder.fromObject(json)
        .with("sex", "male")
        .build();//{"id":1,"name":"test name","sex":"male"}
  1. Building arrays based on existing JSON
String json = "[1,2]";
json = JsonBuilder.fromArray(json)
        .add(3)
        .add(4)
        .build();//[1,2,3,4]

4. Function introduction

This tool class is based on the idea of builder mode, and uses the chain call of methods to achieve the purpose of smooth writing and clear expression.

4.1 start and end of build

JsonBuilder provides the following static methods for starting json Construction:

  • forArray() and forArray(int capacity) are used to build arrays;
  • forObject() is used to build objects;
  • fromObject(String json) is used to build objects from existing json;
  • fromArray(String json) is used to build arrays from existing json.

The completion of json construction depends on the call to the abstract method build().

4.2 with, add and set methods

The with method is used to add field properties to the object, including the following overloaded forms:

  • with(String key, String value): adds a string field
  • with(String key, Number value): adds a numeric field
  • with(String key, boolean value): adds a Boolean field
  • With (string key, character): adds a character field
  • with(String key, JsonElement element): add other JSON elements (see the description of toJsonObject and toJsonArray methods below for details)

The add method is used to add elements to the array and contains the following overloaded forms:

  • add(boolean value): adds a Boolean value
  • add(String value): adds a string
  • Add (character): adds a character
  • Add (number): adds a number
  • add(JsonElement json): add other JSON elements (see the description of toJsonObject and toJsonArray methods below for details)

The set method is used to set the indexed elements in the array, including the following overloaded forms:

  • set(int index, boolean value): set the element at index as the corresponding Boolean value
  • set(int index, String value): set the element at index as the corresponding string value
  • Set (int index, character): set the element at index as the corresponding character value
  • Set (int index, number): set the element at index as the corresponding number value
  • set(int index, JsonElement element):: set the element at index to the corresponding JSON element value

4.3 toJsonObject and toJsonArray methods

The values returned by these two methods can be used to call with(String key, JsonElement element) or add(JsonElement json) to realize the nesting of JSON data.

For example, if we implement JSON like the following:

{
  "id": 1,
  "name": "test name",
  "role": {
    "id": 11,
    "name": "student"
  }
}

Using JSON API to build is:

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", 1);
jsonObject.addProperty("name", "test name");

JsonObject roleJson = new JsonObject();
roleJson.addProperty("id", 11);
roleJson.addProperty("name", "student");
jsonObject.add("role", roleJson);
String json = jsonObject.toString();

If using object mapping:

Gson gson = new Gson();
User user = new User();
user.setId(1);
user.setName("test name");
Role role = new Role();
role.setId(11);
role.setName("student");
user.setRole(role);
String json = gson.toJson(user);

Note that jsonobject add("role", roleJson); And user setRole(role); To detect that it is a nested structure, replace it with JsonBuilder:

String json = JsonBuilder.forObject()
        .with("id", 1)
        .with("name", "test name")
        .with("role", JsonBuilder.forObject()
                .with("id", 11)
                .with("name", "student")
                .toJsonObject())
        .build();

The structure of JSON data is clear at a glance. (nested data uses nested code)

5. Complete code

import androidx.annotation.NonNull;
import com.google.gson.*;

public abstract class JsonBuilder {
    @NonNull
    @Override
    public String toString() {
        return build();
    }

    public abstract String build();

    public static ObjectBuilder forObject() {
        return new ObjectBuilder();
    }

    public static ArrayBuilder forArray() {
        return new ArrayBuilder();
    }

    public static ArrayBuilder forArray(int capacity) {
        return new ArrayBuilder(capacity);
    }

    public static ObjectBuilder fromObject(String json) {
        return new ObjectBuilder(json);
    }

    public static ArrayBuilder fromArray(String json) {
        return new ArrayBuilder(json);
    }

    public static class ObjectBuilder extends JsonBuilder {
        private final JsonObject object;

        ObjectBuilder() {
            this.object = new JsonObject();
        }

        ObjectBuilder(String json) {
            object = JsonParser.parseString(json).getAsJsonObject();
        }

        public ObjectBuilder with(String key, JsonElement element) {
            object.add(key, element);
            return this;
        }

        public ObjectBuilder with(String key, String value) {
            object.addProperty(key, value);
            return this;
        }

        public ObjectBuilder with(String key, Number value) {
            object.addProperty(key, value);
            return this;
        }

        public ObjectBuilder with(String key, boolean value) {
            object.addProperty(key, value);
            return this;
        }

        public ObjectBuilder with(String key, Character character) {
            object.addProperty(key, character);
            return this;
        }

        @Override
        public String build() {
            return object.toString();
        }

        public JsonObject toJsonObject() {
            return object;
        }
    }

    public static class ArrayBuilder extends JsonBuilder {
        private final JsonArray array;

        ArrayBuilder(String json) {
            array = JsonParser.parseString(json).getAsJsonArray();
        }

        ArrayBuilder(int capacity) {
            this.array = new JsonArray(capacity);
        }

        ArrayBuilder() {
            this.array = new JsonArray();
        }

        public ArrayBuilder add(boolean value) {
            array.add(value);
            return this;
        }

        public ArrayBuilder add(String value) {
            array.add(value);
            return this;
        }

        public ArrayBuilder add(Character character) {
            array.add(character);
            return this;
        }

        public ArrayBuilder add(Number number) {
            array.add(number);
            return this;
        }

        public ArrayBuilder add(JsonElement json) {
            array.add(json);
            return this;
        }

        public ArrayBuilder set(int index, boolean value) {
            array.set(index, new JsonPrimitive(value));
            return this;
        }

        public ArrayBuilder set(int index, String value) {
            array.set(index, new JsonPrimitive(value));
            return this;
        }

        public ArrayBuilder set(int index, Character character) {
            array.set(index, new JsonPrimitive(character));
            return this;
        }

        public ArrayBuilder set(int index, Number number) {
            array.set(index, new JsonPrimitive(number));
            return this;
        }

        public ArrayBuilder set(int index, JsonElement element) {
            array.set(index, element);
            return this;
        }

        @Override
        public String build() {
            return array.toString();
        }

        public JsonArray toJsonArray() {
            return array;
        }
    }
}

Note: the main functions of this class are implemented based on gson. If you want to change to other json libraries, you only need to replace JsonElement, JsonArray and JsonObject with corresponding classes and modify the return values of toJsonArray and toJsonObject methods.

Keywords: Java JSON gson

Added by public-image on Mon, 31 Jan 2022 03:45:07 +0200