我目前正在开展一个项目,我需要从Database
获取大量数据并将其解析为特定的 Json格式,当我将List传递给Gson
时,我已经构建了自定义序列化程序并且它正常工作。但由于我已经在Streams
Layer中使用JPA
,我认为我可以将Stream传递给Gson
解析器,以便它可以将其直接转换为我的Json数据。但是我得到一个空的Json对象而不是正确填充的对象。
所以,如果有人能指出我Gson
与Java 8 Streams
合作的方法,或者目前无法做到这一点......我在 Google上找不到任何东西,所以我来到 Stackoverflow 。
答案 0 :(得分:1)
您可以使用JsonWriter
将数据流式传输到输出流:
public void writeJsonStream(OutputStream out, Stream<DataObject> data) throws IOException {
try(JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"))) {
writer.setIndent(" ");
writer.beginArray();
data.forEach(d -> {
d.beginObject();
d.name("yourField").value(d.getYourField());
....
d.endObject();
});
writer.endArray();
}
}
请注意,您负责控制json结构。
也就是说,如果您的DataObject
包含嵌套对象,则必须分别编写beginObject()/endObject()
。嵌套数组也是如此。
答案 1 :(得分:1)
它并不像人们期望的那样微不足道,但它可以通用的方式完成。
当您查看Javadoc到TypeAdapterFactory
时,它们为自定义类型提供了一种非常简单的TypeAdapterFactory
编写方式。唉,由于元素类型检测的问题,它无法按预期工作。可以在Gson-internal CollectionTypeAdapterFactory
中找到执行此操作的正确方法。这是非常复杂的,但采取必要的一个可以得出类似的东西:
final class StreamTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType();
if (!Stream.class.isAssignableFrom(rawType)) {
return null;
}
Type elementType = ExtraGsonTypes.getStreamElementType(type, rawType);
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
return (TypeAdapter<T>) new StreamTypeAdapter<>(elementAdapter);
}
private static class StreamTypeAdapter<E> extends TypeAdapter<Stream<E>> {
private final TypeAdapter<E> elementAdapter;
StreamTypeAdapter(TypeAdapter<E> elementAdapter) {
this.elementAdapter = elementAdapter;
}
public void write(JsonWriter out, Stream<E> value) throws IOException {
out.beginArray();
for (E element : iterable(value)) {
elementAdapter.write(out, element);
}
out.endArray();
}
public Stream<E> read(JsonReader in) throws IOException {
Stream.Builder<E> builder = Stream.builder();
in.beginArray();
while (in.hasNext()) {
builder.add(elementAdapter.read(in));
}
in.endArray();
return builder.build();
}
}
private static <T> Iterable<T> iterable(Stream<T> stream) {
return stream::iterator;
}
}
ExtraGsonTypes
是一个特殊的类,我用来绕过对$Gson$Types.getSupertype
方法的包私有访问。如果您不使用JDK 9的模块,这是一个有效的黑客 - 您只需将此类放在与$Gson$Types
相同的包中:
package com.google.gson.internal;
import java.lang.reflect.*;
import java.util.stream.Stream;
public final class ExtraGsonTypes {
public static Type getStreamElementType(Type context, Class<?> contextRawType) {
return getContainerElementType(context, contextRawType, Stream.class);
}
private static Type getContainerElementType(Type context, Class<?> contextRawType, Class<?> containerSupertype) {
Type containerType = $Gson$Types.getSupertype(context, contextRawType, containerSupertype);
if (containerType instanceof WildcardType) {
containerType = ((WildcardType)containerType).getUpperBounds()[0];
}
if (containerType instanceof ParameterizedType) {
return ((ParameterizedType) containerType).getActualTypeArguments()[0];
}
return Object.class;
}
}
(我提交了issue about that in GitHub)
您可以通过以下方式使用它:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new StreamTypeAdapterFactory())
.create();
System.out.println(gson.toJson(Stream.of(1, 2, 3)));