其实,网络传输中JSON数据的构建已经有非常成熟、方便的方案,但是实际工作中难免会遇到一些不规范的特殊情况,例如:
这些问题使得在利用框架和库的功能来构造JSON时显得不是很灵活。而本文就向大家介绍一个用于灵活构建JSON的工具类–JsonBuilder。(完整代码见最后)
首先,我们先来看一下通常可能出现的JSON数据构建方式,并分析其优缺点。
这种方式指的是直接使用Gson、FastJson等流行的JSON库提供的API,例如下方使用gson的代码:
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("id", 1);
jsonObject.addProperty("name", "test name");
String json = jsonObject.toString();
优点:灵活(可以直接构建出所有JSON),对于临时数据不会产生额外的类
缺点:不方便,不易读,不容易维护(尤其是字段多、结构复杂的时候)
这种方式指的是把一个类的对象直接转换成JSON字符串的方式,也是最常用的方式,可以集成到框架中,在项目规范的情况下,应该是最完美的方式。例如下方使用gson的代码:
Gson gson = new Gson();
User user = new User();
user.setId(1);
user.setName("test name");
String json = gson.toJson(user);
优点:方便(比较适合集成到框架中),易读,维护成本低(项目规范的情况下)
缺点:不是特别灵活(构造临时数据会导致一堆临时的类)
基本没人用,不多解释,也不需解释
String json = "{\"id\":1,\"name\":\"test name\"}";
优点:无(即使有我也不说)
缺点:不容易维护,容易出问题,等等等等。
在介绍JsonBuilder
的API之前,先让我们来看几个简单的使用示例:
String json = JsonBuilder.forObject()
.with("id", 1)
.with("name", "test name")
.build();
//对象嵌套对象
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"}}
String json = JsonBuilder.forArray()
.add(1)
.add(2)
.build();//[1,2]
json = JsonBuilder.forObject()
.with("id", 1)
.with("array", JsonBuilder.forArray()
.add(1)
.add(2)
.toJsonArray())
.build();//{"id":1,"array":[1,2]}
json = JsonBuilder.forArray()
.add(1)
.add(JsonBuilder.forArray()
.add("s1")
.add("s2")
.toJsonArray())
.build();//[1,["s1","s2"]]
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"}]
String json = "{\"id\":1,\"name\":\"test name\"}";
json = JsonBuilder.fromObject(json)
.with("sex", "male")
.build();//{"id":1,"name":"test name","sex":"male"}
String json = "[1,2]";
json = JsonBuilder.fromArray(json)
.add(3)
.add(4)
.build();//[1,2,3,4]
这个工具类是基于建造者模式的思想来打造的,利用方法的链式调用来达到流畅编写、表达明确的目的。
JsonBuilder
提供了以下静态方法,用于json构建的开始:
forArray()
和forArray(int capacity)
用于构建数组;forObject()
用于构建对象;fromObject(String json)
用于从已有的json来构建对象;fromArray(String json)
用于从已有的json来构建数组。而完成json构建则依赖于对抽象方法build()
的调用。
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元素(具体见下方对toJsonObject
和toJsonArray
方法的说明)add
方法用于向数组中添加元素,包含以下重载形式:
add(boolean value)
:添加布尔add(String value)
:添加字符串add(Character character)
:添加字符add(Number number)
:添加数字add(JsonElement json)
:添加其他JSON元素(具体见下方对toJsonObject
和toJsonArray
方法的说明)set
方法用于设置数组中制定索引的元素,包含以下重载形式:
set(int index, boolean value)
:设置index处的元素为对应布尔值valueset(int index, String value)
:设置index处的元素为对应字符串valueset(int index, Character character)
:设置index处的元素为对应字符valueset(int index, Number number)
:设置index处的元素为对应数字valueset(int index, JsonElement element)
::设置index处的元素为对应JSON元素value可以用这两个方法返回的值来调用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数据的结构一目了然。(嵌套的数据就用嵌套的代码)
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库,只需要把JsonElement
、JsonArray
和JsonObject
换成对应的类,修改toJsonArray
和toJsonObject
方法的返回值即可。