package com.fasterxml.jackson.jr.ob.impl;
import java.io.*;
import java.util.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.jr.ob.JSON;
import com.fasterxml.jackson.jr.ob.JSONObjectException;
import com.fasterxml.jackson.jr.ob.api.CollectionBuilder;
import com.fasterxml.jackson.jr.ob.api.MapBuilder;
import com.fasterxml.jackson.jr.ob.api.ReaderWriterProvider;
import com.fasterxml.jackson.jr.ob.api.ValueReader;
Root-level helper object that handles initial delegation to actual readers (which are ValueReader
s), but does not handle any of reading itself (despite name). Life-cycle is such that initial instance (called blueprint) is constructed first (including possible configuration using mutant factory methods). This blueprint object acts as a factory, and is never used for direct reading; instead, per-call instance is created by calling perOperationInstance
.
/**
* Root-level helper object that handles initial delegation to actual
* readers (which are {@link ValueReader}s), but does not handle
* any of reading itself (despite name).
*<p>
* Life-cycle is such that initial instance (called blueprint)
* is constructed first (including possible configuration
* using mutant factory methods). This blueprint object
* acts as a factory, and is never used for direct reading;
* instead, per-call instance is created by calling
* {@link #perOperationInstance}.
*/
public class JSONReader
{
/*
/**********************************************************************
/* Blueprint config
/**********************************************************************
*/
protected final int _features;
protected final TreeCodec _treeCodec;
Object that is used to find value readers dynamically.
/**
* Object that is used to find value readers dynamically.
*/
protected final ValueReaderLocator _readerLocator;
Handler that takes care of constructing Map
s as needed /**
* Handler that takes care of constructing {@link java.util.Map}s as needed
*/
protected final MapBuilder _mapBuilder;
Handler that takes care of constructing Map
s as needed /**
* Handler that takes care of constructing {@link java.util.Map}s as needed
*/
protected final CollectionBuilder _collectionBuilder;
/*
/**********************************************************************
/* Instance config, state
/**********************************************************************
*/
protected final JsonParser _parser;
/*
/**********************************************************************
/* Blueprint construction
/**********************************************************************
*/
Constructor used for creating the blueprint instances.
/**
* Constructor used for creating the blueprint instances.
*/
public JSONReader(int features, ValueReaderLocator td, TreeCodec treeCodec,
CollectionBuilder lb, MapBuilder mb)
{
_features = features;
_readerLocator = td;
_treeCodec = treeCodec;
_collectionBuilder = lb;
_mapBuilder = mb;
_parser = null;
}
Constructor used for per-operation (non-blueprint) instance.
/**
* Constructor used for per-operation (non-blueprint) instance.
*/
protected JSONReader(JSONReader base, int features, ValueReaderLocator td, JsonParser p)
{
_features = features;
_readerLocator = td;
_treeCodec = base._treeCodec;
_collectionBuilder = base._collectionBuilder.newBuilder(features);
_mapBuilder = base._mapBuilder.newBuilder(features);
_parser = p;
}
/*
/**********************************************************************
/* Mutant factories for blueprint
/**********************************************************************
*/
public JSONReader withCacheCheck(int features) {
// 07-Jun-2019, tatu: No cache-dependant clearing needed... yet.
return this;
}
public JSONReader with(MapBuilder mb) {
if (_mapBuilder == mb) return this;
return _with(_features, _readerLocator, _treeCodec, _collectionBuilder, mb);
}
public JSONReader with(CollectionBuilder lb) {
if (_collectionBuilder == lb) return this;
return _with(_features, _readerLocator, _treeCodec, lb, _mapBuilder);
}
public JSONReader with(ReaderWriterProvider rwp) {
ValueReaderLocator l = _readerLocator.with(rwp);
if (_readerLocator == l) {
return this;
}
return _with(_features, l, _treeCodec, _collectionBuilder, _mapBuilder);
}
Overridable method that all mutant factories call if a new instance
is to be constructed
/**
* Overridable method that all mutant factories call if a new instance
* is to be constructed
*/
protected JSONReader _with(int features,
ValueReaderLocator td, TreeCodec tc, CollectionBuilder lb, MapBuilder mb)
{
if (getClass() != JSONReader.class) { // sanity check
throw new IllegalStateException("Sub-classes MUST override _with(...)");
}
return new JSONReader(features, td, tc, lb, mb);
}
/*
/**********************************************************************
/* New instance creation
/**********************************************************************
*/
public JSONReader perOperationInstance(int features, JsonParser p)
{
if (getClass() != JSONReader.class) { // sanity check
throw new IllegalStateException("Sub-classes MUST override perOperationInstance(...)");
}
return new JSONReader(this, features,
_readerLocator.perOperationInstance(this, features), p);
}
/*
/**********************************************************************
/* Simple accessors
/**********************************************************************
*/
Since: 2.8
/**
* @since 2.8
*/
public boolean arraysAsLists() {
return JSON.Feature.READ_JSON_ARRAYS_AS_JAVA_ARRAYS.isDisabled(_features);
}
/*
/**********************************************************************
/* Public entry points for reading Simple objects from JSON
/**********************************************************************
*/
/**
* Method for reading a "simple" Object of type indicated by JSON
* content: {@link java.util.Map} for JSON Object, {@link java.util.Map}
* for JSON Array (or, <code>Object[]</code> if so configured),
* {@link java.lang.String} for JSON String value and so on.
*/
public Object readValue() throws IOException {
return AnyReader.std.read(this, _parser);
}
Method for reading a JSON Object from input and building a Map
out of it. Note that if input does NOT contain a JSON Object, JSONObjectException
will be thrown. /**
* Method for reading a JSON Object from input and building a {@link java.util.Map}
* out of it. Note that if input does NOT contain a
* JSON Object, {@link JSONObjectException} will be thrown.
*/
public Map<Object,Object> readMap() throws IOException {
JsonToken t = _parser.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return null;
}
if (t != JsonToken.START_OBJECT) {
throw JSONObjectException.from(_parser,
"Can not read a Map: expect to see START_OBJECT ('{'), instead got: "+ValueReader._tokenDesc(_parser));
}
return AnyReader.std.readFromObject(this, _parser, _mapBuilder);
}
Method for reading a JSON Array from input and building a List
out of it. Note that if input does NOT contain a JSON Array, JSONObjectException
will be thrown. /**
* Method for reading a JSON Array from input and building a {@link java.util.List}
* out of it. Note that if input does NOT contain a
* JSON Array, {@link JSONObjectException} will be thrown.
*/
public List<Object> readList() throws IOException {
JsonToken t = _parser.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return null;
}
if (t != JsonToken.START_ARRAY) {
throw JSONObjectException.from(_parser,
"Can not read a List: expect to see START_ARRAY ('['), instead got: "+ValueReader._tokenDesc(_parser));
}
return (List<Object>) AnyReader.std.readCollectionFromArray(this, _parser, _collectionBuilder);
}
Method for reading a JSON Array from input and building a Object[]
out of it. Note that if input does NOT contain a JSON Array, JSONObjectException
will be thrown. /**
* Method for reading a JSON Array from input and building a <code>Object[]</code>
* out of it. Note that if input does NOT contain a
* JSON Array, {@link JSONObjectException} will be thrown.
*/
public Object[] readArray() throws IOException
{
JsonToken t = _parser.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return null;
}
if (t != JsonToken.START_ARRAY) {
throw JSONObjectException.from(_parser,
"Can not read an array: expect to see START_ARRAY ('['), instead got: "+ValueReader._tokenDesc(_parser));
}
return AnyReader.std.readArrayFromArray(this, _parser, _collectionBuilder);
}
/*
/**********************************************************************
/* Public entry points for reading (more) typed types
/**********************************************************************
*/
Method for reading a JSON Object from input and building a Bean of
specified type out of it; Bean has to conform to standard Java Bean
specification by having setters for passing JSON Object properties.
/**
* Method for reading a JSON Object from input and building a Bean of
* specified type out of it; Bean has to conform to standard Java Bean
* specification by having setters for passing JSON Object properties.
*/
@SuppressWarnings("unchecked")
public <T> T readBean(Class<T> type) throws IOException {
final Object ob = _readerLocator.findReader(type)
.read(this, _parser);
return (T) ob;
}
@SuppressWarnings("unchecked")
public <T> T[] readArrayOf(Class<T> type) throws IOException {
JsonToken t = _parser.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return null;
}
if (t != JsonToken.START_ARRAY) {
throw JSONObjectException.from(_parser,
"Can not read an array: expect to see START_ARRAY ('['), instead got: "+ValueReader._tokenDesc(_parser));
}
// NOTE: "array type" we give is incorrect, but should usually not matter
// -- to fix would need to instantiate 0-element array, get that type
return (T[]) new ArrayReader(type, type, _readerLocator.findReader(type))
.read(this, _parser);
}
Method for reading a JSON Array from input and building a List
out of it, binding values into specified type
. Note that if input does NOT contain a JSON Array, JSONObjectException
will be thrown. /**
* Method for reading a JSON Array from input and building a {@link java.util.List}
* out of it, binding values into specified {@code type}.
* Note that if input does NOT contain a JSON Array, {@link JSONObjectException} will be thrown.
*/
@SuppressWarnings("unchecked")
public <T> List<T> readListOf(Class<T> type) throws IOException
{
JsonToken t = _parser.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return null;
}
if (t != JsonToken.START_ARRAY) {
throw JSONObjectException.from(_parser,
"Can not read a List: expect to see START_ARRAY ('['), instead got: "+ValueReader._tokenDesc(_parser));
}
return (List<T>) new CollectionReader(List.class, _readerLocator.findReader(type))
.read(this, _parser);
}
Method for reading a JSON Object from input and building a Map
out of it, binding values into specified type
. Note that if input does NOT contain a JSON Object, JSONObjectException
will be thrown. Since: 2.10
/**
* Method for reading a JSON Object from input and building a {@link java.util.Map}
* out of it, binding values into specified {@code type}.
* Note that if input does NOT contain a JSON Object, {@link JSONObjectException} will be thrown.
*
* @since 2.10
*/
@SuppressWarnings("unchecked")
public <T> Map<String, T> readMapOf(Class<T> type) throws IOException
{
JsonToken t = _parser.getCurrentToken();
if (t == JsonToken.VALUE_NULL) {
return null;
}
if (t != JsonToken.START_OBJECT) {
throw JSONObjectException.from(_parser,
"Can not read a Map: expect to see START_OBJECT ('{'), instead got: "+ValueReader._tokenDesc(_parser));
}
return (Map<String, T>) new MapReader(Map.class, _readerLocator.findReader(type))
.read(this, _parser);
}
/*
/**********************************************************************
/* Internal methods; overridable for custom coercions
/**********************************************************************
*/
protected TreeCodec _treeCodec() throws JSONObjectException {
if (_treeCodec == null) {
throw new JSONObjectException("No TreeCodec specified: can not bind JSON into TreeNode types");
}
return _treeCodec;
}
protected MapBuilder _mapBuilder(Class<?> mapType) {
return (mapType == null) ? _mapBuilder : _mapBuilder.newBuilder(mapType);
}
protected CollectionBuilder _collectionBuilder(Class<?> collType) {
return (collType == null) ? _collectionBuilder : _collectionBuilder.newBuilder(collType);
}
}