| /* Jackson JSON-processor. | |
| * | |
| * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi | |
| * | |
| * Licensed under the License specified in file LICENSE, included with | |
| * the source code and binary code bundles. | |
| * You may not use this file except in compliance with the License. | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package org.codehaus.jackson; | |
| import java.io.*; | |
| import java.lang.ref.SoftReference; | |
| import java.net.URL; | |
| import org.codehaus.jackson.format.InputAccessor; | |
| import org.codehaus.jackson.format.MatchStrength; | |
| import org.codehaus.jackson.io.*; | |
| import org.codehaus.jackson.impl.ByteSourceBootstrapper; | |
| import org.codehaus.jackson.impl.ReaderBasedParser; | |
| import org.codehaus.jackson.impl.Utf8Generator; | |
| import org.codehaus.jackson.impl.WriterBasedGenerator; | |
| import org.codehaus.jackson.sym.BytesToNameCanonicalizer; | |
| import org.codehaus.jackson.sym.CharsToNameCanonicalizer; | |
| import org.codehaus.jackson.util.BufferRecycler; | |
| import org.codehaus.jackson.util.VersionUtil; | |
| /** | |
| * The main factory class of Jackson package, used to configure and | |
| * construct reader (aka parser, {@link JsonParser}) | |
| * and writer (aka generator, {@link JsonGenerator}) | |
| * instances. | |
| *<p> | |
| * Factory instances are thread-safe and reusable after configuration | |
| * (if any). Typically applications and services use only a single | |
| * globally shared factory instance, unless they need differently | |
| * configured factories. Factory reuse is important if efficiency matters; | |
| * most recycling of expensive construct is done on per-factory basis. | |
| *<p> | |
| * Creation of a factory instance is a light-weight operation, | |
| * and since there is no need for pluggable alternative implementations | |
| * (as there is no "standard" JSON processor API to implement), | |
| * the default constructor is used for constructing factory | |
| * instances. | |
| * | |
| * @author Tatu Saloranta | |
| */ | |
| public class JsonFactory implements Versioned | |
| { | |
| /** | |
| * Name used to identify JSON format | |
| * (and returned by {@link #getFormatName()} | |
| */ | |
| public final static String FORMAT_NAME_JSON = "JSON"; | |
| /** | |
| * Bitfield (set of flags) of all parser features that are enabled | |
| * by default. | |
| */ | |
| final static int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults(); | |
| /** | |
| * Bitfield (set of flags) of all generator features that are enabled | |
| * by default. | |
| */ | |
| final static int DEFAULT_GENERATOR_FEATURE_FLAGS = JsonGenerator.Feature.collectDefaults(); | |
| /* | |
| /********************************************************** | |
| /* Buffer, symbol table management | |
| /********************************************************** | |
| */ | |
| /** | |
| * This <code>ThreadLocal</code> contains a {@link java.lang.ref.SoftRerefence} | |
| * to a {@link BufferRecycler} used to provide a low-cost | |
| * buffer recycling between reader and writer instances. | |
| */ | |
| final protected static ThreadLocal<SoftReference<BufferRecycler>> _recyclerRef | |
| = new ThreadLocal<SoftReference<BufferRecycler>>(); | |
| /** | |
| * Each factory comes equipped with a shared root symbol table. | |
| * It should not be linked back to the original blueprint, to | |
| * avoid contents from leaking between factories. | |
| */ | |
| protected CharsToNameCanonicalizer _rootCharSymbols = CharsToNameCanonicalizer.createRoot(); | |
| /** | |
| * Alternative to the basic symbol table, some stream-based | |
| * parsers use different name canonicalization method. | |
| *<p> | |
| * TODO: should clean up this; looks messy having 2 alternatives | |
| * with not very clear differences. | |
| */ | |
| protected BytesToNameCanonicalizer _rootByteSymbols = BytesToNameCanonicalizer.createRoot(); | |
| /* | |
| /********************************************************** | |
| /* Configuration | |
| /********************************************************** | |
| */ | |
| /** | |
| * Object that implements conversion functionality between | |
| * Java objects and JSON content. For base JsonFactory implementation | |
| * usually not set by default, but can be explicitly set. | |
| * Sub-classes (like @link org.codehaus.jackson.map.MappingJsonFactory} | |
| * usually provide an implementation. | |
| */ | |
| protected ObjectCodec _objectCodec; | |
| /** | |
| * Currently enabled parser features. | |
| */ | |
| protected int _parserFeatures = DEFAULT_PARSER_FEATURE_FLAGS; | |
| /** | |
| * Currently enabled generator features. | |
| */ | |
| protected int _generatorFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS; | |
| /** | |
| * Definition of custom character escapes to use for generators created | |
| * by this factory, if any. If null, standard data format specific | |
| * escapes are used. | |
| * | |
| * @since 1.8 | |
| */ | |
| protected CharacterEscapes _characterEscapes; | |
| /** | |
| * Optional helper object that may decorate input sources, to do | |
| * additional processing on input during parsing. | |
| * | |
| * @since 1.8 | |
| */ | |
| protected InputDecorator _inputDecorator; | |
| /** | |
| * Optional helper object that may decorate output object, to do | |
| * additional processing on output during content generation. | |
| * | |
| * @since 1.8 | |
| */ | |
| protected OutputDecorator _outputDecorator; | |
| /* | |
| /********************************************************** | |
| /* Construction | |
| /********************************************************** | |
| */ | |
| /** | |
| * Default constructor used to create factory instances. | |
| * Creation of a factory instance is a light-weight operation, | |
| * but it is still a good idea to reuse limited number of | |
| * factory instances (and quite often just a single instance): | |
| * factories are used as context for storing some reused | |
| * processing objects (such as symbol tables parsers use) | |
| * and this reuse only works within context of a single | |
| * factory instance. | |
| */ | |
| public JsonFactory() { this(null); } | |
| public JsonFactory(ObjectCodec oc) { _objectCodec = oc; } | |
| /* | |
| /********************************************************** | |
| /* Format detection functionality (since 1.8) | |
| /********************************************************** | |
| */ | |
| /** | |
| * Method that returns short textual id identifying format | |
| * this factory supports. | |
| *<p> | |
| * Note: sub-classes should override this method; default | |
| * implementation will return null for all sub-classes | |
| * | |
| * @since 1.8 | |
| */ | |
| public String getFormatName() | |
| { | |
| /* Somewhat nasty check: since we can't make this abstract | |
| * (due to backwards compatibility concerns), need to prevent | |
| * format name "leakage" | |
| */ | |
| if (getClass() == JsonFactory.class) { | |
| return FORMAT_NAME_JSON; | |
| } | |
| return null; | |
| } | |
| public MatchStrength hasFormat(InputAccessor acc) throws IOException | |
| { | |
| // since we can't keep this abstract, only implement for "vanilla" instance | |
| if (getClass() == JsonFactory.class) { | |
| return hasJSONFormat(acc); | |
| } | |
| return null; | |
| } | |
| protected MatchStrength hasJSONFormat(InputAccessor acc) throws IOException | |
| { | |
| return ByteSourceBootstrapper.hasJSONFormat(acc); | |
| } | |
| /* | |
| /********************************************************** | |
| /* Versioned | |
| /********************************************************** | |
| */ | |
| @Override | |
| public Version version() { | |
| // VERSION is included under impl, so can't pass this class: | |
| return VersionUtil.versionFor(Utf8Generator.class); | |
| } | |
| /* | |
| /********************************************************** | |
| /* Configuration, parser settings | |
| /********************************************************** | |
| */ | |
| /** | |
| * Method for enabling or disabling specified parser feature | |
| * (check {@link JsonParser.Feature} for list of features) | |
| * | |
| * @since 1.2 | |
| */ | |
| public final JsonFactory configure(JsonParser.Feature f, boolean state) | |
| { | |
| if (state) { | |
| enable(f); | |
| } else { | |
| disable(f); | |
| } | |
| return this; | |
| } | |
| /** | |
| * Method for enabling specified parser feature | |
| * (check {@link JsonParser.Feature} for list of features) | |
| * | |
| * @since 1.2 | |
| */ | |
| public JsonFactory enable(JsonParser.Feature f) { | |
| _parserFeatures |= f.getMask(); | |
| return this; | |
| } | |
| /** | |
| * Method for disabling specified parser features | |
| * (check {@link JsonParser.Feature} for list of features) | |
| * | |
| * @since 1.2 | |
| */ | |
| public JsonFactory disable(JsonParser.Feature f) { | |
| _parserFeatures &= ~f.getMask(); | |
| return this; | |
| } | |
| /** | |
| * Checked whether specified parser feature is enabled. | |
| * | |
| * @since 1.2 | |
| */ | |
| public final boolean isEnabled(JsonParser.Feature f) { | |
| return (_parserFeatures & f.getMask()) != 0; | |
| } | |
| // // // Older deprecated (as of 1.2) methods | |
| /** | |
| * @deprecated Use {@link #enable(JsonParser.Feature)} instead | |
| */ | |
| @SuppressWarnings("dep-ann") | |
| public final void enableParserFeature(JsonParser.Feature f) { | |
| enable(f); | |
| } | |
| /** | |
| * @deprecated Use {@link #disable(JsonParser.Feature)} instead | |
| */ | |
| @SuppressWarnings("dep-ann") | |
| public final void disableParserFeature(JsonParser.Feature f) { | |
| disable(f); | |
| } | |
| /** | |
| * @deprecated Use {@link #configure(JsonParser.Feature, boolean)} instead | |
| */ | |
| @SuppressWarnings("dep-ann") | |
| public final void setParserFeature(JsonParser.Feature f, boolean state) { | |
| configure(f, state); | |
| } | |
| /** | |
| * @deprecated Use {@link #isEnabled(JsonParser.Feature)} instead | |
| */ | |
| @SuppressWarnings("dep-ann") | |
| public final boolean isParserFeatureEnabled(JsonParser.Feature f) { | |
| return (_parserFeatures & f.getMask()) != 0; | |
| } | |
| /** | |
| * Method for getting currently configured input decorator (if any; | |
| * there is no default decorator). | |
| * | |
| * @since 1.8 | |
| */ | |
| public InputDecorator getInputDecorator() { | |
| return _inputDecorator; | |
| } | |
| /** | |
| * Method for overriding currently configured input decorator | |
| * | |
| * @since 1.8 | |
| */ | |
| public JsonFactory setInputDecorator(InputDecorator d) { | |
| _inputDecorator = d; | |
| return this; | |
| } | |
| /* | |
| /********************************************************** | |
| /* Configuration, generator settings | |
| /********************************************************** | |
| */ | |
| /** | |
| * Method for enabling or disabling specified generator feature | |
| * (check {@link JsonGenerator.Feature} for list of features) | |
| * | |
| * @since 1.2 | |
| */ | |
| public final JsonFactory configure(JsonGenerator.Feature f, boolean state) { | |
| if (state) { | |
| enable(f); | |
| } else { | |
| disable(f); | |
| } | |
| return this; | |
| } | |
| /** | |
| * Method for enabling specified generator features | |
| * (check {@link JsonGenerator.Feature} for list of features) | |
| * | |
| * @since 1.2 | |
| */ | |
| public JsonFactory enable(JsonGenerator.Feature f) { | |
| _generatorFeatures |= f.getMask(); | |
| return this; | |
| } | |
| /** | |
| * Method for disabling specified generator feature | |
| * (check {@link JsonGenerator.Feature} for list of features) | |
| * | |
| * @since 1.2 | |
| */ | |
| public JsonFactory disable(JsonGenerator.Feature f) { | |
| _generatorFeatures &= ~f.getMask(); | |
| return this; | |
| } | |
| /** | |
| * Check whether specified generator feature is enabled. | |
| * | |
| * @since 1.2 | |
| */ | |
| public final boolean isEnabled(JsonGenerator.Feature f) { | |
| return (_generatorFeatures & f.getMask()) != 0; | |
| } | |
| // // // Older deprecated (as of 1.2) methods | |
| /** | |
| * @deprecated Use {@link #enable(JsonGenerator.Feature)} instead | |
| */ | |
| @Deprecated | |
| public final void enableGeneratorFeature(JsonGenerator.Feature f) { | |
| enable(f); | |
| } | |
| /** | |
| * @deprecated Use {@link #disable(JsonGenerator.Feature)} instead | |
| */ | |
| @Deprecated | |
| public final void disableGeneratorFeature(JsonGenerator.Feature f) { | |
| disable(f); | |
| } | |
| /** | |
| * @deprecated Use {@link #configure(JsonGenerator.Feature, boolean)} instead | |
| */ | |
| @Deprecated | |
| public final void setGeneratorFeature(JsonGenerator.Feature f, boolean state) { | |
| configure(f, state); | |
| } | |
| /** | |
| * @deprecated Use {@link #isEnabled(JsonGenerator.Feature)} instead | |
| */ | |
| @Deprecated | |
| public final boolean isGeneratorFeatureEnabled(JsonGenerator.Feature f) { | |
| return isEnabled(f); | |
| } | |
| /** | |
| * Method for accessing custom escapes factory uses for {@link JsonGenerator}s | |
| * it creates. | |
| * | |
| * @since 1.8 | |
| */ | |
| public CharacterEscapes getCharacterEscapes() { | |
| return _characterEscapes; | |
| } | |
| /** | |
| * Method for defining custom escapes factory uses for {@link JsonGenerator}s | |
| * it creates. | |
| * | |
| * @since 1.8 | |
| */ | |
| public JsonFactory setCharacterEscapes(CharacterEscapes esc) { | |
| _characterEscapes = esc; | |
| return this; | |
| } | |
| /** | |
| * Method for getting currently configured output decorator (if any; | |
| * there is no default decorator). | |
| * | |
| * @since 1.8 | |
| */ | |
| public OutputDecorator getOutputDecorator() { | |
| return _outputDecorator; | |
| } | |
| /** | |
| * Method for overriding currently configured output decorator | |
| * | |
| * @since 1.8 | |
| */ | |
| public JsonFactory setOutputDecorator(OutputDecorator d) { | |
| _outputDecorator = d; | |
| return this; | |
| } | |
| /* | |
| /********************************************************** | |
| /* Configuration, other | |
| /********************************************************** | |
| */ | |
| /** | |
| * Method for associating a {@link ObjectCodec} (typically | |
| * a {@link org.codehaus.jackson.map.ObjectMapper}) with | |
| * this factory (and more importantly, parsers and generators | |
| * it constructs). This is needed to use data-binding methods | |
| * of {@link JsonParser} and {@link JsonGenerator} instances. | |
| */ | |
| public JsonFactory setCodec(ObjectCodec oc) { | |
| _objectCodec = oc; | |
| return this; | |
| } | |
| public ObjectCodec getCodec() { return _objectCodec; } | |
| /* | |
| /********************************************************** | |
| /* Reader factories | |
| /********************************************************** | |
| */ | |
| /** | |
| * Method for constructing JSON parser instance to parse | |
| * contents of specified file. Encoding is auto-detected | |
| * from contents according to JSON specification recommended | |
| * mechanism. | |
| *<p> | |
| * Underlying input stream (needed for reading contents) | |
| * will be <b>owned</b> (and managed, i.e. closed as need be) by | |
| * the parser, since caller has no access to it. | |
| * | |
| * @param f File that contains JSON content to parse | |
| */ | |
| public JsonParser createJsonParser(File f) | |
| throws IOException, JsonParseException | |
| { | |
| // true, since we create InputStream from File | |
| IOContext ctxt = _createContext(f, true); | |
| InputStream in = new FileInputStream(f); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| in = _inputDecorator.decorate(ctxt, in); | |
| } | |
| return _createJsonParser(in, ctxt); | |
| } | |
| /** | |
| * Method for constructing JSON parser instance to parse | |
| * contents of resource reference by given URL. | |
| * Encoding is auto-detected | |
| * from contents according to JSON specification recommended | |
| * mechanism. | |
| *<p> | |
| * Underlying input stream (needed for reading contents) | |
| * will be <b>owned</b> (and managed, i.e. closed as need be) by | |
| * the parser, since caller has no access to it. | |
| * | |
| * @param url URL pointing to resource that contains JSON content to parse | |
| */ | |
| public JsonParser createJsonParser(URL url) | |
| throws IOException, JsonParseException | |
| { | |
| // true, since we create InputStream from URL | |
| IOContext ctxt = _createContext(url, true); | |
| InputStream in = _optimizedStreamFromURL(url); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| in = _inputDecorator.decorate(ctxt, in); | |
| } | |
| return _createJsonParser(in, ctxt); | |
| } | |
| /** | |
| * Method for constructing JSON parser instance to parse | |
| * the contents accessed via specified input stream. | |
| *<p> | |
| * The input stream will <b>not be owned</b> by | |
| * the parser, it will still be managed (i.e. closed if | |
| * end-of-stream is reacher, or parser close method called) | |
| * if (and only if) {@link org.codehaus.jackson.JsonParser.Feature#AUTO_CLOSE_SOURCE} | |
| * is enabled. | |
| *<p> | |
| * Note: no encoding argument is taken since it can always be | |
| * auto-detected as suggested by Json RFC. | |
| * | |
| * @param in InputStream to use for reading JSON content to parse | |
| */ | |
| public JsonParser createJsonParser(InputStream in) | |
| throws IOException, JsonParseException | |
| { | |
| IOContext ctxt = _createContext(in, false); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| in = _inputDecorator.decorate(ctxt, in); | |
| } | |
| return _createJsonParser(in, ctxt); | |
| } | |
| /** | |
| * Method for constructing parser for parsing | |
| * the contents accessed via specified Reader. | |
| <p> | |
| * The read stream will <b>not be owned</b> by | |
| * the parser, it will still be managed (i.e. closed if | |
| * end-of-stream is reacher, or parser close method called) | |
| * if (and only if) {@link org.codehaus.jackson.JsonParser.Feature#AUTO_CLOSE_SOURCE} | |
| * is enabled. | |
| *<p> | |
| * | |
| * @param r Reader to use for reading JSON content to parse | |
| */ | |
| public JsonParser createJsonParser(Reader r) | |
| throws IOException, JsonParseException | |
| { | |
| // false -> we do NOT own Reader (did not create it) | |
| IOContext ctxt = _createContext(r, false); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| r = _inputDecorator.decorate(ctxt, r); | |
| } | |
| return _createJsonParser(r, ctxt); | |
| } | |
| /** | |
| * Method for constructing parser for parsing | |
| * the contents of given byte array. | |
| */ | |
| public JsonParser createJsonParser(byte[] data) | |
| throws IOException, JsonParseException | |
| { | |
| IOContext ctxt = _createContext(data, true); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| InputStream in = _inputDecorator.decorate(ctxt, data, 0, data.length); | |
| if (in != null) { | |
| return _createJsonParser(in, ctxt); | |
| } | |
| } | |
| return _createJsonParser(data, 0, data.length, ctxt); | |
| } | |
| /** | |
| * Method for constructing parser for parsing | |
| * the contents of given byte array. | |
| * | |
| * @param data Buffer that contains data to parse | |
| * @param offset Offset of the first data byte within buffer | |
| * @param len Length of contents to parse within buffer | |
| */ | |
| public JsonParser createJsonParser(byte[] data, int offset, int len) | |
| throws IOException, JsonParseException | |
| { | |
| IOContext ctxt = _createContext(data, true); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| InputStream in = _inputDecorator.decorate(ctxt, data, offset, len); | |
| if (in != null) { | |
| return _createJsonParser(in, ctxt); | |
| } | |
| } | |
| return _createJsonParser(data, offset, len, ctxt); | |
| } | |
| /** | |
| * Method for constructing parser for parsing | |
| * contens of given String. | |
| */ | |
| public JsonParser createJsonParser(String content) | |
| throws IOException, JsonParseException | |
| { | |
| Reader r = new StringReader(content); | |
| // true -> we own the Reader (and must close); not a big deal | |
| IOContext ctxt = _createContext(r, true); | |
| // [JACKSON-512]: allow wrapping with InputDecorator | |
| if (_inputDecorator != null) { | |
| r = _inputDecorator.decorate(ctxt, r); | |
| } | |
| return _createJsonParser(r, ctxt); | |
| } | |
| /* | |
| /********************************************************** | |
| /* Generator factories | |
| /********************************************************** | |
| */ | |
| /** | |
| * Method for constructing JSON generator for writing JSON content | |
| * using specified output stream. | |
| * Encoding to use must be specified, and needs to be one of available | |
| * types (as per JSON specification). | |
| *<p> | |
| * Underlying stream <b>is NOT owned</b> by the generator constructed, | |
| * so that generator will NOT close the output stream when | |
| * {@link JsonGenerator#close} is called (unless auto-closing | |
| * feature, | |
| * {@link org.codehaus.jackson.JsonGenerator.Feature#AUTO_CLOSE_TARGET} | |
| * is enabled). | |
| * Using application needs to close it explicitly if this is the case. | |
| *<p> | |
| * Note: there are formats that use fixed encoding (like most binary data formats) | |
| * and that ignore passed in encoding. | |
| * | |
| * @param out OutputStream to use for writing JSON content | |
| * @param enc Character encoding to use | |
| */ | |
| public JsonGenerator createJsonGenerator(OutputStream out, JsonEncoding enc) | |
| throws IOException | |
| { | |
| // false -> we won't manage the stream unless explicitly directed to | |
| IOContext ctxt = _createContext(out, false); | |
| ctxt.setEncoding(enc); | |
| if (enc == JsonEncoding.UTF8) { | |
| // [JACKSON-512]: allow wrapping with _outputDecorator | |
| if (_outputDecorator != null) { | |
| out = _outputDecorator.decorate(ctxt, out); | |
| } | |
| return _createUTF8JsonGenerator(out, ctxt); | |
| } | |
| Writer w = _createWriter(out, enc, ctxt); | |
| // [JACKSON-512]: allow wrapping with _outputDecorator | |
| if (_outputDecorator != null) { | |
| w = _outputDecorator.decorate(ctxt, w); | |
| } | |
| return _createJsonGenerator(w, ctxt); | |
| } | |
| /** | |
| * Method for constructing JSON generator for writing JSON content | |
| * using specified Writer. | |
| *<p> | |
| * Underlying stream <b>is NOT owned</b> by the generator constructed, | |
| * so that generator will NOT close the Reader when | |
| * {@link JsonGenerator#close} is called (unless auto-closing | |
| * feature, | |
| * {@link org.codehaus.jackson.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). | |
| * Using application needs to close it explicitly. | |
| * | |
| * @param out Writer to use for writing JSON content | |
| */ | |
| public JsonGenerator createJsonGenerator(Writer out) | |
| throws IOException | |
| { | |
| IOContext ctxt = _createContext(out, false); | |
| // [JACKSON-512]: allow wrapping with _outputDecorator | |
| if (_outputDecorator != null) { | |
| out = _outputDecorator.decorate(ctxt, out); | |
| } | |
| return _createJsonGenerator(out, ctxt); | |
| } | |
| /** | |
| * Convenience method for constructing generator that uses default | |
| * encoding of the format (UTF-8 for JSON and most other data formats). | |
| *<p> | |
| * Note: there are formats that use fixed encoding (like most binary data formats). | |
| * | |
| * @since 1.8 | |
| */ | |
| public JsonGenerator createJsonGenerator(OutputStream out) throws IOException { | |
| return createJsonGenerator(out, JsonEncoding.UTF8); | |
| } | |
| /** | |
| * Method for constructing JSON generator for writing JSON content | |
| * to specified file, overwriting contents it might have (or creating | |
| * it if such file does not yet exist). | |
| * Encoding to use must be specified, and needs to be one of available | |
| * types (as per JSON specification). | |
| *<p> | |
| * Underlying stream <b>is owned</b> by the generator constructed, | |
| * i.e. generator will handle closing of file when | |
| * {@link JsonGenerator#close} is called. | |
| * | |
| * @param f File to write contents to | |
| * @param enc Character encoding to use | |
| */ | |
| public JsonGenerator createJsonGenerator(File f, JsonEncoding enc) | |
| throws IOException | |
| { | |
| OutputStream out = new FileOutputStream(f); | |
| // true -> yes, we have to manage the stream since we created it | |
| IOContext ctxt = _createContext(out, true); | |
| ctxt.setEncoding(enc); | |
| if (enc == JsonEncoding.UTF8) { | |
| // [JACKSON-512]: allow wrapping with _outputDecorator | |
| if (_outputDecorator != null) { | |
| out = _outputDecorator.decorate(ctxt, out); | |
| } | |
| return _createUTF8JsonGenerator(out, ctxt); | |
| } | |
| Writer w = _createWriter(out, enc, ctxt); | |
| // [JACKSON-512]: allow wrapping with _outputDecorator | |
| if (_outputDecorator != null) { | |
| w = _outputDecorator.decorate(ctxt, w); | |
| } | |
| return _createJsonGenerator(w, ctxt); | |
| } | |
| /* | |
| /********************************************************** | |
| /* Factory methods used by factory for creating parser instances, | |
| /* overridable by sub-classes | |
| /********************************************************** | |
| */ | |
| /** | |
| * Overridable factory method that actually instantiates desired parser | |
| * given {@link InputStream} and context object. | |
| *<p> | |
| * This method is specifically designed to remain | |
| * compatible between minor versions so that sub-classes can count | |
| * on it being called as expected. That is, it is part of official | |
| * interface from sub-class perspective, although not a public | |
| * method available to users of factory implementations. | |
| */ | |
| protected JsonParser _createJsonParser(InputStream in, IOContext ctxt) | |
| throws IOException, JsonParseException | |
| { | |
| return new ByteSourceBootstrapper(ctxt, in).constructParser(_parserFeatures, | |
| _objectCodec, _rootByteSymbols, _rootCharSymbols); | |
| } | |
| /** | |
| * Overridable factory method that actually instantiates parser | |
| * using given {@link Reader} object for reading content. | |
| *<p> | |
| * This method is specifically designed to remain | |
| * compatible between minor versions so that sub-classes can count | |
| * on it being called as expected. That is, it is part of official | |
| * interface from sub-class perspective, although not a public | |
| * method available to users of factory implementations. | |
| */ | |
| protected JsonParser _createJsonParser(Reader r, IOContext ctxt) | |
| throws IOException, JsonParseException | |
| { | |
| return new ReaderBasedParser(ctxt, _parserFeatures, r, _objectCodec, | |
| _rootCharSymbols.makeChild(isEnabled(JsonParser.Feature.CANONICALIZE_FIELD_NAMES), | |
| isEnabled(JsonParser.Feature.INTERN_FIELD_NAMES))); | |
| } | |
| /** | |
| * Overridable factory method that actually instantiates parser | |
| * using given {@link Reader} object for reading content | |
| * passed as raw byte array. | |
| *<p> | |
| * This method is specifically designed to remain | |
| * compatible between minor versions so that sub-classes can count | |
| * on it being called as expected. That is, it is part of official | |
| * interface from sub-class perspective, although not a public | |
| * method available to users of factory implementations. | |
| */ | |
| protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt) | |
| throws IOException, JsonParseException | |
| { | |
| return new ByteSourceBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures, | |
| _objectCodec, _rootByteSymbols, _rootCharSymbols); | |
| } | |
| /* | |
| /********************************************************** | |
| /* Factory methods used by factory for creating generator instances, | |
| /* overridable by sub-classes | |
| /********************************************************** | |
| */ | |
| /** | |
| * Overridable factory method that actually instantiates generator for | |
| * given {@link Writer} and context object. | |
| *<p> | |
| * This method is specifically designed to remain | |
| * compatible between minor versions so that sub-classes can count | |
| * on it being called as expected. That is, it is part of official | |
| * interface from sub-class perspective, although not a public | |
| * method available to users of factory implementations. | |
| */ | |
| protected JsonGenerator _createJsonGenerator(Writer out, IOContext ctxt) | |
| throws IOException | |
| { | |
| WriterBasedGenerator gen = new WriterBasedGenerator(ctxt, _generatorFeatures, _objectCodec, out); | |
| if (_characterEscapes != null) { | |
| gen.setCharacterEscapes(_characterEscapes); | |
| } | |
| return gen; | |
| } | |
| /** | |
| * Overridable factory method that actually instantiates generator for | |
| * given {@link OutputStream} and context object, using UTF-8 encoding. | |
| *<p> | |
| * This method is specifically designed to remain | |
| * compatible between minor versions so that sub-classes can count | |
| * on it being called as expected. That is, it is part of official | |
| * interface from sub-class perspective, although not a public | |
| * method available to users of factory implementations. | |
| */ | |
| protected JsonGenerator _createUTF8JsonGenerator(OutputStream out, IOContext ctxt) | |
| throws IOException | |
| { | |
| Utf8Generator gen = new Utf8Generator(ctxt, _generatorFeatures, _objectCodec, out); | |
| if (_characterEscapes != null) { | |
| gen.setCharacterEscapes(_characterEscapes); | |
| } | |
| return gen; | |
| } | |
| protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException | |
| { | |
| // note: this should not get called any more (caller checks, dispatches) | |
| if (enc == JsonEncoding.UTF8) { // We have optimized writer for UTF-8 | |
| return new UTF8Writer(ctxt, out); | |
| } | |
| // not optimal, but should do unless we really care about UTF-16/32 encoding speed | |
| return new OutputStreamWriter(out, enc.getJavaName()); | |
| } | |
| /* | |
| /********************************************************** | |
| /* Internal factory methods, other | |
| /********************************************************** | |
| */ | |
| /** | |
| * Overridable factory method that actually instantiates desired | |
| * context object. | |
| */ | |
| protected IOContext _createContext(Object srcRef, boolean resourceManaged) | |
| { | |
| return new IOContext(_getBufferRecycler(), srcRef, resourceManaged); | |
| } | |
| /** | |
| * Method used by factory to create buffer recycler instances | |
| * for parsers and generators. | |
| *<p> | |
| * Note: only public to give access for <code>ObjectMapper</code> | |
| */ | |
| public BufferRecycler _getBufferRecycler() | |
| { | |
| SoftReference<BufferRecycler> ref = _recyclerRef.get(); | |
| BufferRecycler br = (ref == null) ? null : ref.get(); | |
| if (br == null) { | |
| br = new BufferRecycler(); | |
| _recyclerRef.set(new SoftReference<BufferRecycler>(br)); | |
| } | |
| return br; | |
| } | |
| /** | |
| * Helper methods used for constructing an optimal stream for | |
| * parsers to use, when input is to be read from an URL. | |
| * This helps when reading file content via URL. | |
| */ | |
| protected InputStream _optimizedStreamFromURL(URL url) | |
| throws IOException | |
| { | |
| if ("file".equals(url.getProtocol())) { | |
| /* Can not do this if the path refers | |
| * to a network drive on windows. This fixes the problem; | |
| * might not be needed on all platforms (NFS?), but should not | |
| * matter a lot: performance penalty of extra wrapping is more | |
| * relevant when accessing local file system. | |
| */ | |
| String host = url.getHost(); | |
| if (host == null || host.length() == 0) { | |
| return new FileInputStream(url.getPath()); | |
| } | |
| } | |
| return url.openStream(); | |
| } | |
| } |