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