ObjectReader.java
package tools.jackson.databind;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import tools.jackson.core.*;
import tools.jackson.core.exc.JacksonIOException;
import tools.jackson.core.filter.FilteringParserDelegate;
import tools.jackson.core.filter.JsonPointerBasedFilter;
import tools.jackson.core.filter.TokenFilter;
import tools.jackson.core.filter.TokenFilter.Inclusion;
import tools.jackson.core.type.ResolvedType;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.cfg.ContextAttributes;
import tools.jackson.databind.cfg.DatatypeFeature;
import tools.jackson.databind.cfg.DeserializationContexts;
import tools.jackson.databind.deser.CollectingProblemHandler;
import tools.jackson.databind.deser.DeserializationContextExt;
import tools.jackson.databind.deser.DeserializationProblemHandler;
import tools.jackson.databind.exc.CollectedProblem;
import tools.jackson.databind.exc.DeferredBindingException;
import tools.jackson.databind.node.ArrayNode;
import tools.jackson.databind.node.JsonNodeFactory;
import tools.jackson.databind.node.ObjectNode;
import tools.jackson.databind.node.TreeTraversingParser;
import tools.jackson.databind.type.SimpleType;
import tools.jackson.databind.type.TypeFactory;
import tools.jackson.databind.util.ClassUtil;
import tools.jackson.databind.util.LinkedNode;
import tools.jackson.databind.util.TokenBuffer;
/**
* Builder object that can be used for per-serialization configuration of
* deserialization parameters, such as root type to use or object
* to update (instead of constructing new instance).
*<p>
* Uses "mutant factory" pattern so that instances are immutable
* (and thus fully thread-safe with no external synchronization);
* new instances are constructed for different configurations.
* Instances are initially constructed by {@link ObjectMapper} and can be
* reused, shared, cached; both because of thread-safety and because
* instances are relatively light-weight.
*<p>
* NOTE: this class is NOT meant as sub-classable by users. It is left as
* non-final mostly to allow frameworks that require byte code generation for proxying
* and similar use cases, but there is no expectation that functionality
* should be extended by sub-classing.
*/
public class ObjectReader
implements Versioned, TreeCodec
// NOTE: since 3.x, NO LONGER JDK Serializable
{
protected final static JavaType JSON_NODE_TYPE = SimpleType.constructUnsafe(JsonNode.class);
/*
/**********************************************************************
/* Immutable configuration from ObjectMapper
/**********************************************************************
*/
/**
* General serialization configuration settings; while immutable,
* can use copy-constructor to create modified instances as necessary.
*/
protected final DeserializationConfig _config;
/**
* Blueprint instance of deserialization context; used for creating
* actual instance when needed.
*/
protected final DeserializationContexts _contexts;
/**
* Factory used for constructing {@link JsonParser}s
*/
protected final TokenStreamFactory _parserFactory;
/**
* Flag that indicates whether root values are expected to be unwrapped or not
*/
protected final boolean _unwrapRoot;
/**
* Filter to be consider for JsonParser.
* Default value to be null as filter not considered.
*/
private final TokenFilter _filter;
/*
/**********************************************************************
/* Configuration that can be changed during building
/**********************************************************************
*/
/**
* Declared type of value to instantiate during deserialization.
* Defines which deserializer to use; as well as base type of instance
* to construct if an updatable value is not configured to be used
* (subject to changes by embedded type information, for polymorphic
* types). If {@link #_valueToUpdate} is non-null, only used for
* locating deserializer.
*/
protected final JavaType _valueType;
/**
* We may pre-fetch deserializer as soon as {@link #_valueType}
* is known, and if so, reuse it afterwards.
* This allows avoiding further deserializer lookups and increases
* performance a bit on cases where readers are reused.
*/
protected final ValueDeserializer<Object> _rootDeserializer;
/**
* Instance to update with data binding; if any. If null,
* a new instance is created, if non-null, properties of
* this value object will be updated instead.
* Note that value can be of almost any type, except not
* {@link tools.jackson.databind.type.ArrayType}; array
* types cannot be modified because array size is immutable.
*/
protected final Object _valueToUpdate;
/**
* When using data format that uses a schema, schema is passed
* to parser.
*/
protected final FormatSchema _schema;
/**
* Values that can be injected during deserialization, if any.
*/
protected final InjectableValues _injectableValues;
/*
/**********************************************************************
/* Caching
/**********************************************************************
*/
/**
* Root-level cached deserializers.
* Passed by {@link ObjectMapper}, shared with it.
*/
final protected ConcurrentHashMap<JavaType, ValueDeserializer<Object>> _rootDeserializers;
/*
/**********************************************************************
/* Life-cycle, construction
/**********************************************************************
*/
/**
* Constructor used by {@link ObjectMapper} for initial instantiation
*/
protected ObjectReader(ObjectMapper mapper, DeserializationConfig config) {
this(mapper, config, null, null, null, null);
}
/**
* Constructor called when a root deserializer should be fetched based
* on other configuration.
*/
protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,
JavaType valueType, Object valueToUpdate,
FormatSchema schema, InjectableValues injectableValues)
{
_config = config;
_contexts = mapper._deserializationContexts;
_rootDeserializers = mapper._rootDeserializers;
_parserFactory = mapper._streamFactory;
_valueType = valueType;
_valueToUpdate = valueToUpdate;
_schema = schema;
_injectableValues = injectableValues;
_unwrapRoot = config.useRootWrapping();
_rootDeserializer = _prefetchRootDeserializer(valueType);
_filter = null;
}
/**
* Copy constructor used for building variations.
*/
protected ObjectReader(ObjectReader base, DeserializationConfig config,
JavaType valueType, ValueDeserializer<Object> rootDeser, Object valueToUpdate,
FormatSchema schema, InjectableValues injectableValues)
{
_config = config;
_contexts = base._contexts;
_rootDeserializers = base._rootDeserializers;
_parserFactory = base._parserFactory;
_valueType = valueType;
_rootDeserializer = rootDeser;
_valueToUpdate = valueToUpdate;
_schema = schema;
_injectableValues = injectableValues;
_unwrapRoot = config.useRootWrapping();
_filter = base._filter;
}
/**
* Copy constructor used when modifying simple feature flags
*/
protected ObjectReader(ObjectReader base, DeserializationConfig config)
{
_config = config;
_contexts = base._contexts;
_rootDeserializers = base._rootDeserializers;
_parserFactory = base._parserFactory;
_valueType = base._valueType;
_rootDeserializer = base._rootDeserializer;
_valueToUpdate = base._valueToUpdate;
_schema = base._schema;
_injectableValues = base._injectableValues;
_unwrapRoot = config.useRootWrapping();
_filter = base._filter;
}
protected ObjectReader(ObjectReader base, TokenFilter filter) {
_config = base._config;
_contexts = base._contexts;
_rootDeserializers = base._rootDeserializers;
_parserFactory = base._parserFactory;
_valueType = base._valueType;
_rootDeserializer = base._rootDeserializer;
_valueToUpdate = base._valueToUpdate;
_schema = base._schema;
_injectableValues = base._injectableValues;
_unwrapRoot = base._unwrapRoot;
_filter = filter;
}
/**
* 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;
}
/*
/**********************************************************************
/* Helper methods used internally for invoking constructors
/* Need to be overridden if sub-classing (not recommended)
/* is used.
/**********************************************************************
*/
/**
* Factory method called by various "withXxx()" methods
*/
protected ObjectReader _new(ObjectReader base, DeserializationConfig config) {
return new ObjectReader(base, config);
}
/**
* Factory method called by various "withXxx()" methods
*/
protected ObjectReader _new(ObjectReader base, DeserializationConfig config,
JavaType valueType, ValueDeserializer<Object> rootDeser, Object valueToUpdate,
FormatSchema schema, InjectableValues injectableValues) {
return new ObjectReader(base, config, valueType, rootDeser, valueToUpdate,
schema, injectableValues);
}
/**
* Factory method used to create {@link MappingIterator} instances;
* either default, or custom subtype.
*/
protected <T> MappingIterator<T> _newIterator(JsonParser p, DeserializationContext ctxt,
ValueDeserializer<?> deser, boolean parserManaged)
{
return new MappingIterator<T>(_valueType, p, ctxt,
deser, parserManaged, _valueToUpdate);
}
/*
/**********************************************************************
/* Methods for initializing parser instance to use
/**********************************************************************
*/
protected JsonToken _initForReading(DeserializationContextExt ctxt, JsonParser p)
{
ctxt.assignParser(p);
// 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
ctxt.reportInputMismatch(_valueType,
"No content to map due to end-of-input");
}
}
return t;
}
/**
* Alternative to {@link #_initForReading} used in cases where reading
* of multiple values means that we may or may not want to advance the stream,
* but need to do other initialization.
*<p>
* Base implementation only sets configured {@link FormatSchema}, if any, on parser.
*/
protected void _initForMultiRead(DeserializationContextExt ctxt, JsonParser p)
{
ctxt.assignParser(p);
}
/*
/**********************************************************************
/* Life-cycle, fluent factory methods for DeserializationFeatures
/**********************************************************************
*/
/**
* Method for constructing a new reader instance that is configured
* with specified feature enabled.
*/
public ObjectReader with(DeserializationFeature feature) {
return _with(_config.with(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features enabled.
*/
public ObjectReader with(DeserializationFeature first,
DeserializationFeature... other)
{
return _with(_config.with(first, other));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features enabled.
*/
public ObjectReader withFeatures(DeserializationFeature... features) {
return _with(_config.withFeatures(features));
}
/**
* Method for constructing a new reader instance that is configured
* with specified feature disabled.
*/
public ObjectReader without(DeserializationFeature feature) {
return _with(_config.without(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features disabled.
*/
public ObjectReader without(DeserializationFeature first,
DeserializationFeature... other) {
return _with(_config.without(first, other));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features disabled.
*/
public ObjectReader withoutFeatures(DeserializationFeature... features) {
return _with(_config.withoutFeatures(features));
}
/*
/**********************************************************************
/* Life-cycle, fluent factory methods for DatatypeFeatures
/**********************************************************************
*/
/**
* Method for constructing a new reader instance that is configured
* with specified feature enabled.
*/
public ObjectReader with(DatatypeFeature feature) {
return _with(_config.with(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features enabled.
*/
public ObjectReader withFeatures(DatatypeFeature... features) {
return _with(_config.withFeatures(features));
}
/**
* Method for constructing a new reader instance that is configured
* with specified feature disabled.
*/
public ObjectReader without(DatatypeFeature feature) {
return _with(_config.without(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features disabled.
*/
public ObjectReader withoutFeatures(DatatypeFeature... features) {
return _with(_config.withoutFeatures(features));
}
/*
/**********************************************************
/* Life-cycle, fluent factory methods for StreamReadFeatures
/**********************************************************
*/
/**
* Method for constructing a new reader instance that is configured
* with specified feature enabled.
*/
public ObjectReader with(StreamReadFeature feature) {
return _with(_config.with(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features enabled.
*/
public ObjectReader withFeatures(StreamReadFeature... features) {
return _with(_config.withFeatures(features));
}
/**
* Method for constructing a new reader instance that is configured
* with specified feature disabled.
*/
public ObjectReader without(StreamReadFeature feature) {
return _with(_config.without(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features disabled.
*/
public ObjectReader withoutFeatures(StreamReadFeature... features) {
return _with(_config.withoutFeatures(features));
}
/*
/**********************************************************************
/* Life-cycle, fluent factory methods for FormatFeature
/**********************************************************************
*/
/**
* Method for constructing a new reader instance that is configured
* with specified feature enabled.
*/
public ObjectReader with(FormatFeature feature) {
return _with(_config.with(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features enabled.
*/
public ObjectReader withFeatures(FormatFeature... features) {
return _with(_config.withFeatures(features));
}
/**
* Method for constructing a new reader instance that is configured
* with specified feature disabled.
*/
public ObjectReader without(FormatFeature feature) {
return _with(_config.without(feature));
}
/**
* Method for constructing a new reader instance that is configured
* with specified features disabled.
*/
public ObjectReader withoutFeatures(FormatFeature... features) {
return _with(_config.withoutFeatures(features));
}
/*
/**********************************************************************
/* Life-cycle, fluent factory methods, other
/**********************************************************************
*/
/**
* Convenience method to bind from {@link JsonPointer}.
* {@link JsonPointerBasedFilter} is registered and will be used for parsing later.
*/
public ObjectReader at(String pointerExpr) {
_assertNotNull("pointerExpr", pointerExpr);
return new ObjectReader(this, new JsonPointerBasedFilter(pointerExpr));
}
/**
* Convenience method to bind from {@link JsonPointer}
* {@link JsonPointerBasedFilter} is registered and will be used for parsing later.
*/
public ObjectReader at(JsonPointer pointer) {
_assertNotNull("pointer", pointer);
return new ObjectReader(this, new JsonPointerBasedFilter(pointer));
}
/**
* Mutant factory method that will construct a new instance that has
* specified underlying {@link DeserializationConfig}.
*<p>
* NOTE: use of this method is not recommended, as there are many other
* re-configuration methods available.
*/
public ObjectReader with(DeserializationConfig config) {
return _with(config);
}
/**
* Method for constructing a new instance with configuration that uses
* passed {@link InjectableValues} to provide injectable values.
*<p>
* Note that the method does NOT change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader with(InjectableValues injectableValues)
{
if (_injectableValues == injectableValues) {
return this;
}
return _new(this, _config,
_valueType, _rootDeserializer, _valueToUpdate,
_schema, injectableValues);
}
/**
* Method for constructing a new reader instance with configuration that uses
* passed {@link JsonNodeFactory} for constructing {@link JsonNode}
* instances.
*<p>
* Note that the method does NOT change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader with(JsonNodeFactory f) {
return _with(_config.with(f));
}
/**
* Method for constructing a new instance with configuration that
* specifies what root name to expect for "root name unwrapping".
* See {@link DeserializationConfig#withRootName(String)} for
* details.
*<p>
* Note that the method does NOT change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader withRootName(String rootName) {
return _with(_config.withRootName(rootName));
}
public ObjectReader withRootName(PropertyName rootName) {
return _with(_config.withRootName(rootName));
}
/**
* Convenience method that is same as calling:
*<code>
* withRootName("")
*</code>
* which will forcibly prevent use of root name wrapping when writing
* values with this {@link ObjectReader}.
*/
public ObjectReader withoutRootName() {
return _with(_config.withRootName(PropertyName.NO_NAME));
}
/**
* Method for constructing a new instance with configuration that
* passes specified {@link FormatSchema} to {@link JsonParser} that
* is constructed for parsing content.
*<p>
* Note that the method does NOT change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader with(FormatSchema schema)
{
if (_schema == schema) {
return this;
}
_verifySchemaType(schema);
return _new(this, _config, _valueType, _rootDeserializer, _valueToUpdate,
schema, _injectableValues);
}
/**
* Method for constructing a new reader instance that is configured
* to data bind into specified type.
*<p>
* Note that the method does not change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader forType(JavaType valueType)
{
if (valueType != null && valueType.equals(_valueType)) {
return this;
}
ValueDeserializer<Object> rootDeser = _prefetchRootDeserializer(valueType);
return _new(this, _config, valueType, rootDeser,
_valueToUpdate, _schema, _injectableValues);
}
/**
* Method for constructing a new reader instance that is configured
* to data bind into specified type.
*<p>
* Note that the method does not change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader forType(Class<?> valueType) {
return forType(_config.constructType(valueType));
}
/**
* Method for constructing a new reader instance that is configured
* to data bind into specified type.
*<p>
* Note that the method does not change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader forType(TypeReference<?> valueTypeRef) {
return forType(_config.getTypeFactory().constructType(valueTypeRef.getType()));
}
/**
* Method for constructing a new instance with configuration that
* updates passed Object (as root value), instead of constructing
* a new value.
*<p>
* Note that the method does NOT change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader withValueToUpdate(Object value)
{
if (value == _valueToUpdate) return this;
if (value == null) {
// 18-Oct-2016, tatu: Actually, should be allowed, to remove value
// to update, if any
return _new(this, _config, _valueType, _rootDeserializer, null,
_schema, _injectableValues);
}
JavaType t;
/* no real benefit from pre-fetching, as updating readers are much
* less likely to be reused, and value type may also be forced
* with a later chained call...
*/
if (_valueType == null) {
t = _config.constructType(value.getClass());
} else {
t = _valueType;
}
return _new(this, _config, t, _rootDeserializer, value,
_schema, _injectableValues);
}
/**
* Method for constructing a new instance with configuration that
* uses specified View for filtering.
*<p>
* Note that the method does NOT change state of this reader, but
* rather construct and returns a newly configured instance.
*/
public ObjectReader withView(Class<?> activeView) {
return _with(_config.withView(activeView));
}
public ObjectReader with(Locale l) {
return _with(_config.with(l));
}
public ObjectReader with(TimeZone tz) {
return _with(_config.with(tz));
}
public ObjectReader withHandler(DeserializationProblemHandler h) {
return _with(_config.withHandler(h));
}
/**
* Returns a new {@link ObjectReader} configured to collect deserialization problems
* instead of failing on the first error. Uses default problem limit (100 problems).
*
* <p><b>IMPORTANT</b>: This method registers a {@link CollectingProblemHandler},
* inserting it before possible other handlers.
* If you need custom problem handling in addition to collection, you need to create
* your own handler that delegates to {@code CollectingProblemHandler} (or sub-classes it)
* and use {@link #problemCollectingReader(CollectingProblemHandler)} overload
* instead of this method.
*
* <p>Future versions may support handler chaining; for now, only one handler is active.
*
* <p><b>Thread-safety</b>: The returned reader is immutable and thread-safe. Each call to
* {@link #readValueCollectingProblems} allocates a fresh problem bucket, so concurrent
* calls do not interfere.
*
* <p>Usage:
* <pre>
* ObjectReader reader = mapper.reader()
* .forType(MyBean.class)
* .problemCollectingReader();
*
* MyBean bean = reader.readValueCollectingProblems(json);
* </pre>
*
* @return A new ObjectReader configured for problem collection
* @since 3.1
*/
public ObjectReader problemCollectingReader() {
return problemCollectingReader(CollectingProblemHandler.DEFAULT_MAX_PROBLEMS);
}
/**
* Variant of {@link #problemCollectingReader()} that allows overriding maximum
* number of problems to collect.
*
* @param maxProblems Maximum number of problems to collect (must be {@code >} 0)
* @return A new ObjectReader configured for problem collection
* @throws IllegalArgumentException if maxProblems is {@code <= 0}
*
* @since 3.1
*/
public ObjectReader problemCollectingReader(int maxProblems) {
if (maxProblems <= 0) {
throw new IllegalArgumentException("maxProblems must be positive");
}
return problemCollectingReader(new CollectingProblemHandler(maxProblems));
}
/**
* Variant of {@link #problemCollectingReader()} that allows passing custom
* {@link CollectingProblemHandler} (usually sub-class).
*
* @param problemHandler Custom handler instance to use
*
* @return A new ObjectReader configured for problem collection
*
* @since 3.1
*/
public ObjectReader problemCollectingReader(CollectingProblemHandler problemHandler)
{
DeserializationConfig newConfig = _config.withHandler(problemHandler);
return _new(this, newConfig, _valueType, _rootDeserializer, _valueToUpdate,
_schema, _injectableValues);
}
public ObjectReader with(Base64Variant defaultBase64) {
return _with(_config.with(defaultBase64));
}
/**
* Mutant factory for overriding set of (default) attributes for
* {@link ObjectReader} to use.
*<p>
* Note that this will replace defaults passed by {@link ObjectMapper}.
*
* @param attrs Default {@link ContextAttributes} to use with a reader
*
* @return {@link ObjectReader} instance with specified default attributes (which
* is usually a newly constructed reader instance with otherwise identical settings)
*/
public ObjectReader with(ContextAttributes attrs) {
return _with(_config.with(attrs));
}
public ObjectReader withAttributes(Map<?,?> attrs) {
return _with(_config.withAttributes(attrs));
}
public ObjectReader withAttribute(Object key, Object value) {
return _with( _config.withAttribute(key, value));
}
public ObjectReader withoutAttribute(Object key) {
return _with(_config.withoutAttribute(key));
}
/*
/**********************************************************************
/* Internal factory methods
/**********************************************************************
*/
protected final ObjectReader _with(DeserializationConfig newConfig) {
if (newConfig == _config) {
return this;
}
return _new(this, newConfig);
}
/*
/**********************************************************************
/* Simple accessors
/**********************************************************************
*/
public boolean isEnabled(DeserializationFeature f) {
return _config.isEnabled(f);
}
public boolean isEnabled(MapperFeature f) {
return _config.isEnabled(f);
}
public boolean isEnabled(DatatypeFeature f) {
return _config.isEnabled(f);
}
public boolean isEnabled(StreamReadFeature f) {
return _config.isEnabled(f);
}
public DeserializationConfig getConfig() {
return _config;
}
/**
* @since 3.0
*/
public TokenStreamFactory parserFactory() {
return _parserFactory;
}
/**
* @since 3.0
*/
public TypeFactory typeFactory() {
return _config.getTypeFactory();
}
public ContextAttributes getAttributes() {
return _config.getAttributes();
}
public InjectableValues getInjectableValues() {
return _injectableValues;
}
public JavaType getValueType() {
return _valueType;
}
/**
* @deprecated Since 3.0 use {@link #typeFactory}
*/
@Deprecated
public TypeFactory getTypeFactory() {
return typeFactory();
}
/*
/**********************************************************************
/* 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(_parserFactory.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(_parserFactory.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 src) throws JacksonException {
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return ctxt.assignAndReturnParser(_parserFactory.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,Reader)}.
*
* @since 3.0
*/
public JsonParser createParser(Reader src) throws JacksonException {
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return ctxt.assignAndReturnParser(_parserFactory.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,byte[])}.
*
* @since 3.0
*/
public JsonParser createParser(byte[] content) throws JacksonException {
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return ctxt.assignAndReturnParser(_parserFactory.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(_parserFactory.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(_parserFactory.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(_parserFactory.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(_parserFactory.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(_parserFactory.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(_parserFactory.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(_parserFactory.createNonBlockingByteBufferParser(ctxt));
}
/*
/**********************************************************************
/* TreeCodec implementation
/**********************************************************************
*/
@Override
public ObjectNode createObjectNode() {
return _config.getNodeFactory().objectNode();
}
@Override
public ArrayNode createArrayNode() {
return _config.getNodeFactory().arrayNode();
}
@Override
public JsonNode booleanNode(boolean b) {
return _config.getNodeFactory().booleanNode(b);
}
@Override
public JsonNode stringNode(String text) {
return _config.getNodeFactory().stringNode(text);
}
@Override
public JsonNode missingNode() {
return _config.getNodeFactory().missingNode();
}
@Override
public JsonNode nullNode() {
return _config.getNodeFactory().nullNode();
}
@Override
public JsonParser treeAsTokens(TreeNode n) {
_assertNotNull("n", n);
return treeAsTokens((JsonNode) n, _deserializationContext());
}
protected JsonParser treeAsTokens(JsonNode n, DeserializationContext ctxt) {
_assertNotNull("n", n);
return new TreeTraversingParser(n, ctxt);
}
/**
* Convenience method that binds content read using given parser, using
* configuration of this reader, except that content is bound as
* JSON tree instead of configured root value type.
* 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}
*<p>
* Note: if an object was specified with {@link #withValueToUpdate}, it
* will be ignored.
*/
@SuppressWarnings("unchecked")
@Override
public JsonNode readTree(JsonParser p) throws JacksonException {
_assertNotNull("p", p);
return _bindAsTreeOrNull(_deserializationContext(p), p);
}
// Alas, can't really support this part...
@Override
public void writeTree(JsonGenerator g, TreeNode tree) {
throw new UnsupportedOperationException();
}
/*
/**********************************************************************
/* Deserialization methods; first ones for pre-constructed parsers
/**********************************************************************
*/
/**
* Method that binds content read using given parser, using
* configuration of this reader, including expected result type.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*/
@SuppressWarnings("unchecked")
public <T> T readValue(JsonParser p) throws JacksonException {
_assertNotNull("p", p);
DeserializationContextExt ctxt = _deserializationContext(p);
return (T) _bind(ctxt, p, _valueToUpdate);
}
/**
* Convenience method that is equivalent to:
*<pre>
* withType(valueType).readValues(p);
*</pre>
*<p>
* Method reads a 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.
*/
public <T> Iterator<T> readValues(JsonParser p, Class<T> valueType)
throws JacksonException
{
_assertNotNull("p", p);
return forType(valueType).readValues(p);
}
/**
* Convenience method that is equivalent to:
*<pre>
* withType(valueTypeRef).readValues(p);
*</pre>
*<p>
* Method reads a 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.
*/
public <T> Iterator<T> readValues(JsonParser p, TypeReference<T> valueTypeRef)
throws JacksonException
{
_assertNotNull("p", p);
return forType(valueTypeRef).readValues(p);
}
/**
* Convenience method that is equivalent to:
*<pre>
* withType(valueType).readValues(p);
*</pre>
*<p>
* Method reads a 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.
*/
public <T> Iterator<T> readValues(JsonParser p, ResolvedType valueType) throws JacksonException {
_assertNotNull("p", p);
return readValues(p, (JavaType) valueType);
}
/**
* Convenience method that is equivalent to:
*<pre>
* withType(valueType).readValues(p);
*</pre>
*<p>
* Method reads a 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.
*/
public <T> Iterator<T> readValues(JsonParser p, JavaType valueType) throws JacksonException {
_assertNotNull("p", p);
return forType(valueType).readValues(p);
}
/*
/**********************************************************************
/* Deserialization methods; others similar to what ObjectMapper has
/**********************************************************************
*/
/**
* Method that binds content read from given input source,
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*/
@SuppressWarnings("unchecked")
public <T> T readValue(InputStream in) throws JacksonException
{
_assertNotNull("in", in);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, in), false));
}
/**
* Method that binds content read from given input source,
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param r Source to read content from
*/
@SuppressWarnings("unchecked")
public <T> T readValue(Reader r) throws JacksonException
{
_assertNotNull("r", r);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, r), false));
}
/**
* Method that binds content read from given JSON string,
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param content String that contains content to read
*/
@SuppressWarnings("unchecked")
public <T> T readValue(String content) throws JacksonException
{
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* Method that binds content read from given byte array,
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param content Byte array that contains encoded content to read
*/
@SuppressWarnings("unchecked")
public <T> T readValue(byte[] content) throws JacksonException
{
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* Method that binds content read from given byte array,
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param buffer Byte array that contains encoded content to read
* @param offset Offset of the first content byte in {@code buffer}
* @param length Length of content in {@code buffer}, in bytes
*/
@SuppressWarnings("unchecked")
public <T> T readValue(byte[] buffer, int offset, int length) throws JacksonException
{
_assertNotNull("buffer", buffer);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, buffer, offset, length), false));
}
/**
* Method that binds content read from given {@link File}
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param f File that contains content to read
*/
@SuppressWarnings("unchecked")
public <T> T readValue(File f) throws JacksonException
{
_assertNotNull("f", f);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, f), false));
}
/**
* Method that binds content read from given {@link Path}
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param path Path that contains content to read
*/
@SuppressWarnings("unchecked")
public <T> T readValue(Path path) throws JacksonException
{
_assertNotNull("path", path);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, path), false));
}
/**
* Convenience method for converting results from given JSON tree into given
* value type. Basically short-cut for:
*<pre>
* objectReader.readValue(src.traverse())
*</pre>
*
* @param node Tree that contains content to convert
*/
@SuppressWarnings("unchecked")
public <T> T readValue(JsonNode node) throws JacksonException
{
_assertNotNull("node", node);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(treeAsTokens(node, ctxt), false));
}
@SuppressWarnings("unchecked")
public <T> T readValue(DataInput input) throws JacksonException
{
_assertNotNull("input", input);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, input), false));
}
/**
* Method that binds content read from given {@link TokenBuffer}
* using configuration of this reader.
* Value return is either newly constructed, or root value that
* was specified with {@link #withValueToUpdate(Object)}.
*
* @param src {@link TokenBuffer} that contains content to read
*/
@SuppressWarnings("unchecked")
public <T> T readValue(TokenBuffer src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _bindAndClose(ctxt,
_considerFilter(src.asParser(ctxt) , false));
}
/*
/**********************************************************************
/* Deserialization methods with error collection
/**********************************************************************
*/
/**
* Deserializes JSON content into a Java object, collecting multiple
* problems if encountered. If any problems were collected, throws
* {@link DeferredBindingException} with all problems.
*
* <p><b>Usage</b>: This method should be called on an ObjectReader created via
* {@link #problemCollectingReader()} or {@link #problemCollectingReader(int)}. If called on a regular
* reader (without problem collection enabled), it behaves the same as
* {@link #readValue(JsonParser)} since no handler is registered.
*
* <p><b>Error handling</b>:
* <ul>
* <li>Recoverable errors are accumulated and thrown as
* {@link DeferredBindingException} after parsing</li>
* <li>Hard (non-recoverable) failures throw immediately, with collected problems
* attached as suppressed exceptions</li>
* <li>When the configured limit is reached, collection stops</li>
* </ul>
*
* <p><b>Exception Handling Strategy</b>:
*
* <p>This method catches only {@link DatabindException} subtypes (not all
* {@link JacksonException}s) because:
*
* <ul>
* <li>Core streaming errors ({@link tools.jackson.core.exc.StreamReadException},
* {@link tools.jackson.core.exc.StreamWriteException}) represent structural
* JSON problems that cannot be recovered from (malformed JSON, I/O errors)</li>
*
* <li>Only databind-level errors (type conversion, unknown properties, instantiation
* failures) are potentially recoverable and suitable for collection</li>
*
* <li>Catching all JacksonExceptions would hide critical parsing errors that should
* fail fast</li>
* </ul>
*
* <p>If a hard failure occurs after some problems have been collected, those problems
* are attached as suppressed exceptions to the thrown exception for debugging purposes.
*
* <p><b>Thread-safety</b>: Each call allocates a fresh problem bucket,
* so multiple concurrent calls on the same reader instance are safe.
*
* <p><b>Parser filtering</b>: Unlike convenience overloads ({@link #readValueCollectingProblems(String)},
* {@link #readValueCollectingProblems(byte[])}, etc.), this method does <i>not</i> apply
* parser filtering. Callers are responsible for filter wrapping if needed.
*
* @param <T> Type to deserialize
* @param p JsonParser to read from (will not be closed by this method)
* @return Deserialized object
* @throws DeferredBindingException if recoverable problems were collected
* @throws DatabindException if a non-recoverable error occurred
* @since 3.1
*/
public <T> T readValueCollectingProblems(JsonParser p) throws JacksonException {
_assertNotNull("p", p);
DeserializationContextExt ctxt = _deserializationContext();
return _collectingBind(ctxt, p);
}
/**
* Convenience overload for {@link #readValueCollectingProblems(JsonParser)}.
*/
public <T> T readValueCollectingProblems(String content) throws JacksonException {
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return _collectingBindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* Convenience overload for {@link #readValueCollectingProblems(JsonParser)}.
*/
public <T> T readValueCollectingProblems(byte[] content) throws JacksonException {
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return _collectingBindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* Convenience overload for {@link #readValueCollectingProblems(JsonParser)}.
*/
public <T> T readValueCollectingProblems(File src) throws JacksonException {
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _collectingBindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), false));
}
/**
* Convenience overload for {@link #readValueCollectingProblems(JsonParser)}.
*/
@SuppressWarnings("unchecked")
public <T> T readValueCollectingProblems(Path path) throws JacksonException
{
_assertNotNull("path", path);
DeserializationContextExt ctxt = _deserializationContext();
return (T) _collectingBindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, path), false));
}
/**
* Convenience overload for {@link #readValueCollectingProblems(JsonParser)}.
*/
public <T> T readValueCollectingProblems(InputStream src) throws JacksonException {
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _collectingBindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), false));
}
/**
* Convenience overload for {@link #readValueCollectingProblems(JsonParser)}.
*/
public <T> T readValueCollectingProblems(Reader src) throws JacksonException {
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _collectingBindAndClose(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), false));
}
/*
/**********************************************************************
/* Deserialization methods; JsonNode ("tree")
/**********************************************************************
*/
/**
* Method that reads content from given input source,
* using configuration of this reader, and binds it as JSON Tree.
* Returns {@link JsonNode} that represents the root of the resulting tree, if there
* was content to read, or "missing node" (instance of {@link JsonNode} for which
* {@link JsonNode#isMissingNode()} returns true, and behaves otherwise similar to
* "null node") if no more content is accessible through passed-in input source.
*<p>
* NOTE! Behavior with end-of-input (no more content) differs between this
* {@code readTree} method, and {@link #readTree(JsonParser)} -- latter returns
* {@code null} for "no content" case.
*<p>
* Note that if an object was specified with a call to
* {@link #withValueToUpdate(Object)}
* it will just be ignored; result is always a newly constructed
* {@link JsonNode} instance.
*/
public JsonNode readTree(InputStream src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndCloseAsTree(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), false));
}
/**
* Same as {@link #readTree(InputStream)} except content accessed through
* passed-in {@link Reader}
*/
public JsonNode readTree(Reader src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndCloseAsTree(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), false));
}
/**
* 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 _bindAndCloseAsTree(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* 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 _bindAndCloseAsTree(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* 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 _bindAndCloseAsTree(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content, offset, len), false));
}
/**
* Same as {@link #readTree(InputStream)} except content read using
* passed-in {@link DataInput}.
*/
public JsonNode readTree(DataInput content) throws JacksonException
{
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndCloseAsTree(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content), false));
}
/**
* Same as {@link #readTree(InputStream)} except content read using
* passed-in {@link TokenBuffer}.
*/
public JsonNode readTree(TokenBuffer src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndCloseAsTree(ctxt,
_considerFilter(src.asParser(ctxt), false));
}
/*
/**********************************************************************
/* Deserialization methods; reading sequence of values
/**********************************************************************
*/
/**
* Method for reading sequence of Objects from parser stream.
*<p>
* 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} must 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> but rather
* to the token following it.
*/
public <T> MappingIterator<T> readValues(JsonParser p)
throws JacksonException
{
_assertNotNull("p", p);
DeserializationContext ctxt = _deserializationContext(p);
// false -> do not close as caller gave parser instance
return _newIterator(p, ctxt, _findRootDeserializer(ctxt), false);
}
/**
* Method for reading sequence of Objects from parser stream.
*<p>
* Sequence can be either wrapped or unwrapped root-level sequence:
* wrapped means that the elements are enclosed in JSON Array;
* and unwrapped that elements are directly accessed at main level.
* Assumption is that iff the first token of the document is
* <code>START_ARRAY</code>, we have a wrapped sequence; otherwise
* unwrapped. For wrapped sequences, leading <code>START_ARRAY</code>
* is skipped, so that for both cases, underlying {@link JsonParser}
* will point to what is expected to be the first token of the first
* element.
*<p>
* Note that the wrapped vs unwrapped logic means that it is NOT
* possible to use this method for reading an unwrapped sequence
* of elements written as JSON Arrays: to read such sequences, one
* has to use {@link #readValues(JsonParser)}, making sure parser
* points to the first token of the first element (i.e. the second
* <code>START_ARRAY</code> which is part of the first element).
*/
public <T> MappingIterator<T> readValues(InputStream src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndReadValues(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), true));
}
/**
* Overloaded version of {@link #readValue(InputStream)}.
*/
@SuppressWarnings("resource")
public <T> MappingIterator<T> readValues(Reader src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
JsonParser p = _considerFilter(_parserFactory.createParser(ctxt, src), true);
_initForMultiRead(ctxt, p);
p.nextToken();
return _newIterator(p, ctxt, _findRootDeserializer(ctxt), true);
}
/**
* Overloaded version of {@link #readValue(InputStream)}.
*
* @param content String that contains JSON content to parse
*/
@SuppressWarnings("resource")
public <T> MappingIterator<T> readValues(String content) throws JacksonException
{
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
JsonParser p = _considerFilter(_parserFactory.createParser(ctxt, content), true);
_initForMultiRead(ctxt, p);
p.nextToken();
return _newIterator(p, ctxt, _findRootDeserializer(ctxt), true);
}
/**
* Overloaded version of {@link #readValue(InputStream)}.
*/
public <T> MappingIterator<T> readValues(byte[] content, int offset, int length) throws JacksonException
{
_assertNotNull("content", content);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndReadValues(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, content, offset, length), true));
}
/**
* Overloaded version of {@link #readValue(InputStream)}.
*/
public final <T> MappingIterator<T> readValues(byte[] content) throws JacksonException {
_assertNotNull("content", content);
return readValues(content, 0, content.length);
}
/**
* Overloaded version of {@link #readValue(InputStream)}.
*/
public <T> MappingIterator<T> readValues(File src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndReadValues(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), true));
}
/**
* Overloaded version of {@link #readValues(InputStream)}.
*
* @since 3.0
*/
public <T> MappingIterator<T> readValues(Path src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndReadValues(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), true));
}
public <T> MappingIterator<T> readValues(DataInput src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndReadValues(ctxt,
_considerFilter(_parserFactory.createParser(ctxt, src), true));
}
public <T> MappingIterator<T> readValues(TokenBuffer src) throws JacksonException
{
_assertNotNull("src", src);
DeserializationContextExt ctxt = _deserializationContext();
return _bindAndReadValues(ctxt,
_considerFilter(src.asParser(ctxt), true));
}
/*
/**********************************************************************
/* Misc conversion methods
/**********************************************************************
*/
public <T> T treeToValue(TreeNode n, Class<T> valueType) throws JacksonException
{
_assertNotNull("n", n);
return forType(valueType).readValue(treeAsTokens(n));
}
/**
* Same as {@link #treeToValue(TreeNode, Class)} but with type-resolved target value type.
*/
public <T> T treeToValue(TreeNode n, JavaType valueType) throws JacksonException
{
_assertNotNull("n", n);
return forType(valueType).readValue(treeAsTokens(n));
}
/*
/**********************************************************************
/* Helper methods, data-binding
/**********************************************************************
*/
/**
* Actual implementation of value reading+binding operation.
*/
protected Object _bind(DeserializationContextExt ctxt,
JsonParser p, Object valueToUpdate) 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)
Object result;
JsonToken t = _initForReading(ctxt, p);
if (t == JsonToken.VALUE_NULL) {
if (valueToUpdate == null) {
result = _findRootDeserializer(ctxt).getNullValue(ctxt);
} else {
result = valueToUpdate;
}
} else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
result = valueToUpdate;
} else if (t == JsonToken.NOT_AVAILABLE) {
// 28-Jan-2025, tatu: [databind#4932] Need to handle this case too
result = valueToUpdate;
} else { // pointing to event other than null
result = ctxt.readRootValue(p, _valueType, _findRootDeserializer(ctxt), _valueToUpdate);
}
// Need to consume the token too
p.clearCurrentToken();
if (_config.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
_verifyNoTrailingTokens(p, ctxt, _valueType);
}
return result;
}
protected Object _bindAndClose(DeserializationContextExt ctxt,
JsonParser p0) throws JacksonException
{
try (JsonParser p = p0) {
Object result;
JsonToken t = _initForReading(ctxt, p);
if (t == JsonToken.VALUE_NULL) {
if (_valueToUpdate == null) {
result = _findRootDeserializer(ctxt).getNullValue(ctxt);
} else {
result = _valueToUpdate;
}
} else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) {
result = _valueToUpdate;
} else if (t == JsonToken.NOT_AVAILABLE) {
// 28-Jan-2025, tatu: [databind#4932] Need to handle this case too
result = _valueToUpdate;
} else {
result = ctxt.readRootValue(p, _valueType, _findRootDeserializer(ctxt), _valueToUpdate);
}
// No need to consume the token as parser gets closed anyway
if (_config.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
_verifyNoTrailingTokens(p, ctxt, _valueType);
}
return result;
}
}
/**
* Internal helper for problem-collecting deserialization that does NOT close the parser.
* Caller is responsible for parser lifecycle management.
*
* @since 3.1
*/
protected <T> T _collectingBind(DeserializationContextExt ctxt, JsonParser p)
throws JacksonException {
// CRITICAL: Allocate a FRESH bucket for THIS call (thread-safety)
List<CollectedProblem> bucket = new ArrayList<>();
// Set bucket in context attributes (mutable per-call state)
ctxt.setAttribute(CollectingProblemHandler.class, bucket);
// Find the CollectingProblemHandler to get maxProblems limit
int maxProblems = CollectingProblemHandler.DEFAULT_MAX_PROBLEMS;
LinkedNode<DeserializationProblemHandler> handlers = _config.getProblemHandlers();
while (handlers != null) {
if (handlers.value() instanceof CollectingProblemHandler cph) {
maxProblems = cph.getMaxProblems();
break;
}
handlers = handlers.next();
}
try {
// Directly invoke _bind with the prepared context
@SuppressWarnings("unchecked")
T result = (T) _bind(ctxt, p, _valueToUpdate);
// Check if any problems were collected
if (!bucket.isEmpty()) {
boolean limitReached = (bucket.size() >= maxProblems);
throw new DeferredBindingException(p, bucket, limitReached);
}
return result;
} catch (DeferredBindingException e) {
throw e; // Already properly formatted
} catch (DatabindException e) {
// Hard failure occurred; attach collected problems as suppressed
if (!bucket.isEmpty()) {
boolean limitReached = (bucket.size() >= maxProblems);
if (limitReached) {
// Limit was hit - throw DeferredBindingException as primary exception
DeferredBindingException dbe = new DeferredBindingException(p, bucket, true);
dbe.addSuppressed(e); // Original error as suppressed for debugging
throw dbe;
} else {
// Hard failure unrelated to limit - keep original as primary
e.addSuppressed(new DeferredBindingException(p, bucket, false));
}
}
throw e;
}
}
/**
* Internal helper for problem-collecting deserialization that DOES close the parser.
* Mirrors {@link #_bindAndClose} but with problem collection enabled.
*
* @since 3.1
*/
protected <T> T _collectingBindAndClose(DeserializationContextExt ctxt, JsonParser p0)
throws JacksonException {
try (JsonParser p = p0) {
return _collectingBind(ctxt, p);
}
}
protected final JsonNode _bindAndCloseAsTree(DeserializationContextExt ctxt,
JsonParser p0) throws JacksonException {
try (JsonParser p = ctxt.assignAndReturnParser(p0)) {
return _bindAsTree(ctxt, p);
}
}
protected final JsonNode _bindAsTree(DeserializationContextExt ctxt,
JsonParser p)
throws JacksonException
{
// 16-Apr-2021, tatu: Should usually NOT be called this way but
// as per [databind#3122] should still work
if (_valueToUpdate != null) {
return (JsonNode) _bind(ctxt, p, _valueToUpdate);
}
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 _config.getNodeFactory().missingNode();
}
}
final JsonNode resultNode;
if (t == JsonToken.VALUE_NULL) {
resultNode = ctxt.getNodeFactory().nullNode();
} else {
// Will not be called for merge (need not pass _valueToUpdate)
resultNode = (JsonNode) ctxt.readRootValue(p, JSON_NODE_TYPE, _findTreeDeserializer(ctxt), null);
}
// Need to consume the token too
p.clearCurrentToken();
if (_config.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
_verifyNoTrailingTokens(p, ctxt, JSON_NODE_TYPE);
}
return resultNode;
}
/**
* Same as {@link #_bindAsTree} except end-of-input is reported by returning
* {@code null}, not "missing node"
*/
protected final JsonNode _bindAsTreeOrNull(DeserializationContextExt ctxt,
JsonParser p) throws JacksonException
{
// 16-Apr-2021, tatu: Should usually NOT be called this way but
// as per [databind#3122] should still work
if (_valueToUpdate != null) {
return (JsonNode) _bind(ctxt, p, _valueToUpdate);
}
ctxt.assignParser(p);
JsonToken t = p.currentToken();
if (t == null) {
t = p.nextToken();
if (t == null) { // unlike above, here we do return `null`
return null;
}
}
final JsonNode resultNode;
if (t == JsonToken.VALUE_NULL) {
resultNode = ctxt.getNodeFactory().nullNode();
} else {
// Will not be called for merge (need not pass _valueToUpdate)
resultNode = (JsonNode) ctxt.readRootValue(p, JSON_NODE_TYPE, _findTreeDeserializer(ctxt), null);
}
// Need to consume the token too
p.clearCurrentToken();
if (_config.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) {
_verifyNoTrailingTokens(p, ctxt, JSON_NODE_TYPE);
}
return resultNode;
}
protected <T> MappingIterator<T> _bindAndReadValues(DeserializationContextExt ctxt,
JsonParser p) throws JacksonException
{
_initForMultiRead(ctxt, p);
p.nextToken();
return _newIterator(p, ctxt, _findRootDeserializer(ctxt), true);
}
/**
* Consider filter when creating JsonParser.
*/
protected JsonParser _considerFilter(final JsonParser p, boolean multiValue) {
// 26-Mar-2016, tatu: Need to allow multiple-matches at least if we have
// a multiple-value read (that is, "readValues()").
return ((_filter == null) || FilteringParserDelegate.class.isInstance(p))
? p : new FilteringParserDelegate(p, _filter, Inclusion.ONLY_INCLUDE_ALL, multiValue);
}
protected final void _verifyNoTrailingTokens(JsonParser p, DeserializationContext ctxt,
JavaType bindType)
throws JacksonException
{
JsonToken t = p.nextToken();
if (t != null) {
Class<?> bt = ClassUtil.rawClass(bindType);
if (bt == null) {
if (_valueToUpdate != null) {
bt = _valueToUpdate.getClass();
}
}
ctxt.reportTrailingTokens(bt, p, t);
}
}
/*
/**********************************************************************
/* Internal methods, other
/**********************************************************************
*/
protected void _verifySchemaType(FormatSchema schema)
{
if (schema != null) {
if (!_parserFactory.canUseSchema(schema)) {
throw new IllegalArgumentException("Cannot use FormatSchema of type "+schema.getClass().getName()
+" for format "+_parserFactory.getFormatName());
}
}
}
/**
* 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() {
return _contexts.createContext(_config, _schema, _injectableValues);
}
protected DeserializationContextExt _deserializationContext(JsonParser p) {
return _contexts.createContext(_config, _schema, _injectableValues)
.assignParser(p);
}
protected InputStream _inputStream(File f) throws JacksonException {
try {
return new FileInputStream(f);
} catch (IOException e) {
throw JacksonIOException.construct(e);
}
}
protected InputStream _inputStream(Path path) throws JacksonException {
try {
return Files.newInputStream(path);
} catch (IOException e) {
throw JacksonIOException.construct(e);
}
}
protected final void _assertNotNull(String paramName, Object src) {
if (src == null){
throw new IllegalArgumentException(String.format("argument \"%s\" is null", paramName));
}
}
/*
/**********************************************************************
/* Helper methods, locating deserializers etc
/**********************************************************************
*/
/**
* Method called to locate deserializer for the passed root-level value.
*/
protected ValueDeserializer<Object> _findRootDeserializer(DeserializationContext ctxt)
throws DatabindException
{
if (_rootDeserializer != null) {
return _rootDeserializer;
}
// Sanity check: must have actual type...
JavaType t = _valueType;
if (t == null) {
ctxt.reportBadDefinition((JavaType) null,
"No value type configured for ObjectReader");
}
// First: have we already seen it?
ValueDeserializer<Object> deser = _rootDeserializers.get(t);
if (deser != null) {
return deser;
}
// Nope: need to ask provider to resolve it
deser = ctxt.findRootValueDeserializer(t);
if (deser == null) { // can this happen?
ctxt.reportBadDefinition(t, "Cannot find a deserializer for type "+t);
}
_rootDeserializers.put(t, deser);
return deser;
}
protected ValueDeserializer<Object> _findTreeDeserializer(DeserializationContext ctxt)
throws DatabindException
{
ValueDeserializer<Object> deser = _rootDeserializers.get(JSON_NODE_TYPE);
if (deser == null) {
// Nope: need to ask provider to resolve it
deser = ctxt.findRootValueDeserializer(JSON_NODE_TYPE);
if (deser == null) { // can this happen?
ctxt.reportBadDefinition(JSON_NODE_TYPE,
"Cannot find a deserializer for type "+JSON_NODE_TYPE);
}
_rootDeserializers.put(JSON_NODE_TYPE, deser);
}
return deser;
}
/**
* Method called to locate deserializer ahead of time, if permitted
* by configuration. Method also is NOT to throw an exception if
* access fails.
*/
protected ValueDeserializer<Object> _prefetchRootDeserializer(JavaType valueType)
{
if ((valueType == null) || !_config.isEnabled(DeserializationFeature.EAGER_DESERIALIZER_FETCH)) {
return null;
}
// already cached?
ValueDeserializer<Object> deser = _rootDeserializers.get(valueType);
if (deser == null) {
try {
// If not, need to resolve; for which we need a temporary context as well:
DeserializationContext ctxt = _deserializationContext();
deser = ctxt.findRootValueDeserializer(valueType);
if (deser != null) {
_rootDeserializers.put(valueType, deser);
}
return deser;
} catch (JacksonException e) {
// need to swallow?
// 20-Jan-2021, tatu: Not 100% sure actually... but was that way in 2.x
// so leaving for now
}
}
return deser;
}
}