• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.core.base;
2 
3 import com.fasterxml.jackson.core.*;
4 import com.fasterxml.jackson.core.json.DupDetector;
5 import com.fasterxml.jackson.core.json.JsonWriteContext;
6 import com.fasterxml.jackson.core.json.PackageVersion;
7 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
8 
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.math.BigDecimal;
12 
13 /**
14  * This base class implements part of API that a JSON generator exposes
15  * to applications, adds shared internal methods that sub-classes
16  * can use and adds some abstract methods sub-classes must implement.
17  */
18 public abstract class GeneratorBase extends JsonGenerator
19 {
20     public final static int SURR1_FIRST = 0xD800;
21     public final static int SURR1_LAST = 0xDBFF;
22     public final static int SURR2_FIRST = 0xDC00;
23     public final static int SURR2_LAST = 0xDFFF;
24 
25     /**
26      * Set of feature masks related to features that need updates of other
27      * local configuration or state.
28      *
29      * @since 2.5
30      */
31     @SuppressWarnings("deprecation")
32     protected final static int DERIVED_FEATURES_MASK =
33             Feature.WRITE_NUMBERS_AS_STRINGS.getMask()
34             | Feature.ESCAPE_NON_ASCII.getMask()
35             | Feature.STRICT_DUPLICATE_DETECTION.getMask()
36             ;
37 
38     // // // Constants for validation messages (since 2.6)
39 
40     protected final static String WRITE_BINARY = "write a binary value";
41     protected final static String WRITE_BOOLEAN = "write a boolean value";
42     protected final static String WRITE_NULL = "write a null";
43     protected final static String WRITE_NUMBER = "write a number";
44     protected final static String WRITE_RAW = "write a raw (unencoded) value";
45     protected final static String WRITE_STRING = "write a string";
46 
47     /**
48      * This value is the limit of scale allowed for serializing {@link BigDecimal}
49      * in "plain" (non-engineering) notation; intent is to prevent asymmetric
50      * attack whereupon simple eng-notation with big scale is used to generate
51      * huge "plain" serialization. See [core#315] for details.
52      *
53      * @since 2.7.7
54      */
55     protected final static int MAX_BIG_DECIMAL_SCALE = 9999;
56 
57     /*
58     /**********************************************************
59     /* Configuration
60     /**********************************************************
61      */
62 
63     protected ObjectCodec _objectCodec;
64 
65     /**
66      * Bit flag composed of bits that indicate which
67      * {@link com.fasterxml.jackson.core.JsonGenerator.Feature}s
68      * are enabled.
69      */
70     protected int _features;
71 
72     /**
73      * Flag set to indicate that implicit conversion from number
74      * to JSON String is needed (as per
75      * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#WRITE_NUMBERS_AS_STRINGS}).
76      */
77     protected boolean _cfgNumbersAsStrings;
78 
79     /*
80     /**********************************************************
81     /* State
82     /**********************************************************
83      */
84 
85     /**
86      * Object that keeps track of the current contextual state
87      * of the generator.
88      */
89     protected JsonWriteContext _writeContext;
90 
91     /**
92      * Flag that indicates whether generator is closed or not. Gets
93      * set when it is closed by an explicit call
94      * ({@link #close}).
95      */
96     protected boolean _closed;
97 
98     /*
99     /**********************************************************
100     /* Life-cycle
101     /**********************************************************
102      */
103 
104     @SuppressWarnings("deprecation")
GeneratorBase(int features, ObjectCodec codec)105     protected GeneratorBase(int features, ObjectCodec codec) {
106         super();
107         _features = features;
108         _objectCodec = codec;
109         DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
110                 ? DupDetector.rootDetector(this) : null;
111         _writeContext = JsonWriteContext.createRootContext(dups);
112         _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(features);
113     }
114 
115     /**
116      * @since 2.5
117      */
118     @SuppressWarnings("deprecation")
GeneratorBase(int features, ObjectCodec codec, JsonWriteContext ctxt)119     protected GeneratorBase(int features, ObjectCodec codec, JsonWriteContext ctxt) {
120         super();
121         _features = features;
122         _objectCodec = codec;
123         _writeContext = ctxt;
124         _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(features);
125     }
126 
127     /**
128      * Implemented with standard version number detection algorithm, typically using
129      * a simple generated class, with information extracted from Maven project file
130      * during build.
131      */
version()132     @Override public Version version() { return PackageVersion.VERSION; }
133 
134     @Override
getCurrentValue()135     public Object getCurrentValue() {
136         return _writeContext.getCurrentValue();
137     }
138 
139     @Override
setCurrentValue(Object v)140     public void setCurrentValue(Object v) {
141         if (_writeContext != null) {
142             _writeContext.setCurrentValue(v);
143         }
144     }
145 
146     /*
147     /**********************************************************
148     /* Configuration
149     /**********************************************************
150      */
151 
152 
isEnabled(Feature f)153     @Override public final boolean isEnabled(Feature f) { return (_features & f.getMask()) != 0; }
getFeatureMask()154     @Override public int getFeatureMask() { return _features; }
155 
156     //public JsonGenerator configure(Feature f, boolean state) { }
157 
158     @SuppressWarnings("deprecation")
159     @Override
enable(Feature f)160     public JsonGenerator enable(Feature f) {
161         final int mask = f.getMask();
162         _features |= mask;
163         if ((mask & DERIVED_FEATURES_MASK) != 0) {
164             // why not switch? Requires addition of a generated class, alas
165             if (f == Feature.WRITE_NUMBERS_AS_STRINGS) {
166                 _cfgNumbersAsStrings = true;
167             } else if (f == Feature.ESCAPE_NON_ASCII) {
168                 setHighestNonEscapedChar(127);
169             } else if (f == Feature.STRICT_DUPLICATE_DETECTION) {
170                 if (_writeContext.getDupDetector() == null) { // but only if disabled currently
171                     _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this));
172                 }
173             }
174         }
175         return this;
176     }
177 
178     @SuppressWarnings("deprecation")
179     @Override
disable(Feature f)180     public JsonGenerator disable(Feature f) {
181         final int mask = f.getMask();
182         _features &= ~mask;
183         if ((mask & DERIVED_FEATURES_MASK) != 0) {
184             if (f == Feature.WRITE_NUMBERS_AS_STRINGS) {
185                 _cfgNumbersAsStrings = false;
186             } else if (f == Feature.ESCAPE_NON_ASCII) {
187                 setHighestNonEscapedChar(0);
188             } else if (f == Feature.STRICT_DUPLICATE_DETECTION) {
189                 _writeContext = _writeContext.withDupDetector(null);
190             }
191         }
192         return this;
193     }
194 
195     @Override
196     @Deprecated
setFeatureMask(int newMask)197     public JsonGenerator setFeatureMask(int newMask) {
198         int changed = newMask ^ _features;
199         _features = newMask;
200         if (changed != 0) {
201             _checkStdFeatureChanges(newMask, changed);
202         }
203         return this;
204     }
205 
206     @Override // since 2.7
overrideStdFeatures(int values, int mask)207     public JsonGenerator overrideStdFeatures(int values, int mask) {
208         int oldState = _features;
209         int newState = (oldState & ~mask) | (values & mask);
210         int changed = oldState ^ newState;
211         if (changed != 0) {
212             _features = newState;
213             _checkStdFeatureChanges(newState, changed);
214         }
215         return this;
216     }
217 
218     /**
219      * Helper method called to verify changes to standard features.
220      *
221      * @param newFeatureFlags Bitflag of standard features after they were changed
222      * @param changedFeatures Bitflag of standard features for which setting
223      *    did change
224      *
225      * @since 2.7
226      */
227     @SuppressWarnings("deprecation")
_checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)228     protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
229     {
230         if ((changedFeatures & DERIVED_FEATURES_MASK) == 0) {
231             return;
232         }
233         _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(newFeatureFlags);
234         if (Feature.ESCAPE_NON_ASCII.enabledIn(changedFeatures)) {
235             if (Feature.ESCAPE_NON_ASCII.enabledIn(newFeatureFlags)) {
236                 setHighestNonEscapedChar(127);
237             } else {
238                 setHighestNonEscapedChar(0);
239             }
240         }
241         if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(changedFeatures)) {
242             if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newFeatureFlags)) { // enabling
243                 if (_writeContext.getDupDetector() == null) { // but only if disabled currently
244                     _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this));
245                 }
246             } else { // disabling
247                 _writeContext = _writeContext.withDupDetector(null);
248             }
249         }
250     }
251 
useDefaultPrettyPrinter()252     @Override public JsonGenerator useDefaultPrettyPrinter() {
253         // Should not override a pretty printer if one already assigned.
254         if (getPrettyPrinter() != null) {
255             return this;
256         }
257         return setPrettyPrinter(_constructDefaultPrettyPrinter());
258     }
259 
setCodec(ObjectCodec oc)260     @Override public JsonGenerator setCodec(ObjectCodec oc) {
261         _objectCodec = oc;
262         return this;
263     }
264 
getCodec()265     @Override public ObjectCodec getCodec() { return _objectCodec; }
266 
267     /*
268     /**********************************************************
269     /* Public API, accessors
270     /**********************************************************
271      */
272 
273     /**
274      * Note: type was co-variant until Jackson 2.7; reverted back to
275      * base type in 2.8 to allow for overriding by subtypes that use
276      * custom context type.
277      */
getOutputContext()278     @Override public JsonStreamContext getOutputContext() { return _writeContext; }
279 
280     /*
281     /**********************************************************
282     /* Public API, write methods, structural
283     /**********************************************************
284      */
285 
286     //public void writeStartArray() throws IOException
287     //public void writeEndArray() throws IOException
288     //public void writeStartObject() throws IOException
289     //public void writeEndObject() throws IOException
290 
291     @Override // since 2.8
writeStartObject(Object forValue)292     public void writeStartObject(Object forValue) throws IOException
293     {
294         writeStartObject();
295         if (forValue != null) {
296             setCurrentValue(forValue);
297         }
298     }
299 
300     /*
301     /**********************************************************
302     /* Public API, write methods, textual
303     /**********************************************************
304      */
305 
writeFieldName(SerializableString name)306     @Override public void writeFieldName(SerializableString name) throws IOException {
307         writeFieldName(name.getValue());
308     }
309 
310     //public abstract void writeString(String text) throws IOException;
311 
312     //public abstract void writeString(char[] text, int offset, int len) throws IOException;
313 
314     //public abstract void writeString(Reader reader, int len) throws IOException;
315 
316     //public abstract void writeRaw(String text) throws IOException,;
317 
318     //public abstract void writeRaw(char[] text, int offset, int len) throws IOException;
319 
320     @Override
writeString(SerializableString text)321     public void writeString(SerializableString text) throws IOException {
322         writeString(text.getValue());
323     }
324 
writeRawValue(String text)325     @Override public void writeRawValue(String text) throws IOException {
326         _verifyValueWrite("write raw value");
327         writeRaw(text);
328     }
329 
writeRawValue(String text, int offset, int len)330     @Override public void writeRawValue(String text, int offset, int len) throws IOException {
331         _verifyValueWrite("write raw value");
332         writeRaw(text, offset, len);
333     }
334 
writeRawValue(char[] text, int offset, int len)335     @Override public void writeRawValue(char[] text, int offset, int len) throws IOException {
336         _verifyValueWrite("write raw value");
337         writeRaw(text, offset, len);
338     }
339 
writeRawValue(SerializableString text)340     @Override public void writeRawValue(SerializableString text) throws IOException {
341         _verifyValueWrite("write raw value");
342         writeRaw(text);
343     }
344 
345     @Override
writeBinary(Base64Variant b64variant, InputStream data, int dataLength)346     public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException {
347         // Let's implement this as "unsupported" to make it easier to add new parser impls
348         _reportUnsupportedOperation();
349         return 0;
350     }
351 
352     /*
353     /**********************************************************
354     /* Public API, write methods, primitive
355     /**********************************************************
356      */
357 
358     // Not implemented at this level, added as placeholders
359 
360      /*
361     public abstract void writeNumber(int i)
362     public abstract void writeNumber(long l)
363     public abstract void writeNumber(double d)
364     public abstract void writeNumber(float f)
365     public abstract void writeNumber(BigDecimal dec)
366     public abstract void writeBoolean(boolean state)
367     public abstract void writeNull()
368     */
369 
370     /*
371     /**********************************************************
372     /* Public API, write methods, POJOs, trees
373     /**********************************************************
374      */
375 
376     @Override
writeObject(Object value)377     public void writeObject(Object value) throws IOException {
378         if (value == null) {
379             // important: call method that does check value write:
380             writeNull();
381         } else {
382             /* 02-Mar-2009, tatu: we are NOT to call _verifyValueWrite here,
383              *   because that will be done when codec actually serializes
384              *   contained POJO. If we did call it it would advance state
385              *   causing exception later on
386              */
387             if (_objectCodec != null) {
388                 _objectCodec.writeValue(this, value);
389                 return;
390             }
391             _writeSimpleObject(value);
392         }
393     }
394 
395     @Override
writeTree(TreeNode rootNode)396     public void writeTree(TreeNode rootNode) throws IOException {
397         // As with 'writeObject()', we are not check if write would work
398         if (rootNode == null) {
399             writeNull();
400         } else {
401             if (_objectCodec == null) {
402                 throw new IllegalStateException("No ObjectCodec defined");
403             }
404             _objectCodec.writeValue(this, rootNode);
405         }
406     }
407 
408     /*
409     /**********************************************************
410     /* Public API, low-level output handling
411     /**********************************************************
412      */
413 
flush()414     @Override public abstract void flush() throws IOException;
close()415     @Override public void close() throws IOException { _closed = true; }
isClosed()416     @Override public boolean isClosed() { return _closed; }
417 
418     /*
419     /**********************************************************
420     /* Package methods for this, sub-classes
421     /**********************************************************
422      */
423 
424     /**
425      * Method called to release any buffers generator may be holding,
426      * once generator is being closed.
427      */
_releaseBuffers()428     protected abstract void _releaseBuffers();
429 
430     /**
431      * Method called before trying to write a value (scalar or structured),
432      * to verify that this is legal in current output state, as well as to
433      * output separators if and as necessary.
434      *
435      * @param typeMsg Additional message used for generating exception message
436      *   if value output is NOT legal in current generator output state.
437      */
_verifyValueWrite(String typeMsg)438     protected abstract void _verifyValueWrite(String typeMsg) throws IOException;
439 
440     /**
441      * Overridable factory method called to instantiate an appropriate {@link PrettyPrinter}
442      * for case of "just use the default one", when {@link #useDefaultPrettyPrinter()} is called.
443      *
444      * @since 2.6
445      */
_constructDefaultPrettyPrinter()446     protected PrettyPrinter _constructDefaultPrettyPrinter() {
447         return new DefaultPrettyPrinter();
448     }
449 
450     /**
451      * Helper method used to serialize a {@link java.math.BigDecimal} as a String,
452      * for serialization, taking into account configuration settings
453      *
454      * @since 2.7.7
455      */
_asString(BigDecimal value)456     protected String _asString(BigDecimal value) throws IOException {
457         if (Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)) {
458             // 24-Aug-2016, tatu: [core#315] prevent possible DoS vector
459             int scale = value.scale();
460             if ((scale < -MAX_BIG_DECIMAL_SCALE) || (scale > MAX_BIG_DECIMAL_SCALE)) {
461                 _reportError(String.format(
462 "Attempt to write plain `java.math.BigDecimal` (see JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) with illegal scale (%d): needs to be between [-%d, %d]",
463 scale, MAX_BIG_DECIMAL_SCALE, MAX_BIG_DECIMAL_SCALE));
464             }
465             return value.toPlainString();
466         }
467         return value.toString();
468     }
469 
470     /*
471     /**********************************************************
472     /* UTF-8 related helper method(s)
473     /**********************************************************
474      */
475 
476     /**
477      * @since 2.5
478      */
_decodeSurrogate(int surr1, int surr2)479     protected final int _decodeSurrogate(int surr1, int surr2) throws IOException
480     {
481         // First is known to be valid, but how about the other?
482         if (surr2 < SURR2_FIRST || surr2 > SURR2_LAST) {
483             String msg = "Incomplete surrogate pair: first char 0x"+Integer.toHexString(surr1)+", second 0x"+Integer.toHexString(surr2);
484             _reportError(msg);
485         }
486         int c = 0x10000 + ((surr1 - SURR1_FIRST) << 10) + (surr2 - SURR2_FIRST);
487         return c;
488     }
489 }
490