Skip to content

Commit 56b96c5

Browse files
committed
#23 - Stream support when using jackson-core
1 parent dcb5594 commit 56b96c5

File tree

4 files changed

+228
-1
lines changed

4 files changed

+228
-1
lines changed

jsonb-jackson/src/main/java/io/avaje/jsonb/jackson/JacksonReader.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ final class JacksonReader implements JsonReader {
1515

1616
private final JsonParser parser;
1717
private final boolean failOnUnknown;
18+
private boolean streamArray;
1819

1920
JacksonReader(JsonParser parser, boolean failOnUnknown) {
2021
this.parser = parser;
@@ -61,6 +62,28 @@ public String readRaw() {
6162
}
6263
}
6364

65+
@Override
66+
public JsonReader streamArray(boolean streamArray) {
67+
this.streamArray = streamArray;
68+
return this;
69+
}
70+
71+
@Override
72+
public void beginStream() {
73+
try {
74+
if (streamArray && parser.currentToken() == null) {
75+
parser.nextToken();
76+
}
77+
} catch (IOException e) {
78+
throw new JsonIoException(e);
79+
}
80+
}
81+
82+
@Override
83+
public void endStream() {
84+
85+
}
86+
6487
@Override
6588
public void beginArray() {
6689
try {
@@ -81,7 +104,8 @@ public void endArray() {
81104
public boolean hasNextElement() {
82105
try {
83106
JsonToken token = parser.nextToken();
84-
return token != JsonToken.END_ARRAY;
107+
// token can be null when streaming new line delimited content
108+
return token != null && token != JsonToken.END_ARRAY;
85109
} catch (IOException e) {
86110
throw new JsonIoException(e);
87111
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.example;
2+
3+
import io.avaje.jsonb.JsonAdapter;
4+
import io.avaje.jsonb.JsonReader;
5+
import io.avaje.jsonb.JsonWriter;
6+
import io.avaje.jsonb.Jsonb;
7+
import io.avaje.jsonb.spi.Generated;
8+
import io.avaje.jsonb.spi.PropertyNames;
9+
import io.avaje.jsonb.spi.ViewBuilder;
10+
import io.avaje.jsonb.spi.ViewBuilderAware;
11+
12+
import java.lang.invoke.MethodHandle;
13+
14+
@Generated
15+
public final class MyBasicJsonAdapter extends JsonAdapter<StreamBasicTest.MyBasic> implements ViewBuilderAware {
16+
17+
// naming convention Match
18+
// id [int] name:id constructor
19+
// name [java.lang.String] name:name constructor
20+
21+
private final JsonAdapter<Integer> pintJsonAdapter;
22+
private final JsonAdapter<String> stringJsonAdapter;
23+
private final PropertyNames names;
24+
25+
public MyBasicJsonAdapter(Jsonb jsonb) {
26+
this.pintJsonAdapter = jsonb.adapter(Integer.TYPE);
27+
this.stringJsonAdapter = jsonb.adapter(String.class);
28+
this.names = jsonb.properties("id", "name");
29+
}
30+
31+
@Override
32+
public boolean isViewBuilderAware() {
33+
return true;
34+
}
35+
36+
@Override
37+
public ViewBuilderAware viewBuild() {
38+
return this;
39+
}
40+
41+
@Override
42+
public void build(ViewBuilder builder, String name, MethodHandle handle) {
43+
builder.beginObject(name, handle);
44+
builder.add("id", pintJsonAdapter, builder.method(StreamBasicTest.MyBasic.class, "id", int.class));
45+
builder.add("name", stringJsonAdapter, builder.method(StreamBasicTest.MyBasic.class, "name", String.class));
46+
builder.endObject();
47+
}
48+
49+
@Override
50+
public void toJson(JsonWriter writer, StreamBasicTest.MyBasic myBasic) {
51+
writer.beginObject();
52+
writer.names(names);
53+
writer.name(0);
54+
pintJsonAdapter.toJson(writer, myBasic.id);
55+
writer.name(1);
56+
stringJsonAdapter.toJson(writer, myBasic.name);
57+
writer.endObject();
58+
}
59+
60+
@Override
61+
public StreamBasicTest.MyBasic fromJson(JsonReader reader) {
62+
// variables to read json values into, constructor params don't need _set$ flags
63+
int _val$id = 0;
64+
String _val$name = null;
65+
66+
// read json
67+
reader.beginObject();
68+
reader.names(names);
69+
while (reader.hasNextField()) {
70+
String fieldName = reader.nextField();
71+
switch (fieldName) {
72+
case "id": {
73+
_val$id = pintJsonAdapter.fromJson(reader); break;
74+
}
75+
case "name": {
76+
_val$name = stringJsonAdapter.fromJson(reader); break;
77+
}
78+
default: {
79+
reader.unmappedField(fieldName);
80+
reader.skipValue();
81+
}
82+
}
83+
}
84+
reader.endObject();
85+
86+
// build and return MyBasic
87+
StreamBasicTest.MyBasic _$myBasic = new StreamBasicTest.MyBasic(_val$id, _val$name);
88+
return _$myBasic;
89+
}
90+
}

jsonb-jackson/src/test/java/org/example/MyComponent.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ public void register(Jsonb.Builder builder) {
1313
builder.add(Customer.class, CustomerJsonAdapter::new);
1414
builder.add(Contact.class, ContactJsonAdapter::new);
1515
builder.add(Address.class, AddressJsonAdapter::new);
16+
builder.add(StreamBasicTest.MyBasic.class, MyBasicJsonAdapter::new);
1617
}
1718
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package org.example;
2+
3+
import io.avaje.jsonb.Json;
4+
import io.avaje.jsonb.JsonReader;
5+
import io.avaje.jsonb.JsonType;
6+
import io.avaje.jsonb.Jsonb;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.stream.Stream;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
15+
class StreamBasicTest {
16+
17+
Jsonb jsonb = Jsonb.newBuilder()
18+
.add(MyBasic.class, MyBasicJsonAdapter::new)
19+
.build();
20+
21+
JsonType<MyBasic> type = jsonb.type(MyBasic.class);
22+
23+
@Json
24+
public static class MyBasic {
25+
public final int id;
26+
public final String name;
27+
28+
public MyBasic(int id, String name) {
29+
this.id = id;
30+
this.name = name;
31+
}
32+
33+
@Override
34+
public String toString() {
35+
return "MyBasic[id=" + id + ", name=" + name + "]";
36+
}
37+
}
38+
39+
private List<MyBasic> basicList() {
40+
List<MyBasic> basics = new ArrayList<>();
41+
basics.add(new MyBasic(1,"a"));
42+
basics.add(new MyBasic(2,"b"));
43+
basics.add(new MyBasic(3,"c"));
44+
return basics;
45+
}
46+
47+
@Test
48+
void stream_toJson() {
49+
String asJson = type.stream().toJson(basicList().stream());
50+
assertThat(asJson).isEqualTo("[{\"id\":1,\"name\":\"a\"},{\"id\":2,\"name\":\"b\"},{\"id\":3,\"name\":\"c\"}]");
51+
}
52+
53+
@Test
54+
void stream_traditionalArray() {
55+
String arrayJson = jsonb.toJson(basicList());
56+
StringBuilder sb = new StringBuilder();
57+
58+
try (JsonReader reader = jsonb.reader(arrayJson)) {
59+
Stream<MyBasic> asStream = type.stream(reader.streamArray(true));
60+
asStream.forEach(sb::append);
61+
}
62+
63+
assertThat(sb.toString()).isEqualTo("MyBasic[id=1, name=a]MyBasic[id=2, name=b]MyBasic[id=3, name=c]");
64+
65+
// same test but using - JsonType<Stream<T>>
66+
JsonType<Stream<MyBasic>> streamJsonType = type.stream();
67+
68+
sb = new StringBuilder();
69+
streamJsonType
70+
.fromJson(arrayJson)
71+
.forEach(sb::append);
72+
73+
assertThat(sb.toString()).isEqualTo("MyBasic[id=1, name=a]MyBasic[id=2, name=b]MyBasic[id=3, name=c]");
74+
}
75+
76+
@Test
77+
void stream_newLineDelimited() {
78+
String arrayJson = jsonb.toJson(basicList());
79+
String newLineDelimitedJson = arrayJson.replaceAll("[\\[|\\]]", "").replace("},{", "}\n{");
80+
81+
StringBuilder sb = new StringBuilder();
82+
try (JsonReader reader = jsonb.reader(newLineDelimitedJson)) {
83+
Stream<MyBasic> asStream = type.stream(reader.streamArray(false));
84+
asStream.forEach(sb::append);
85+
}
86+
87+
assertThat(sb.toString()).isEqualTo("MyBasic[id=1, name=a]MyBasic[id=2, name=b]MyBasic[id=3, name=c]");
88+
89+
// same test but using - JsonType<Stream<T>>
90+
JsonType<Stream<MyBasic>> streamJsonType = type.stream();
91+
92+
sb = new StringBuilder();
93+
try (Stream<MyBasic> myBasicStream = streamJsonType.fromJson(newLineDelimitedJson)) {
94+
myBasicStream.forEach(sb::append);
95+
assertThat(sb.toString()).isEqualTo("MyBasic[id=1, name=a]MyBasic[id=2, name=b]MyBasic[id=3, name=c]");
96+
}
97+
}
98+
99+
@Test
100+
void stream_spaceDelimited() {
101+
String arrayJson = "\n" + jsonb.toJson(basicList()) + "\n";
102+
String spaceDelimitedJson = arrayJson.replaceAll("[\\[|\\]]", "").replace("},{", "} {");
103+
104+
StringBuilder sb = new StringBuilder();
105+
try (JsonReader reader = jsonb.reader(spaceDelimitedJson)) {
106+
type.stream(reader).forEach(sb::append);
107+
}
108+
109+
assertThat(sb.toString()).isEqualTo("MyBasic[id=1, name=a]MyBasic[id=2, name=b]MyBasic[id=3, name=c]");
110+
}
111+
112+
}

0 commit comments

Comments
 (0)