[英]Using GSON to transform a nested JSON Stream
目的:使用 GSON 获取大型 JSON 文件的输入 stream 并将其公开为迭代器的下游功能; 加上我物理上无法将整个 JSON 文件存储在 memory 中的约束。 目前,我确实使用一些基本的 Java 代码进行了这项工作,这些代码执行以下操作:
期望的结果看看 GSON 是否具有替换我自定义 Java 代码的内置功能。
样本输入文件
{
"header":
{
"header1":"value1",
"header2":"value2",
"header3":"value3"
},
"body":
{
"obj-1":
{
"id":"obj-1",
"name":"obj-1-name",
"description":"obj-1-description"
},
"obj-2":
{
"id":"obj-2",
"name":"obj-2-name",
"description":"obj-2-description"
},
"obj-3":
{
"id":"obj-3",
"name":"obj-3-name",
"description":"obj-3-description"
},
"obj-4":
{
"id":"obj-4",
"name":"obj-4-name",
"description":"obj-4-description"
}
}
}
样品 OUTPUT 文档
{
"header":
{
"header1":"value1",
"header2":"value2",
"header3":"value3"
},
"object":
{
"id":"obj-1",
"name":"obj-1-name",
"description":"obj-1-description"
}
}
POJO's have been created for the "header" object, the individual elements in the "body" JSON Object, and the output document.
使用以下内容作为初步解决问题的垫脚石, https://howtodoinjava.com/gson/jsonreader-streaming-json-parser/ ,我的理解是,由于存在 JSON 结构的转换,我需要执行基本的 3 步过程; 只是翻译成GSON具体功能?
如链接教程中所述,当您想以流方式处理 JSON 数据时,应使用JsonReader
。 然后,您可以使用从 Gson 获得的相应TypeAdapter
实例用于您的 POJO 类,并使用它们来解析 header 和各个主体对象。
您也可以使用Gson.fromJson(JsonReader, ...)
方法,而不是直接使用TypeAdapter
实例; 然而 Gson 不幸的是不尊重宽大设置/总是让读者宽大。 除非您明确需要这样做,否则我建议您不要这样做,而是直接使用TypeAdapter
实例,因为这样会尊重JsonReader
的宽松设置。
假设您有以下 POJO 类:
public class Header {
public String header1;
public String header2;
public String header3;
}
public class BodyObject {
public String id;
public String name;
public String description;
}
public class OutputDocument {
public Header header;
public BodyObject object;
}
然后,您可以创建一个创建Stream<OutputDocument>
的方法,如下所示。 在此处使用Stream
的优点是它的close
方法可用于关闭提供 JSON 数据的Reader
。 但是,它也可以使用Iterator
以类似的方式实现。
/**
* Creates a {@link Stream} which transforms the data to {@link OutputDocument} elements.
*
* <p><b>Important:</b> The provided reader will be closed by this method, or by the created
* stream. It is therefore necessary to call {@link Stream#close()} (for example by using a
* try-with-resources statement).
*
* @param inputDocumentReader JSON data stream
* @param gson Gson object used for looking up adapters
* @return Stream of transformed elements
*/
public static Stream<OutputDocument> transform(Reader inputDocumentReader, Gson gson) throws IOException {
JsonReader jsonReader = new JsonReader(inputDocumentReader);
try {
jsonReader.beginObject();
String headerProperty = jsonReader.nextName();
if (!headerProperty.equals("header")) {
throw new IllegalArgumentException("Expected 'header' property at " + jsonReader.getPath());
}
// Read the Header
TypeAdapter<Header> headerAdapter = gson.getAdapter(Header.class);
Header header = headerAdapter.read(jsonReader);
String bodyProperty = jsonReader.nextName();
if (!bodyProperty.equals("body")) {
throw new IllegalArgumentException("Expected 'body' property at " + jsonReader.getPath());
}
// Start reading body
jsonReader.beginObject();
TypeAdapter<BodyObject> bodyObjectAdapter = gson.getAdapter(BodyObject.class);
long estimatedSize = Long.MAX_VALUE; // unknown size
// Could also add `| NONNULL`, if there are no null body objects
int characteristics = Spliterator.Spliterator.ORDERED;
Spliterator<OutputDocument> spliterator = new AbstractSpliterator<>(estimatedSize, characteristics) {
@Override
public boolean tryAdvance(Consumer<? super OutputDocument> action) {
try {
// Check if end of 'body' object has been reached
if (!jsonReader.hasNext()) {
// End 'body'
jsonReader.endObject();
// End top level object
jsonReader.endObject();
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new IllegalStateException("Expected end of JSON document at " + jsonReader.getPath());
}
// Reached end
return false;
} else {
// Skip entry name
jsonReader.skipValue();
BodyObject object = bodyObjectAdapter.read(jsonReader);
// Create combined OutputDocument
OutputDocument result = new OutputDocument();
result.header = header;
result.object = object;
action.accept(result);
return true;
}
} catch (IOException e) {
throw new UncheckedIOException("Failed reading next element", e);
}
}
};
return StreamSupport.stream(spliterator, false) // false, don't create parallel stream
.onClose(() -> {
try {
jsonReader.close();
} catch (IOException e) {
throw new UncheckedIOException("Failed closing JsonReader", e);
}
});
}
catch (Exception e) {
try {
jsonReader.close();
} catch (IOException suppressed) {
e.addSuppressed(suppressed);
}
throw e;
}
}
然后可以像这样调用此方法:
try (Stream<OutputDocument> stream = transform(inputDocumentReader, new Gson())) {
...
}
inputDocumentReader
是您为 InputDocument 文件创建的Reader
。 Gson
实例可以是新实例(如上例所示),也可以是您使用GsonBuilder
创建的实例,以防您注册自定义适配器以自定义 POJO 类或其字段的反序列化方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.