Skip to content
Commits on Source (8)
......@@ -50,7 +50,7 @@ If you are not sure which package to use, the answer is usually `jr-objects`, an
[![Build Status](https://travis-ci.org/FasterXML/jackson-jr.svg)](https://travis-ci.org/FasterXML/jackson-jr)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.fasterxml.jackson.jr/jackson-jr-objects/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.fasterxml.jackson.jr/jackson-jr-objects/)
[![Javadoc](https://javadoc-emblem.rhcloud.com/doc/com.fasterxml.jackson.jr/jackson-jr-objects/badge.svg)](http://www.javadoc.io/doc/com.fasterxml.jackson.jr/jackson-jr-objects)
[![Javadoc](https://javadoc.io/badge/com.fasterxml.jackson.jr/jackson-jr-objects.svg)](http://www.javadoc.io/doc/com.fasterxml.jackson.jr/jackson-jr-objects)
## Usage
......
jackson-jr (2.10.0-1) unstable; urgency=medium
* New upstream version 2.10.0.
* Declare compliance with Debian Policy 4.4.1.
-- Markus Koschany <apo@debian.org> Thu, 03 Oct 2019 18:13:37 +0200
jackson-jr (2.9.9-1) unstable; urgency=medium
* New upstream version 2.9.9.
......
......@@ -18,7 +18,7 @@ Build-Depends:
libreplacer-java,
maven-debian-helper (>= 2.1),
xmlstarlet
Standards-Version: 4.4.0
Standards-Version: 4.4.1
Vcs-Git: https://salsa.debian.org/java-team/jackson-jr.git
Vcs-Browser: https://salsa.debian.org/java-team/jackson-jr
Homepage: https://github.com/FasterXML/jackson-jr
......
......@@ -4,3 +4,4 @@ com.fasterxml.jackson.jr jackson-jr-retrofit2 bundle * * *
com.fasterxml.jackson.jr jackson-jr-stree bundle * * *
junit junit * * * *
org.apache.maven.plugins maven-surefire-plugin * * * *
org.moditect moditect-maven-plugin * * * *
......@@ -15,7 +15,7 @@ index 7d448ff..1373f4c 100644
<parent>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-base</artifactId>
- <version>2.9.9</version>
- <version>2.10.0</version>
+ <version>debian</version>
</parent>
<groupId>com.fasterxml.jackson.jr</groupId>
......
......@@ -4,4 +4,4 @@
dh $@
override_dh_installchangelogs:
dh_installchangelogs release-notes/VERSION
dh_installchangelogs release-notes/VERSION-2.x
version=4
opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/jackson-jr-$1\.tar\.gz/ \
opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/jackson-jr-$1\.tar\.gz/,uversionmangle=s/_/./g;s/\.Beta/~beta/;s/\.pr\d//;s/\.Final//;s/-rc/~rc/ \
https://github.com/FasterXML/jackson-jr/tags .*/jackson-jr-parent-?(\d\S+)\.tar\.gz
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.fasterxml.jackson.jr</groupId>
<artifactId>jackson-jr-parent</artifactId>
<version>2.9.9</version>
<version>2.10.0</version>
</parent>
<artifactId>jackson-jr-all</artifactId>
<name>jackson-jr-all</name>
......
......@@ -3,7 +3,7 @@
<parent>
<groupId>com.fasterxml.jackson.jr</groupId>
<artifactId>jackson-jr-parent</artifactId>
<version>2.9.9</version>
<version>2.10.0</version>
</parent>
<artifactId>jackson-jr-objects</artifactId>
<packaging>bundle</packaging>
......@@ -89,6 +89,11 @@ has no other dependencies, and provides additional builder-style content generat
</excludes>
</configuration>
</plugin>
<!-- 11-Mar-2019, tatu: Add basic JDK8-includable module-info, generated by Moditect -->
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
......
......@@ -8,22 +8,39 @@ import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.SegmentedStringWriter;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
import com.fasterxml.jackson.core.util.Instantiatable;
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.comp.CollectionComposer;
import com.fasterxml.jackson.jr.ob.comp.ComposerBase;
import com.fasterxml.jackson.jr.ob.comp.MapComposer;
import com.fasterxml.jackson.jr.ob.impl.*;
/**
* Main entry point for functionality.
* Main entry point for functionality for reading and writing JSON
* and configuring details of reading and writing.
*<p>
* Note that instances are fully immutable, and thereby thread-safe.
*<p>
* Note on source types: source to read is declared as {@link java.lang.Object}
* but covers following types:
*<ul>
* <li>{@link InputStream}</li>
* <li>{@link Reader}</li>
* <li>{@code byte[]}</li>
* <li>{@code char[]}</li>
* <li>{@link String}/{@link CharSequence}</li>
* <li>{@link URL}</li>
* <li>{@link File}</li>
* </ul>
*
*/
@SuppressWarnings("resource")
public class JSON implements Versioned
{
/**
* Simple on/off (enabled/disabled) features for {@link JSON}; used for simple configuration
* aspects.
* Simple on/off (enabled/disabled) features for {@link JSON}; used for simple
* configuration aspects.
*/
public enum Feature
{
......@@ -72,7 +89,7 @@ public class JSON implements Versioned
/**
* This feature can be used to indicate that the reader should preserve
* order of the properties same as what input document has.
* Note that it is up to {@link com.fasterxml.jackson.jr.ob.impl.MapBuilder}
* Note that it is up to {@link com.fasterxml.jackson.jr.ob.api.MapBuilder}
* to support this feature; custom implementations may ignore the setting.
*<p>
* Default setting is <code>true</code>, meaning that reader is expected to try to
......@@ -250,13 +267,12 @@ public class JSON implements Versioned
* Feature that enables use of public fields instead of setters and getters,
* in cases where no setter/getter is available.
*<p>
* Feature is disabled by default (for backwards compatibility), so fields
* are not used unless explicitly enabled.
* Feature is <b>enabled</b> by default since 2.10 (but was <b>disabled</b> for
* 2.8 and 2.9), so public fields are discovered by default.
*
* @since 2.8
* @since 2.8 (enabled by default since 2.10)
*/
USE_FIELDS(false, true),
USE_FIELDS(true, true),
;
/*
......@@ -331,6 +347,8 @@ public class JSON implements Versioned
// Important: has to come before 'std' instance, since it refers to it
private final static int DEFAULT_FEATURES = Feature.defaults();
public final static int CACHE_FLAGS = Feature.cacheBreakers();
/**
* Singleton instance with standard, default configuration.
* May be used with direct references like:
......@@ -365,7 +383,7 @@ public class JSON implements Versioned
protected final JSONReader _reader;
/**
* Blueprint isntance of the writer to use for writing JSON given
* Blueprint instance of the writer to use for writing JSON given
* simple Objects.
*/
protected final JSONWriter _writer;
......@@ -387,15 +405,13 @@ public class JSON implements Versioned
*/
public JSON() {
this(DEFAULT_FEATURES, new JsonFactory(), null);
this(DEFAULT_FEATURES, new JsonFactory(), null,
null, null, null); // reader / writer / pretty-printer
}
protected JSON(int features,
JsonFactory jsonF, TreeCodec trees)
{
this(features, jsonF, trees,
null, null, // reader, writer
null);
public JSON(JsonFactory jsonF) {
this(DEFAULT_FEATURES, jsonF, null,
null, null, null); // reader / writer / pretty-printer
}
protected JSON(int features,
......@@ -406,23 +422,18 @@ public class JSON implements Versioned
_features = features;
_jsonFactory = jsonF;
_treeCodec = trees;
TypeDetector td = _defaultTypeDetector(features);
_reader = (r == null) ? _defaultReader(features, trees, td) : r;
_writer = (w == null) ? _defaultWriter(features, trees, td) : w;
_reader = (r != null) ? r : _defaultReader(features, trees, null);
_writer = (w != null) ? w : _defaultWriter(features, trees, null);
_prettyPrinter = pp;
}
protected TypeDetector _defaultTypeDetector(int features) {
return TypeDetector.blueprint(features);
}
protected JSONReader _defaultReader(int features, TreeCodec tc, TypeDetector td) {
return new JSONReader(features, td, tc,
protected JSONReader _defaultReader(int features, TreeCodec tc, ReaderWriterProvider rwp) {
return new JSONReader(features, ValueReaderLocator.blueprint(features, rwp), tc,
CollectionBuilder.defaultImpl(), MapBuilder.defaultImpl());
}
protected JSONWriter _defaultWriter(int features, TreeCodec tc, TypeDetector td) {
return new JSONWriter(features, td, tc);
protected JSONWriter _defaultWriter(int features, TreeCodec tc, ReaderWriterProvider rwp) {
return new JSONWriter(features, ValueWriterLocator.blueprint(features, rwp), tc);
}
/*
......@@ -542,6 +553,22 @@ public class JSON implements Versioned
r, _writer, _prettyPrinter);
}
/**
* Mutant factory for constructing an instance with specified {@link ReaderWriterProvider},
* and returning new instance (or, if there would be no change, this instance).
*
* @since 2.10
*/
public JSON with(ReaderWriterProvider rwp) {
JSONReader r = _reader.with(rwp);
JSONWriter w = _writer.with(rwp);
if ((r == _reader) && (w == _writer)) {
return this;
}
return _with(_features, _jsonFactory, _treeCodec,
r, w, _prettyPrinter);
}
/**
* Mutant factory for constructing an instance with specified feature
* enabled or disabled (depending on <code>state</code>), and returning
......@@ -593,8 +620,14 @@ public class JSON implements Versioned
if (_features == features) {
return this;
}
// 07-Jun-2019, tatu: May need to force clearing of state if cache-afflicted
// changes
JSONReader r = _reader.withCacheCheck(features);
JSONWriter w = _writer.withCacheCheck(features);
return _with(features, _jsonFactory, _treeCodec,
_reader, _writer, _prettyPrinter);
r, w, _prettyPrinter);
}
/*
......@@ -603,7 +636,7 @@ public class JSON implements Versioned
/**********************************************************************
*/
protected final JSON _with(int features,
protected JSON _with(int features,
JsonFactory jsonF, TreeCodec trees,
JSONReader reader, JSONWriter writer,
PrettyPrinter pp)
......@@ -632,6 +665,34 @@ public class JSON implements Versioned
return (f.mask() & _features) != 0;
}
/*
/**********************************************************************
/* Public factory methods for parsers, generators
/**********************************************************************
*/
/**
* Factory method for opening a {@link JsonParser} to read content from one of
* following supported sources
*<ul>
* <li>{@link InputStream}</li>
* <li>{@link Reader}</li>
* <li>{@code byte[]}</li>
* <li>{@code char[]}</li>
* <li>{@link String}/{@link CharSequence}</li>
* <li>{@link URL}</li>
* <li>{@link File}</li>
* </ul>
*<p>
* Rules regarding closing of the underlying source follow rules
* that {@link JsonFactory} has for its {@code createParser} method.
*
* @since 2.10
*/
public JsonParser createParser(Object source) throws IOException, JSONObjectException {
return _parser(source);
}
/*
/**********************************************************************
/* API: writing Simple objects as JSON
......@@ -837,22 +898,49 @@ public class JSON implements Versioned
}
@SuppressWarnings("unchecked")
public <T> Map<T,Object> mapFrom(Object source) throws IOException, JSONObjectException
public Map<String,Object> mapFrom(Object source) throws IOException, JSONObjectException
{
if (source instanceof JsonParser) {
JsonParser p = _initForReading((JsonParser) source);
Map<?,?> result = _readerForOperation(p).readMap();
p.clearCurrentToken();
return (Map<String,Object>) result;
}
JsonParser p = _parser(source);
try {
_initForReading(_config(p));
Map<?,?> result = _readerForOperation(p).readMap();
JsonParser p0 = p;
p = null;
_close(p0, null);
return (Map<String,Object>) result;
} catch (Exception e) {
return _closeWithError(p, e);
}
}
/**
* Read method for reading a {@link Map} of {@code type} (usually POJO) values.
*
* @since 2.10
*/
@SuppressWarnings("unchecked")
public <T> Map<String,T> mapOfFrom(Class<T> type, Object source) throws IOException, JSONObjectException
{
if (source instanceof JsonParser) {
JsonParser p = _initForReading((JsonParser) source);
Map<Object,Object> result = _readerForOperation(p).readMap();
Map<?,?> result = _readerForOperation(p).readMapOf(type);
p.clearCurrentToken();
return (Map<T,Object>) result;
return (Map<String,T>) result;
}
JsonParser p = _parser(source);
try {
_initForReading(_config(p));
Map<Object,Object> result = _readerForOperation(p).readMap();
Map<?,?> result = _readerForOperation(p).readMapOf(type);
JsonParser p0 = p;
p = null;
_close(p0, null);
return (Map<T,Object>) result;
return (Map<String,T>) result;
} catch (Exception e) {
return _closeWithError(p, e);
}
......@@ -926,7 +1014,7 @@ public class JSON implements Versioned
* @since 2.8
*/
@SuppressWarnings("unchecked")
public <T extends TreeNode> TreeNode treeFrom(Object source)
public <T extends TreeNode> T treeFrom(Object source)
throws IOException, JSONObjectException
{
if (_treeCodec == null) {
......@@ -952,6 +1040,91 @@ public class JSON implements Versioned
}
}
/*
/**********************************************************************
/* API: reading sequence of JSON values (LD-JSON and like)
/**********************************************************************
*/
/**
* Method for creating {@link ValueIterator} for reading
* <a href="https://en.wikipedia.org/wiki/JSON_streaming">streaming JSON</a>
* content (specifically line-delimited and concatenated variants);
* individual values are bound to specific Bean (POJO) type.
*
* @since 2.10
*/
public <T> ValueIterator<T> beanSequenceFrom(Class<T> type, Object source)
throws IOException, JSONObjectException
{
JsonParser p;
final boolean managed = !(source instanceof JsonParser);
if (managed) {
p = _parser(source);
} else {
p = (JsonParser) source;
}
p = _initForReading(_config(p));
JSONReader reader = _readerForOperation(p);
return new ValueIterator<T>(ValueIterator.MODE_BEAN, type,
p, reader, _treeCodec, managed);
}
/**
* Method for creating {@link ValueIterator} for reading
* <a href="https://en.wikipedia.org/wiki/JSON_streaming">streaming JSON</a>
* content (specifically line-delimited and concatenated variants);
* individual values are bound as "Simple" type: {@link java.util.Map},
* {@link java.util.List}, {@link String}, {@link Number} or {@link Boolean}.
*
* @since 2.10
*/
public ValueIterator<Object> anySequenceFrom(Object source)
throws IOException, JSONObjectException
{
JsonParser p;
final boolean managed = !(source instanceof JsonParser);
if (managed) {
p = _parser(source);
} else {
p = (JsonParser) source;
}
p = _initForReading(_config(p));
JSONReader reader = _readerForOperation(p);
return new ValueIterator<Object>(ValueIterator.MODE_ANY, Object.class,
p, reader, _treeCodec, managed);
}
/**
* Method for creating {@link ValueIterator} for reading
* <a href="https://en.wikipedia.org/wiki/JSON_streaming">streaming JSON</a>
* content (specifically line-delimited and concatenated variants);
* individual values are bound as JSON Trees(of type that configured
* {@link TreeCodec}, see {@link #with(TreeCodec)}) supports.
*/
public <T extends TreeNode> ValueIterator<T> treeSequenceFrom(Object source)
throws IOException, JSONObjectException
{
if (_treeCodec == null) {
_noTreeCodec("read TreeNode");
}
JsonParser p;
final boolean managed = !(source instanceof JsonParser);
if (managed) {
p = _parser(source);
} else {
p = (JsonParser) source;
}
p = _initForReading(_config(p));
JSONReader reader = _readerForOperation(p);
return new ValueIterator<T>(ValueIterator.MODE_TREE, TreeNode.class,
p, reader, _treeCodec, managed);
}
/*
/**********************************************************************
/* API: TreeNode construction
......
package com.fasterxml.jackson.jr.ob;
import java.io.Closeable;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.jr.ob.impl.JSONReader;
/**
* Iterator exposed by {@link JSON} when binding sequence of
* objects. Extension is done to allow more convenient exposing of
* {@link IOException} (which basic {@link Iterator} does not expose).
*<p>
* NOTE: adapted from `jackson-databind` {@code MappingIterator}
*/
public class ValueIterator<T> implements Iterator<T>, Closeable
{
/**
* Mode in which values are read as POJOs/Beans.
*/
protected final static int MODE_BEAN = 1;
/**
* Mode in which values are read as "Simple" content,
* {@link java.util.Map}s, {@link java.util.List}s, {@link String}s,
* {@link Number}s and {@link Boolean}s.
*/
protected final static int MODE_ANY = 2;
/**
* Mode in which values are read as "Tree" values, as bound
* by registered {@link TreeCodec}.
*/
protected final static int MODE_TREE = 3;
protected final static ValueIterator<?> EMPTY_ITERATOR =
new ValueIterator<Object>(MODE_BEAN, null, null, null, null, false);
/*
/**********************************************************************
/* State constants
/**********************************************************************
*/
/**
* State in which iterator is closed
*/
protected final static int STATE_CLOSED = 0;
/**
* State in which value read failed
*/
protected final static int STATE_NEED_RESYNC = 1;
/**
* State in which no recovery is needed, but "hasNextValue()" needs
* to be called first
*/
protected final static int STATE_MAY_HAVE_VALUE = 2;
/**
* State in which "hasNextValue()" has been successfully called
* and deserializer can be called to fetch value
*/
protected final static int STATE_HAS_VALUE = 3;
/*
/**********************************************************************
/* Configuration
/**********************************************************************
*/
/**
* Mode: kind of values we are iterating over
*/
protected final int _mode;
/**
* Type to bind individual elements to.
*/
protected final Class<?> _type;
/**
* Context for deserialization, needed to pass through to deserializer
*/
protected final JSONReader _reader;
/**
* If "Tree" values are read, codec we need to use for binding
*/
protected final TreeCodec _treeCodec;
/**
* Underlying parser used for reading content to bind. Initialized
* as not <code>null</code> but set as <code>null</code> when
* iterator is closed, to denote closing.
*/
protected final JsonParser _parser;
/**
* Context to resynchronize to, in case an exception is encountered
* but caller wants to try to read more elements.
*/
protected final JsonStreamContext _seqContext;
/**
* Flag that indicates whether input {@link JsonParser} should be closed
* when we are done or not; generally only called when caller did not
* pass JsonParser.
*/
protected final boolean _closeParser;
/*
/**********************************************************************
/* Parsing state
/**********************************************************************
*/
/**
* State of the iterator
*/
protected int _state;
/*
/**********************************************************************
/* Construction
/**********************************************************************
*/
/**
* @param managedParser Whether we "own" the {@link JsonParser} passed or not:
* if true, it was created by {@code Json} and code here needs to
* close it; if false, it was passed by calling code and should not be
* closed by iterator.
*/
protected ValueIterator(int mode, Class<?> type, JsonParser p, JSONReader reader,
TreeCodec treeCodec, boolean managedParser)
{
_mode = mode;
_type = type;
_parser = p;
_reader = reader;
_treeCodec = treeCodec;
_closeParser = managedParser;
/* Ok: one more thing; we may have to skip START_ARRAY, assuming
* "wrapped" sequence; but this is ONLY done for 'managed' parsers
* and never if JsonParser was directly passed by caller (if it
* was, caller must have either positioned it over first token of
* the first element, or cleared the START_ARRAY token explicitly).
* Note, however, that we do not try to guess whether this could be
* an unwrapped sequence of arrays/Lists: we just assume it is wrapped;
* and if not, caller needs to hand us JsonParser instead, pointing to
* the first token of the first element.
*/
if (p == null) { // can this occur?
_seqContext = null;
_state = STATE_CLOSED;
} else {
JsonStreamContext sctxt = p.getParsingContext();
if (managedParser && p.isExpectedStartArrayToken()) {
// If pointing to START_ARRAY, context should be that ARRAY
p.clearCurrentToken();
} else {
// regardless, recovery context should be whatever context we have now, with
// sole exception of pointing to a start marker, in which case it's the parent
JsonToken t = p.getCurrentToken();
if ((t == JsonToken.START_OBJECT) || (t == JsonToken.START_ARRAY)) {
sctxt = sctxt.getParent();
}
}
_seqContext = sctxt;
_state = STATE_MAY_HAVE_VALUE;
}
}
@SuppressWarnings("unchecked")
protected static <T> ValueIterator<T> emptyIterator() {
return (ValueIterator<T>) EMPTY_ITERATOR;
}
/*
/**********************************************************************
/* Basic iterator impl
/**********************************************************************
*/
@Override
public boolean hasNext()
{
try {
return hasNextValue();
} catch (JSONObjectException e) {
return (Boolean) _handleMappingException(e);
} catch (IOException e) {
return (Boolean) _handleIOException(e);
}
}
@SuppressWarnings("unchecked")
@Override
public T next()
{
try {
return nextValue();
} catch (JSONObjectException e) {
return (T) _handleMappingException(e);
} catch (IOException e) {
return (T) _handleIOException(e);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void close() throws IOException {
if (_state != STATE_CLOSED) {
_state = STATE_CLOSED;
if (_parser != null) {
_parser.close();
}
}
}
/*
/**********************************************************************
/* Extended API, iteration
/**********************************************************************
*/
/**
* Equivalent of {@link #next} but one that may throw checked
* exceptions from Jackson due to invalid input.
*/
public boolean hasNextValue() throws IOException
{
switch (_state) {
case STATE_CLOSED:
return false;
case STATE_NEED_RESYNC:
_resync();
// fall-through
case STATE_MAY_HAVE_VALUE:
JsonToken t = _parser.getCurrentToken();
if (t == null) { // un-initialized or cleared; find next
t = _parser.nextToken();
// If EOF, no more, or if we hit END_ARRAY (although we don't clear the token).
if (t == null || t == JsonToken.END_ARRAY) {
_state = STATE_CLOSED;
if (_closeParser && (_parser != null)) {
_parser.close();
}
return false;
}
}
_state = STATE_HAS_VALUE;
return true;
case STATE_HAS_VALUE:
// fall through
}
return true;
}
public T nextValue() throws IOException
{
switch (_state) {
case STATE_CLOSED:
return _throwNoSuchElement();
case STATE_NEED_RESYNC: // fall-through, will do re-sync
case STATE_MAY_HAVE_VALUE:
if (!hasNextValue()) {
return _throwNoSuchElement();
}
break;
case STATE_HAS_VALUE:
break;
}
int nextState = STATE_NEED_RESYNC;
try {
Object value;
switch (_mode) {
case MODE_BEAN:
value = _reader.readBean(_type);
break;
case MODE_ANY:
value = _reader.readValue();
break;
case MODE_TREE:
value = _treeCodec.readTree(_parser);
break;
default:
throw new IllegalStateException("Invalid mode: "+_mode);
}
nextState = STATE_MAY_HAVE_VALUE;
{
@SuppressWarnings("unchecked")
T result = (T) value;
return result;
}
} finally {
_state = nextState;
// Need to mark token consumed no matter what, to avoid infinite loop for certain
// failure cases.
_parser.clearCurrentToken();
}
}
/**
* Convenience method for reading all entries accessible via
* this iterator; resulting container will be a {@link java.util.ArrayList}.
*
* @return List of entries read
*/
public List<T> readAll() throws IOException {
return readAll(new ArrayList<T>());
}
/**
* Convenience method for reading all entries accessible via
* this iterator
*
* @return List of entries read (same as passed-in argument)
*/
public <L extends List<? super T>> L readAll(L resultList) throws IOException
{
while (hasNextValue()) {
resultList.add(nextValue());
}
return resultList;
}
/**
* Convenience method for reading all entries accessible via this iterator
*/
public <C extends Collection<? super T>> C readAll(C results) throws IOException
{
while (hasNextValue()) {
results.add(nextValue());
}
return results;
}
/*
/**********************************************************************
/* Extended API, accessors
/**********************************************************************
*/
/**
* Accessor for getting underlying parser this iterator uses.
*/
public JsonParser getParser() {
return _parser;
}
/**
* Convenience method, functionally equivalent to:
*<code>
* iterator.getParser().getCurrentLocation()
*</code>
*
* @return Location of the input stream of the underlying parser
*/
public JsonLocation getCurrentLocation() {
return _parser.getCurrentLocation();
}
/*
/**********************************************************************
/* Helper methods
/**********************************************************************
*/
protected void _resync() throws IOException
{
final JsonParser p = _parser;
// First, a quick check to see if we might have been lucky and no re-sync needed
if (p.getParsingContext() == _seqContext) {
return;
}
while (true) {
JsonToken t = p.nextToken();
if ((t == JsonToken.END_ARRAY) || (t == JsonToken.END_OBJECT)) {
if (p.getParsingContext() == _seqContext) {
p.clearCurrentToken();
return;
}
} else if ((t == JsonToken.START_ARRAY) || (t == JsonToken.START_OBJECT)) {
p.skipChildren();
} else if (t == null) {
return;
}
}
}
protected <R> R _throwNoSuchElement() {
throw new NoSuchElementException();
}
protected <R> R _handleMappingException(JSONObjectException e) {
throw new UncheckedIOException(e.getMessage(), e);
}
protected <R> R _handleIOException(IOException e) {
throw new UncheckedIOException(e.getMessage(), e);
}
}
package com.fasterxml.jackson.jr.ob.impl;
package com.fasterxml.jackson.jr.ob.api;
import java.lang.reflect.Array;
import java.util.*;
......@@ -86,7 +86,7 @@ public abstract class CollectionBuilder
public Object[] buildArray() {
// sub-optimal, but defined for convenience
Collection<Object> l = buildCollection();
return l.toArray(new Object[l.size()]);
return l.toArray();
}
@SuppressWarnings("unchecked")
......
package com.fasterxml.jackson.jr.ob.impl;
package com.fasterxml.jackson.jr.ob.api;
import java.util.*;
import com.fasterxml.jackson.jr.ob.JSON;
import com.fasterxml.jackson.jr.ob.JSON.Feature;
import com.fasterxml.jackson.jr.ob.impl.DeferredMap;
import com.fasterxml.jackson.jr.ob.JSONObjectException;
/**
......
package com.fasterxml.jackson.jr.ob.api;
import com.fasterxml.jackson.jr.ob.impl.JSONReader;
import com.fasterxml.jackson.jr.ob.impl.JSONWriter;
import com.fasterxml.jackson.jr.type.ResolvedType;
/**
* API to implement to provide custom {@link ValueReader}s and
* {@link ValueWriter}s.
*
* @since 2.10
*/
public abstract class ReaderWriterProvider {
// // Reader access
/**
* Method called to find custom reader for given type that is NOT one of
* special container types ({@link java.util.Collection},
* {@link java.util.Map}): typically value is a scalar, Bean or Enum.
*
* @param readContext context object that may be needed for resolving dependant
* readers
* @param type Raw type of bean to find reader for
*/
public ValueReader findValueReader(JSONReader readContext, Class<?> type) {
return null;
}
public ValueReader findCollectionReader(JSONReader readContext, Class<?> type,
ResolvedType valueType, ValueReader readerForValues) {
return null;
}
public ValueReader findMapReader(JSONReader readContext, Class<?> type,
ResolvedType valueType, ValueReader readerForValues) {
return null;
}
// // Writer access
public ValueWriter findValueWriter(JSONWriter writeContext, Class<?> type) {
return null;
}
}
package com.fasterxml.jackson.jr.ob.api;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.jr.ob.impl.JSONReader;
/**
* API and base class for all "deserializer" implementations used to actually read
* values of Java types from (JSON) input.
*/
public abstract class ValueReader
{
/**
* Type of values this reader will read
*
* @since 2.10
*/
protected final Class<?> _valueType;
protected ValueReader(Class<?> valueType) {
_valueType = valueType;
}
/*
/**********************************************************************
/* Basic API to implement for actual read operations
/**********************************************************************
*/
/**
* Method called to deserialize value of type supported by this reader, using
* given parser. Parser is already positioned to the (first) token
* of the value to read.
*
* @param reader Context object that allows calling other read methods for contained
* values of different types (for example for collection readers).
* @param p Underlying parser used for reading decoded token stream
*/
public abstract Object read(JSONReader reader, JsonParser p) throws IOException;
/**
* Method called to deserialize value of type supported by this reader, using
* given parser. Parser is not yet positioned to the (first) token
* of the value to read and needs to be advanced.
*<p>
* Default implementation simply calls `p.nextToken()` first, then calls
* {#link {@link #read(JSONReader, JsonParser)}, but some implementations
* may decide to implement this differently to use (slightly) more efficient
* accessor in {@link JsonParser}, like {@link JsonParser#nextIntValue(int)}.
*
* @param reader Context object that allows calling other read methods for contained
* values of different types (for example for collection readers).
* @param p Underlying parser used for reading decoded token stream
*/
public Object readNext(JSONReader reader, JsonParser p) throws IOException {
p.nextToken();
return read(reader, p);
}
/*
/**********************************************************************
/* Minimal metadata
/**********************************************************************
*/
/**
* Accessor for non-generic (type-erased) type of values this reader
* produces from input.
*
* @since 2.10
*/
public Class<?> valueType() {
return _valueType;
}
/*
/**********************************************************************
/* Helper methods for sub-classes
/**********************************************************************
*/
/**
* Helper method for getting description of the token parser currently points to,
* for use in descriptions and exception messages.
*/
public static String _tokenDesc(JsonParser p) throws IOException {
return _tokenDesc(p, p.currentToken());
}
/**
* Helper method for getting description of given token
* for use in descriptions and exception messages.
*/
public static String _tokenDesc(JsonParser p, JsonToken t) throws IOException {
if (t == null) {
return "NULL";
}
switch (t) {
case FIELD_NAME:
return "JSON Field name '"+p.getCurrentName()+"'";
case START_ARRAY:
return "JSON Array";
case START_OBJECT:
return "JSON Object";
case VALUE_FALSE:
return "`false`";
case VALUE_NULL:
return "'null'";
case VALUE_NUMBER_FLOAT:
case VALUE_NUMBER_INT:
return "JSON Number";
case VALUE_STRING:
return "JSON String";
case VALUE_TRUE:
return "`true`";
case VALUE_EMBEDDED_OBJECT:
{
final Object value = p.getEmbeddedObject();
if (value == null) {
return "EMBEDDED_OBJECT `null`";
}
return "EMBEDDED_OBJECT of type "+p.getClass().getName();
}
default:
return t.toString();
}
}
}
package com.fasterxml.jackson.jr.ob.api;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.jr.ob.impl.JSONWriter;
/**
*
* @since 2.10
*/
public interface ValueWriter {
public void writeValue(JSONWriter context, JsonGenerator g, Object value)
throws IOException;
/*
/**********************************************************************
/* Minimal metadata
/**********************************************************************
*/
/**
* Accessor for non-generic (type-erased) type of values this reader
* produces from input.
*
* @since 2.10
*/
public Class<?> valueType();
}
......@@ -10,6 +10,9 @@ import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.jr.ob.*;
import com.fasterxml.jackson.jr.ob.api.CollectionBuilder;
import com.fasterxml.jackson.jr.ob.api.MapBuilder;
import com.fasterxml.jackson.jr.ob.api.ValueReader;
/**
* {@link ValueReader} used for "untyped" values; ones that are bound
......@@ -20,6 +23,8 @@ public class AnyReader extends ValueReader
{
public final static AnyReader std = new AnyReader();
public AnyReader() { super(Object.class); }
@Override
public Object readNext(JSONReader r, JsonParser p) throws IOException
{
......
......@@ -4,6 +4,8 @@ import java.io.IOException;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.jr.ob.JSONObjectException;
import com.fasterxml.jackson.jr.ob.api.CollectionBuilder;
import com.fasterxml.jackson.jr.ob.api.ValueReader;
/**
* Reader for typed Array values.
......@@ -13,8 +15,9 @@ public class ArrayReader extends ValueReader
protected final Class<?> _elementType;
protected final ValueReader _valueReader;
public ArrayReader(Class<?> t, ValueReader vr) {
_elementType = t;
public ArrayReader(Class<?> arrayType, Class<?> elementType, ValueReader vr) {
super(arrayType);
_elementType = elementType;
_valueReader = vr;
}
......@@ -24,7 +27,8 @@ public class ArrayReader extends ValueReader
if (p.hasToken(JsonToken.VALUE_NULL)) {
return null;
}
throw JSONObjectException.from(p, "Unexpected token "+p.getCurrentToken()+"; should get START_ARRAY");
throw JSONObjectException.from(p, "Unexpected token %s; should get START_ARRAY",
p.getCurrentToken());
}
CollectionBuilder b = r._collectionBuilder(null);
......
......@@ -7,6 +7,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type;
import com.fasterxml.jackson.jr.ob.JSONObjectException;
import com.fasterxml.jackson.jr.ob.api.ValueReader;
/**
* @since 2.8 (formerly part of `BeanDefinition`)
......
......@@ -18,21 +18,30 @@ public final class BeanPropertyWriter
public final SerializedString name;
public final int typeId;
private final Method _getter;
private final Field _field;
private final Method _getter;
public BeanPropertyWriter(int typeId, String n, Field f, Method getter)
{
this.typeId = typeId;
name = new SerializedString(n);
_field = f;
if ((getter == null) && (f == null)) {
throw new IllegalArgumentException("Missing getter and field");
}
_field = f;
_getter = getter;
}
/**
* @since 2.10
*/
public BeanPropertyWriter withName(String newName) {
if (name.toString().equals(newName)) {
return this;
}
return new BeanPropertyWriter(typeId, newName, _field, _getter);
}
public Object getValueFor(Object bean) throws IOException
{
try {
......@@ -41,9 +50,12 @@ public final class BeanPropertyWriter
}
return _getter.invoke(bean);
} catch (Exception e) {
final String accessorDesc = (_getter != null)
? String.format("method %s.%s()", _bean(), _getter.getName())
: String.format("field %s.%s", _bean(), _field.getName());
throw new JSONObjectException(String.format(
"Failed to access property '%s'; exception (%s): %s",
name, e.getClass().getName(), e.getMessage()), e);
"Failed to access property '%s' (using %s); exception (%s): %s",
name, e.getClass().getName(), accessorDesc, e.getMessage()), e);
}
}
......