Skip to content

Commit e6cf3d5

Browse files
committed
#3 - Add JsonWriter.writeRaw() to support x-json-stream content
Additionally, #2 Add JsonWriter.pretty(boolean) to support pretty formatted json
1 parent e0ea1af commit e6cf3d5

File tree

6 files changed

+136
-5
lines changed

6 files changed

+136
-5
lines changed

blackbox-test/src/test/java/org/example/customer/CustomerTest.java

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ class CustomerTest {
1313

1414
final String jsonStart = "{\"id\":42,\"name\":\"rob\",\"status\":\"ACTIVE\",\"whenCreated\":";
1515

16+
Jsonb jsonb = Jsonb.newBuilder().build();
17+
1618
@Test
1719
void toJson_view() {
18-
Jsonb jsonb = Jsonb.newBuilder().build();
1920
JsonView<Customer> customerJsonView = jsonb.type(Customer.class).view("(id, name)");
2021

2122
var customer = new Customer().id(42L).name("rob").status(Customer.Status.ACTIVE).whenCreated(Instant.now());
@@ -31,7 +32,6 @@ void toJson() {
3132
customer.contacts().add(new Contact(UUID.randomUUID(), "fo", "nar"));
3233
customer.contacts().add(new Contact(UUID.randomUUID(), "ba", "zar"));
3334

34-
Jsonb jsonb = Jsonb.newBuilder().build();
3535
JsonType<Customer> customerType = jsonb.type(Customer.class);
3636
String asJson = customerType.toJson(customer);
3737
assertThat(asJson).startsWith(jsonStart);
@@ -61,7 +61,6 @@ void toJson() {
6161

6262
@Test
6363
void fromObject() {
64-
var jsonb = Jsonb.newBuilder().build();
6564

6665
var customerJson = jsonb.type(Customer.class);
6766

@@ -99,7 +98,6 @@ void toJson_viaTypeObject() {
9998

10099
Object customerAsObject = new Customer().id(42L).name("rob").status(Customer.Status.ACTIVE);
101100

102-
Jsonb jsonb = Jsonb.newBuilder().build();
103101
String asJson = jsonb.type(Object.class).toJson(customerAsObject);
104102
assertThat(asJson).isEqualTo("{\"id\":42,\"name\":\"rob\",\"status\":\"ACTIVE\"}");
105103

@@ -108,4 +106,78 @@ void toJson_viaTypeObject() {
108106
assertThat(from1.name()).isEqualTo("rob");
109107
assertThat(from1.status()).isEqualTo(Customer.Status.ACTIVE);
110108
}
109+
110+
@Test
111+
void toJson_pretty() {
112+
StringWriter stringWriter = new StringWriter();
113+
try (JsonWriter writer = jsonb.writer(stringWriter)) {
114+
writer.pretty(true);
115+
Customer customer = new Customer().id(42L).name("rob").status(Customer.Status.ACTIVE);
116+
jsonb.type(Customer.class).toJson(writer, customer);
117+
}
118+
assertThat(stringWriter.toString()).isEqualTo("""
119+
{
120+
"id" : 42,
121+
"name" : "rob",
122+
"status" : "ACTIVE"
123+
}""");
124+
}
125+
126+
@Test
127+
void toJsonStream() {
128+
129+
var customers = List.of(
130+
new Customer().id(42L).name("rob").status(Customer.Status.ACTIVE),
131+
new Customer().id(43L).name("job").status(Customer.Status.NEW),
132+
new Customer().id(44L).name("bob").status(Customer.Status.ACTIVE));
133+
134+
JsonType<Customer> type = jsonb.type(Customer.class);
135+
StringWriter writer = new StringWriter();
136+
137+
try (JsonWriter jsonWriter = jsonb.writer(writer)) {
138+
jsonWriter.pretty(false);
139+
for (Customer customer : customers) {
140+
type.toJson(jsonWriter, customer);
141+
jsonWriter.writeRaw('\n');
142+
}
143+
}
144+
String streamJson = writer.toString();
145+
assertThat(streamJson).isEqualTo(
146+
"{\"id\":42,\"name\":\"rob\",\"status\":\"ACTIVE\"}\n" +
147+
" {\"id\":43,\"name\":\"job\",\"status\":\"NEW\"}\n" +
148+
" {\"id\":44,\"name\":\"bob\",\"status\":\"ACTIVE\"}\n");
149+
}
150+
151+
@Test
152+
void toJsonStream_viaMethod() {
153+
var customers = List.of(
154+
new Customer().id(42L).name("rob").status(Customer.Status.ACTIVE),
155+
new Customer().id(43L).name("job").status(Customer.Status.NEW),
156+
new Customer().id(44L).name("bob").status(Customer.Status.ACTIVE));
157+
158+
StringWriter writer = new StringWriter();
159+
try (JsonWriter jsonWriter = jsonb.writer(writer)) {
160+
toStream(customers.iterator(), jsonWriter);
161+
}
162+
163+
String streamJson = writer.toString();
164+
assertThat(streamJson).isEqualTo(
165+
"{\"id\":42,\"name\":\"rob\",\"status\":\"ACTIVE\"}\n" +
166+
" {\"id\":43,\"name\":\"job\",\"status\":\"NEW\"}\n" +
167+
" {\"id\":44,\"name\":\"bob\",\"status\":\"ACTIVE\"}\n");
168+
}
169+
170+
<T> void toStream(Iterator<T> iterator, JsonWriter jsonWriter) {
171+
if (iterator.hasNext()) {
172+
jsonWriter.pretty(false);
173+
T first = iterator.next();
174+
JsonType<T> type = jsonb.typeOf(first);
175+
type.toJson(jsonWriter, first);
176+
jsonWriter.writeRaw('\n');
177+
while (iterator.hasNext()) {
178+
type.toJson(jsonWriter, iterator.next());
179+
jsonWriter.writeRaw('\n');
180+
}
181+
}
182+
}
111183
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public interface JsonWriter extends Closeable, Flushable {
4747
*/
4848
boolean serializeEmpty();
4949

50+
/**
51+
* Set tp true to output json in pretty format.
52+
*/
53+
void pretty(boolean pretty);
54+
5055
/**
5156
* Return the current path.
5257
*/
@@ -159,6 +164,12 @@ public interface JsonWriter extends Closeable, Flushable {
159164
*/
160165
void jsonValue(Object value);
161166

167+
/**
168+
* Write raw content. This is typically used to write new line characters for
169+
* {@code x-json-stream} content.
170+
*/
171+
void writeRaw(char ch);
172+
162173
/**
163174
* Flush the writer.
164175
*/

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
import io.avaje.jsonb.spi.Bootstrap;
55
import io.avaje.jsonb.spi.PropertyNames;
66

7-
import java.io.*;
7+
import java.io.InputStream;
8+
import java.io.OutputStream;
9+
import java.io.Reader;
10+
import java.io.Writer;
811
import java.lang.reflect.Type;
912
import java.util.Iterator;
1013
import java.util.ServiceLoader;
@@ -115,6 +118,17 @@ static Builder newBuilder() {
115118
*/
116119
<T> JsonType<T> type(Type type);
117120

121+
/**
122+
* Return the JsonType for the given value using the values class.
123+
* <p>
124+
* This is a helper method that supports returning an inferred generic type.
125+
*
126+
* @param value The value of the given type
127+
* @param <T> The inferred generic parameter type
128+
* @return JsonType for the given value
129+
*/
130+
<T> JsonType<T> typeOf(Object value);
131+
118132
/**
119133
* Return the JsonAdapter used to read and write json for the given class.
120134
*/

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ public <T> JsonType<T> type(Type type) {
8383
return typeWithCache(type);
8484
}
8585

86+
@Override
87+
public <T> JsonType<T> typeOf(Object first) {
88+
requireNonNull(first);
89+
return type((Type)first.getClass());
90+
}
91+
8692
@SuppressWarnings("unchecked")
8793
private <T> JsonType<T> typeWithCache(Type type) {
8894
return (JsonType<T>) typeCache.computeIfAbsent(type, _type -> new DJsonType<>(this, _type, adapter(_type)));

jsonb/src/main/java/io/avaje/jsonb/jackson/JacksonWriter.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ public void flush() {
4747
}
4848
}
4949

50+
@Override
51+
public void pretty(boolean pretty) {
52+
if (!pretty) {
53+
generator.setPrettyPrinter(null);
54+
} else {
55+
generator.useDefaultPrettyPrinter();
56+
}
57+
}
58+
5059
@Override
5160
public void serializeNulls(boolean serializeNulls) {
5261
this.serializeNulls = serializeNulls;
@@ -324,6 +333,15 @@ public void value(BigInteger value) {
324333
}
325334
}
326335

336+
@Override
337+
public void writeRaw(char ch) {
338+
try {
339+
generator.writeRaw(ch);
340+
} catch (IOException e) {
341+
throw new JsonIoException(e);
342+
}
343+
}
344+
327345
@Override
328346
public void jsonValue(Object value) {
329347
if (value instanceof Map<?, ?>) {

jsonb/src/main/java/io/avaje/jsonb/spi/DelegateJsonWriter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public void serializeEmpty(boolean serializeEmpty) {
3636
delegate.serializeEmpty(serializeEmpty);
3737
}
3838

39+
@Override
40+
public void pretty(boolean pretty) {
41+
delegate.pretty(pretty);
42+
}
43+
3944
@Override
4045
public String path() {
4146
return delegate.path();
@@ -146,6 +151,11 @@ public void jsonValue(Object value) {
146151
delegate.jsonValue(value);
147152
}
148153

154+
@Override
155+
public void writeRaw(char ch) {
156+
delegate.writeRaw(ch);
157+
}
158+
149159
@Override
150160
public void close() {
151161
delegate.close();

0 commit comments

Comments
 (0)