1. 问题场景
Java处理JSON数据一般的做法便是经过第三方库将其转换为一个Java类的目标,可是这样会导致产生很多跟产品事务无关的临时类。在JavaScript中,则能够直接提取,例如obj.user.name
,十分便利。可是在Java中,假如不转换为类的目标,就得小心谨慎地编写像下面这样的代码:
try {
JsonElement element = JsonParser.parseString(jsonStr);
if (element.isJsonObject()) {
JsonObject userJson = element.getAsJsonObject().getAsJsonObject("user");
if (userJson != null) {
JsonPrimitive nameJson = userJson.getAsJsonPrimitive("name");
if (nameJson != null && nameJson.isString()) {
String name = nameJson.getAsString();
}
}
}
} catch (JsonParseException e) {
e.printStackTrace();
}
这样的办法十分繁琐,而且里边充溢防御性的代码,显得罗嗦,要害信息其实只要jsonStr.user.name
这样。而本文要介绍的便是不将JSON数据转换为某个 Java Bean 目标来提取JSON数据内容的一个东西类–JsonExtractor
。
2. 功能介绍
这个类比较简单,可是办法不少,因此我将这个类里的办法分为两类来讲
2.1 构建办法
如名,用于构建JsonExtractor
的办法,这里不推荐直接调用结构办法,而是以下几个办法来构建
- 静态办法
Builder from(String json)
:这个办法是整个进程的开端,传入参数为需求解析的JSON字符串,回来的目标是用于构建JsonExtractor
的制作者。 - 制作者办法
JsonExtractor<Integer, JsonArray> forJsonArray()
:这个办法指定要处理的JSON数组是数组类型,回来对应的处理JSON数组的提取器。 - 制作者办法
JsonExtractor<Void, JsonNull> forNull()
:这个办法指定要处理的JSON数据是null,根本不用。 - 制作者办法
JsonExtractor<Void, JsonPrimitive> forPrimitive()
:这个办法指定要处理的JSON数据是原始类型(例如,int、String等等),回来处理原始类型的提取器。 - 制作者办法
JsonExtractor<String, JsonObject> forJsonObject()
:这个办法指定要处理的JSON数据是JSON目标,回来处理JSON目标的提取器,比较常用。
2.2 提取办法
这些办法的参数根据JsonExtractor
的泛型K决定,假如当前目标为数组,则K为Integer
,表明数组的索引;假如是目标,则K为String
,表明特点对应的键值;假如是原始类型或null,由于没有下一级特点或内容,因此为Void
。
-
JsonArray getArray(K key)
:提取对应键值的特点为数组。 -
Optional<JsonArray> optArray(K key)
:getArray
的Optional版别。 -
int getInt(K key)
:提取对应键值的特点为int
,没有则回来0。 -
Optional<Integer> optInt(K key)
:getInt
的Optional版别。 -
boolean getBool(K key)
:提取对应键值的特点为boolean
,没有则回来false。 -
Optional<Boolean> optBool(K key)
:getBool
的Optional版别。 -
long getLong(K key)
:提取对应键值的特点为long
,没有则回来0。 -
Optional<Long> optLong(K key)
:getLong
的Optional版别。 -
String getString(K key)
:提取对应键值的特点为字符串,没有则回来空字符串。 -
Optional<String> optString(K key)
:getString
的Optional版别。 -
JsonElement get(K key)
和<T> T get(K key, Class<T> typeClass)
:提取指定键值的特点为JsonElement或指定Java类型。 -
Optional<JsonElement> opt(K key)
和<T> Optional<T> opt(K key, Class<T> typeClass)
:get
的Optional版别。 -
Builder into(K key)
:对指定键值的特点进行下一步提取,用于像data.user.name
这样的多级提取。 -
void forEach(BiConsumer<K, JsonElement> entryConsumer)
:对JSON数据的内容进行遍历。
3. 使用示例
例如,我们要提取的json如下:
{
"id": 1,
"name": "Li Lei",
"pet": {
"name": "huahua",
"type": "dog",
"id": 11
},
"live": true,
"age": 20,
"friends": [
"James",
"Andy",
"Tom"
]
}
对应的 Java Bean 如下:
class Pet {
private String name;
private String type;
private long id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
class User {
private long id;
private String name;
private Pet pet;
private boolean live;
private int age;
private String[] friends;
public String[] getFriends() {
return friends;
}
public void setFriends(String[] friends) {
this.friends = friends;
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
那么提取代码便是:
String json = "{\"id\":1,\"name\":\"Li Lei\",\"pet\":{\"name\":\"huahua\",\"type\":\"dog\",\"id\":11},\"live\":true,\"age\":20,\"friends\":[\"James\",\"Andy\",\"Tom\"]}";
JsonExtractor<String, JsonObject> extractor = JsonExtractor.from(json).forJsonObject();
//直接获取特点
long id = extractor.getLong("id");
//按Optional风格获取根本类型的特点
extractor.optString("name").ifPresent((String name) -> {
System.out.println("name:" + name);
});
extractor.optString("name").ifPresent(System.out::println);
//按Optional风格获取特点并手动转换为指定类
extractor.opt("pet").ifPresent((JsonElement element) -> {
System.out.println("pet json:" + element);
Pet pet = new Gson().fromJson(element, Pet.class);
System.out.println("pet bean 1:" + pet.getName());
});
//按Optional风格获取特点主动转换为指定类
extractor.opt("pet", Pet.class).ifPresent((Pet pet) -> {
System.out.println("pet bean 2:" + pet.getName());
});
//直接将特点提取为指定类型
Pet pet = extractor.get("pet", Pet.class);
//提取多级字段,类似js的 user.pet.name 这样的风格
extractor.into("pet").forJsonObject()
.optString("name").ifPresent((String name) -> {
System.out.println("pet.name:" + name);
});
//提取并遍历数组
extractor.into("friends").forJsonArray()
.forEach((Integer index, JsonElement element) -> {
System.out.println(index + ":" + element.getAsString());
});
4. 完好完成
import com.google.gson.*;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
public abstract class JsonExtractor<K, V> {
private static final Gson gson = new Gson();
protected V jsonElement;
JsonExtractor(V jsonElement) {
this.jsonElement = jsonElement;
}
public V getJsonElement() {
return jsonElement;
}
public static class Builder {
private JsonElement element;
protected Builder() {
}
public Builder(JsonElement element) {
this.element = element;
}
public JsonExtractor<Void, JsonNull> forNull() {
try {
return new NullExtractor(element.getAsJsonNull());
} catch (RuntimeException e) {
return new ErrorExtractor<>(e);
}
}
public JsonExtractor<Void, JsonPrimitive> forPrimitive() {
try {
return new PrimitiveExtractor(element.getAsJsonPrimitive());
} catch (RuntimeException e) {
return new ErrorExtractor<>(e);
}
}
public JsonExtractor<String, JsonObject> forJsonObject() {
try {
return new ObjectExtractor(element.getAsJsonObject());
} catch (RuntimeException e) {
return new ErrorExtractor<>(e);
}
}
public JsonExtractor<Integer, JsonArray> forJsonArray() {
try {
return new ArrayExtractor(element.getAsJsonArray());
} catch (RuntimeException e) {
return new ErrorExtractor<>(e);
}
}
}
private static class ErrorBuilder extends Builder {
private final Exception exception;
public ErrorBuilder(Exception exception) {
this.exception = exception;
}
@Override
public JsonExtractor<Integer, JsonArray> forJsonArray() {
return new ErrorExtractor<>(exception);
}
@Override
public JsonExtractor<Void, JsonNull> forNull() {
return new ErrorExtractor<>(exception);
}
@Override
public JsonExtractor<Void, JsonPrimitive> forPrimitive() {
return new ErrorExtractor<>(exception);
}
@Override
public JsonExtractor<String, JsonObject> forJsonObject() {
return new ErrorExtractor<>(exception);
}
}
public static Builder from(String json) {
try {
return new Builder(JsonParser.parseString(json));
} catch (Exception e) {
return new ErrorBuilder(e);
}
}
public Builder into(K key) {
return new ErrorBuilder(new RuntimeException("not implements!"));
}
public Optional<JsonElement> opt(K key) {
return Optional.ofNullable(get(key));
}
public <T> Optional<T> opt(K key, Class<T> typeClass) {
return Optional.empty();
}
public JsonElement get(K key) {
return null;
}
public <T> T get(K key, Class<T> typeClass) {
return opt(key, typeClass).orElse(null);
}
public JsonArray getArray(K key) {
return null;
}
public Optional<JsonArray> optArray(K key) {
return Optional.ofNullable(getArray(key));
}
public int getInt(K key) {
return optInt(key).orElse(0);
}
public Optional<Integer> optInt(K key) {
return Optional.empty();
}
public double getDouble(K key) {
return optDouble(key).orElse(0d);
}
public Optional<Double> optDouble(K key) {
return Optional.empty();
}
public boolean getBool(K key) {
return optBool(key).orElse(false);
}
public Optional<Boolean> optBool(K key) {
return Optional.empty();
}
public long getLong(K key) {
return optLong(key).orElse(0L);
}
public Optional<Long> optLong(K key) {
return Optional.empty();
}
public String getString(K key) {
return optString(key).orElse("");
}
public Optional<String> optString(K key) {
return Optional.empty();
}
public void forEach(BiConsumer<K, JsonElement> entryConsumer) {
}
private static class ObjectExtractor extends JsonExtractor<String, JsonObject> {
private ObjectExtractor(JsonObject jsonObject) {
super(jsonObject);
}
@Override
public Builder into(String key) {
JsonElement element = this.jsonElement.get(key);
return element == null ? new Builder(JsonNull.INSTANCE) : new Builder(element);
}
@Override
public JsonElement get(String key) {
return this.jsonElement.getAsJsonObject(key);
}
@Override
public Optional<JsonArray> optArray(String key) {
return Optional.ofNullable(this.jsonElement.getAsJsonArray(key));
}
@Override
public Optional<Integer> optInt(String key) {
return Optional.ofNullable(this.jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsInt);
}
@Override
public Optional<Double> optDouble(String key) {
return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsDouble);
}
@Override
public Optional<Boolean> optBool(String key) {
return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsBoolean);
}
@Override
public Optional<Long> optLong(String key) {
return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsLong);
}
@Override
public Optional<String> optString(String key) {
return Optional.ofNullable(jsonElement.getAsJsonPrimitive(key)).map(JsonPrimitive::getAsString);
}
@Override
public <T> Optional<T> opt(String key, Class<T> typeClass) {
try {
return Optional.ofNullable(jsonElement.get(key)).map(e -> gson.fromJson(e, typeClass));
} catch (JsonSyntaxException e) {
return Optional.empty();
}
}
@Override
public void forEach(BiConsumer<String, JsonElement> entryConsumer) {
Set<Map.Entry<String, JsonElement>> entrySet = jsonElement.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
entryConsumer.accept(entry.getKey(), entry.getValue());
}
}
}
private static class ArrayExtractor extends JsonExtractor<Integer, JsonArray> {
private ArrayExtractor(JsonArray array) {
super(array);
}
@Override
public Builder into(Integer index) {
try {
return new Builder(getJsonElement().get(index));
} catch (IndexOutOfBoundsException e) {
return new ErrorBuilder(e);
}
}
@Override
public JsonElement get(Integer index) {
try {
return getJsonElement().get(index);
} catch (IndexOutOfBoundsException e) {
return null;
}
}
@Override
public Optional<JsonArray> optArray(Integer index) {
return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsJsonArray);
}
@Override
public Optional<Integer> optInt(Integer index) {
try {
return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsInt);
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}
@Override
public Optional<Double> optDouble(Integer index) {
try {
return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsDouble);
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}
@Override
public Optional<Boolean> optBool(Integer index) {
try {
return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsBoolean);
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}
@Override
public Optional<Long> optLong(Integer index) {
try {
return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsLong);
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}
@Override
public Optional<String> optString(Integer index) {
try {
return Optional.ofNullable(getJsonElement().get(index)).map(JsonElement::getAsString);
} catch (IndexOutOfBoundsException e) {
return Optional.empty();
}
}
@Override
public <T> Optional<T> opt(Integer index, Class<T> typeClass) {
try {
return Optional.ofNullable(getJsonElement().get(index)).map(e -> gson.fromJson(e, typeClass));
} catch (JsonSyntaxException e) {
return Optional.empty();
}
}
@Override
public void forEach(BiConsumer<Integer, JsonElement> entryConsumer) {
for (int i = 0; i < getJsonElement().size(); i++) {
entryConsumer.accept(i, getJsonElement().get(i));
}
}
}
private static class NullExtractor extends JsonExtractor<Void, JsonNull> {
NullExtractor(JsonNull jsonElement) {
super(jsonElement);
}
}
private static class PrimitiveExtractor extends JsonExtractor<Void, JsonPrimitive> {
PrimitiveExtractor(JsonPrimitive jsonElement) {
super(jsonElement);
}
}
private static class ErrorExtractor<K, V> extends JsonExtractor<K, V> {
private final Exception exception;
private ErrorExtractor(Exception exception) {
super(null);
this.exception = exception;
}
@Override
public Builder into(K key) {
return new ErrorBuilder(exception);
}
}
}