Java JSON提取工具JsonExtractor的使用
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); } } }
到此这篇关于Java JSON提取工具JsonExtractor的使用的文章就介绍到这了,更多相关Java JSON提取工具JsonExtractor内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
基于 SpringBoot 实现 MySQL 读写分离的问题
这篇文章主要介绍了基于 SpringBoot 实现 MySQL 读写分离的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-02-02查找native方法的本地实现函数native_function详解
JDK开放给用户的源码中随处可见Native方法,被Native关键字声明的方法说明该方法不是以Java语言实现的,而是以本地语言实现的,Java可以直接拿来用。这里介绍下查找native方法的本地实现函数native_function,感兴趣的朋友跟随小编一起看看吧2021-12-12
最新评论