Skip to content

Commit c896ac9

Browse files
committed
Some changes past #1051; add tests, release notes
1 parent edc944e commit c896ac9

File tree

6 files changed

+115
-16
lines changed

6 files changed

+115
-16
lines changed

release-notes/CREDITS-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ Aaron Digulla:
5656
* Contributed #1042: Allow configuring spaces before and/or after the colon in
5757
`DefaultPrettyPrinter`
5858
(2.16.0)
59+
* Contributed #1051: Add `JsonGeneratorDecorator` to allow decorating `JsonGenerator`s
60+
(2.16.0)
5961

6062
Derek Clarkson (drekka@github)
6163
* Reported #184: WRITE_NUMBERS_AS_STRINGS disables WRITE_BIGDECIMAL_AS_PLAIN

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ a pure JSON library.
3333
(contributed by @digulla)
3434
#1050: Compare `_snapshotInfo` in `Version`
3535
(contributed by @artoonie)
36+
#1051: Add `JsonGeneratorDecorator` to allow decorating `JsonGenerator`s
37+
(contributed by @digulla)
3638

3739
2.15.2 (30-May-2023)
3840

src/main/java/com/fasterxml/jackson/core/JsonFactory.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.fasterxml.jackson.core.util.BufferRecycler;
2323
import com.fasterxml.jackson.core.util.BufferRecyclers;
2424
import com.fasterxml.jackson.core.util.JacksonFeature;
25+
import com.fasterxml.jackson.core.util.JsonGeneratorDecorator;
2526
import com.fasterxml.jackson.core.util.Separators;
2627

2728
/**
@@ -293,6 +294,14 @@ public static int collectDefaults() {
293294
*/
294295
protected OutputDecorator _outputDecorator;
295296

297+
/**
298+
* List of {@link JsonGeneratorDecorator}s to apply to {@link JsonGenerator}s
299+
* after construction; applied in the order of addition.
300+
*
301+
* @since 2.16
302+
*/
303+
protected final List<JsonGeneratorDecorator> _generatorDecorators;
304+
296305
/**
297306
* Separator used between root-level values, if any; null indicates
298307
* "do not add separator".
@@ -319,9 +328,6 @@ public static int collectDefaults() {
319328
*/
320329
protected final char _quoteChar;
321330

322-
/** @since 2.16 */
323-
protected List<JsonGeneratorDecorator> _generatorDecorators = new ArrayList<>();
324-
325331
/*
326332
/**********************************************************
327333
/* Construction
@@ -344,6 +350,7 @@ public JsonFactory(ObjectCodec oc) {
344350
_objectCodec = oc;
345351
_quoteChar = DEFAULT_QUOTE_CHAR;
346352
_streamReadConstraints = StreamReadConstraints.defaults();
353+
_generatorDecorators = null;
347354
}
348355

349356
/**
@@ -364,6 +371,7 @@ protected JsonFactory(JsonFactory src, ObjectCodec codec)
364371
_generatorFeatures = src._generatorFeatures;
365372
_inputDecorator = src._inputDecorator;
366373
_outputDecorator = src._outputDecorator;
374+
_generatorDecorators = _copy(src._generatorDecorators);
367375
_streamReadConstraints = src._streamReadConstraints == null ?
368376
StreamReadConstraints.defaults() : src._streamReadConstraints;
369377

@@ -390,6 +398,7 @@ public JsonFactory(JsonFactoryBuilder b) {
390398
_generatorFeatures = b._streamWriteFeatures;
391399
_inputDecorator = b._inputDecorator;
392400
_outputDecorator = b._outputDecorator;
401+
_generatorDecorators = _copy(b._generatorDecorators);
393402
_streamReadConstraints = b._streamReadConstraints == null ?
394403
StreamReadConstraints.defaults() : b._streamReadConstraints;
395404

@@ -398,7 +407,6 @@ public JsonFactory(JsonFactoryBuilder b) {
398407
_rootValueSeparator = b._rootValueSeparator;
399408
_maximumNonEscapedChar = b._maximumNonEscapedChar;
400409
_quoteChar = b._quoteChar;
401-
_generatorDecorators = new ArrayList<>(b._generatorDecorators);
402410
}
403411

404412
/**
@@ -417,6 +425,7 @@ protected JsonFactory(TSFBuilder<?,?> b, boolean bogus) {
417425
_generatorFeatures = b._streamWriteFeatures;
418426
_inputDecorator = b._inputDecorator;
419427
_outputDecorator = b._outputDecorator;
428+
_generatorDecorators = _copy(b._generatorDecorators);
420429
_streamReadConstraints = b._streamReadConstraints == null ?
421430
StreamReadConstraints.defaults() : b._streamReadConstraints;
422431

@@ -487,6 +496,14 @@ protected void _checkInvalidCopy(Class<?> exp)
487496
}
488497
}
489498

499+
// @since 2.16
500+
protected static <T> List<T> _copy(List<T> src) {
501+
if (src == null) {
502+
return src;
503+
}
504+
return new ArrayList<T>(src);
505+
}
506+
490507
/*
491508
/**********************************************************
492509
/* Serializable overrides
@@ -1901,13 +1918,6 @@ protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOEx
19011918
return _decorate(gen);
19021919
}
19031920

1904-
private JsonGenerator _decorate(JsonGenerator result) {
1905-
for(JsonGeneratorDecorator decorator : _generatorDecorators) {
1906-
result = decorator.decorate(this, result);
1907-
}
1908-
return result;
1909-
}
1910-
19111921
/**
19121922
* Overridable factory method that actually instantiates generator for
19131923
* given {@link OutputStream} and context object, using UTF-8 encoding.
@@ -2008,6 +2018,25 @@ protected final Writer _decorate(Writer out, IOContext ctxt) throws IOException
20082018
return out;
20092019
}
20102020

2021+
/**
2022+
* Helper method for applying all registered {@link JsonGeneratorDecorator}s
2023+
* on freshly constructed {@link JsonGenerator}.
2024+
*
2025+
* @param g Generator constructed that is to be decorated
2026+
*
2027+
* @return Generator after applying all registered {@link JsonGeneratorDecorator}s.
2028+
*
2029+
* @since 2.16
2030+
*/
2031+
protected JsonGenerator _decorate(JsonGenerator g) {
2032+
if (_generatorDecorators != null) {
2033+
for (JsonGeneratorDecorator decorator : _generatorDecorators) {
2034+
g = decorator.decorate(this, g);
2035+
}
2036+
}
2037+
return g;
2038+
}
2039+
20112040
/*
20122041
/**********************************************************
20132042
/* Internal factory methods, other

src/main/java/com/fasterxml/jackson/core/TSFBuilder.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.core.io.OutputDecorator;
88
import com.fasterxml.jackson.core.json.JsonReadFeature;
99
import com.fasterxml.jackson.core.json.JsonWriteFeature;
10+
import com.fasterxml.jackson.core.util.JsonGeneratorDecorator;
1011

1112
/**
1213
* Since 2.10, Builder class is offered for creating token stream factories
@@ -87,8 +88,10 @@ public abstract class TSFBuilder<F extends JsonFactory,
8788
*/
8889
protected StreamReadConstraints _streamReadConstraints;
8990

90-
/** @since 2.16 */
91-
protected List<JsonGeneratorDecorator> _generatorDecorators = new ArrayList<>();
91+
/**
92+
* @since 2.16
93+
*/
94+
protected List<JsonGeneratorDecorator> _generatorDecorators;
9295

9396
/*
9497
/**********************************************************************
@@ -291,6 +294,9 @@ public B streamReadConstraints(StreamReadConstraints streamReadConstraints) {
291294
// // // Other methods
292295

293296
public B decorateWith(JsonGeneratorDecorator decorator) {
297+
if (_generatorDecorators == null) {
298+
_generatorDecorators = new ArrayList<>();
299+
}
294300
_generatorDecorators.add(decorator);
295301
return _this();
296302
}

src/main/java/com/fasterxml/jackson/core/JsonGeneratorDecorator.java renamed to src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDecorator.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
package com.fasterxml.jackson.core;
1+
package com.fasterxml.jackson.core.util;
22

3-
public interface JsonGeneratorDecorator {
3+
import com.fasterxml.jackson.core.JsonFactory;
4+
import com.fasterxml.jackson.core.JsonGenerator;
5+
6+
/**
7+
* Simple interface to allow adding decorators around {@link JsonGenerator}s.
8+
*
9+
* @since 2.16
10+
*/
11+
public interface JsonGeneratorDecorator
12+
{
413
/**
514
* Allow to decorate {@link JsonGenerator} instances returned by {@link JsonFactory}.
615
*

src/test/java/com/fasterxml/jackson/core/json/TestDecorators.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import com.fasterxml.jackson.core.io.IOContext;
77
import com.fasterxml.jackson.core.io.InputDecorator;
88
import com.fasterxml.jackson.core.io.OutputDecorator;
9+
import com.fasterxml.jackson.core.util.JsonGeneratorDecorator;
10+
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
911

1012
/**
1113
* Unit tests to verify that input and output decorators work as
@@ -63,9 +65,28 @@ public Writer decorate(IOContext ctxt, Writer w) throws IOException
6365
}
6466
}
6567

68+
static class SimpleGeneratorDecorator implements JsonGeneratorDecorator
69+
{
70+
@Override
71+
public JsonGenerator decorate(JsonFactory factory, JsonGenerator generator) {
72+
return new TextHider(generator);
73+
}
74+
75+
static class TextHider extends JsonGeneratorDelegate {
76+
public TextHider(JsonGenerator g) {
77+
super(g);
78+
}
79+
80+
@Override
81+
public void writeString(String text) throws IOException {
82+
delegate.writeString("***");
83+
}
84+
}
85+
}
86+
6687
/*
6788
/**********************************************************
68-
/* Unit tests
89+
/* Unit tests: input/output decoration
6990
/**********************************************************
7091
*/
7192

@@ -142,4 +163,34 @@ public void testDeprecatedMethods() throws IOException
142163
f.setOutputDecorator(outDec);
143164
assertSame(outDec, f.getOutputDecorator());
144165
}
166+
167+
/*
168+
/**********************************************************
169+
/* Unit tests: input/output decoration
170+
/**********************************************************
171+
*/
172+
173+
public void testGeneratorDecoration() throws IOException
174+
{
175+
JsonFactory f = JsonFactory.builder()
176+
.decorateWith(new SimpleGeneratorDecorator())
177+
.build();
178+
179+
StringWriter sw = new StringWriter();
180+
try (JsonGenerator g = f.createGenerator(sw)) {
181+
g.writeStartObject();
182+
g.writeStringField("password", "s3cr37!!!");
183+
g.writeEndObject();
184+
}
185+
assertEquals(a2q("{'password':'***'}"), sw.toString());
186+
187+
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
188+
try (JsonGenerator g = f.createGenerator(bytes)) {
189+
g.writeStartObject();
190+
g.writeStringField("password", "s3cr37x!!");
191+
g.writeEndObject();
192+
}
193+
assertEquals(a2q("{'password':'***'}"), utf8String(bytes));
194+
}
195+
145196
}

0 commit comments

Comments
 (0)