ObjectMapper.java

package tools.jackson.databind;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.file.Path;
import java.text.DateFormat;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

import tools.jackson.core.*;
import tools.jackson.core.exc.JacksonIOException;
import tools.jackson.core.exc.StreamReadException;
import tools.jackson.core.io.CharacterEscapes;
import tools.jackson.core.io.SegmentedStringWriter;
import tools.jackson.core.json.JsonFactory;
import tools.jackson.core.type.ResolvedType;
import tools.jackson.core.type.TypeReference;
import tools.jackson.core.util.*;
import tools.jackson.databind.cfg.*;
import tools.jackson.databind.deser.DeserializationContextExt;
import tools.jackson.databind.exc.MismatchedInputException;
import tools.jackson.databind.introspect.*;
import tools.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import tools.jackson.databind.jsontype.SubtypeResolver;
import tools.jackson.databind.node.*;
import tools.jackson.databind.ser.*;
import tools.jackson.databind.type.*;
import tools.jackson.databind.util.ClassUtil;
import tools.jackson.databind.util.RootNameLookup;
import tools.jackson.databind.util.TokenBuffer;

/**
 * ObjectMapper provides functionality for reading and writing JSON,
 * either to and from basic POJOs (Plain Old Java Objects), or to and from
 * a general-purpose JSON Tree Model ({@link JsonNode}), as well as
 * related functionality for performing conversions.
 * In addition to directly reading and writing JSON (and with different underlying
 * {@link TokenStreamFactory} configuration, other formats), it is also the
 * mechanism for creating {@link ObjectReader}s and {@link ObjectWriter}s which
 * offer more advancing reading/writing functionality.
 *<p>
 * Construction of mapper instances proceeds either via no-arguments constructor
 * (producing instance with default configuration); or through one of two build
 * methods.
 * First build method is the static <code>builder()</code> on exact type
 * and second {@link #rebuild()} method on an existing mapper.
 * Former starts with default configuration (same as one that no-arguments constructor
 * created mapper has), and latter starts with configuration of the mapper it is called
 * on.
 * In both cases, after configuration (including addition of {@link JacksonModule}s) is complete,
 * instance is created by calling {@link MapperBuilder#build()} method.
 *<p>
 * Mapper (and {@link ObjectReader}s, {@link ObjectWriter}s it constructs) will
 * use instances of {@link JsonParser} and {@link JsonGenerator}
 * for implementing actual reading/writing of JSON.
 * Note that although most read and write methods are exposed through this class,
 * some of the functionality is only exposed via {@link ObjectReader} and
 * {@link ObjectWriter}: specifically, reading/writing of longer sequences of
 * values is only available through {@link ObjectReader#readValues(InputStream)}
 * and {@link ObjectWriter#writeValues(OutputStream)}.
 *<p>
Simplest usage is of form:
<pre>
  final ObjectMapper mapper = new ObjectMapper(); // can use static singleton, inject: just make sure to reuse!
  MyValue value = new MyValue();
  // ... and configure
  File newState = new File("my-stuff.json");
  mapper.writeValue(newState, value); // writes JSON serialization of MyValue instance
  // or, read
  MyValue older = mapper.readValue(new File("my-older-stuff.json"), MyValue.class);

  // Or if you prefer JSON Tree representation:
  JsonNode root = mapper.readTree(newState);
  // and find values by, for example, using a {@link tools.jackson.core.JsonPointer} expression:
  int age = root.at("/personal/age").getValueAsInt();
</pre>
 *<p>
 * Mapper instances are fully thread-safe as of Jackson 3.0.
 *<p>
 * Note on caching: root-level deserializers are always cached, and accessed
 * using full (generics-aware) type information. This is different from
 * caching of referenced types, which is more limited and is done only
 * for a subset of all deserializer types. The main reason for difference
 * is that at root-level there is no incoming reference (and hence no
 * referencing property, no referral information or annotations to
 * produce differing deserializers), and that the performance impact
 * greatest at root level (since it'll essentially cache the full
 * graph of deserializers involved).
 */
public class ObjectMapper
    implements TreeCodec, Versioned,
        java.io.Serializable
{
    private static final long serialVersionUID = 3L;

    /*
    /**********************************************************************
    /* Helper classes, enums
    /**********************************************************************
     */

    /**
     * Base implementation for "Vanilla" {@link ObjectMapper}, only defined to support
     * backwards-compatibility with some of 2.x usage patterns.
     */
    private static class PrivateBuilder extends MapperBuilder<ObjectMapper, PrivateBuilder>
    {
        public PrivateBuilder(TokenStreamFactory tsf) {
            super(tsf);
        }

        @Override
        public ObjectMapper build() {
            return new ObjectMapper(this);
        }

        @Override
        protected MapperBuilderState _saveState() {
            return new StateImpl(this);
        }

        public PrivateBuilder(MapperBuilderState state) {
            super(state);
        }

     // We also need actual instance of state as base class cannot implement logic
     // for reinstating mapper (via mapper builder) from state.
        static class StateImpl extends MapperBuilderState {
            private static final long serialVersionUID = 3L;

            public StateImpl(PrivateBuilder b) {
                super(b);
            }

            @Override
            protected Object readResolve() {
                return new PrivateBuilder(this).build();
            }
        }
    }

    /*
    /**********************************************************************
    /* Internal constants, singletons
    /**********************************************************************
     */

    // Quick little shortcut, to avoid having to use global TypeFactory instance...
    // 19-Oct-2015, tatu: Not sure if this is really safe to do; let's at least allow
    //   some amount of introspection
    private final static JavaType JSON_NODE_TYPE =
            SimpleType.constructUnsafe(JsonNode.class);
//          TypeFactory.defaultInstance().constructType(JsonNode.class);

    /*
    /**********************************************************************
    /* Configuration settings, shared
    /**********************************************************************
     */

    /**
     * Factory used to create {@link JsonParser} and {@link JsonGenerator}
     * instances as necessary.
     */
    protected final TokenStreamFactory _streamFactory;

    /**
     * Specific factory used for creating {@link JavaType} instances;
     * needed to allow modules to add more custom type handling
     * (mostly to support types of non-Java JVM languages)
     */
    protected final TypeFactory _typeFactory;

    /**
     * Provider for values to inject in deserialized POJOs.
     */
    protected final InjectableValues _injectableValues;

    /*
    /**********************************************************************
    /* Configuration settings, serialization
    /**********************************************************************
     */

    /**
     * Factory used for constructing per-call {@link SerializationContext} instances.
     */
    protected final SerializationContexts _serializationContexts;

    /**
     * Configuration object that defines basic global
     * settings for the serialization process
     */
    protected final SerializationConfig _serializationConfig;

    /*
    /**********************************************************************
    /* Configuration settings, deserialization
    /**********************************************************************
     */

    /**
     * Factory used for constructing per-call {@link DeserializationContext} instances.
     */
    protected final DeserializationContexts _deserializationContexts;

    /**
     * Configuration object that defines basic global
     * settings for the serialization process
     */
    protected final DeserializationConfig _deserializationConfig;

    /*
    /**********************************************************************
    /* Caching
    /**********************************************************************
     */

    /* Note: handling of serializers and deserializers is not symmetric;
     * and as a result, only root-level deserializers can be cached here.
     * This is mostly because typing and resolution for deserializers is
     * fully static; whereas it is quite dynamic for serialization.
     */

    /**
     * We will use a separate main-level Map for keeping track
     * of root-level deserializers. This is where most successful
     * cache lookups get resolved.
     * Map will contain resolvers for all kinds of types, including
     * container types: this is different from the component cache
     * which will only cache bean deserializers.
     *<p>
     * Given that we don't expect much concurrency for additions
     * (should very quickly converge to zero after startup), let's
     * explicitly define a low concurrency setting.
     *<p>
     * These may are either "raw" deserializers (when
     * no type information is needed for base type), or type-wrapped
     * deserializers (if it is needed)
     */
    protected final ConcurrentHashMap<JavaType, ValueDeserializer<Object>> _rootDeserializers
        = new ConcurrentHashMap<JavaType, ValueDeserializer<Object>>(64, 0.6f, 2);

    /*
    /**********************************************************************
    /* Saved state to allow re-building
    /**********************************************************************
     */

    /**
     * Minimal state retained to allow both re-building (by
     * creating new builder) and JDK serialization of this mapper.
     *
     * @since 3.0
     */
    protected final MapperBuilderState _savedBuilderState;

    /*
    /**********************************************************************
    /* Life-cycle: legacy constructors
    /**********************************************************************
     */

    /**
     * Default constructor, which will construct the default JSON-handling
     * {@link TokenStreamFactory} as necessary and all other unmodified
     * default settings, and no additional registered modules.
     */
    public ObjectMapper() {
        this(new PrivateBuilder(new JsonFactory()));
    }

    /**
     * Constructs instance that uses specified {@link TokenStreamFactory}
     * for constructing necessary {@link JsonParser}s and/or
     * {@link JsonGenerator}s, but without registering additional modules.
     */
    public ObjectMapper(TokenStreamFactory streamFactory) {
        this(new PrivateBuilder(streamFactory));
    }

    /*
    /**********************************************************************
    /* Life-cycle: builder-style construction
    /**********************************************************************
     */

    /**
     * Constructor usually called either by {@link MapperBuilder#build} or
     * by sub-class constructor: will get all the settings through passed-in
     * builder, including registration of any modules added to builder.
     */
    protected ObjectMapper(MapperBuilder<?,?> builder)
    {
        // First things first: finalize building process. Saved state
        // consists of snapshots and is safe to keep references to; used
        // for rebuild()ing mapper instances

        _savedBuilderState = builder.saveStateApplyModules();

        // But we will ALSO need to take snapshot of anything builder has,
        // in case caller keeps on tweaking with builder. So rules are the
        // as with above call, or when creating new builder for rebuild()ing

        // General framework factories
        _streamFactory = builder.streamFactory();

        final ConfigOverrides configOverrides;
        {
            // bit tricky as we do NOT want to expose simple accessors (to a mutable thing)
            final AtomicReference<ConfigOverrides> ref = new AtomicReference<>();
            builder.withAllConfigOverrides(overrides -> ref.set(overrides));
            configOverrides = Snapshottable.takeSnapshot(ref.get());
        }
        final CoercionConfigs coercionConfigs;
        {
            final AtomicReference<CoercionConfigs> ref = new AtomicReference<>();
            builder.withAllCoercionConfigs(overrides -> ref.set(overrides));
            coercionConfigs = Snapshottable.takeSnapshot(ref.get());
        }

        // Handlers, introspection
        _typeFactory =  Snapshottable.takeSnapshot(builder.typeFactory());
        ClassIntrospector classIntr = builder.classIntrospector().forMapper();
        SubtypeResolver subtypeResolver =  Snapshottable.takeSnapshot(builder.subtypeResolver());
        MixInHandler mixIns = (MixInHandler) Snapshottable.takeSnapshot(builder.mixInHandler());
        // NOTE: TypeResolverProvider apparently ok without snapshot, hence config objects fetch
        // it directly from MapperBuilder, not passed by us.

        // And then finalize serialization/deserialization Config containers

        RootNameLookup rootNames = new RootNameLookup();
        FilterProvider filterProvider = Snapshottable.takeSnapshot(builder.filterProvider());
        _deserializationConfig = builder.buildDeserializationConfig(configOverrides,
                mixIns, _typeFactory, classIntr, subtypeResolver,
                rootNames, coercionConfigs);
        _serializationConfig = builder.buildSerializationConfig(configOverrides,
                mixIns, _typeFactory, classIntr, subtypeResolver,
                rootNames, filterProvider);

        // Serialization factories
        _serializationContexts = builder.serializationContexts()
                .forMapper(this, _serializationConfig,
                        _streamFactory, builder.serializerFactory());

        // Deserialization factories
        _deserializationContexts = builder.deserializationContexts()
                .forMapper(this, _deserializationConfig,
                        _streamFactory, builder.deserializerFactory());
        _injectableValues = Snapshottable.takeSnapshot(builder.injectableValues());
    }

    /**
     * Method for creating a new {@link MapperBuilder} for constructing differently configured
     * {@link ObjectMapper} instance, starting with current configuration including base settings
     * and registered modules.
     *
     * @since 3.0
     */
    @SuppressWarnings("unchecked")
    public <M extends ObjectMapper, B extends MapperBuilder<M,B>> MapperBuilder<M,B> rebuild() {
        // 27-Feb-2018, tatu: since we still have problem with `ObjectMapper` being both API
        //    and implementation for JSON, need more checking here
        ClassUtil.verifyMustOverride(ObjectMapper.class, this, "rebuild");
        return (MapperBuilder<M,B>) new PrivateBuilder(_savedBuilderState);
    }

    /*
    /**********************************************************************
    /* Life-cycle: JDK serialization support
    /**********************************************************************
     */

    // Logic here is simple: instead of serializing mapper via its contents,
    // we have pre-packaged `MapperBuilderState` in a way that makes serialization
    // easier, and we go with that.
    // But note that return direction has to be supported, then, by that state object
    // and NOT anything in here.
    protected Object writeReplace() {
        return _savedBuilderState;
    }

    // Just as a sanity check verify there is no attempt at directly instantiating mapper here
    protected Object readResolve() {
        throw new IllegalStateException("Should never deserialize `"+getClass().getName()+"` directly");
    }

    /*
    /**********************************************************************
    /* Versioned impl
    /**********************************************************************
     */

    /**
     * Method that will return version information stored in and read from jar
     * that contains this class.
     */
    @Override
    public Version version() {
        return tools.jackson.databind.cfg.PackageVersion.VERSION;
    }

    /*
    /**********************************************************************
    /* Configuration: main config object access
    /**********************************************************************
     */

    /**
     * Accessor for internal configuration object that contains settings for
     * serialization operations (<code>writeValue(...)</code> methods)
     *<br>
     * NOTE: Not to be used by application code; needed by some tests
     */
    public SerializationConfig serializationConfig() {
        return _serializationConfig;
    }

    /**
     * Accessor for internal configuration object that contains settings for
     * deserialization operations (<code>readValue(...)</code> methods)
     *<br>
     * NOTE: Not to be used by application code; needed by some tests
     */
    public DeserializationConfig deserializationConfig() {
        return _deserializationConfig;
    }

    /**
     * Method that can be used to get hold of {@link TokenStreamFactory} that this
     * mapper uses if it needs to construct {@link JsonParser}s
     * and/or {@link JsonGenerator}s.
     *<p>
     * WARNING: note that all {@link ObjectReader} and {@link ObjectWriter}
     * instances created by this mapper usually share the same configured
     * {@link TokenStreamFactory}, so changes to its configuration will "leak".
     * To avoid such observed changes you should always use "with()" and
     * "without()" method of {@link ObjectReader} and {@link ObjectWriter}
     * for changing {@link StreamReadFeature}
     * and {@link StreamWriteFeature}
     * settings to use on per-call basis.
     *
     * @return {@link TokenStreamFactory} that this mapper uses when it needs to
     *   construct Json parser and generators
     *
     * @since 3.0
     */
    public TokenStreamFactory tokenStreamFactory() { return _streamFactory; }

    /**
     * Method that can be used to get hold of {@link JsonNodeFactory}
     * that this mapper will use when directly constructing
     * root {@link JsonNode} instances for Trees.
     *<p>
     * Note: this is just a shortcut for calling
     *<pre>
     *   getDeserializationConfig().getNodeFactory()
     *</pre>
     */
    public JsonNodeFactory getNodeFactory() {
        return _deserializationConfig.getNodeFactory();
    }

    public InjectableValues getInjectableValues() {
        return _injectableValues;
    }

    /*
    /**********************************************************************
    /* Configuration, access to type factory, type resolution
    /**********************************************************************
     */

    /**
     * Accessor for getting currently configured {@link TypeFactory} instance.
     */
    public TypeFactory getTypeFactory() {
        return _typeFactory;
    }

    /**
     * Convenience method for constructing {@link JavaType} out of given
     * type (typically <code>java.lang.Class</code>), but without explicit
     * context.
     */
    public JavaType constructType(Type type) {
        _assertNotNull("type", type);
        return _typeFactory.constructType(type);
    }

    /**
     * Convenience method for constructing {@link JavaType} out of given
     * type reference.
     */
    public JavaType constructType(TypeReference<?> typeReference) {
        _assertNotNull("typeReference", typeReference);
        return _typeFactory.constructType(typeReference);
    }

    /*
    /**********************************************************************
    /* Configuration, accessing features
    /**********************************************************************
     */

    public boolean isEnabled(TokenStreamFactory.Feature f) {
        return _streamFactory.isEnabled(f);
    }

    public boolean isEnabled(StreamReadFeature f) {
        return _deserializationConfig.isEnabled(f);
    }

    public boolean isEnabled(StreamWriteFeature f) {
        return _serializationConfig.isEnabled(f);
    }

    /**
     * Method for checking whether given {@link MapperFeature} is enabled.
     */
    public boolean isEnabled(MapperFeature f) {
        // ok to use either one, should be kept in sync
        return _serializationConfig.isEnabled(f);
    }

    /**
     * Method for checking whether given deserialization-specific
     * feature is enabled.
     */
    public boolean isEnabled(DeserializationFeature f) {
        return _deserializationConfig.isEnabled(f);
    }

    /**
     * Method for checking whether given serialization-specific
     * feature is enabled.
     */
    public boolean isEnabled(SerializationFeature f) {
        return _serializationConfig.isEnabled(f);
    }

    /**
     * Method for checking whether given datatype-specific
     * feature is enabled.
     */
    public boolean isEnabled(DatatypeFeature f) {
        // could call either config object:
        return _serializationConfig.isEnabled(f);
    }

    /*
    /**********************************************************************
    /* Configuration, accessing module information
    /**********************************************************************
     */

    /**
     * Method that may be used to find out {@link JacksonModule}s that were registered
     * when creating this mapper (if any).
     *<p>
     * NOTE: in 2.x this method was called <code>getRegisteredModuleIds()</code> and
     * returned Module identifiers (typically {@code String}s); but since 3.0 it returns actual
     * {@link JacksonModule} instances.
     *
     * @since 3.0
     */
    public Collection<JacksonModule> registeredModules() {
        return _savedBuilderState.modules();
    }

    /*
    /**********************************************************************
    /* Public API: constructing Parsers that are properly linked
    /* to `ObjectReadContext`
    /**********************************************************************
     */

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,java.io.File)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(File src) throws JacksonException {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, src));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,Path)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(Path src) throws JacksonException {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, src));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,InputStream)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(InputStream in) throws JacksonException {
        _assertNotNull("in", in);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, in));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,Reader)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(Reader r) throws JacksonException {
        _assertNotNull("r", r);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, r));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,byte[])}.
     *
     * @since 3.0
     */
    public JsonParser createParser(byte[] content) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, content));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,byte[],int,int)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(byte[] content, int offset, int len) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, content, offset, len));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,String)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(String content) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, content));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,char[])}.
     *
     * @since 3.0
     */
    public JsonParser createParser(char[] content) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, content));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,char[],int,int)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(char[] content, int offset, int len) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, content, offset, len));
    }

    /**
     * Factory method for constructing {@link JsonParser} that is properly
     * wired to allow callbacks for deserialization: basically
     * constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createParser(ObjectReadContext,DataInput)}.
     *
     * @since 3.0
     */
    public JsonParser createParser(DataInput content) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createParser(ctxt, content));
    }

    /**
     * Factory method for constructing non-blocking {@link JsonParser} that is properly
     * wired to allow configuration access (and, if relevant for parser, callbacks):
     * essentially constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createNonBlockingByteArrayParser(ObjectReadContext)}.
     *
     * @since 3.0
     */
    public JsonParser createNonBlockingByteArrayParser() throws JacksonException {
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createNonBlockingByteArrayParser(ctxt));
    }

    /**
     * Factory method for constructing non-blocking {@link JsonParser} that is properly
     * wired to allow configuration access (and, if relevant for parser, callbacks):
     * essentially constructs a {@link ObjectReadContext} and then calls
     * {@link TokenStreamFactory#createNonBlockingByteBufferParser(ObjectReadContext)}.
     *
     * @since 3.0
     */
    public JsonParser createNonBlockingByteBufferParser() throws JacksonException {
        DeserializationContextExt ctxt = _deserializationContext();
        return ctxt.assignAndReturnParser(_streamFactory.createNonBlockingByteBufferParser(ctxt));
    }

    /*
    /**********************************************************************
    /* Public API: constructing Generator that are properly linked
    /* to `ObjectWriteContext`
    /**********************************************************************
     */

    /**
     * Factory method for constructing {@link JsonGenerator} that is properly
     * wired to allow callbacks for serialization: basically
     * constructs a {@link ObjectWriteContext} and then calls
     * {@link TokenStreamFactory#createGenerator(ObjectWriteContext,OutputStream)}.
     *
     * @since 3.0
     */
    public JsonGenerator createGenerator(OutputStream out) throws JacksonException {
        _assertNotNull("out", out);
        return _streamFactory.createGenerator(_serializationContext(), out);
    }

    /**
     * Factory method for constructing {@link JsonGenerator} that is properly
     * wired to allow callbacks for serialization: basically
     * constructs a {@link ObjectWriteContext} and then calls
     * {@link TokenStreamFactory#createGenerator(ObjectWriteContext,OutputStream,JsonEncoding)}.
     *
     * @since 3.0
     */
    public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws JacksonException {
        _assertNotNull("out", out);
        return _streamFactory.createGenerator(_serializationContext(), out, enc);
    }

    /**
     * Factory method for constructing {@link JsonGenerator} that is properly
     * wired to allow callbacks for serialization: basically
     * constructs a {@link ObjectWriteContext} and then calls
     * {@link TokenStreamFactory#createGenerator(ObjectWriteContext,Writer)}.
     *
     * @since 3.0
     */
    public JsonGenerator createGenerator(Writer w) throws JacksonException {
        _assertNotNull("w", w);
        return _streamFactory.createGenerator(_serializationContext(), w);
    }

    /**
     * Factory method for constructing {@link JsonGenerator} that is properly
     * wired to allow callbacks for serialization: basically
     * constructs a {@link ObjectWriteContext} and then calls
     * {@link TokenStreamFactory#createGenerator(ObjectWriteContext,File,JsonEncoding)}.
     *
     * @since 3.0
     */
    public JsonGenerator createGenerator(File f, JsonEncoding enc) throws JacksonException {
        _assertNotNull("f", f);
        return _streamFactory.createGenerator(_serializationContext(), f, enc);
    }

    /**
     * Factory method for constructing {@link JsonGenerator} that is properly
     * wired to allow callbacks for serialization: basically
     * constructs a {@link ObjectWriteContext} and then calls
     * {@link TokenStreamFactory#createGenerator(ObjectWriteContext,Path,JsonEncoding)}.
     *
     * @since 3.0
     */
    public JsonGenerator createGenerator(Path path, JsonEncoding enc) throws JacksonException {
        _assertNotNull("path", path);
        return _streamFactory.createGenerator(_serializationContext(), path, enc);
    }

    /**
     * Factory method for constructing {@link JsonGenerator} that is properly
     * wired to allow callbacks for serialization: basically
     * constructs a {@link ObjectWriteContext} and then calls
     * {@link TokenStreamFactory#createGenerator(ObjectWriteContext,DataOutput)}.
     *
     * @since 3.0
     */
    public JsonGenerator createGenerator(DataOutput out) throws JacksonException {
        _assertNotNull("out", out);
        return _streamFactory.createGenerator(_serializationContext(), out);
    }

    /*
    /**********************************************************************
    /* TreeCodec implementation
    /**********************************************************************
     */

    /**
     *<p>
     * Note: return type is co-variant, as basic {@link TreeCodec}
     * abstraction cannot refer to concrete node types (as it's
     * part of core package, whereas impls are part of mapper
     * package)
     */
    @Override
    public ObjectNode createObjectNode() {
        return _deserializationConfig.getNodeFactory().objectNode();
    }

    /**
     *<p>
     * Note: return type is co-variant, as basic {@link TreeCodec}
     * abstraction cannot refer to concrete node types (as it's
     * part of core package, whereas impls are part of mapper
     * package)
     */
    @Override
    public ArrayNode createArrayNode() {
        return _deserializationConfig.getNodeFactory().arrayNode();
    }

    @Override
    public JsonNode booleanNode(boolean b) {
        return _deserializationConfig.getNodeFactory().booleanNode(b);
    }

    @Override
    public JsonNode stringNode(String text) {
        return _deserializationConfig.getNodeFactory().stringNode(text);
    }

    @Override
    public JsonNode missingNode() {
        return _deserializationConfig.getNodeFactory().missingNode();
    }

    @Override
    public JsonNode nullNode() {
        return _deserializationConfig.getNodeFactory().nullNode();
    }

    /**
     * Method for constructing a {@link JsonParser} out of JSON tree
     * representation.
     *
     * @param n Root node of the tree that resulting parser will read from
     */
    @Override
    public JsonParser treeAsTokens(TreeNode n) {
        _assertNotNull("n", n);
        DeserializationContext ctxt = _deserializationContext();
        return new TreeTraversingParser((JsonNode) n, ctxt);
    }

    /**
     * Method to deserialize JSON content as a tree {@link JsonNode}.
     * Returns {@link JsonNode} that represents the root of the resulting tree, if there
     * was content to read, or {@code null} if no more content is accessible
     * via passed {@link JsonParser}.
     *<p>
     * NOTE! Behavior with end-of-input (no more content) differs between this
     * {@code readTree} method, and all other methods that take input source: latter
     * will return "missing node", NOT {@code null}
     *
     * @return a {@link JsonNode}, if valid JSON content found; null
     *   if input has no content to bind -- note, however, that if
     *   JSON <code>null</code> token is found, it will be represented
     *   as a non-null {@link JsonNode} (one that returns <code>true</code>
     *   for {@link JsonNode#isNull()}
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     */
    @SuppressWarnings("unchecked")
    @Override
    public JsonNode readTree(JsonParser p) throws JacksonException
    {
        _assertNotNull("p", p);
        // Must check for EOF here before calling readValue(), since that'll choke on it otherwise
        JsonToken t = p.currentToken();
        if (t == null) {
            t = p.nextToken();
            if (t == null) {
                return null;
            }
        }
        // NOTE! _readValue() will check for trailing tokens
        JsonNode n = (JsonNode) _readValue(_deserializationContext(p), p, JSON_NODE_TYPE);
        if (n == null) {
            n = getNodeFactory().nullNode();
        }
        return n;
    }

    @Override
    public void writeTree(JsonGenerator g, TreeNode rootNode) throws JacksonException
    {
        _assertNotNull("g", g);
        SerializationConfig config = serializationConfig();
        _serializationContext(config).serializeValue(g, rootNode);
        if (config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
            g.flush();
        }
    }

    /*
    /**********************************************************************
    /* Public API deserialization, main methods
    /**********************************************************************
     */

    /**
     * Method to deserialize JSON content into a non-container
     * type (it can be an array type, however): typically a bean, array
     * or a wrapper type (like {@link java.lang.Boolean}).
     *<p>
     * Note: this method should NOT be used if the result type is a
     * container ({@link java.util.Collection} or {@link java.util.Map}.
     * The reason is that due to type erasure, key and value types
     * cannot be introspected when using this method.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(JsonParser p, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("p", p);
        return (T) _readValue(_deserializationContext(p), p, _typeFactory.constructType(valueType));
    }

    /**
     * Method to deserialize JSON content into a Java type, reference
     * to which is passed as argument. Type is passed using so-called
     * "super type token" (see )
     * and specifically needs to be used if the root type is a
     * parameterized (generic) container type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(JsonParser p, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("p", p);
        return (T) _readValue(_deserializationContext(p), p, _typeFactory.constructType(valueTypeRef));
    }

    /**
     * Method to deserialize JSON content into a Java type, reference
     * to which is passed as argument. Type is passed using
     * Jackson specific type; instance of which can be constructed using
     * {@link TypeFactory}.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(JsonParser p, ResolvedType valueType) throws JacksonException
    {
        _assertNotNull("p", p);
        return (T) _readValue(_deserializationContext(p), p, (JavaType) valueType);
    }

    /**
     * Type-safe overloaded method, basically alias for {@link #readValue(JsonParser, Class)}.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(JsonParser p, JavaType valueType) throws JacksonException
    {
        _assertNotNull("p", p);
        return (T) _readValue(_deserializationContext(p), p, valueType);
    }

    /**
     * Convenience method, equivalent in function to:
     *<pre>
     *   readerFor(valueType).readValues(p);
     *</pre>
     *<p>
     * Method for reading sequence of Objects from parser stream.
     * Sequence can be either root-level "unwrapped" sequence (without surrounding
     * JSON array), or a sequence contained in a JSON Array.
     * In either case {@link JsonParser} <b>MUST</b> point to the first token of
     * the first element, OR not point to any token (in which case it is advanced
     * to the next token). This means, specifically, that for wrapped sequences,
     * parser MUST NOT point to the surrounding <code>START_ARRAY</code> (one that
     * contains values to read) but rather to the token following it which is the first
     * token of the first value to read.
     *<p>
     * Note that {@link ObjectReader} has more complete set of variants.
     */
    public <T> MappingIterator<T> readValues(JsonParser p, JavaType valueType)
        throws JacksonException
    {
        _assertNotNull("p", p);
        DeserializationContext ctxt = _deserializationContext(p);
        ValueDeserializer<?> deser = _findRootDeserializer(ctxt, valueType);
        // false -> do NOT close JsonParser (since caller passed it)
        return new MappingIterator<T>(valueType, p, ctxt, deser,
                false, null);
    }

    /**
     * Convenience method, equivalent in function to:
     *<pre>
     *   readerFor(valueType).readValues(p);
     *</pre>
     *<p>
     * Type-safe overload of {@link #readValues(JsonParser, JavaType)}.
     */
    public <T> MappingIterator<T> readValues(JsonParser p, Class<T> valueType)
        throws JacksonException
    {
        _assertNotNull("p", p);
        return readValues(p, _typeFactory.constructType(valueType));
    }

    // Used by Kotlin module
    public <T> MappingIterator<T> readValues(JsonParser p, TypeReference<T> valueType)
        throws JacksonException
    {
        _assertNotNull("p", p);
        return readValues(p, _typeFactory.constructType(valueType));
    }

    /*
    /**********************************************************************
    /* Public API: deserialization
    /* (mapping from token stream to Java types)
    /**********************************************************************
     */

    /**
     * Method to deserialize JSON content as tree expressed
     * using set of {@link JsonNode} instances.
     * Returns root of the resulting tree (where root can consist
     * of just a single node if the current event is a
     * value event, not container).
     *<p>
     * If a low-level I/O problem (missing input, network error) occurs,
     * a {@link IOException} will be thrown.
     * If a parsing problem occurs (invalid JSON),
     * {@link StreamReadException} will be thrown.
     * If no content is found from input (end-of-input), Java
     * <code>null</code> will be returned.
     *
     * @param in Input stream used to read JSON content
     *   for building the JSON tree.
     *
     * @return a {@link JsonNode}, if valid JSON content found; null
     *   if input has no content to bind -- note, however, that if
     *   JSON <code>null</code> token is found, it will be represented
     *   as a non-null {@link JsonNode} (one that returns <code>true</code>
     *   for {@link JsonNode#isNull()}
     *
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     */
    public JsonNode readTree(InputStream in) throws JacksonException
    {
        _assertNotNull("in", in);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, in));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content accessed through
     * passed-in {@link Reader}
     */
    public JsonNode readTree(Reader r) throws JacksonException {
        _assertNotNull("r", r);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, r));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content read from
     * passed-in {@link String}
     */
    public JsonNode readTree(String content) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, content));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content read from
     * passed-in byte array.
     */
    public JsonNode readTree(byte[] content) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, content));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content read from
     * passed-in byte array.
     */
    public JsonNode readTree(byte[] content, int offset, int len) throws JacksonException {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, content, offset, len));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content read from
     * passed-in {@link File}.
     */
    public JsonNode readTree(File file) throws JacksonException
    {
        _assertNotNull("file", file);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, file));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content read from
     * passed-in {@link Path}.
     */
    public JsonNode readTree(Path path) throws JacksonException
    {
        _assertNotNull("path", path);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, _streamFactory.createParser(ctxt, path));
    }

    /**
     * Same as {@link #readTree(InputStream)} except content read from
     * passed-in {@link TokenBuffer}.
     */
    public JsonNode readTree(TokenBuffer src) throws JacksonException {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return _readTreeAndClose(ctxt, src.asParser(ctxt));
    }

    /*
    /**********************************************************************
    /* Public API serialization
    /* (mapping from Java types to token streams)
    /**********************************************************************
     */

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, using provided {@link JsonGenerator}.
     */
    public void writeValue(JsonGenerator g, Object value) throws JacksonException
    {
        _assertNotNull("g", g);
        SerializationConfig config = serializationConfig();
        // 04-Oct-2017, tatu: Generator should come properly configured and we should not
        //   change its state in any way, I think (at least with Jackson 3.0)
        /*
        if (config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
            if (g.getPrettyPrinter() == null) {
                g.setPrettyPrinter(config.constructDefaultPrettyPrinter());
            }
        }
        */
        if (config.isEnabled(SerializationFeature.CLOSE_CLOSEABLE)
                && (value instanceof AutoCloseable)) {
            _writeCloseableValue(g, value, config);
        } else {
            _serializationContext(config).serializeValue(g, value);
            if (config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
                g.flush();
            }
        }
    }

    /*
    /**********************************************************************
    /* Public API: Additional Tree Model support beyond TreeCodec
    /**********************************************************************
     */

    /**
     * Convenience conversion method that will bind data given JSON tree
     * contains into specific value (usually bean) type.
     *<p>
     * Functionally equivalent to:
     *<pre>
     *   objectMapper.convertValue(n, valueClass);
     *</pre>
     */
    @SuppressWarnings("unchecked")
    public <T> T treeToValue(TreeNode n, Class<T> valueType)
        throws JacksonException
    {
        if (n == null) {
            return null;
        }
        // 25-Jan-2019, tatu: [databind#2220] won't prevent existing coercions here
        // Simple cast when we just want to cast to, say, ObjectNode
        if (TreeNode.class.isAssignableFrom(valueType)
                && valueType.isAssignableFrom(n.getClass())) {
            return (T) n;
        }
        final JsonToken tt = n.asToken();
        // 20-Apr-2016, tatu: Another thing: for VALUE_EMBEDDED_OBJECT, assume similar
        //    short-cut coercion
        if (tt == JsonToken.VALUE_EMBEDDED_OBJECT) {
            if (n instanceof POJONode pNode) {
                Object ob = pNode.getPojo();
                if ((ob == null) || valueType.isInstance(ob)) {
                    return (T) ob;
                }
            }
        }
        // 22-Aug-2019, tatu: [databind#2430] Consider "null node" (minor optimization)
        // 08-Dec-2020, tatu: Alas, lead to [databind#2972], optimization gets complicated
        //    so leave out for now...
        /*if (tt == JsonToken.VALUE_NULL) {
             return null;
        }*/
        return readValue(treeAsTokens(n), valueType);
    }

    /**
     * Same as {@link #treeToValue(TreeNode, Class)} but target type specified
     * using fully resolved {@link JavaType}.
     */
    @SuppressWarnings("unchecked")
    public <T> T treeToValue(TreeNode n, JavaType valueType)
        throws JacksonException
    {
        // Implementation copied from the type-erased variant
        if (n == null) {
            return null;
        }
        if (valueType.isTypeOrSubTypeOf(TreeNode.class)
                && valueType.isTypeOrSuperTypeOf(n.getClass())) {
            return (T) n;
        }
        final JsonToken tt = n.asToken();
        if (tt == JsonToken.VALUE_EMBEDDED_OBJECT) {
            if (n instanceof POJONode pNode) {
                Object ob = pNode.getPojo();
                if ((ob == null) || valueType.isTypeOrSuperTypeOf(ob.getClass())) {
                    return (T) ob;
                }
            }
        }
        return (T) readValue(treeAsTokens(n), valueType);
    }

    /**
     * Same as {@link #treeToValue(TreeNode, JavaType)} but target type specified
     * using fully resolved {@link TypeReference}.
     */
    public <T> T treeToValue(TreeNode n, TypeReference<T> toValueTypeRef)
        throws JacksonException
    {
        return treeToValue(n, constructType(toValueTypeRef));
    }

    /**
     * Method that is reverse of {@link #treeToValue}: it
     * will convert given Java value (usually bean) into its
     * equivalent Tree model {@link JsonNode} representation.
     * Functionally similar to serializing value into token stream and parsing that
     * stream back as tree model node,
     * but more efficient as {@link TokenBuffer} is used to contain the intermediate
     * representation instead of fully serialized contents.
     *<p>
     * NOTE: while results are usually identical to that of serialization followed
     * by deserialization, this is not always the case. In some cases serialization
     * into intermediate representation will retain encapsulation of things like
     * raw value ({@link tools.jackson.databind.util.RawValue}) or basic
     * node identity ({@link JsonNode}). If so, result is a valid tree, but values
     * are not re-constructed through actual format representation. So if transformation
     * requires actual materialization of encoded content,
     * it will be necessary to do actual serialization.
     *
     * @param <T> Actual node type; usually either basic {@link JsonNode} or
     *  {@link tools.jackson.databind.node.ObjectNode}
     * @param fromValue Java value to convert
     *
     * @return (non-null) Root node of the resulting content tree: in case of
     *   {@code null} value node for which {@link JsonNode#isNull()} returns {@code true}.
     */
    public <T extends JsonNode> T valueToTree(Object fromValue)
        throws JacksonException
    {
        // 02-Mar-2021, tatu: [databind#2411] Rewrite "valueToTree()" impl; old
        //   impl left for reference
        return _serializationContext().valueToTree(fromValue);
    }

    /*
    /**********************************************************************
    /* Public API, deserialization (ext format to Java Objects)
    /**********************************************************************
     */

    /**
     * Method to deserialize JSON content from given file into given Java type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(File src, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt, _streamFactory.createParser(ctxt, src),
                _typeFactory.constructType(valueType));
    }

    /**
     * Method to deserialize JSON content from given file into given Java type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(File src, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt, _streamFactory.createParser(ctxt, src),
                _typeFactory.constructType(valueTypeRef));
    }

    /**
     * Method to deserialize JSON content from given file into given Java type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(File src, JavaType valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt, _streamFactory.createParser(ctxt, src), valueType);
    }

    /**
     * Method to deserialize JSON content from given path into given Java type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     *
     * @since 3.0
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(Path src, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt, _streamFactory.createParser(ctxt, src),
                _typeFactory.constructType(valueType));
    }

    /**
     * Method to deserialize JSON content from given path into given Java type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     *
     * @since 3.0
     */
    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(Path src, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt, _streamFactory.createParser(ctxt, src),
                _typeFactory.constructType(valueTypeRef));
    }

    /**
     * Method to deserialize JSON content from given path into given Java type.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     *
     * @since 3.0
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(Path src, JavaType valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt, _streamFactory.createParser(ctxt, src), valueType);
    }

    /**
     * Method to deserialize JSON content from given JSON content String.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(String content, Class<T> valueType)
        throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content), _typeFactory.constructType(valueType));
    }

    /**
     * Method to deserialize JSON content from given JSON content String.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(String content, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content), _typeFactory.constructType(valueTypeRef));
    }

    /**
     * Method to deserialize JSON content from given JSON content String.
     *
     * @throws JacksonIOException if a low-level I/O problem (unexpected end-of-input,
     *   network error) occurs (passed through as-is without additional wrapping -- note
     *   that this is one case where {@link DeserializationFeature#WRAP_EXCEPTIONS}
     *   does NOT result in wrapping of exception even if enabled)
     * @throws StreamReadException if underlying input contains invalid content
     *    of type {@link JsonParser} supports (JSON for default case)
     * @throws DatabindException if the input JSON structure does not match structure
     *   expected for result type (or has other mismatch issues)
     */
    @SuppressWarnings("unchecked")
    public <T> T readValue(String content, JavaType valueType) throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(Reader src, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), _typeFactory.constructType(valueType));
    }

    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(Reader src, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), _typeFactory.constructType(valueTypeRef));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(Reader src, JavaType valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(InputStream src, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), _typeFactory.constructType(valueType));
    }

    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(InputStream src, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), _typeFactory.constructType(valueTypeRef));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(InputStream src, JavaType valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(byte[] content, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content), _typeFactory.constructType(valueType));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(byte[] content, int offset, int len, Class<T> valueType)
        throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content, offset, len), _typeFactory.constructType(valueType));
    }

    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(byte[] content, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content), _typeFactory.constructType(valueTypeRef));
    }

    @SuppressWarnings({ "unchecked" })
    public <T> T readValue(byte[] content, int offset, int len, TypeReference<T> valueTypeRef)
        throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content, offset, len),
                _typeFactory.constructType(valueTypeRef));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(byte[] content, JavaType valueType) throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(byte[] content, int offset, int len, JavaType valueType)
                    throws JacksonException
    {
        _assertNotNull("content", content);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, content, offset, len), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(DataInput src, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), _typeFactory.constructType(valueType));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(DataInput src, JavaType valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(DataInput src, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                _streamFactory.createParser(ctxt, src), _typeFactory.constructType(valueTypeRef));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(TokenBuffer src, Class<T> valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                src.asParser(ctxt), _typeFactory.constructType(valueType));
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(TokenBuffer src, JavaType valueType) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                src.asParser(ctxt), valueType);
    }

    @SuppressWarnings("unchecked")
    public <T> T readValue(TokenBuffer src, TypeReference<T> valueTypeRef) throws JacksonException
    {
        _assertNotNull("src", src);
        DeserializationContextExt ctxt = _deserializationContext();
        return (T) _readMapAndClose(ctxt,
                src.asParser(ctxt), _typeFactory.constructType(valueTypeRef));
    }

    /*
    /**********************************************************************
    /* Public API: serialization (mapping from Java types to external format)
    /**********************************************************************
     */

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, written to File provided.
     */
    public void writeValue(File file, Object value) throws JacksonException
    {
        _assertNotNull("file", file);
        SerializationContextExt prov = _serializationContext();
        _configAndWriteValue(prov,
                _streamFactory.createGenerator(prov, file, JsonEncoding.UTF8), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, written to Path provided.
     *
     * @since 3.0
     */
    public void writeValue(Path path, Object value) throws JacksonException
    {
        _assertNotNull("path", path);
        SerializationContextExt prov = _serializationContext();
        _configAndWriteValue(prov,
                _streamFactory.createGenerator(prov, path, JsonEncoding.UTF8), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, using output stream provided (using encoding
     * {@link JsonEncoding#UTF8}).
     *<p>
     * Note: method does not close the underlying stream explicitly
     * here; however, {@link TokenStreamFactory} this mapper uses may choose
     * to close the stream depending on its settings (by default,
     * it will try to close it when {@link JsonGenerator} we construct
     * is closed).
     */
    public void writeValue(OutputStream out, Object value) throws JacksonException
    {
        _assertNotNull("out", out);
        SerializationContextExt prov = _serializationContext();
        _configAndWriteValue(prov,
                _streamFactory.createGenerator(prov, out, JsonEncoding.UTF8), value);
    }

    public void writeValue(DataOutput out, Object value) throws JacksonException
    {
        _assertNotNull("out", out);
        SerializationContextExt prov = _serializationContext();
        _configAndWriteValue(prov,
                _streamFactory.createGenerator(prov, out), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, using Writer provided.
     *<p>
     * Note: method does not close the underlying stream explicitly
     * here; however, {@link TokenStreamFactory} this mapper uses may choose
     * to close the stream depending on its settings (by default,
     * it will try to close it when {@link JsonGenerator} we construct
     * is closed).
     */
    public void writeValue(Writer w, Object value) throws JacksonException
    {
        _assertNotNull("w", w);
        SerializationContextExt prov = _serializationContext();
        _configAndWriteValue(prov, _streamFactory.createGenerator(prov, w), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * a String. Functionally equivalent to calling
     * {@link #writeValue(Writer,Object)} with {@link java.io.StringWriter}
     * and constructing String, but more efficient.
     */
    @SuppressWarnings("resource")
    public String writeValueAsString(Object value) throws JacksonException
    {
        final BufferRecycler br = _streamFactory._getBufferRecycler();
        // alas, we have to pull the recycler directly here...
        try (SegmentedStringWriter sw = new SegmentedStringWriter(br)) {
            SerializationContextExt prov = _serializationContext();
            _configAndWriteValue(prov, _streamFactory.createGenerator(prov, sw), value);
            return sw.getAndClear();
        } finally {
            br.releaseToPool();
        }
    }

    /**
     * Method that can be used to serialize any Java value as
     * a byte array. Functionally equivalent to calling
     * {@link #writeValue(Writer,Object)} with {@link java.io.ByteArrayOutputStream}
     * and getting bytes, but more efficient.
     * Encoding used will be UTF-8.
     */
    @SuppressWarnings("resource")
    public byte[] writeValueAsBytes(Object value) throws JacksonException
    {
        final BufferRecycler br = _streamFactory._getBufferRecycler();
        try (ByteArrayBuilder bb = new ByteArrayBuilder(br)) {
            final SerializationContextExt ctxt = _serializationContext();
            _configAndWriteValue(ctxt,
                    _streamFactory.createGenerator(ctxt, bb, JsonEncoding.UTF8), value);
            return bb.getClearAndRelease();
        } finally {
            br.releaseToPool();
        }
    }

    /**
     * Convenience method that can be used to serialize any Java value into newly created
     * {@link TokenBuffer}. Functionally equivalent to calling
     * {@link #writeValue(JsonGenerator, Object)} passing buffer as generator.
     */
    public TokenBuffer writeValueIntoBuffer(Object value) throws JacksonException
    {
        final SerializationContextExt ctxt = _serializationContext();
        try (TokenBuffer buf = ctxt.bufferForValueConversion()) {
            _configAndWriteValue(ctxt, buf, value);
            return buf;
        }
    }

    /**
     * Method called to configure the generator as necessary and then
     * call write functionality
     */
    protected final void _configAndWriteValue(SerializationContextExt prov,
            JsonGenerator g, Object value)
        throws JacksonException
    {
        if (prov.isEnabled(SerializationFeature.CLOSE_CLOSEABLE)
                && (value instanceof AutoCloseable)) {
            _configAndWriteCloseable(prov, g, value);
            return;
        }
        try {
            prov.serializeValue(g, value);
        } catch (Exception e) {
            ClassUtil.closeOnFailAndThrowAsJacksonE(g, e);
            return;
        }
        g.close();
    }

    /**
     * Helper method used when value to serialize is {@link Closeable} and its <code>close()</code>
     * method is to be called right after serialization has been called
     */
    private final void _configAndWriteCloseable(SerializationContextExt prov,
            JsonGenerator g, Object value)
        throws JacksonException
    {
        AutoCloseable toClose = (AutoCloseable) value;
        try {
            prov.serializeValue(g, value);
            AutoCloseable tmpToClose = toClose;
            toClose = null;
            tmpToClose.close();
        } catch (Exception e) {
            ClassUtil.closeOnFailAndThrowAsJacksonE(g, toClose, e);
            return;
        }
        g.close();
    }

    /**
     * Helper method used when value to serialize is {@link Closeable} and its <code>close()</code>
     * method is to be called right after serialization has been called
     */
    protected final void _writeCloseableValue(JsonGenerator g, Object value, SerializationConfig cfg)
        throws JacksonException
    {
        Closeable toClose = (Closeable) value;
        try {
            _serializationContext(cfg).serializeValue(g, value);
            if (cfg.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
                g.flush();
            }
        } catch (Exception e) {
            ClassUtil.closeOnFailAndThrowAsJacksonE(null, toClose, e);
            return;
        }
        try {
            toClose.close();
        } catch (IOException e) {
            throw JacksonIOException.construct(e);
        }
    }

    /*
    /**********************************************************************
    /* Public API: constructing ObjectWriters
    /* for more advanced configuration
    /**********************************************************************
     */

    /**
     * Convenience method for constructing {@link ObjectWriter}
     * with default settings.
     */
    public ObjectWriter writer() {
        return _newWriter(serializationConfig());
    }

    /**
     * Factory method for constructing {@link ObjectWriter} with
     * specified feature enabled (compared to settings that this
     * mapper instance has).
     */
    public ObjectWriter writer(SerializationFeature feature) {
        return _newWriter(serializationConfig().with(feature));
    }

    /**
     * Factory method for constructing {@link ObjectWriter} with
     * specified features enabled (compared to settings that this
     * mapper instance has).
     */
    public ObjectWriter writer(SerializationFeature first,
            SerializationFeature... other) {
        return _newWriter(serializationConfig().with(first, other));
    }

    /**
     * Factory method for constructing {@link ObjectWriter} with
     * specified features enabled (compared to settings that this
     * mapper instance has).
     */
    public ObjectWriter writer(DatatypeFeature f) {
        return _newWriter(serializationConfig().with(f));
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using specified {@link DateFormat}; or, if
     * null passed, using timestamp (64-bit number.
     */
    public ObjectWriter writer(DateFormat df) {
        return _newWriter(serializationConfig().with(df));
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using specified JSON View (filter).
     */
    public ObjectWriter writerWithView(Class<?> serializationView) {
        return _newWriter(serializationConfig().withView(serializationView));
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using specified root type, instead of actual
     * runtime type of value. Type must be a super-type of runtime type.
     *<p>
     * Main reason for using this method is performance, as writer is able
     * to pre-fetch serializer to use before write, and if writer is used
     * more than once this avoids addition per-value serializer lookups.
     */
    public ObjectWriter writerFor(Class<?> rootType) {
        return _newWriter(serializationConfig(),
                ((rootType == null) ? null :_typeFactory.constructType(rootType)),
                /*PrettyPrinter*/null);
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using specified root type, instead of actual
     * runtime type of value. Type must be a super-type of runtime type.
     *<p>
     * Main reason for using this method is performance, as writer is able
     * to pre-fetch serializer to use before write, and if writer is used
     * more than once this avoids addition per-value serializer lookups.
     */
    public ObjectWriter writerFor(TypeReference<?> rootType) {
        return _newWriter(serializationConfig(),
                ((rootType == null) ? null : _typeFactory.constructType(rootType)),
                /*PrettyPrinter*/null);
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using specified root type, instead of actual
     * runtime type of value. Type must be a super-type of runtime type.
     *<p>
     * Main reason for using this method is performance, as writer is able
     * to pre-fetch serializer to use before write, and if writer is used
     * more than once this avoids addition per-value serializer lookups.
     */
    public ObjectWriter writerFor(JavaType rootType) {
        return _newWriter(serializationConfig(), rootType, /*PrettyPrinter*/null);
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using the default pretty printer for indentation
     */
    public ObjectWriter writerWithDefaultPrettyPrinter() {
        SerializationConfig config = serializationConfig();
        return _newWriter(config,
                /*root type*/ null, config.getDefaultPrettyPrinter());
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * serialize objects using specified filter provider.
     */
    public ObjectWriter writer(FilterProvider filterProvider) {
        return _newWriter(serializationConfig().withFilters(filterProvider));
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * pass specific schema object to {@link JsonGenerator} used for
     * writing content.
     *
     * @param schema Schema to pass to generator
     */
    public ObjectWriter writer(FormatSchema schema) {
        _verifySchemaType(schema);
        return _newWriter(serializationConfig(), schema);
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * use specified Base64 encoding variant for Base64-encoded binary data.
     */
    public ObjectWriter writer(Base64Variant defaultBase64) {
        return _newWriter(serializationConfig().with(defaultBase64));
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * use specified character escaping details for output.
     */
    public ObjectWriter writer(CharacterEscapes escapes) {
        return _newWriter(serializationConfig()).with(escapes);
    }

    /**
     * Factory method for constructing {@link ObjectWriter} that will
     * use specified default attributes.
     */
    public ObjectWriter writer(ContextAttributes attrs) {
        return _newWriter(serializationConfig().with(attrs));
    }

    /*
    /**********************************************************************
    /* Extended Public API: constructing ObjectReaders
    /* for more advanced configuration
    /**********************************************************************
     */

    /**
     * Factory method for constructing {@link ObjectReader} with
     * default settings. Note that the resulting instance is NOT usable as is,
     * without defining expected value type.
     */
    public ObjectReader reader() {
        return _newReader(deserializationConfig()).with(_injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} with
     * specified feature enabled (compared to settings that this
     * mapper instance has).
     * Note that the resulting instance is NOT usable as is,
     * without defining expected value type.
     */
    public ObjectReader reader(DeserializationFeature feature) {
        return _newReader(deserializationConfig().with(feature));
    }

    /**
     * Factory method for constructing {@link ObjectReader} with
     * specified features enabled (compared to settings that this
     * mapper instance has).
     * Note that the resulting instance is NOT usable as is,
     * without defining expected value type.
     */
    public ObjectReader reader(DeserializationFeature first,
            DeserializationFeature... other) {
        return _newReader(deserializationConfig().with(first, other));
    }

    /**
     * Factory method for constructing {@link ObjectReader} with
     * specified feature enabled (compared to settings that this
     * mapper instance has).
     * Note that the resulting instance is NOT usable as is,
     * without defining expected value type.
     */
    public ObjectReader reader(DatatypeFeature feature) {
        return _newReader(deserializationConfig().with(feature));
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * update given Object (usually Bean, but can be a Collection or Map
     * as well, but NOT an array) with JSON data. Deserialization occurs
     * normally except that the root-level value in JSON is not used for
     * instantiating a new object; instead give updateable object is used
     * as root.
     * Runtime type of value object is used for locating deserializer,
     * unless overridden by other factory methods of {@link ObjectReader}
     */
    public ObjectReader readerForUpdating(Object valueToUpdate) {
        JavaType t = (valueToUpdate == null) ? null
                : _typeFactory.constructType(valueToUpdate.getClass());
        return _newReader(deserializationConfig(), t, valueToUpdate,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * read or update instances of specified type
     */
    public ObjectReader readerFor(JavaType type) {
        _assertNotNull("type", type);
        return _newReader(deserializationConfig(), type, null,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * read or update instances of specified type
     */
    public ObjectReader readerFor(Class<?> type) {
        _assertNotNull("type", type);
        return _newReader(deserializationConfig(), _typeFactory.constructType(type), null,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * read or update instances of specified type
     */
    public ObjectReader readerFor(TypeReference<?> typeRef) {
        _assertNotNull("typeRef", typeRef);
        return _newReader(deserializationConfig(), _typeFactory.constructType(typeRef), null,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * read values of a type {@code List<type>}.
     * Functionally same as:
     *<pre>
     *    readerFor(type[].class);
     *</pre>
     */
    public ObjectReader readerForArrayOf(Class<?> type) {
        _assertNotNull("type", type);
        return _newReader(deserializationConfig(),
                _typeFactory.constructArrayType(type), null,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * read or update instances of a type {@code List<type>}.
     * Functionally same as:
     *<pre>
     *    readerFor(new TypeReference&lt;List&lt;type&gt;&gt;() { });
     *</pre>
     */
    public ObjectReader readerForListOf(Class<?> type) {
        _assertNotNull("type", type);
        return _newReader(deserializationConfig(),
                _typeFactory.constructCollectionType(List.class, type), null,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * read or update instances of a type {@code Map<String, type>}
     * Functionally same as:
     *<pre>
     *    readerFor(new TypeReference&lt;Map&lt;String, type&gt;&gt;() { });
     *</pre>
     *
     * @since 2.11
     */
    public ObjectReader readerForMapOf(Class<?> type) {
        _assertNotNull("type", type);
        return _newReader(deserializationConfig(),
                _typeFactory.constructMapType(Map.class, String.class, type), null,
                null, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * use specified {@link JsonNodeFactory} for constructing JSON trees.
     */
    public ObjectReader reader(JsonNodeFactory nodeFactory) {
        _assertNotNull("nodeFactory", nodeFactory);
        return _newReader(deserializationConfig()).with(nodeFactory);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * pass specific schema object to {@link JsonParser} used for
     * reading content.
     *
     * @param schema Schema to pass to parser
     */
    public ObjectReader reader(FormatSchema schema) {
        _verifySchemaType(schema);
        return _newReader(deserializationConfig(), null, null,
                schema, _injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * use specified injectable values.
     *
     * @param injectableValues Injectable values to use
     */
    public ObjectReader reader(InjectableValues injectableValues) {
        return _newReader(deserializationConfig(), null, null,
                null, injectableValues);
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * deserialize objects using specified JSON View (filter).
     */
    public ObjectReader readerWithView(Class<?> view) {
        return _newReader(deserializationConfig().withView(view));
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * use specified Base64 encoding variant for Base64-encoded binary data.
     */
    public ObjectReader reader(Base64Variant defaultBase64) {
        _assertNotNull("defaultBase64", defaultBase64);
        return _newReader(deserializationConfig().with(defaultBase64));
    }

    /**
     * Factory method for constructing {@link ObjectReader} that will
     * use specified default attributes.
     */
    public ObjectReader reader(ContextAttributes attrs) {
        return _newReader(deserializationConfig().with(attrs));
    }

    /*
    /**********************************************************************
    /* Extended Public API: convenience type conversion
    /**********************************************************************
     */

    /**
     * Convenience method for doing two-step conversion from given value, into
     * instance of given value type, by writing value into temporary buffer
     * and reading from the buffer into specified target type.
     *<p>
     * This method is functionally similar to first
     * serializing given value into JSON, and then binding JSON data into value
     * of given type, but should be more efficient since full serialization does
     * not (need to) occur.
     * However, same converters (serializers, deserializers) will be used as for
     * data binding, meaning same object mapper configuration works.
     *<p>
     * Note that behavior changed slightly between Jackson 2.9 and 2.10 so that
     * whereas earlier some optimizations were used to avoid write/read cycle
     * in case input was of target type, from 2.10 onwards full processing is
     * always performed. See
     * <a href="https://github.com/FasterXML/jackson-databind/issues/2220">databind#2220</a>
     * for full details of the change.
     *<p>
     * Further note that it is possible that in some cases behavior does differ
     * from full serialize-then-deserialize cycle: in most case differences are
     * unintentional (that is, flaws to fix) and should be reported, but
     * the behavior is not guaranteed to be 100% the same:
     * the goal is to allow efficient value conversions for structurally
     * compatible Objects, according to standard Jackson configuration.
     *<p>
     * Further note that this functionality is not designed to support "advanced" use
     * cases, such as conversion of polymorphic values, or cases where Object Identity
     * is used.
     *
     * @throws IllegalArgumentException If conversion fails due to incompatible type;
     *    if so, root cause will contain underlying checked exception data binding
     *    functionality threw
     */
    @SuppressWarnings("unchecked")
    public <T> T convertValue(Object fromValue, Class<T> toValueType)
        throws IllegalArgumentException
    {
        _assertNotNull("toValueType", toValueType);
        return (T) _convert(fromValue, _typeFactory.constructType(toValueType));
    }

    /**
     * See {@link #convertValue(Object, Class)}
     */
    @SuppressWarnings("unchecked")
    public <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef)
        throws IllegalArgumentException
    {
        _assertNotNull("toValueTypeRef", toValueTypeRef);
        return (T) _convert(fromValue, _typeFactory.constructType(toValueTypeRef));
    }

    /**
     * See {@link #convertValue(Object, Class)}
     */
    @SuppressWarnings("unchecked")
    public <T> T convertValue(Object fromValue, JavaType toValueType)
        throws IllegalArgumentException
    {
        _assertNotNull("toValueType", toValueType);
        return (T) _convert(fromValue, toValueType);
    }

    /**
     * Actual conversion implementation: instead of using existing read
     * and write methods, much of code is inlined. Reason for this is
     * that we must avoid root value wrapping/unwrapping both for efficiency and
     * for correctness. If root value wrapping/unwrapping is actually desired,
     * caller must use explicit <code>writeValue</code> and
     * <code>readValue</code> methods.
     */
    @SuppressWarnings("resource")
    protected Object _convert(Object fromValue, JavaType toValueType)
        throws JacksonException
    {
        // [databind#5368]: Optimize case where fromValue is already a TokenBuffer
        // TokenBuffer has no read state, so safe to reuse directly via asParser()
        TokenBuffer buf;
        if (fromValue instanceof TokenBuffer tb) {
            buf = tb;
        } else {
            // inlined 'writeValue' with minor changes:
            // first: disable wrapping when writing
            final SerializationConfig config = serializationConfig()
                    .without(SerializationFeature.WRAP_ROOT_VALUE);
            final SerializationContextExt ctxt = _serializationContext(config);
            buf = ctxt.bufferForValueConversion();
            // Would like to let buffer decide, but it won't have deser config to check so...
            if (isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
                buf = buf.forceUseOfBigDecimal(true);
            }
            ctxt.serializeValue(buf, fromValue);
        }

        // then matching read, inlined 'readValue' with minor mods:
        DeserializationContextExt readCtxt = _deserializationContext();
        try (final JsonParser p = buf.asParser(readCtxt)) {
            readCtxt.assignParser(p);
            Object result;
            // ok to pass in existing feature flags; unwrapping handled by mapper
            JsonToken t = _initForReading(p, toValueType);
            if (t == JsonToken.VALUE_NULL) {
                result = _findRootDeserializer(readCtxt, toValueType).getNullValue(readCtxt);
            } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
                result = null;
            } else if (t == JsonToken.NOT_AVAILABLE) {
                // 28-Jan-2025, tatu: [databind#4932] Need to handle this case too
                result = null;
            } else { // pointing to event other than null
                ValueDeserializer<Object> deser = _findRootDeserializer(readCtxt, toValueType);
                // note: no handling of unwrapping
                result = deser.deserialize(p, readCtxt);
            }
            return result;
        }
    }

    /**
     * Convenience method similar to {@link #convertValue(Object, JavaType)} but one
     * in which
     *<p>
     * Implementation is approximately as follows:
     *<ol>
     * <li>Serialize `updateWithValue` into {@link TokenBuffer}</li>
     * <li>Construct {@link ObjectReader} with `valueToUpdate` (using {@link #readerForUpdating(Object)})
     *   </li>
     * <li>Construct {@link JsonParser} (using {@link TokenBuffer#asParser(ObjectReadContext)})
     *   </li>
     * <li>Update using {@link ObjectReader#readValue(JsonParser)}.
     *   </li>
     * <li>Return `valueToUpdate`
     *   </li>
     *</ol>
     *<p>
     * Note that update is "shallow" in that only first level of properties (or, immediate contents
     * of container to update) are modified, unless properties themselves indicate that
     * merging should be applied for contents. Such merging can be specified using
     * annotations (see <code>JsonMerge</code>) as well as using "config overrides" (see
     * {@link MapperBuilder#withConfigOverride} and {@link MapperBuilder#defaultMergeable}).
     *
     * @param valueToUpdate Object to update
     * @param overrides Object to conceptually serialize and merge into value to
     *     update; can be thought of as a provider for overrides to apply.
     *
     * @return Either the first argument (`valueToUpdate`), if it is mutable; or a result of
     *     creating new instance that is result of "merging" values (for example, "updating" a
     *     Java array will create a new array)
     *
     * @throws JacksonException if there are structural incompatibilities that prevent update.
     */
    @SuppressWarnings("resource")
    public <T> T updateValue(T valueToUpdate, Object overrides)
        throws JacksonException
    {
        if ((valueToUpdate == null) || (overrides == null)) {
            return valueToUpdate;
        }
        SerializationConfig config = serializationConfig()
                .without(SerializationFeature.WRAP_ROOT_VALUE);
        SerializationContextExt ctxt = _serializationContext(config);
        TokenBuffer buf = ctxt.bufferForValueConversion();
        // Would like to let buffer decide, but it won't have deser config to check so...
        if (isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
            buf = buf.forceUseOfBigDecimal(true);
        }
        ctxt.serializeValue(buf, overrides);
        // 11-Apr-2019, tatu: Should we create "real" DeserializationContext or is this ok?
        try (JsonParser p = buf.asParser(ObjectReadContext.empty())) {
            return readerForUpdating(valueToUpdate).readValue(p);
        }
    }

    /*
    /**********************************************************************
    /* Extended Public API: JSON Schema generation
    /**********************************************************************
     */

    /**
     * Method for visiting type hierarchy for given type, using specified visitor.
     *<p>
     * This method can be used for things like
     * generating <a href="http://json-schema.org/">JSON Schema</a>
     * instance for specified type.
     *
     * @param type Type to generate schema for (possibly with generic signature)
     */
    public void acceptJsonFormatVisitor(Class<?> type, JsonFormatVisitorWrapper visitor)
    {
        _assertNotNull("type", type);
        _assertNotNull("visitor", visitor);
        acceptJsonFormatVisitor(_typeFactory.constructType(type), visitor);
    }

    public void acceptJsonFormatVisitor(TypeReference<?> typeRef, JsonFormatVisitorWrapper visitor)
    {
        _assertNotNull("typeRef", typeRef);
        _assertNotNull("visitor", visitor);
        acceptJsonFormatVisitor(_typeFactory.constructType(typeRef), visitor);
    }

    /**
     * Method for visiting type hierarchy for given type, using specified visitor.
     * Visitation uses <code>Serializer</code> hierarchy and related properties
     *<p>
     * This method can be used for things like
     * generating <a href="http://json-schema.org/">JSON Schema</a>
     * instance for specified type.
     *
     * @param type Type to generate schema for (possibly with generic signature)
     */
    public void acceptJsonFormatVisitor(JavaType type, JsonFormatVisitorWrapper visitor)
    {
        _assertNotNull("type", type);
        _assertNotNull("visitor", visitor);
        _serializationContext().acceptJsonFormatVisitor(type, visitor);
    }

    /*
    /**********************************************************************
    /* Extended Public API: caches
    /**********************************************************************
     */

    /**
     * Method that will clear all caches this mapper owns.
     *<p>
     * This method should not be needed in normal operation, but may be
     * useful to avoid class-loader memory leaks when reloading applications.
     *
     * @since 2.19
     */
    public void clearCaches() {
        _rootDeserializers.clear();
        _typeFactory.clearCache();
        _deserializationContexts.flushCachedDeserializers();
        _serializationContexts.flushCachedSerializers();
    }

    /*
    /**********************************************************************
    /* Internal methods for serialization, overridable
    /**********************************************************************
     */

    /**
     * Overridable helper method used for constructing
     * {@link SerializationContext} to use for serialization.
     */
    protected SerializationContextExt _serializationContext(SerializationConfig config) {
        // 03-Oct-2017, tatu: Should be ok to pass "empty" generator settings...
        return _serializationContexts.createContext(config,
                GeneratorSettings.empty());
    }

    // NOTE: only public to allow for testing
    public SerializationContextExt _serializationContext() {
        // 03-Oct-2017, tatu: Should be ok to pass "empty" generator settings...
        return _serializationContexts.createContext(serializationConfig(),
                GeneratorSettings.empty());
    }

    /*
    /**********************************************************************
    /* Internal methods for deserialization, overridable
    /**********************************************************************
     */

    /**
     * Actual implementation of value reading+binding operation.
     */
    protected Object _readValue(DeserializationContextExt ctxt, JsonParser p,
            JavaType valueType)
        throws JacksonException
    {
        // First: may need to read the next token, to initialize
        // state (either before first read from parser, or after
        // previous token has been cleared)
        final Object result;
        JsonToken t = _initForReading(p, valueType);

        if (t == JsonToken.VALUE_NULL) {
            // Ask deserializer what 'null value' to use:
            result = _findRootDeserializer(ctxt, valueType).getNullValue(ctxt);
        } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
            result = null;
        } else if (t == JsonToken.NOT_AVAILABLE) {
            // 28-Jan-2025, tatu: [databind#4932] Need to handle this case too
            result = null;
        } else { // pointing to event other than null
            result = ctxt.readRootValue(p, valueType, _findRootDeserializer(ctxt, valueType), null);
        }
        // Need to consume the token too
        p.clearCurrentToken();
        if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
            _verifyNoTrailingTokens(p, ctxt, valueType);
        }
        return result;
    }

    protected Object _readMapAndClose(DeserializationContextExt ctxt,
            JsonParser p0, JavaType valueType)
        throws JacksonException
    {
        ctxt.assignParser(p0);
        try (JsonParser p = p0) {
            Object result;
            JsonToken t = _initForReading(p, valueType);
            if (t == JsonToken.VALUE_NULL) {
                // Ask deserializer what 'null value' to use:
                result = _findRootDeserializer(ctxt, valueType).getNullValue(ctxt);
            } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
                result = null;
            } else if (t == JsonToken.NOT_AVAILABLE) {
                // 28-Jan-2025, tatu: [databind#4932] Need to handle this case too
                result = null;
            } else {
                result = ctxt.readRootValue(p, valueType,
                        _findRootDeserializer(ctxt, valueType), null);
                ctxt.checkUnresolvedObjectId();
            }
            if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
                _verifyNoTrailingTokens(p, ctxt, valueType);
            }
            return result;
        }
    }

    /**
     * Similar to {@link #_readMapAndClose} but specialized for <code>JsonNode</code> reading.
     */
    protected JsonNode _readTreeAndClose(DeserializationContextExt ctxt,
            JsonParser p0) throws JacksonException
    {
        try (JsonParser p = ctxt.assignAndReturnParser(p0)) {

            final JavaType valueType = JSON_NODE_TYPE;
            DeserializationConfig cfg = deserializationConfig();

            // 27-Oct-2016, tatu: Need to inline `_initForReading()` due to
            //   special requirements by tree reading (no fail on eof)
            JsonToken t = p.currentToken();
            if (t == null) {
                t = p.nextToken();
                if (t == null) {
                    // [databind#2211]: return `MissingNode` (supercedes [databind#1406] which dictated
                    // returning `null`
                    return cfg.getNodeFactory().missingNode();
                }
            }
            final JsonNode resultNode;
            if (t == JsonToken.VALUE_NULL) {
                resultNode = cfg.getNodeFactory().nullNode();
            } else {
                resultNode = (JsonNode) ctxt.readRootValue(p, valueType,
                        _findRootDeserializer(ctxt, valueType), null);
                // No ObjectIds so can ignore
//              ctxt.checkUnresolvedObjectId();
            }
            if (cfg.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
                _verifyNoTrailingTokens(p, ctxt, valueType);
            }
            return resultNode;
        }
    }

    /**
     * Internal helper method called to create an instance of {@link DeserializationContext}
     * for deserializing a single root value.
     * Can be overridden if a custom context is needed.
     */
    protected DeserializationContextExt _deserializationContext(JsonParser p) {
        return _deserializationContexts.createContext(deserializationConfig(),
                /* FormatSchema */ null, _injectableValues)
                .assignParser(p);
    }

    // NOTE: only public to allow for testing
    public DeserializationContextExt _deserializationContext() {
        return _deserializationContexts.createContext(deserializationConfig(),
                /* FormatSchema */ null, _injectableValues);
    }

    protected DeserializationContextExt _deserializationContext(DeserializationConfig config,
            JsonParser p) {
        return _deserializationContexts.createContext(config,
                /* FormatSchema */ null, _injectableValues)
                .assignParser(p);
    }

    /**
     * Method called to ensure that given parser is ready for reading
     * content for data binding.
     *
     * @return First token to be used for data binding after this call:
     *  can never be null as exception will be thrown if parser cannot
     *  provide more tokens.
     *
     * @throws JacksonException if the initialization fails during initialization
     *   of the streaming parser
     */
    protected JsonToken _initForReading(JsonParser p, JavaType targetType)
        throws JacksonException
    {
        // First: must point to a token; if not pointing to one, advance.
        // This occurs before first read from JsonParser, as well as
        // after clearing of current token.
        JsonToken t = p.currentToken();
        if (t == null) {
            // and then we must get something...
            t = p.nextToken();
            if (t == null) {
                // Throw mapping exception, since it's failure to map,
                //   not an actual parsing problem
                throw MismatchedInputException.from(p, targetType,
                        "No content to map due to end-of-input");
            }
        }
        return t;
    }

    protected final void _verifyNoTrailingTokens(JsonParser p, DeserializationContext ctxt,
            JavaType bindType)
        throws JacksonException
    {
        JsonToken t = p.nextToken();
        if (t != null) {
            Class<?> bt = ClassUtil.rawClass(bindType);
            ctxt.reportTrailingTokens(bt, p, t);
        }
    }

    /*
    /**********************************************************************
    /* Internal factory methods for ObjectReaders/-Writers
    /**********************************************************************
     */

    /**
     * Factory method sub-classes must override, to produce {@link ObjectReader}
     * instances of proper sub-type
     */
    protected ObjectReader _newReader(DeserializationConfig config) {
        return new ObjectReader(this, config);
    }

    /**
     * Factory method sub-classes must override, to produce {@link ObjectReader}
     * instances of proper sub-type
     */
    protected ObjectReader _newReader(DeserializationConfig config,
            JavaType valueType, Object valueToUpdate,
            FormatSchema schema, InjectableValues injectableValues) {
        return new ObjectReader(this, config, valueType, valueToUpdate, schema, injectableValues);
    }

    /**
     * Factory method sub-classes must override, to produce {@link ObjectWriter}
     * instances of proper sub-type
     */
    protected ObjectWriter _newWriter(SerializationConfig config) {
        return new ObjectWriter(this, config);
    }

    /**
     * Factory method sub-classes must override, to produce {@link ObjectWriter}
     * instances of proper sub-type
     */
    protected ObjectWriter _newWriter(SerializationConfig config, FormatSchema schema) {
        return new ObjectWriter(this, config, schema);
    }

    /**
     * Factory method sub-classes must override, to produce {@link ObjectWriter}
     * instances of proper sub-type
     */
    protected ObjectWriter _newWriter(SerializationConfig config,
            JavaType rootType, PrettyPrinter pp) {
        return new ObjectWriter(this, config, rootType, pp);
    }

    /*
    /**********************************************************************
    /* Internal methods, other
    /**********************************************************************
     */

    /**
     * Method called to locate deserializer for the passed root-level value.
     */
    protected ValueDeserializer<Object> _findRootDeserializer(DeserializationContext ctxt,
            JavaType valueType)
        throws JacksonException
    {
        // First: have we already seen it?
        ValueDeserializer<Object> deser = _rootDeserializers.get(valueType);
        if (deser != null) {
            return deser;
        }
        // Nope: need to ask provider to resolve it
        deser = ctxt.findRootValueDeserializer(valueType);
        if (deser == null) { // can this happen?
            return ctxt.reportBadDefinition(valueType,
                    "Cannot find a deserializer for type "+valueType);
        }
        _rootDeserializers.put(valueType, deser);
        return deser;
    }

    protected void _verifySchemaType(FormatSchema schema)
    {
        if (schema != null) {
            if (!_streamFactory.canUseSchema(schema)) {
                    throw new IllegalArgumentException("Cannot use FormatSchema of type "+schema.getClass().getName()
                            +" for format "+_streamFactory.getFormatName());
            }
        }
    }

    protected final void _assertNotNull(String paramName, Object src) {
        if (src == null){
            throw new IllegalArgumentException("argument \"" + paramName + "\" is null");
        }
    }
}