• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.core.json;
2 
3 import java.io.IOException;
4 
5 import com.fasterxml.jackson.core.*;
6 import com.fasterxml.jackson.core.base.GeneratorBase;
7 import com.fasterxml.jackson.core.io.CharTypes;
8 import com.fasterxml.jackson.core.io.CharacterEscapes;
9 import com.fasterxml.jackson.core.io.IOContext;
10 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
11 import com.fasterxml.jackson.core.util.JacksonFeatureSet;
12 import com.fasterxml.jackson.core.util.VersionUtil;
13 
14 /**
15  * Intermediate base class shared by JSON-backed generators
16  * like {@link UTF8JsonGenerator} and {@link WriterBasedJsonGenerator}.
17  *
18  * @since 2.1
19  */
20 public abstract class JsonGeneratorImpl extends GeneratorBase
21 {
22     /*
23     /**********************************************************
24     /* Constants
25     /**********************************************************
26      */
27 
28     /**
29      * This is the default set of escape codes, over 7-bit ASCII range
30      * (first 128 character codes), used for single-byte UTF-8 characters.
31      */
32     protected final static int[] sOutputEscapes = CharTypes.get7BitOutputEscapes();
33 
34     /**
35      * Default capabilities for JSON generator implementations which do not
36      * different from "general textual" defaults
37      *
38      * @since 2.12
39      */
40     protected final static JacksonFeatureSet<StreamWriteCapability> JSON_WRITE_CAPABILITIES
41         = DEFAULT_TEXTUAL_WRITE_CAPABILITIES;
42 
43     /*
44     /**********************************************************
45     /* Configuration, basic I/O
46     /**********************************************************
47      */
48 
49     final protected IOContext _ioContext;
50 
51     /*
52     /**********************************************************
53     /* Configuration, output escaping
54     /**********************************************************
55      */
56 
57     /**
58      * Currently active set of output escape code definitions (whether
59      * and how to escape or not) for 7-bit ASCII range (first 128
60      * character codes). Defined separately to make potentially
61      * customizable
62      */
63     protected int[] _outputEscapes = sOutputEscapes;
64 
65     /**
66      * Value between 128 (0x80) and 65535 (0xFFFF) that indicates highest
67      * Unicode code point that will not need escaping; or 0 to indicate
68      * that all characters can be represented without escaping.
69      * Typically used to force escaping of some portion of character set;
70      * for example to always escape non-ASCII characters (if value was 127).
71      *<p>
72      * NOTE: not all sub-classes make use of this setting.
73      */
74     protected int _maximumNonEscapedChar;
75 
76     /**
77      * Definition of custom character escapes to use for generators created
78      * by this factory, if any. If null, standard data format specific
79      * escapes are used.
80      */
81     protected CharacterEscapes _characterEscapes;
82 
83     /*
84     /**********************************************************
85     /* Configuration, other
86     /**********************************************************
87      */
88 
89     /**
90      * Separator to use, if any, between root-level values.
91      *
92      * @since 2.1
93      */
94     protected SerializableString _rootValueSeparator
95         = DefaultPrettyPrinter.DEFAULT_ROOT_VALUE_SEPARATOR;
96 
97     /**
98      * Flag that is set if quoting is not to be added around
99      * JSON Object property names.
100      *
101      * @since 2.7
102      */
103     protected boolean _cfgUnqNames;
104 
105     /*
106     /**********************************************************
107     /* Life-cycle
108     /**********************************************************
109      */
110 
111     @SuppressWarnings("deprecation")
JsonGeneratorImpl(IOContext ctxt, int features, ObjectCodec codec)112     public JsonGeneratorImpl(IOContext ctxt, int features, ObjectCodec codec)
113     {
114         super(features, codec);
115         _ioContext = ctxt;
116         if (Feature.ESCAPE_NON_ASCII.enabledIn(features)) {
117             // inlined `setHighestNonEscapedChar()`
118             _maximumNonEscapedChar = 127;
119         }
120         _cfgUnqNames = !Feature.QUOTE_FIELD_NAMES.enabledIn(features);
121     }
122 
123     /*
124     /**********************************************************
125     /* Versioned
126     /**********************************************************
127      */
128 
129     @Override
version()130     public Version version() {
131         return VersionUtil.versionFor(getClass());
132     }
133 
134     /*
135     /**********************************************************
136     /* Overridden configuration methods
137     /**********************************************************
138      */
139 
140     @SuppressWarnings("deprecation")
141     @Override
enable(Feature f)142     public JsonGenerator enable(Feature f) {
143         super.enable(f);
144         if (f == Feature.QUOTE_FIELD_NAMES) {
145             _cfgUnqNames = false;
146         }
147         return this;
148     }
149 
150     @SuppressWarnings("deprecation")
151     @Override
disable(Feature f)152     public JsonGenerator disable(Feature f) {
153         super.disable(f);
154         if (f == Feature.QUOTE_FIELD_NAMES) {
155             _cfgUnqNames = true;
156         }
157         return this;
158     }
159 
160     @SuppressWarnings("deprecation")
161     @Override
_checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)162     protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures) {
163         super._checkStdFeatureChanges(newFeatureFlags, changedFeatures);
164         _cfgUnqNames = !Feature.QUOTE_FIELD_NAMES.enabledIn(newFeatureFlags);
165     }
166 
167     @Override
setHighestNonEscapedChar(int charCode)168     public JsonGenerator setHighestNonEscapedChar(int charCode) {
169         _maximumNonEscapedChar = (charCode < 0) ? 0 : charCode;
170         return this;
171     }
172 
173     @Override
getHighestEscapedChar()174     public int getHighestEscapedChar() {
175         return _maximumNonEscapedChar;
176     }
177 
178     @Override
setCharacterEscapes(CharacterEscapes esc)179     public JsonGenerator setCharacterEscapes(CharacterEscapes esc)
180     {
181         _characterEscapes = esc;
182         if (esc == null) { // revert to standard escapes
183             _outputEscapes = sOutputEscapes;
184         } else {
185             _outputEscapes = esc.getEscapeCodesForAscii();
186         }
187         return this;
188     }
189 
190     /**
191      * Method for accessing custom escapes factory uses for {@link JsonGenerator}s
192      * it creates.
193      */
194     @Override
getCharacterEscapes()195     public CharacterEscapes getCharacterEscapes() {
196         return _characterEscapes;
197     }
198 
199     @Override
setRootValueSeparator(SerializableString sep)200     public JsonGenerator setRootValueSeparator(SerializableString sep) {
201         _rootValueSeparator = sep;
202         return this;
203     }
204 
205     @Override
getWriteCapabilities()206     public JacksonFeatureSet<StreamWriteCapability> getWriteCapabilities() {
207         return JSON_WRITE_CAPABILITIES;
208     }
209 
210     /*
211     /**********************************************************
212     /* Shared helper methods
213     /**********************************************************
214      */
215 
_verifyPrettyValueWrite(String typeMsg, int status)216     protected void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException
217     {
218         // If we have a pretty printer, it knows what to do:
219         switch (status) {
220         case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
221             _cfgPrettyPrinter.writeArrayValueSeparator(this);
222             break;
223         case JsonWriteContext.STATUS_OK_AFTER_COLON:
224             _cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
225             break;
226         case JsonWriteContext.STATUS_OK_AFTER_SPACE:
227             _cfgPrettyPrinter.writeRootValueSeparator(this);
228             break;
229         case JsonWriteContext.STATUS_OK_AS_IS:
230             // First entry, but of which context?
231             if (_writeContext.inArray()) {
232                 _cfgPrettyPrinter.beforeArrayValues(this);
233             } else if (_writeContext.inObject()) {
234                 _cfgPrettyPrinter.beforeObjectEntries(this);
235             }
236             break;
237         case JsonWriteContext.STATUS_EXPECT_NAME:
238             _reportCantWriteValueExpectName(typeMsg);
239             break;
240         default:
241             _throwInternal();
242             break;
243         }
244     }
245 
_reportCantWriteValueExpectName(String typeMsg)246     protected void _reportCantWriteValueExpectName(String typeMsg) throws IOException
247     {
248         _reportError(String.format("Can not %s, expecting field name (context: %s)",
249                 typeMsg, _writeContext.typeDesc()));
250     }
251 }
252