Skip to content

Commit e2c5e39

Browse files
Add JsonType.streamAsLines() supporting writing new line delimited content / application/x-json-stream (#391)
Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
1 parent 1472c78 commit e2c5e39

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

blackbox-test/src/test/java/org/example/customer/stream/StreamBasicTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ void stream_toJson() {
2222
assertThat(asJson).isEqualTo("[{\"id\":1,\"name\":\"a\"},{\"id\":2,\"name\":\"b\"},{\"id\":3,\"name\":\"c\"}]");
2323
}
2424

25+
@Test
26+
void streamAsLines_toJsonFromJson() {
27+
JsonType<Stream<MyBasic>> streamType = type.streamAsLines();
28+
29+
String asJson = streamType.toJson(basics.stream());
30+
String expected = "{\"id\":1,\"name\":\"a\"}\n{\"id\":2,\"name\":\"b\"}\n{\"id\":3,\"name\":\"c\"}\n";
31+
assertThat(asJson)
32+
.describedAs("expect new line delimited json content")
33+
.isEqualTo(expected);
34+
35+
Stream<MyBasic> myBasicStream = streamType.fromJson(expected);
36+
List<MyBasic> list = myBasicStream.toList();
37+
assertThat(list).describedAs("reads new line delimited").isEqualTo(basics);
38+
39+
Stream<MyBasic> streamFromArray = streamType.fromJson("[{\"id\":1,\"name\":\"a\"},{\"id\":2,\"name\":\"b\"},{\"id\":3,\"name\":\"c\"}]");
40+
assertThat(streamFromArray.toList()).describedAs("reads array as well").isEqualTo(basics);
41+
}
42+
2543
@Test
2644
void stream_traditionalArray() {
2745
String arrayJson = jsonb.toJson(basics);

jsonb/src/main/java/io/avaje/jsonb/JsonType.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ public interface JsonType<T> extends JsonView<T>, JsonMapper.Type<T> {
9898
*/
9999
JsonType<Stream<T>> stream();
100100

101+
/**
102+
* Support a stream of beans writing as new line delimited json (application/x-json-stream).
103+
* <p>
104+
* This type can read content that is either new lime delimited or in array form.
105+
*
106+
* @return The stream type for this base JsonType.
107+
*/
108+
JsonType<Stream<T>> streamAsLines();
109+
101110
/**
102111
* Return the set type for this JsonType.
103112
*/

jsonb/src/main/java/io/avaje/jsonb/core/DJsonType.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,16 @@ public final JsonView<T> view(String dsl) {
3434

3535
@Override
3636
public JsonType<Stream<T>> stream() {
37-
return new DJsonStreamType<>(jsonb, Types.newParameterizedType(Stream.class, type), new StreamAdapter<>(adapter));
37+
return stream(false);
38+
}
39+
40+
@Override
41+
public JsonType<Stream<T>> streamAsLines() {
42+
return stream(true);
43+
}
44+
45+
private JsonType<Stream<T>> stream(boolean lineDelimited) {
46+
return new DJsonStreamType<>(jsonb, Types.newParameterizedType(Stream.class, type), new StreamAdapter<>(adapter, lineDelimited));
3847
}
3948

4049
@Override
@@ -125,7 +134,7 @@ private void close(Closeable outputStream) {
125134

126135
@Override
127136
public final Stream<T> stream(JsonReader reader) {
128-
return new StreamAdapter<>(adapter).fromJson(reader);
137+
return new StreamAdapter<>(adapter, false).fromJson(reader);
129138
}
130139

131140
@Override

jsonb/src/main/java/io/avaje/jsonb/core/StreamAdapter.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,26 @@
1414
final class StreamAdapter<T> implements DJsonClosable<Stream<T>>, JsonAdapter<Stream<T>> {
1515

1616
private final JsonAdapter<T> elementAdapter;
17+
private final boolean lineDelimited;
1718

18-
StreamAdapter(JsonAdapter<T> elementAdapter) {
19+
StreamAdapter(JsonAdapter<T> elementAdapter, boolean lineDelimited) {
1920
this.elementAdapter = elementAdapter;
21+
this.lineDelimited = lineDelimited;
2022
}
2123

2224
@Override
2325
public void toJson(JsonWriter writer, Stream<T> value) {
24-
writer.beginArray();
25-
value.forEach(bean -> elementAdapter.toJson(writer, bean));
26-
writer.endArray();
26+
if (lineDelimited) {
27+
writer.pretty(false);
28+
value.forEach(bean -> {
29+
elementAdapter.toJson(writer, bean);
30+
writer.writeNewLine();
31+
});
32+
} else {
33+
writer.beginArray();
34+
value.forEach(bean -> elementAdapter.toJson(writer, bean));
35+
writer.endArray();
36+
}
2737
}
2838

2939
@Override

0 commit comments

Comments
 (0)