用途:使用GSON获取一个大型JSON文件的输入流,并将其作为Iterator向下游函数公开;添加的约束使我无法将整个JSON存储在内存中。目前,我确实使用了一些基本的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"
}
}
}示例输出文档
{
"header":
{
"header1":"value1",
"header2":"value2",
"header3":"value3"
},
"object":
{
"id":"obj-1",
"name":"obj-1-name",
"description":"obj-1-description"
}
}POJO是为"header“对象、"body”JSON对象中的各个元素以及输出文档创建的。
使用下面的垫脚石作为初始解决问题的跳板,https://howtodoinjava.com/gson/jsonreader-streaming-json-parser/,我的理解是,由于JSON结构有一个转换,我需要完成这个基本的3步过程,只需将它转换为GSON特定的函数即可?
发布于 2021-11-26 15:25:22
正如链接教程中提到的,当您想要以流的方式处理JSON数据时,应该使用JsonReader。然后,您可以为POJO类使用从Gson获得的相应的TypeAdapter实例,并使用它们解析标头和单个body对象。
您还可以使用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类或它们的字段如何反序列化。
https://stackoverflow.com/questions/70099221
复制相似问题