Java小技巧:一个灵活的JSON构建工具

1. 问题场景

其实,网络传输中JSON数据的构建已经有非常成熟、方便的方案,但是实际工作中难免会遇到一些不规范的特殊情况,例如:

  1. 相似的数据同一字段在不同接口具有不同意义,不同的值的范围;
  2. 同一业务实体在不同接口交互中字段的数量不同,比如,一些需要A字段,而一些没有。

这些问题使得在利用框架和库的功能来构造JSON时显得不是很灵活。而本文就向大家介绍一个用于灵活构建JSON的工具类–JsonBuilder。(完整代码见最后)

2. 常见的JSON构建方式

首先,我们先来看一下通常可能出现的JSON数据构建方式,并分析其优缺点。

2.1 直接使用JSON三方库的API

这种方式指的是直接使用Gson、FastJson等流行的JSON库提供的API,例如下方使用gson的代码:

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

优点:灵活(可以直接构建出所有JSON),对于临时数据不会产生额外的类

缺点:不方便,不易读,不容易维护(尤其是字段多、结构复杂的时候)

2.2 类对象映射

这种方式指的是把一个类的对象直接转换成JSON字符串的方式,也是最常用的方式,可以集成到框架中,在项目规范的情况下,应该是最完美的方式。例如下方使用gson的代码:

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

优点:方便(比较适合集成到框架中),易读,维护成本低(项目规范的情况下)

缺点:不是特别灵活(构造临时数据会导致一堆临时的类)

2.3 直接编写JSON字符串

基本没人用,不多解释,也不需解释

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

优点:无(即使有我也不说)

缺点:不容易维护,容易出问题,等等等等。

3. 使用示例

在介绍JsonBuilder的API之前,先让我们来看几个简单的使用示例:

  1. 构建JSON对象
String json = JsonBuilder.forObject()
        .with("id", 1)
        .with("name", "test name")
        .build();
  1. 构建嵌套的JSON对象
//对象嵌套对象
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. 构建JSON数组
String json = JsonBuilder.forArray()
        .add(1)
        .add(2)
        .build();//[1,2]
  1. 构建包含数组的对象
json = JsonBuilder.forObject()
        .with("id", 1)
        .with("array", JsonBuilder.forArray()
                .add(1)
                .add(2)
                .toJsonArray())
        .build();//{"id":1,"array":[1,2]}
  1. 构建包含数组的数组
json = JsonBuilder.forArray()
        .add(1)
        .add(JsonBuilder.forArray()
                .add("s1")
                .add("s2")
                .toJsonArray())
        .build();//[1,["s1","s2"]]
  1. 构建包含对象的数组
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. 基于已有JSON来构建对象
String json = "{\"id\":1,\"name\":\"test name\"}";
json = JsonBuilder.fromObject(json)
        .with("sex", "male")
        .build();//{"id":1,"name":"test name","sex":"male"}
  1. 基于已有JSON来构建数组
String json = "[1,2]";
json = JsonBuilder.fromArray(json)
        .add(3)
        .add(4)
        .build();//[1,2,3,4]

4. 功能介绍

这个工具类是基于建造者模式的思想来打造的,利用方法的链式调用来达到流畅编写、表达明确的目的。

4.1 构建的开始和结束

JsonBuilder提供了以下静态方法,用于json构建的开始:

  • forArray()forArray(int capacity)用于构建数组;
  • forObject()用于构建对象;
  • fromObject(String json)用于从已有的json来构建对象;
  • fromArray(String json)用于从已有的json来构建数组。

而完成json构建则依赖于对抽象方法build()的调用。

4.2 with、add 和 set 方法

with方法用于向对象中添加字段属性,包含以下重载形式:

  • with(String key, String value):添加字符串字段
  • with(String key, Number value):添加数字字段
  • with(String key, boolean value):添加布尔字段
  • with(String key, Character character):添加字符字段
  • with(String key, JsonElement element):添加其他JSON元素(具体见下方对toJsonObjecttoJsonArray方法的说明)

add方法用于向数组中添加元素,包含以下重载形式:

  • add(boolean value):添加布尔
  • add(String value):添加字符串
  • add(Character character):添加字符
  • add(Number number):添加数字
  • add(JsonElement json):添加其他JSON元素(具体见下方对toJsonObjecttoJsonArray方法的说明)

set方法用于设置数组中制定索引的元素,包含以下重载形式:

  • set(int index, boolean value):设置index处的元素为对应布尔值value
  • set(int index, String value):设置index处的元素为对应字符串value
  • set(int index, Character character):设置index处的元素为对应字符value
  • set(int index, Number number):设置index处的元素为对应数字value
  • set(int index, JsonElement element)::设置index处的元素为对应JSON元素value

4.3 toJsonObject 和 toJsonArray 方法

可以用这两个方法返回的值来调用with(String key, JsonElement element)add(JsonElement json)进而实现JSON数据的嵌套。

例如,如果我们像实现下方这样的JSON:

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

使用JSON的API来构建就是:

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

如果用对象映射的方式:

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

这里要注意到jsonObject.add("role", roleJson);user.setRole(role);才能察觉是个嵌套结构,换成JsonBuilder后:

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

JSON数据的结构一目了然。(嵌套的数据就用嵌套的代码)

5. 完整代码

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

附注:这个类的主要功能基于gson来实现,如果要改为其他的json库,只需要把JsonElementJsonArrayJsonObject换成对应的类,修改toJsonArraytoJsonObject方法的返回值即可。

你可能感兴趣的:(Java,json,java,gson,建造者模式,临时JSON)