Ejemplo n.º 1
0
 /** Checked whether specified parser feature is enabled. */
 public final boolean isEnabled(JsonParser.Feature f) {
   return (_parserFeatures & f.getMask()) != 0;
 }
Ejemplo n.º 2
0
 /**
  * Method for enabling specified parser feature (check {@link JsonParser.Feature} for list of
  * features)
  */
 public JsonFactory enable(JsonParser.Feature f) {
   _parserFeatures |= f.getMask();
   return this;
 }
Ejemplo n.º 3
0
 /**
  * Method for disabling specified parser features (check {@link JsonParser.Feature} for list of
  * features)
  */
 public JsonFactory disable(JsonParser.Feature f) {
   _parserFeatures &= ~f.getMask();
   return this;
 }
Ejemplo n.º 4
0
/**
 * 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, java.io.Serializable // since 2.1 (for Android, mostly)
{
  /** Computed for Jackson 2.2.0 release */
  private static final long serialVersionUID = 8726401676402117450L;

  /*
  /**********************************************************
  /* Helper types
  /**********************************************************
   */

  /**
   * Enumeration that defines all on/off features that can only be changed for {@link JsonFactory}.
   */
  public enum Feature {

    // // // Symbol handling (interning etc)

    /**
     * Feature that determines whether JSON object field names are to be canonicalized using {@link
     * String#intern} or not: if enabled, all field names will be intern()ed (and caller can count
     * on this being true for all such names); if disabled, no intern()ing is done. There may still
     * be basic canonicalization (that is, same String will be used to represent all identical
     * object property names for a single document).
     *
     * <p>Note: this setting only has effect if {@link #CANONICALIZE_FIELD_NAMES} is true --
     * otherwise no canonicalization of any sort is done.
     *
     * <p>This setting is enabled by default.
     */
    INTERN_FIELD_NAMES(true),

    /**
     * Feature that determines whether JSON object field names are to be canonicalized (details of
     * how canonicalization is done then further specified by {@link #INTERN_FIELD_NAMES}).
     *
     * <p>This setting is enabled by default.
     */
    CANONICALIZE_FIELD_NAMES(true);

    /** Whether feature is enabled or disabled by default. */
    private final boolean _defaultState;

    /** Method that calculates bit set (flags) of all features that are enabled by default. */
    public static int collectDefaults() {
      int flags = 0;
      for (Feature f : values()) {
        if (f.enabledByDefault()) {
          flags |= f.getMask();
        }
      }
      return flags;
    }

    private Feature(boolean defaultState) {
      _defaultState = defaultState;
    }

    public boolean enabledByDefault() {
      return _defaultState;
    }

    public boolean enabledIn(int flags) {
      return (flags & getMask()) != 0;
    }

    public int getMask() {
      return (1 << ordinal());
    }
  }

  /*
  /**********************************************************
  /* Constants
  /**********************************************************
   */

  /** Name used to identify JSON format (and returned by {@link #getFormatName()} */
  public static final String FORMAT_NAME_JSON = "JSON";

  /** Bitfield (set of flags) of all factory features that are enabled by default. */
  protected static final int DEFAULT_FACTORY_FEATURE_FLAGS = JsonFactory.Feature.collectDefaults();

  /** Bitfield (set of flags) of all parser features that are enabled by default. */
  protected static final int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults();

  /** Bitfield (set of flags) of all generator features that are enabled by default. */
  protected static final int DEFAULT_GENERATOR_FEATURE_FLAGS =
      JsonGenerator.Feature.collectDefaults();

  private static final SerializableString DEFAULT_ROOT_VALUE_SEPARATOR =
      DefaultPrettyPrinter.DEFAULT_ROOT_VALUE_SEPARATOR;

  /*
  /**********************************************************
  /* Buffer, symbol table management
  /**********************************************************
   */

  /**
   * This <code>ThreadLocal</code> contains a {@link java.lang.ref.SoftReference} to a {@link
   * BufferRecycler} used to provide a low-cost buffer recycling between reader and writer
   * instances.
   */
  protected static final 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 final transient 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 final transient 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 factory features. */
  protected int _factoryFeatures = DEFAULT_FACTORY_FEATURE_FLAGS;

  /** 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.
   */
  protected CharacterEscapes _characterEscapes;

  /**
   * Optional helper object that may decorate input sources, to do additional processing on input
   * during parsing.
   */
  protected InputDecorator _inputDecorator;

  /**
   * Optional helper object that may decorate output object, to do additional processing on output
   * during content generation.
   */
  protected OutputDecorator _outputDecorator;

  /**
   * Separator used between root-level values, if any; null indicates "do not add separator".
   * Default separator is a single space character.
   *
   * @since 2.1
   */
  protected SerializableString _rootValueSeparator = DEFAULT_ROOT_VALUE_SEPARATOR;

  /*
  /**********************************************************
  /* 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((ObjectCodec) null);
  }

  public JsonFactory(ObjectCodec oc) {
    _objectCodec = oc;
  }

  /**
   * Constructor used when copy()ing a factory instance.
   *
   * @since 2.2.1
   */
  protected JsonFactory(JsonFactory src, ObjectCodec codec) {
    _objectCodec = null;
    _factoryFeatures = src._factoryFeatures;
    _parserFeatures = src._parserFeatures;
    _generatorFeatures = src._generatorFeatures;
    _characterEscapes = src._characterEscapes;
    _inputDecorator = src._inputDecorator;
    _outputDecorator = src._outputDecorator;
    _rootValueSeparator = src._rootValueSeparator;

    /* 27-Apr-2013, tatu: How about symbol table; should we try to
     *   reuse shared symbol tables? Could be more efficient that way;
     *   although can slightly add to concurrency overhead.
     */
  }

  /**
   * Method for constructing a new {@link JsonFactory} that has the same settings as this instance,
   * but is otherwise independent (i.e. nothing is actually shared, symbol tables are separate).
   * Note that {@link ObjectCodec} reference is not copied but is set to null; caller typically
   * needs to set it after calling this method. Reason for this is that the codec is used for
   * callbacks, and assumption is that there is strict 1-to-1 mapping between codec, factory. Caller
   * has to, then, explicitly set codec after making the copy.
   *
   * @since 2.1
   */
  public JsonFactory copy() {
    _checkInvalidCopy(JsonFactory.class);
    // as per above, do clear ObjectCodec
    return new JsonFactory(this, null);
  }

  /**
   * @since 2.1
   * @param exp
   */
  protected void _checkInvalidCopy(Class<?> exp) {
    if (getClass() != exp) {
      throw new IllegalStateException(
          "Failed copy(): "
              + getClass().getName()
              + " (version: "
              + version()
              + ") does not override copy(); it has to");
    }
  }

  /*
  /**********************************************************
  /* Serializable overrides
  /**********************************************************
   */

  /**
   * Method that we need to override to actually make restoration go through constructors etc. Also:
   * must be overridden by sub-classes as well.
   */
  protected Object readResolve() {
    return new JsonFactory(this, _objectCodec);
  }

  /*
  /**********************************************************
  /* Format detection functionality (since 1.8)
  /**********************************************************
   */

  /**
   * Method that can be used to quickly check whether given schema is something that parsers and/or
   * generators constructed by this factory could use. Note that this means possible use, at the
   * level of data format (i.e. schema is for same data format as parsers and generators this
   * factory constructs); individual schema instances may have further usage restrictions.
   *
   * @since 2.1
   */
  public boolean canUseSchema(FormatSchema schema) {
    String ourFormat = getFormatName();
    return (ourFormat != null) && ourFormat.equals(schema.getSchemaType());
  }

  /**
   * 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
   */
  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;
  }

  /**
   * Method that can be called to determine if a custom {@link ObjectCodec} is needed for binding
   * data parsed using {@link JsonParser} constructed by this factory (which typically also implies
   * the same for serialization with {@link JsonGenerator}).
   *
   * @return True if custom codec is needed with parsers and generators created by this factory;
   *     false if a general {@link ObjectCodec} is enough
   * @since 2.1
   */
  public boolean requiresCustomCodec() {
    return false;
  }

  /**
   * Helper method that can be called to determine if content accessed using given accessor seems to
   * be JSON content.
   */
  protected MatchStrength hasJSONFormat(InputAccessor acc) throws IOException {
    return ByteSourceJsonBootstrapper.hasJSONFormat(acc);
  }

  /*
  /**********************************************************
  /* Versioned
  /**********************************************************
   */

  @Override
  public Version version() {
    return PackageVersion.VERSION;
  }

  /*
  /**********************************************************
  /* Configuration, factory features
  /**********************************************************
   */

  /**
   * Method for enabling or disabling specified parser feature (check {@link JsonParser.Feature} for
   * list of features)
   */
  public final JsonFactory configure(JsonFactory.Feature f, boolean state) {
    return state ? enable(f) : disable(f);
  }

  /**
   * Method for enabling specified parser feature (check {@link JsonFactory.Feature} for list of
   * features)
   */
  public JsonFactory enable(JsonFactory.Feature f) {
    _factoryFeatures |= f.getMask();
    return this;
  }

  /**
   * Method for disabling specified parser features (check {@link JsonFactory.Feature} for list of
   * features)
   */
  public JsonFactory disable(JsonFactory.Feature f) {
    _factoryFeatures &= ~f.getMask();
    return this;
  }

  /** Checked whether specified parser feature is enabled. */
  public final boolean isEnabled(JsonFactory.Feature f) {
    return (_factoryFeatures & f.getMask()) != 0;
  }

  /*
  /**********************************************************
  /* Configuration, parser configuration
  /**********************************************************
   */

  /**
   * Method for enabling or disabling specified parser feature (check {@link JsonParser.Feature} for
   * list of features)
   */
  public final JsonFactory configure(JsonParser.Feature f, boolean state) {
    return state ? enable(f) : disable(f);
  }

  /**
   * Method for enabling specified parser feature (check {@link JsonParser.Feature} for list of
   * features)
   */
  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)
   */
  public JsonFactory disable(JsonParser.Feature f) {
    _parserFeatures &= ~f.getMask();
    return this;
  }

  /** Checked whether specified parser feature is enabled. */
  public final boolean isEnabled(JsonParser.Feature f) {
    return (_parserFeatures & f.getMask()) != 0;
  }

  /**
   * Method for getting currently configured input decorator (if any; there is no default
   * decorator).
   */
  public InputDecorator getInputDecorator() {
    return _inputDecorator;
  }

  /** Method for overriding currently configured input decorator */
  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)
   */
  public final JsonFactory configure(JsonGenerator.Feature f, boolean state) {
    return state ? enable(f) : disable(f);
  }

  /**
   * Method for enabling specified generator features (check {@link JsonGenerator.Feature} for list
   * of features)
   */
  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)
   */
  public JsonFactory disable(JsonGenerator.Feature f) {
    _generatorFeatures &= ~f.getMask();
    return this;
  }

  /** Check whether specified generator feature is enabled. */
  public final boolean isEnabled(JsonGenerator.Feature f) {
    return (_generatorFeatures & f.getMask()) != 0;
  }

  /** Method for accessing custom escapes factory uses for {@link JsonGenerator}s it creates. */
  public CharacterEscapes getCharacterEscapes() {
    return _characterEscapes;
  }

  /** Method for defining custom escapes factory uses for {@link JsonGenerator}s it creates. */
  public JsonFactory setCharacterEscapes(CharacterEscapes esc) {
    _characterEscapes = esc;
    return this;
  }

  /**
   * Method for getting currently configured output decorator (if any; there is no default
   * decorator).
   */
  public OutputDecorator getOutputDecorator() {
    return _outputDecorator;
  }

  /** Method for overriding currently configured output decorator */
  public JsonFactory setOutputDecorator(OutputDecorator d) {
    _outputDecorator = d;
    return this;
  }

  /**
   * Method that allows overriding String used for separating root-level JSON values (default is
   * single space character)
   *
   * @param sep Separator to use, if any; null means that no separator is automatically added
   * @since 2.1
   */
  public JsonFactory setRootValueSeparator(String sep) {
    _rootValueSeparator = (sep == null) ? null : new SerializedString(sep);
    return this;
  }

  /** @since 2.1 */
  public String getRootValueSeparator() {
    return (_rootValueSeparator == null) ? null : _rootValueSeparator.getValue();
  }

  /*
  /**********************************************************
  /* Configuration, other
  /**********************************************************
   */

  /**
   * Method for associating a {@link ObjectCodec} (typically a <code>
   * com.fasterxml.jackson.databind.ObjectMapper</code>) 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;
  }

  /*
  /**********************************************************
  /* Parser factories (new ones, as per [Issue-25])
  /**********************************************************
   */

  /**
   * 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
   * @since 2.1
   */
  @SuppressWarnings("resource")
  public JsonParser createParser(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 _createParser(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
   * @since 2.1
   */
  public JsonParser createParser(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 _createParser(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
   * com.fasterxml.jackson.core.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
   * @since 2.1
   */
  public JsonParser createParser(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 _createParser(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
   * com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE} is enabled.
   *
   * @param r Reader to use for reading JSON content to parse
   * @since 2.1
   */
  public JsonParser createParser(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 _createParser(r, ctxt);
  }

  /**
   * Method for constructing parser for parsing the contents of given byte array.
   *
   * @since 2.1
   */
  public JsonParser createParser(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 _createParser(in, ctxt);
      }
    }
    return _createParser(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
   * @since 2.1
   */
  public JsonParser createParser(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 _createParser(in, ctxt);
      }
    }
    return _createParser(data, offset, len, ctxt);
  }

  /**
   * Method for constructing parser for parsing contents of given String.
   *
   * @since 2.1
   */
  public JsonParser createParser(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 _createParser(r, ctxt);
  }

  /*
  /**********************************************************
  /* Parser factories (old ones, as per [Issue-25])
  /**********************************************************
   */

  /**
   * 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.
   *
   * <p>NOTE: as of 2.1, should not be used (will be deprecated in 2.2); instead, should call <code>
   * createParser</code>.
   *
   * @param f File that contains JSON content to parse
   * @deprecated Since 2.2, use {@link #createParser(File)} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(File f) throws IOException, JsonParseException {
    return createParser(f);
  }

  /**
   * 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.
   *
   * <p>NOTE: as of 2.1, should not be used (will be deprecated in 2.2); instead, should call <code>
   * createParser</code>.
   *
   * @param url URL pointing to resource that contains JSON content to parse
   * @deprecated Since 2.2, use {@link #createParser(URL)} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(URL url) throws IOException, JsonParseException {
    return createParser(url);
  }

  /**
   * 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
   * com.fasterxml.jackson.core.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.
   *
   * <p>NOTE: as of 2.1, should not be used (will be deprecated in 2.2); instead, should call <code>
   * createParser</code>.
   *
   * @param in InputStream to use for reading JSON content to parse
   * @deprecated Since 2.2, use {@link #createParser(InputStream)} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(InputStream in) throws IOException, JsonParseException {
    return createParser(in);
  }

  /**
   * 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
   * com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE} is enabled.
   *
   * <p>NOTE: as of 2.1, should not be used (will be deprecated in 2.2); instead, should call <code>
   * createParser</code>.
   *
   * @param r Reader to use for reading JSON content to parse
   * @deprecated Since 2.2, use {@link #createParser(Reader)} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(Reader r) throws IOException, JsonParseException {
    return createParser(r);
  }

  /**
   * Method for constructing parser for parsing the contents of given byte array.
   *
   * <p>NOTE: as of 2.1, should not be used (will be deprecated in 2.2); instead, should call <code>
   * createParser</code>.
   *
   * @deprecated Since 2.2, use {@link #createParser(byte[])} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(byte[] data) throws IOException, JsonParseException {
    return createParser(data);
  }

  /**
   * Method for constructing parser for parsing the contents of given byte array.
   *
   * <p>NOTE: as of 2.1, should not be used (will be deprecated in 2.2); instead, should call <code>
   * createParser</code>.
   *
   * @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
   * @deprecated Since 2.2, use {@link #createParser(byte[],int,int)} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(byte[] data, int offset, int len)
      throws IOException, JsonParseException {
    return createParser(data, offset, len);
  }

  /**
   * Method for constructing parser for parsing contents of given String.
   *
   * @deprecated Since 2.2, use {@link #createParser(String)} instead.
   */
  @Deprecated
  public JsonParser createJsonParser(String content) throws IOException, JsonParseException {
    return createParser(content);
  }

  /*
  /**********************************************************
  /* Generator factories, new (as per [Issue-25]
  /**********************************************************
   */

  /**
   * 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 com.fasterxml.jackson.core.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
   * @since 2.1
   */
  public JsonGenerator createGenerator(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 _createUTF8Generator(out, ctxt);
    }
    Writer w = _createWriter(out, enc, ctxt);
    // [JACKSON-512]: allow wrapping with _outputDecorator
    if (_outputDecorator != null) {
      w = _outputDecorator.decorate(ctxt, w);
    }
    return _createGenerator(w, 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 2.1
   */
  public JsonGenerator createGenerator(OutputStream out) throws IOException {
    return createGenerator(out, JsonEncoding.UTF8);
  }

  /**
   * 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 com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). Using
   * application needs to close it explicitly.
   *
   * @since 2.1
   * @param out Writer to use for writing JSON content
   */
  public JsonGenerator createGenerator(Writer out) throws IOException {
    IOContext ctxt = _createContext(out, false);
    // [JACKSON-512]: allow wrapping with _outputDecorator
    if (_outputDecorator != null) {
      out = _outputDecorator.decorate(ctxt, out);
    }
    return _createGenerator(out, ctxt);
  }

  /**
   * 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
   * @since 2.1
   */
  public JsonGenerator createGenerator(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 _createUTF8Generator(out, ctxt);
    }
    Writer w = _createWriter(out, enc, ctxt);
    // [JACKSON-512]: allow wrapping with _outputDecorator
    if (_outputDecorator != null) {
      w = _outputDecorator.decorate(ctxt, w);
    }
    return _createGenerator(w, ctxt);
  }

  /*
  /**********************************************************
  /* Generator factories, old (as per [Issue-25]
  /**********************************************************
   */

  /**
   * 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 com.fasterxml.jackson.core.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
   * @deprecated Since 2.2, use {@link #createGenerator(OutputStream, JsonEncoding)} instead.
   */
  @Deprecated
  public JsonGenerator createJsonGenerator(OutputStream out, JsonEncoding enc) throws IOException {
    return createGenerator(out, enc);
  }

  /**
   * 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 com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). Using
   * application needs to close it explicitly.
   *
   * @param out Writer to use for writing JSON content
   * @deprecated Since 2.2, use {@link #createGenerator(Writer)} instead.
   */
  @Deprecated
  public JsonGenerator createJsonGenerator(Writer out) throws IOException {
    return createGenerator(out);
  }

  /**
   * 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).
   *
   * @deprecated Since 2.2, use {@link #createGenerator(OutputStream)} instead.
   */
  @Deprecated
  public JsonGenerator createJsonGenerator(OutputStream out) throws IOException {
    return createGenerator(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
   * @deprecated Since 2.2, use {@link #createGenerator(File,JsonEncoding)} instead.
   */
  @Deprecated
  public JsonGenerator createJsonGenerator(File f, JsonEncoding enc) throws IOException {
    return createGenerator(f, enc);
  }

  /*
  /**********************************************************
  /* 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.
   *
   * @since 2.1
   */
  protected JsonParser _createParser(InputStream in, IOContext ctxt)
      throws IOException, JsonParseException {
    // As per [JACKSON-259], may want to fully disable canonicalization:
    return new ByteSourceJsonBootstrapper(ctxt, in)
        .constructParser(
            _parserFeatures,
            _objectCodec,
            _rootByteSymbols,
            _rootCharSymbols,
            isEnabled(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES),
            isEnabled(JsonFactory.Feature.INTERN_FIELD_NAMES));
  }

  /** @deprecated since 2.1 -- use {@link #_createParser(InputStream, IOContext)} instead */
  @Deprecated
  protected JsonParser _createJsonParser(InputStream in, IOContext ctxt)
      throws IOException, JsonParseException {
    return _createParser(in, ctxt);
  }

  /**
   * 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.
   *
   * @since 2.1
   */
  protected JsonParser _createParser(Reader r, IOContext ctxt)
      throws IOException, JsonParseException {
    return new ReaderBasedJsonParser(
        ctxt,
        _parserFeatures,
        r,
        _objectCodec,
        _rootCharSymbols.makeChild(
            isEnabled(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES),
            isEnabled(JsonFactory.Feature.INTERN_FIELD_NAMES)));
  }

  /** @deprecated since 2.1 -- use {@link #_createParser(Reader, IOContext)} instead */
  @Deprecated
  protected JsonParser _createJsonParser(Reader r, IOContext ctxt)
      throws IOException, JsonParseException {
    return _createParser(r, ctxt);
  }

  /**
   * 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 _createParser(byte[] data, int offset, int len, IOContext ctxt)
      throws IOException, JsonParseException {
    return new ByteSourceJsonBootstrapper(ctxt, data, offset, len)
        .constructParser(
            _parserFeatures,
            _objectCodec,
            _rootByteSymbols,
            _rootCharSymbols,
            isEnabled(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES),
            isEnabled(JsonFactory.Feature.INTERN_FIELD_NAMES));
  }

  /** @deprecated since 2.1 -- use {@link #_createParser(byte[], int, int, IOContext)} instead */
  @Deprecated
  protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt)
      throws IOException, JsonParseException {
    return _createParser(data, offset, len, ctxt);
  }

  /*
  /**********************************************************
  /* 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 _createGenerator(Writer out, IOContext ctxt) throws IOException {
    WriterBasedJsonGenerator gen =
        new WriterBasedJsonGenerator(ctxt, _generatorFeatures, _objectCodec, out);
    if (_characterEscapes != null) {
      gen.setCharacterEscapes(_characterEscapes);
    }
    SerializableString rootSep = _rootValueSeparator;
    if (rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) {
      gen.setRootValueSeparator(rootSep);
    }
    return gen;
  }

  /** @deprecated since 2.1 -- use {@link #_createGenerator(Writer, IOContext)} instead */
  @Deprecated
  protected JsonGenerator _createJsonGenerator(Writer out, IOContext ctxt) throws IOException {
    /* NOTE: MUST call the deprecated method until it is deleted, just so
     * that override still works as expected, for now.
     */
    return _createGenerator(out, ctxt);
  }

  /**
   * 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 _createUTF8Generator(OutputStream out, IOContext ctxt)
      throws IOException {
    UTF8JsonGenerator gen = new UTF8JsonGenerator(ctxt, _generatorFeatures, _objectCodec, out);
    if (_characterEscapes != null) {
      gen.setCharacterEscapes(_characterEscapes);
    }
    SerializableString rootSep = _rootValueSeparator;
    if (rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) {
      gen.setRootValueSeparator(rootSep);
    }
    return gen;
  }

  /** @deprecated since 2.1 */
  @Deprecated
  protected JsonGenerator _createUTF8JsonGenerator(OutputStream out, IOContext ctxt)
      throws IOException {
    return _createUTF8Generator(out, ctxt);
  }

  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) {
        // [Issue#48]: Let's try to avoid probs with URL encoded stuff
        String path = url.getPath();
        if (path.indexOf('%') < 0) {
          return new FileInputStream(url.getPath());
        }
        // otherwise, let's fall through and let URL decoder do its magic
      }
    }
    return url.openStream();
  }
}