Merge branch '2.6'
Conflicts:
pom.xml
release-notes/VERSION
diff --git a/README.md b/README.md
index b76d839..b93f417 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
Project contains versions 2.0 and above: source code for earlier (1.x) versions is available from [Codehaus](http://jackson.codehaus.org) SVN repository.
[![Build Status](https://travis-ci.org/FasterXML/jackson-core.svg?branch=master)](https://travis-ci.org/FasterXML/jackson-core) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.fasterxml.jackson.core/jackson-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.fasterxml.jackson.core/jackson-core)
+[![Javadoc](https://javadoc-emblem.rhcloud.com/doc/com.fasterxml.jackson.core/jackson-core/badge.svg)](http://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-core)
# Get it!
@@ -104,6 +105,6 @@
* Project [Wiki](../../wiki) has JavaDocs and links to downloadable artifacts
* [Jackson Github Hub](https://github.com/FasterXML/jackson) has links to all official Jackson components
* [Jackson Github Doc](https://github.com/FasterXML/jackson-docs) is the hub for official Jackson documentation
-* [FasterXML Jackson Project Wiki](http://wiki.fasterxml.com/JacksonHome) has additional documentation (especailly for older Jackson versions)
+* [FasterXML Jackson Project Wiki](http://wiki.fasterxml.com/JacksonHome) has additional documentation (especially for older Jackson versions)
* Commercial support (including alternative licensing arrangements) is available by [FasterXML.com](http://fasterxml.com)
diff --git a/pom.xml b/pom.xml
index f58af18..ae1ecca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,13 +3,13 @@
<parent>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-parent</artifactId>
- <version>2.6.2</version>
+ <version>2.7</version>
</parent>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<name>Jackson-core</name>
- <version>2.6.6-SNAPSHOT</version>
+ <version>2.7.1-SNAPSHOT</version>
<packaging>bundle</packaging>
<description>Core Jackson abstractions, basic JSON streaming API implementation</description>
<inceptionYear>2008</inceptionYear>
@@ -23,6 +23,10 @@
</scm>
<properties>
+ <!-- 02-Oct-2015, tatu: Retain Java6/JDK1.6 compatibility for streaming for Jackson 2.7 -->
+ <javac.src.version>1.6</javac.src.version>
+ <javac.target.version>1.6</javac.target.version>
+
<osgi.export>com.fasterxml.jackson.core;version=${project.version},
com.fasterxml.jackson.core.*;version=${project.version}
</osgi.export>
@@ -44,7 +48,7 @@
<encoding>UTF-8</encoding>
<maxmemory>512m</maxmemory>
<links>
- <link>http://docs.oracle.com/javase/6/docs/api/</link>
+ <link>http://docs.oracle.com/javase/7/docs/api/</link>
</links>
</configuration>
<executions>
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index 4e01f69..f07310b 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -70,3 +70,8 @@
Iskren Ivov Chernev (ichernev@github)
* Reported #213: Parser is sometimes wrong when using CANONICALIZE_FIELD_NAMES
(2.6.2)
+
+Michael Lehenbauer (mikelehen@github)
+ * Reported #37: JsonParser.getTokenLocation() doesn't update after field names
+ (2.7.0)
+
diff --git a/release-notes/VERSION b/release-notes/VERSION
index 000d5b0..8ef10c5 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -14,6 +14,18 @@
=== Releases ===
------------------------------------------------------------------------
+2.7.0 (10-Jun-2016)
+
+#37: JsonParser.getTokenLocation() doesn't update after field names
+ (reported by Michael L)
+#198: Add back-references to `JsonParser` / `JsonGenerator` for low-level parsing issues
+ (via `JsonParseException`, `JsonGenerationException`)
+#211: Typo of function name com.fasterxml.jackson.core.Version.isUknownVersion()
+ (reported by timray@github)
+#229: Array element and field token spans include previous comma.
+- Implemented `ReaderBasedJsonParser.nextFieldName(SerializableString)`
+ (to improved Afterburner performance over String/char[] sources)
+
2.6.6 (not yet released)
#248: VersionUtil.versionFor() unexpectedly return null instead of Version.unknownVersion()
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
index 08037aa..b052507 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java
@@ -205,16 +205,6 @@
*/
protected final transient ByteQuadsCanonicalizer _byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot();
- /**
- * Earlier byte-based symbol table; replaced with 2.6 with a new implementation.
- * Left in for version 2.6.0: will be removed in 2.7 or later.
- *
- * @deprecated Since 2.6.0, only use {@link #_byteSymbolCanonicalizer}
- */
- @Deprecated
- protected final transient com.fasterxml.jackson.core.sym.BytesToNameCanonicalizer _rootByteSymbols
- = com.fasterxml.jackson.core.sym.BytesToNameCanonicalizer.createRoot();
-
/*
/**********************************************************
/* Configuration
@@ -739,9 +729,15 @@
/**
* Method for constructing JSON parser instance to parse
- * contents of specified file. Encoding is auto-detected
- * from contents according to JSON specification recommended
- * mechanism.
+ * contents of specified file.
+ *
+ *<p>
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
*<p>
* Underlying input stream (needed for reading contents)
* will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -761,9 +757,14 @@
/**
* Method for constructing JSON parser instance to parse
* contents of resource reference by given URL.
- * Encoding is auto-detected
- * from contents according to JSON specification recommended
- * mechanism.
+ *
+ *<p>
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
*<p>
* Underlying input stream (needed for reading contents)
* will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -790,8 +791,12 @@
* if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
* is enabled.
*<p>
+ *
* Note: no encoding argument is taken since it can always be
- * auto-detected as suggested by JSON RFC.
+ * auto-detected as suggested by JSON RFC. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
*
* @param in InputStream to use for reading JSON content to parse
*
@@ -907,15 +912,20 @@
/*
/**********************************************************
- /* Parser factories (old ones, as per [Issue-25])
+ /* Parser factories (old ones, pre-2.2)
/**********************************************************
*/
/**
* Method for constructing JSON parser instance to parse
- * contents of specified file. Encoding is auto-detected
- * from contents according to JSON specification recommended
- * mechanism.
+ * contents of specified file.
+ *<p>
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
*<p>
* Underlying input stream (needed for reading contents)
* will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -933,9 +943,14 @@
/**
* Method for constructing JSON parser instance to parse
* contents of resource reference by given URL.
- * Encoding is auto-detected
- * from contents according to JSON specification recommended
- * mechanism.
+ *
+ *<p>
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
*<p>
* Underlying input stream (needed for reading contents)
* will be <b>owned</b> (and managed, i.e. closed as need be) by
@@ -960,8 +975,12 @@
* if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
* is enabled.
*<p>
+ *
* Note: no encoding argument is taken since it can always be
- * auto-detected as suggested by JSON RFC.
+ * auto-detected as suggested by JSON RFC. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
*
* @param in InputStream to use for reading JSON content to parse
*
@@ -1131,7 +1150,7 @@
/*
/**********************************************************
- /* Generator factories, old (as per [Issue-25]
+ /* Generator factories, old (pre-2.2)
/**********************************************************
*/
@@ -1194,27 +1213,6 @@
public JsonGenerator createJsonGenerator(OutputStream out) throws IOException {
return createGenerator(out, JsonEncoding.UTF8);
}
-
- /**
- * Method for constructing JSON generator for writing JSON content
- * to specified file, overwriting contents it might have (or creating
- * it if such file does not yet exist).
- * Encoding to use must be specified, and needs to be one of available
- * types (as per JSON specification).
- *<p>
- * Underlying stream <b>is owned</b> by the generator constructed,
- * i.e. generator will handle closing of file when
- * {@link JsonGenerator#close} is called.
- *
- * @param f File to write contents to
- * @param enc Character encoding to use
- *
- * @deprecated Since 2.2, use {@link #createGenerator(File,JsonEncoding)} instead.
- */
- @Deprecated
- public JsonGenerator createJsonGenerator(File f, JsonEncoding enc) throws IOException {
- return createGenerator(f, enc);
- }
/*
/**********************************************************
@@ -1443,7 +1441,7 @@
}
return br;
}
-
+
/**
* Overridable factory method that actually instantiates desired
* context object.
@@ -1451,7 +1449,7 @@
protected IOContext _createContext(Object srcRef, boolean resourceManaged) {
return new IOContext(_getBufferRecycler(), srcRef, resourceManaged);
}
-
+
/**
* Helper methods used for constructing an optimal stream for
* parsers to use, when input is to be read from an URL.
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java
index 5a9d181..69d825b 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerationException.java
@@ -14,19 +14,59 @@
extends JsonProcessingException
{
private final static long serialVersionUID = 123; // Stupid eclipse...
-
- public JsonGenerationException(Throwable rootCause)
- {
+
+ protected JsonGenerator _processor;
+
+ @Deprecated // since 2.7
+ public JsonGenerationException(Throwable rootCause) {
super(rootCause);
}
- public JsonGenerationException(String msg)
- {
+ @Deprecated // since 2.7
+ public JsonGenerationException(String msg) {
super(msg, (JsonLocation)null);
}
- public JsonGenerationException(String msg, Throwable rootCause)
- {
+ @Deprecated // since 2.7
+ public JsonGenerationException(String msg, Throwable rootCause) {
super(msg, null, rootCause);
}
+
+ /**
+ * @since 2.7
+ */
+ public JsonGenerationException(Throwable rootCause, JsonGenerator g) {
+ super(rootCause);
+ _processor = g;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonGenerationException(String msg, JsonGenerator g) {
+ super(msg, (JsonLocation) null);
+ _processor = g;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonGenerationException(String msg, Throwable rootCause, JsonGenerator g) {
+ super(msg, null, rootCause);
+ _processor = g;
+ }
+
+ /**
+ * Fluent method that may be used to assign originating {@link JsonGenerator},
+ * to be accessed using {@link #getProcessor()}.
+ *
+ * @since 2.7
+ */
+ public JsonGenerationException withGenerator(JsonGenerator g) {
+ _processor = g;
+ return this;
+ }
+
+ @Override
+ public JsonGenerator getProcessor() { return _processor; }
}
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
index 7d57513..aedc30b 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
@@ -146,6 +146,30 @@
*/
ESCAPE_NON_ASCII(false),
+// 23-Nov-2015, tatu: for [core#223], if and when it gets implemented
+ /**
+ * Feature that specifies handling of UTF-8 content that contains
+ * characters beyond BMP (Basic Multilingual Plane), which are
+ * represented in UCS-2 (Java internal character encoding) as two
+ * "surrogate" characters. If feature is enabled, these surrogate
+ * pairs are separately escaped using backslash escapes; if disabled,
+ * native output (4-byte UTF-8 sequence, or, with char-backed output
+ * targets, writing of surrogates as is which is typically converted
+ * by {@link java.io.Writer} into 4-byte UTF-8 sequence eventually)
+ * is used.
+ *<p>
+ * Note that the original JSON specification suggests use of escaping;
+ * but that this is not correct from standard UTF-8 handling perspective.
+ * Because of two competing goals, this feature was added to allow either
+ * behavior to be used, but defaulting to UTF-8 specification compliant
+ * mode.
+ *<p>
+ * Feature is disabled by default.
+ *
+ * @since Xxx
+ */
+// ESCAPE_UTF8_SURROGATES(false),
+
// // Schema/Validity support features
/**
@@ -253,7 +277,7 @@
/**
* Method for accessing the object used for writing Java
- * object as Json content
+ * object as JSON content
* (using method {@link #writeObject}).
*/
public abstract ObjectCodec getCodec();
@@ -303,7 +327,6 @@
*/
public abstract boolean isEnabled(Feature f);
-
/**
* Bulk access method for getting state of all standard (non-dataformat-specific)
* {@link JsonGenerator.Feature}s.
@@ -323,7 +346,10 @@
* and which disabled
*
* @return This parser object, to allow chaining of calls
+ *
+ * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
*/
+ @Deprecated
public abstract JsonGenerator setFeatureMask(int values);
/**
@@ -334,6 +360,7 @@
* int newState = (oldState & ~mask) | (values & mask);
* setFeatureMask(newState);
*</code>
+ * but preferred as this lets caller more efficiently specify actual changes made.
*
* @param values Bit mask of set/clear state for features to change
* @param mask Bit mask of features to change
@@ -953,7 +980,7 @@
* encoded, as a complete String value (surrounded by double quotes).
* This method defaults
*<p>
- * Note: because Json Strings can not contain unescaped linefeeds,
+ * Note: because JSON Strings can not contain unescaped linefeeds,
* if linefeeds are included (as per last argument), they must be
* escaped. This adds overhead for decoding without improving
* readability.
@@ -1142,7 +1169,7 @@
public abstract void writeNumber(String encodedValue) throws IOException;
/**
- * Method for outputting literal Json boolean value (one of
+ * Method for outputting literal JSON boolean value (one of
* Strings 'true' and 'false').
* Can be called in any context where a value is expected
* (Array value, Object field value, root-level value).
@@ -1152,7 +1179,7 @@
public abstract void writeBoolean(boolean state) throws IOException;
/**
- * Method for outputting literal Json null value.
+ * Method for outputting literal JSON null value.
* Can be called in any context where a value is expected
* (Array value, Object field value, root-level value).
* Additional white space may be added around the value
@@ -1178,7 +1205,7 @@
* @since 2.3
*/
public void writeObjectId(Object id) throws IOException {
- throw new JsonGenerationException("No native support for writing Object Ids");
+ throw new JsonGenerationException("No native support for writing Object Ids", this);
}
/**
@@ -1191,7 +1218,7 @@
* a {@link JsonGenerationException} will be thrown.
*/
public void writeObjectRef(Object id) throws IOException {
- throw new JsonGenerationException("No native support for writing Object Ids");
+ throw new JsonGenerationException("No native support for writing Object Ids", this);
}
/**
@@ -1206,9 +1233,9 @@
* @since 2.3
*/
public void writeTypeId(Object id) throws IOException {
- throw new JsonGenerationException("No native support for writing Type Ids");
+ throw new JsonGenerationException("No native support for writing Type Ids", this);
}
-
+
/*
/**********************************************************
/* Public API, write methods, serializing Java objects
@@ -1219,8 +1246,8 @@
* Method for writing given Java object (POJO) as Json.
* Exactly how the object gets written depends on object
* in question (ad on codec, its configuration); for most
- * beans it will result in Json object, but for others Json
- * array, or String or numeric value (and for nulls, Json
+ * beans it will result in JSON Object, but for others JSON
+ * Array, or String or numeric value (and for nulls, JSON
* null literal.
* <b>NOTE</b>: generator must have its <b>object codec</b>
* set to non-null value; for generators created by a mapping
@@ -1436,7 +1463,7 @@
* Method for copying contents of the current event that
* the given parser instance points to.
* Note that the method <b>will not</b> copy any other events,
- * such as events contained within Json Array or Object structures.
+ * such as events contained within JSON Array or Object structures.
*<p>
* Calling this method will not advance the given
* parser, although it may cause parser to internally process
@@ -1534,7 +1561,7 @@
* </li>
* <li>{@link JsonToken#FIELD_NAME} the logical value (which
* can consist of a single scalar value; or a sequence of related
- * events for structured types (Json Arrays, Objects)) will
+ * events for structured types (JSON Arrays, Objects)) will
* be copied along with the name itself. So essentially the
* whole <b>field entry</b> (name and value) will be copied.
* </li>
@@ -1646,7 +1673,7 @@
* or use a {@link JsonGenerationException} sub-class.
*/
protected void _reportError(String msg) throws JsonGenerationException {
- throw new JsonGenerationException(msg);
+ throw new JsonGenerationException(msg, this);
}
protected final void _throwInternal() { VersionUtil.throwInternal(); }
@@ -1654,7 +1681,7 @@
protected void _reportUnsupportedOperation() {
throw new UnsupportedOperationException("Operation not supported by generator of type "+getClass().getName());
}
-
+
/**
* Helper method to try to call appropriate write method for given
* untyped Object. At this point, no structural conversions should be done,
@@ -1702,9 +1729,8 @@
} else if (n instanceof BigDecimal) {
writeNumber((BigDecimal) n);
return;
-
+
// then Atomic types
-
} else if (n instanceof AtomicInteger) {
writeNumber(((AtomicInteger) n).get());
return;
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
index 926f709..17116e3 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
@@ -11,13 +11,69 @@
* is encountered.
*/
public class JsonParseException extends JsonProcessingException {
- private static final long serialVersionUID = 1L;
-
+ private static final long serialVersionUID = 2L; // 2.7
+
+ protected JsonParser _processor;
+
+ @Deprecated // since 2.7
public JsonParseException(String msg, JsonLocation loc) {
super(msg, loc);
}
+ @Deprecated // since 2.7
public JsonParseException(String msg, JsonLocation loc, Throwable root) {
super(msg, loc, root);
}
+
+ /**
+ * Constructor that uses current parsing location as location, and
+ * sets processor (accessible via {@link #getProcessor()}) to
+ * specified parser.
+ *
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg) {
+ super(msg, (p == null) ? null : p.getCurrentLocation());
+ _processor = p;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg, Throwable root) {
+ super(msg, (p == null) ? null : p.getCurrentLocation(), root);
+ _processor = p;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg, JsonLocation loc) {
+ super(msg, loc);
+ _processor = p;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable root) {
+ super(msg, loc, root);
+ _processor = p;
+ }
+
+ /**
+ * Fluent method that may be used to assign originating {@link JsonParser},
+ * to be accessed using {@link #getProcessor()}.
+ *
+ * @since 2.7
+ */
+ public JsonParseException withParser(JsonParser p) {
+ _processor = p;
+ return this;
+ }
+
+ @Override
+ public JsonParser getProcessor() {
+ return _processor;
+ }
}
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
index 0af1d43..b24b660 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
@@ -103,7 +103,7 @@
* Feature that determines whether parser will allow use
* of single quotes (apostrophe, character '\'') for
* quoting Strings (names and String values). If so,
- * this is in addition to other acceptabl markers.
+ * this is in addition to other acceptable markers.
* but not by JSON specification).
*<p>
* Since JSON specification requires use of double quotes for
@@ -529,7 +529,10 @@
* @return This parser object, to allow chaining of calls
*
* @since 2.3
+ *
+ * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
*/
+ @Deprecated
public JsonParser setFeatureMask(int mask) {
_features = mask;
return this;
@@ -543,6 +546,7 @@
* int newState = (oldState & ~mask) | (values & mask);
* setFeatureMask(newState);
*</code>
+ * but preferred as this lets caller more efficiently specify actual changes made.
*
* @param values Bit mask of set/clear state for features to change
* @param mask Bit mask of features to change
@@ -550,8 +554,8 @@
* @since 2.6
*/
public JsonParser overrideStdFeatures(int values, int mask) {
- _features = (_features & ~mask) | (values & mask);
- return this;
+ int newState = (_features & ~mask) | (values & mask);
+ return setFeatureMask(newState);
}
/**
@@ -1172,7 +1176,8 @@
JsonToken t = getCurrentToken();
if (t == JsonToken.VALUE_TRUE) return true;
if (t == JsonToken.VALUE_FALSE) return false;
- throw new JsonParseException("Current token ("+t+") not of boolean type", getCurrentLocation());
+ throw new JsonParseException(this,
+ String.format("Current token (%s) not of boolean type", t));
}
/**
@@ -1578,7 +1583,7 @@
* based on current state of the parser
*/
protected JsonParseException _constructError(String msg) {
- return new JsonParseException(msg, getCurrentLocation());
+ return new JsonParseException(this, msg);
}
/**
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
index ddbab6d..f927336 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
@@ -59,7 +59,7 @@
/*
/**********************************************************
- /* Cosntruction
+ /* Construction
/**********************************************************
*/
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java b/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
index 4cca715..44be053 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonProcessingException.java
@@ -45,14 +45,14 @@
this(null, null, rootCause);
}
- public JsonLocation getLocation() { return _location; }
-
/*
/**********************************************************
/* Extended API
/**********************************************************
*/
+ public JsonLocation getLocation() { return _location; }
+
/**
* Method that allows accessing the original "message" argument,
* without additional decorations (like location information)
@@ -62,6 +62,22 @@
*/
public String getOriginalMessage() { return super.getMessage(); }
+ /**
+ * Method that allows accessing underlying processor that triggered
+ * this exception; typically either {@link JsonParser} or {@link JsonGenerator}
+ * for exceptions that originate from streaming API.
+ * Note that it is possible that `null` may be returned if code throwing
+ * exception either has no access to processor; or has not been retrofitted
+ * to set it; this means that caller needs to take care to check for nulls.
+ * Subtypes override this method with co-variant return type, for more
+ * type-safe access.
+ *
+ * @return Originating processor, if available; null if not.
+ *
+ * @since 2.7
+ */
+ public Object getProcessor() { return null; }
+
/*
/**********************************************************
/* Methods for sub-classes to use, override
diff --git a/src/main/java/com/fasterxml/jackson/core/TreeCodec.java b/src/main/java/com/fasterxml/jackson/core/TreeCodec.java
index b1037b6..9aa1232 100644
--- a/src/main/java/com/fasterxml/jackson/core/TreeCodec.java
+++ b/src/main/java/com/fasterxml/jackson/core/TreeCodec.java
@@ -10,8 +10,8 @@
*/
public abstract class TreeCodec
{
- public abstract <T extends TreeNode> T readTree(JsonParser jp) throws IOException, JsonProcessingException;
- public abstract void writeTree(JsonGenerator jg, TreeNode tree) throws IOException, JsonProcessingException;
+ public abstract <T extends TreeNode> T readTree(JsonParser p) throws IOException, JsonProcessingException;
+ public abstract void writeTree(JsonGenerator g, TreeNode tree) throws IOException, JsonProcessingException;
public abstract TreeNode createArrayNode();
public abstract TreeNode createObjectNode();
public abstract JsonParser treeAsTokens(TreeNode node);
diff --git a/src/main/java/com/fasterxml/jackson/core/Version.java b/src/main/java/com/fasterxml/jackson/core/Version.java
index 48b9163..e43a684 100644
--- a/src/main/java/com/fasterxml/jackson/core/Version.java
+++ b/src/main/java/com/fasterxml/jackson/core/Version.java
@@ -19,7 +19,7 @@
private static final long serialVersionUID = 1L;
private final static Version UNKNOWN_VERSION = new Version(0, 0, 0, null, null, null);
-
+
protected final int _majorVersion;
protected final int _minorVersion;
@@ -27,9 +27,9 @@
protected final int _patchLevel;
protected final String _groupId;
-
+
protected final String _artifactId;
-
+
/**
* Additional information for snapshot versions; null for non-snapshot
* (release) versions.
@@ -46,7 +46,7 @@
{
this(major, minor, patchLevel, snapshotInfo, null, null);
}
-
+
public Version(int major, int minor, int patchLevel, String snapshotInfo,
String groupId, String artifactId)
{
@@ -64,20 +64,29 @@
*/
public static Version unknownVersion() { return UNKNOWN_VERSION; }
- public boolean isUknownVersion() { return (this == UNKNOWN_VERSION); }
+ /**
+ * @since 2.7 to replace misspelled {@link #isUknownVersion()}
+ */
+ public boolean isUnknownVersion() { return (this == UNKNOWN_VERSION); }
public boolean isSnapshot() { return (_snapshotInfo != null && _snapshotInfo.length() > 0); }
-
+
+ /**
+ * @deprecated Since 2.7 use correctly spelled method {@link #isUnknownVersion()}
+ */
+ @Deprecated
+ public boolean isUknownVersion() { return isUnknownVersion(); }
+
public int getMajorVersion() { return _majorVersion; }
public int getMinorVersion() { return _minorVersion; }
public int getPatchLevel() { return _patchLevel; }
public String getGroupId() { return _groupId; }
public String getArtifactId() { return _artifactId; }
-
+
public String toFullString() {
return _groupId + '/' + _artifactId + '/' + toString();
}
-
+
@Override public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(_majorVersion).append('.');
diff --git a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
index f806bdf..38302b5 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
@@ -171,35 +171,64 @@
return this;
}
- @Override public JsonGenerator setFeatureMask(int newMask) {
+ @Override
+ @Deprecated
+ public JsonGenerator setFeatureMask(int newMask) {
int changed = newMask ^ _features;
_features = newMask;
- if ((changed & DERIVED_FEATURES_MASK) != 0) {
- _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(newMask);
- if (Feature.ESCAPE_NON_ASCII.enabledIn(changed)) {
- if (Feature.ESCAPE_NON_ASCII.enabledIn(newMask)) {
- setHighestNonEscapedChar(127);
- } else {
- setHighestNonEscapedChar(0);
- }
- }
- if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(changed)) {
- if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newMask)) { // enabling
- if (_writeContext.getDupDetector() == null) { // but only if disabled currently
- _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this));
- }
- } else { // disabling
- _writeContext = _writeContext.withDupDetector(null);
- }
- }
+ if (changed != 0) {
+ _checkStdFeatureChanges(newMask, changed);
}
return this;
}
+
+ @Override // since 2.7
+ public JsonGenerator overrideStdFeatures(int values, int mask) {
+ int oldState = _features;
+ int newState = (oldState & ~mask) | (values & mask);
+ int changed = oldState ^ newState;
+ if (changed != 0) {
+ _features = newState;
+ _checkStdFeatureChanges(newState, changed);
+ }
+ return this;
+ }
+
+ /**
+ * Helper method called to verify changes to standard features.
+ *
+ * @param newFeatureFlags Bitflag of standard features after they were changed
+ * @param changedFeatures Bitflag of standard features for which setting
+ * did change
+ *
+ * @since 2.7
+ */
+ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
+ {
+ if ((changedFeatures & DERIVED_FEATURES_MASK) == 0) {
+ return;
+ }
+ _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(newFeatureFlags);
+ if (Feature.ESCAPE_NON_ASCII.enabledIn(changedFeatures)) {
+ if (Feature.ESCAPE_NON_ASCII.enabledIn(newFeatureFlags)) {
+ setHighestNonEscapedChar(127);
+ } else {
+ setHighestNonEscapedChar(0);
+ }
+ }
+ if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(changedFeatures)) {
+ if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newFeatureFlags)) { // enabling
+ if (_writeContext.getDupDetector() == null) { // but only if disabled currently
+ _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this));
+ }
+ } else { // disabling
+ _writeContext = _writeContext.withDupDetector(null);
+ }
+ }
+ }
@Override public JsonGenerator useDefaultPrettyPrinter() {
- /* 28-Sep-2012, tatu: As per [Issue#84], should not override a
- * pretty printer if one already assigned.
- */
+ // Should not override a pretty printer if one already assigned.
if (getPrettyPrinter() != null) {
return this;
}
diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
index 7c97e2a..a6f53e0 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
@@ -50,12 +50,12 @@
/**
* Pointer to next available character in buffer
*/
- protected int _inputPtr = 0;
+ protected int _inputPtr;
/**
* Index of character after last available one in the buffer.
*/
- protected int _inputEnd = 0;
+ protected int _inputEnd;
/*
/**********************************************************
@@ -67,7 +67,7 @@
* Number of characters/bytes that were contained in previous blocks
* (blocks that were already processed prior to the current buffer).
*/
- protected long _currInputProcessed = 0L;
+ protected long _currInputProcessed;
/**
* Current row location of current point in input buffer, starting
@@ -81,7 +81,7 @@
* of not having column itself is that this only has to be updated
* once per line.
*/
- protected int _currInputRowStart = 0;
+ protected int _currInputRowStart;
/*
/**********************************************************
@@ -97,7 +97,7 @@
* For big (gigabyte-sized) sizes are possible, needs to be long,
* unlike pointers and sizes related to in-memory buffers.
*/
- protected long _tokenInputTotal = 0;
+ protected long _tokenInputTotal;
/**
* Input row on which current token starts, 1-based
@@ -108,7 +108,7 @@
* Column on input row that current token starts; 0-based (although
* in the end it'll be converted to 1-based)
*/
- protected int _tokenInputCol = 0;
+ protected int _tokenInputCol;
/*
/**********************************************************
@@ -147,20 +147,20 @@
* using {@link #getTextCharacters} method (instead of String
* returning alternatives)
*/
- protected char[] _nameCopyBuffer = null;
+ protected char[] _nameCopyBuffer;
/**
* Flag set to indicate whether the field name is available
* from the name copy buffer or not (in addition to its String
* representation being available via read context)
*/
- protected boolean _nameCopied = false;
+ protected boolean _nameCopied;
/**
* ByteArrayBuilder is needed if 'getBinaryValue' is called. If so,
* we better reuse it for remainder of content.
*/
- protected ByteArrayBuilder _byteArrayBuilder = null;
+ protected ByteArrayBuilder _byteArrayBuilder;
/**
* We will hold on to decoded binary data, for duration of
@@ -326,23 +326,54 @@
}
return this;
}
-
+
@Override
+ @Deprecated
public JsonParser setFeatureMask(int newMask) {
int changes = (_features ^ newMask);
if (changes != 0) {
_features = newMask;
- if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newMask)) { // enabling
- if (_parsingContext.getDupDetector() == null) { // but only if disabled currently
- _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this));
- }
- } else { // disabling
- _parsingContext = _parsingContext.withDupDetector(null);
- }
+ _checkStdFeatureChanges(newMask, changes);
}
return this;
}
-
+
+ @Override // since 2.7
+ public JsonParser overrideStdFeatures(int values, int mask) {
+ int oldState = _features;
+ int newState = (oldState & ~mask) | (values & mask);
+ int changed = oldState ^ newState;
+ if (changed != 0) {
+ _features = newState;
+ _checkStdFeatureChanges(newState, changed);
+ }
+ return this;
+ }
+
+ /**
+ * Helper method called to verify changes to standard features.
+ *
+ * @param newFeatureFlags Bitflag of standard features after they were changed
+ * @param changedFeatures Bitflag of standard features for which setting
+ * did change
+ *
+ * @since 2.7
+ */
+ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
+ {
+ int f = Feature.STRICT_DUPLICATE_DETECTION.getMask();
+
+ if ((changedFeatures & f) != 0) {
+ if ((newFeatureFlags & f) != 0) {
+ if (_parsingContext.getDupDetector() == null) {
+ _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this));
+ } else { // disabling
+ _parsingContext = _parsingContext.withDupDetector(null);
+ }
+ }
+ }
+ }
+
/*
/**********************************************************
/* JsonParser impl
@@ -356,7 +387,7 @@
@Override public String getCurrentName() throws IOException {
// [JACKSON-395]: start markers require information from parent
if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
- JsonReadContext parent = _parsingContext.getParent();
+ JsonReadContext parent = _parsingContext.clearAndGetParent();
return parent.getCurrentName();
}
return _parsingContext.getCurrentName();
@@ -434,7 +465,22 @@
// No embedded objects with base impl...
@Override public Object getEmbeddedObject() throws IOException { return null; }
-
+
+ @SuppressWarnings("resource")
+ @Override // since 2.7
+ public byte[] getBinaryValue(Base64Variant variant) throws IOException
+ {
+ if (_binaryValue == null) {
+ if (_currToken != JsonToken.VALUE_STRING) {
+ _reportError("Current token ("+_currToken+") not VALUE_STRING, can not access as binary");
+ }
+ ByteArrayBuilder builder = _getByteArrayBuilder();
+ _decodeBase64(getText(), builder, variant);
+ _binaryValue = builder.toByteArray();
+ }
+ return _binaryValue;
+ }
+
/*
/**********************************************************
/* Public low-level accessors
diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
index 310ee4e..b6810a9 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
@@ -265,10 +265,7 @@
public int getValueAsInt() throws IOException
{
JsonToken t = _currToken;
- if (t == JsonToken.VALUE_NUMBER_INT) {
- return getIntValue();
- }
- if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
return getIntValue();
}
return getValueAsInt(0);
@@ -278,10 +275,7 @@
public int getValueAsInt(int defaultValue) throws IOException
{
JsonToken t = _currToken;
- if (t == JsonToken.VALUE_NUMBER_INT) {
- return getIntValue();
- }
- if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
return getIntValue();
}
if (t != null) {
@@ -312,10 +306,7 @@
public long getValueAsLong() throws IOException
{
JsonToken t = _currToken;
- if (t == JsonToken.VALUE_NUMBER_INT) {
- return getLongValue();
- }
- if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
return getLongValue();
}
return getValueAsLong(0L);
@@ -325,10 +316,7 @@
public long getValueAsLong(long defaultValue) throws IOException
{
JsonToken t = _currToken;
- if (t == JsonToken.VALUE_NUMBER_INT) {
- return getLongValue();
- }
- if (t == JsonToken.VALUE_NUMBER_FLOAT) {
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
return getLongValue();
}
if (t != null) {
@@ -542,7 +530,7 @@
}
protected final JsonParseException _constructError(String msg, Throwable t) {
- return new JsonParseException(msg, getCurrentLocation(), t);
+ return new JsonParseException(this, msg, t);
}
protected static byte[] _asciiBytes(String str) {
@@ -552,7 +540,7 @@
}
return b;
}
-
+
protected static String _ascii(byte[] b) {
try {
return new String(b, "US-ASCII");
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
index 8468a37..1c7bed3 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
@@ -55,7 +55,7 @@
* Marked as deprecated since its status is uncertain.
*/
@Deprecated
- protected boolean _includeImmediateParent = false;
+ protected boolean _includeImmediateParent;
/*
/**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
index 0d65bff..7900229 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
@@ -57,7 +57,7 @@
* Marked as deprecated since its status is uncertain.
*/
@Deprecated
- protected boolean _includeImmediateParent = false;
+ protected boolean _includeImmediateParent;
/*
/**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java
index fcca317..14848bb 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java
@@ -25,7 +25,7 @@
/**********************************************************
*/
- protected TokenFilterContext _child = null;
+ protected TokenFilterContext _child;
/*
/**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
index 0216fe0..4c616fc 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
@@ -19,7 +19,7 @@
* Lookup table used for determining which input characters
* need special handling when contained in text segment.
*/
- final static int[] sInputCodes;
+ private final static int[] sInputCodes;
static {
/* 96 would do for most cases (backslash is ASCII 94)
* but if we want to do lookups by raw bytes it's better
@@ -40,7 +40,7 @@
* Additionally we can combine UTF-8 decoding info into similar
* data table.
*/
- final static int[] sInputCodesUTF8;
+ private final static int[] sInputCodesUTF8;
static {
final int[] table = new int[sInputCodes.length];
System.arraycopy(sInputCodes, 0, table, 0, table.length);
@@ -70,7 +70,7 @@
* Basically this is list of 8-bit ASCII characters that are legal
* as part of Javascript identifier
*/
- final static int[] sInputCodesJsNames;
+ private final static int[] sInputCodesJsNames;
static {
final int[] table = new int[256];
// Default is "not a name char", mark ones that are
@@ -97,7 +97,7 @@
* code as ok. They will be validated at a later point, when decoding
* name
*/
- final static int[] sInputCodesUtf8JsNames;
+ private final static int[] sInputCodesUtf8JsNames;
static {
final int[] table = new int[256];
// start with 8-bit JS names
@@ -110,7 +110,7 @@
* Decoding table used to quickly determine characters that are
* relevant within comment content.
*/
- final static int[] sInputCodesComment;
+ private final static int[] sInputCodesComment;
static {
final int[] buf = new int[256];
// but first: let's start with UTF-8 multi-byte markers:
@@ -130,7 +130,7 @@
*
* @since 2.3
*/
- final static int[] sInputCodesWS;
+ private final static int[] sInputCodesWS;
static {
// but first: let's start with UTF-8 multi-byte markers:
final int[] buf = new int[256];
@@ -153,7 +153,7 @@
* Lookup table used for determining which output characters in
* 7-bit ASCII range need to be quoted.
*/
- final static int[] sOutputEscapes128;
+ private final static int[] sOutputEscapes128;
static {
int[] table = new int[128];
// Control chars need generic escape sequence
@@ -180,7 +180,7 @@
* range. For actual hex digits, contains corresponding value;
* for others -1.
*/
- final static int[] sHexValues = new int[128];
+ private final static int[] sHexValues = new int[128];
static {
Arrays.fill(sHexValues, -1);
for (int i = 0; i < 10; ++i) {
diff --git a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
index 84fefc1..a4675be 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
@@ -56,33 +56,33 @@
* Reference to the allocated I/O buffer for low-level input reading,
* if any allocated.
*/
- protected byte[] _readIOBuffer = null;
+ protected byte[] _readIOBuffer;
/**
* Reference to the allocated I/O buffer used for low-level
* encoding-related buffering.
*/
- protected byte[] _writeEncodingBuffer = null;
+ protected byte[] _writeEncodingBuffer;
/**
* Reference to the buffer allocated for temporary use with
* base64 encoding or decoding.
*/
- protected byte[] _base64Buffer = null;
+ protected byte[] _base64Buffer;
/**
* Reference to the buffer allocated for tokenization purposes,
* in which character input is read, and from which it can be
* further returned.
*/
- protected char[] _tokenCBuffer = null;
+ protected char[] _tokenCBuffer;
/**
* Reference to the buffer allocated for buffering it for
* output, before being encoded: generally this means concatenating
* output, then encoding when buffer fills up.
*/
- protected char[] _concatCBuffer = null;
+ protected char[] _concatCBuffer;
/**
* Reference temporary buffer Parser instances need if calling
@@ -90,7 +90,7 @@
* Regular text buffer can not be used as it may contain textual
* representation of the value token.
*/
- protected char[] _nameCopyBuffer = null;
+ protected char[] _nameCopyBuffer;
/*
/**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
index 523c401..0cdf8c7 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
@@ -14,8 +14,8 @@
final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE);
- final static char[] LEAD_3 = new char[4000];
- final static char[] FULL_3 = new char[4000];
+ private final static char[] LEAD_3 = new char[4000];
+ private final static char[] FULL_3 = new char[4000];
static {
/* Let's fill it with NULLs for ignorable leading digits,
* and digit chars for others
@@ -42,17 +42,17 @@
}
}
- final static byte[] FULL_TRIPLETS_B = new byte[4000];
+ private final static byte[] FULL_TRIPLETS_B = new byte[4000];
static {
for (int i = 0; i < 4000; ++i) {
FULL_TRIPLETS_B[i] = (byte) FULL_3[i];
}
}
- final static String[] sSmallIntStrs = new String[] {
+ private final static String[] sSmallIntStrs = new String[] {
"0","1","2","3","4","5","6","7","8","9","10"
};
- final static String[] sSmallIntStrs2 = new String[] {
+ private final static String[] sSmallIntStrs2 = new String[] {
"-1","-2","-3","-4","-5","-6","-7","-8","-9","-10"
};
diff --git a/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java b/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java
index 787b3ad..34b126c 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/UTF32Reader.java
@@ -39,12 +39,12 @@
/**
* Total read character count; used for error reporting purposes
*/
- protected int _charCount = 0;
+ protected int _charCount;
/**
* Total read byte count; used for error reporting purposes
*/
- protected int _byteCount = 0;
+ protected int _byteCount;
protected final boolean _managedBuffers;
@@ -81,7 +81,7 @@
}
}
- protected char[] _tmpBuf = null;
+ protected char[] _tmpBuf;
/**
* Although this method is implemented by the base class, AND it should
diff --git a/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java b/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
index ab358d9..3672f88 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
@@ -24,7 +24,7 @@
* To do this, both pairs must be known first; and since it is possible
* pairs may be split, we need temporary storage for the first half
*/
- private int _surrogate = 0;
+ private int _surrogate;
public UTF8Writer(IOContext ctxt, OutputStream out)
{
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
index f59e032..d37079b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
@@ -73,7 +73,7 @@
protected boolean _bigEndian = true;
- protected int _bytesPerChar = 0; // 0 means "dunno yet"
+ protected int _bytesPerChar; // 0 means "dunno yet"
/*
/**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java b/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
index 628556b..e02150c 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
@@ -20,7 +20,7 @@
public class DupDetector
{
/**
- * We need to store a back-reference here to parser/generator, unfortunately.
+ * We need to store a back-reference here to parser/generator.
*/
protected final Object _source;
@@ -63,7 +63,14 @@
// do generators have a way to provide Location? Apparently not...
return null;
}
-
+
+ /**
+ * @since 2.7
+ */
+ public Object getSource() {
+ return _source;
+ }
+
public boolean isDup(String name) throws JsonParseException
{
if (_firstName == null) {
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
index 9ce93e4..c09d2cf 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
@@ -95,7 +95,8 @@
super(features, codec);
_ioContext = ctxt;
if (isEnabled(Feature.ESCAPE_NON_ASCII)) {
- setHighestNonEscapedChar(127);
+ // inlined `setHighestNonEscapedChar()`
+ _maximumNonEscapedChar = 127;
}
}
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java b/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
index 333d3ca..3520b2b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonReadContext.java
@@ -30,7 +30,7 @@
/**********************************************************
*/
- protected JsonReadContext _child = null;
+ protected JsonReadContext _child;
/*
/**********************************************************
@@ -103,20 +103,10 @@
/**********************************************************
*/
- @Deprecated // since 2.3, use variant that takes dup detector
- public static JsonReadContext createRootContext(int lineNr, int colNr) {
- return createRootContext(lineNr, colNr, null);
- }
-
public static JsonReadContext createRootContext(int lineNr, int colNr, DupDetector dups) {
return new JsonReadContext(null, dups, TYPE_ROOT, lineNr, colNr);
}
- @Deprecated // since 2.3, use variant that takes dup detector
- public static JsonReadContext createRootContext() {
- return createRootContext(null);
- }
-
public static JsonReadContext createRootContext(DupDetector dups) {
return new JsonReadContext(null, dups, TYPE_ROOT, 1, 0);
}
@@ -152,6 +142,22 @@
@Override public String getCurrentName() { return _currentName; }
@Override public JsonReadContext getParent() { return _parent; }
+ /**
+ * Method that can be used to both clear the accumulated references
+ * (specifically value set with {@link #setCurrentValue(Object)})
+ * that should not be retained, and returns parent (as would
+ * {@link #getParent()} do). Typically called when closing the active
+ * context when encountering {@link JsonToken#END_ARRAY} or
+ * {@link JsonToken#END_OBJECT}.
+ *
+ * @since 2.7
+ */
+ public JsonReadContext clearAndGetParent() {
+ _currentValue = null;
+ // could also clear the current name, but seems cheap enough to leave?
+ return _parent;
+ }
+
/*
/**********************************************************
/* Extended API
@@ -194,10 +200,12 @@
private void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
if (dd.isDup(name)) {
- throw new JsonParseException("Duplicate field '"+name+"'", dd.findLocation());
+ Object src = dd.getSource();
+ throw new JsonParseException(((src instanceof JsonGenerator) ? ((JsonParser) src) : null),
+ "Duplicate field '"+name+"'");
}
}
-
+
/*
/**********************************************************
/* Overridden standard methods
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
index f15bd54..a9c863e 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteContext.java
@@ -35,7 +35,7 @@
/**********************************************************
*/
- protected JsonWriteContext _child = null;
+ protected JsonWriteContext _child;
/*
/**********************************************************
@@ -136,6 +136,22 @@
@Override public final JsonWriteContext getParent() { return _parent; }
@Override public final String getCurrentName() { return _currentName; }
+ /**
+ * Method that can be used to both clear the accumulated references
+ * (specifically value set with {@link #setCurrentValue(Object)})
+ * that should not be retained, and returns parent (as would
+ * {@link #getParent()} do). Typically called when closing the active
+ * context when encountering {@link JsonToken#END_ARRAY} or
+ * {@link JsonToken#END_OBJECT}.
+ *
+ * @since 2.7
+ */
+ public JsonWriteContext clearAndGetParent() {
+ _currentValue = null;
+ // could also clear the current name, but seems cheap enough to leave?
+ return _parent;
+ }
+
public DupDetector getDupDetector() {
return _dups;
}
@@ -156,7 +172,11 @@
}
private final void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
- if (dd.isDup(name)) { throw new JsonGenerationException("Duplicate field '"+name+"'"); }
+ if (dd.isDup(name)) {
+ Object src = dd.getSource();
+ throw new JsonGenerationException("Duplicate field '"+name+"'",
+ ((src instanceof JsonGenerator) ? ((JsonGenerator) src) : null));
+ }
}
public int writeValue() {
diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
index 1bc9d34..bb211ba 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
@@ -50,7 +50,7 @@
* buffer.
*/
protected boolean _bufferRecyclable;
-
+
/*
/**********************************************************
/* Configuration
@@ -60,7 +60,7 @@
protected ObjectCodec _objectCodec;
final protected CharsToNameCanonicalizer _symbols;
-
+
final protected int _hashSeed;
/*
@@ -68,13 +68,33 @@
/* Parsing state
/**********************************************************
*/
-
+
/**
* Flag that indicates that the current token has not yet
* been fully processed, and needs to be finished for
* some access (or skipped to obtain the next token)
*/
- protected boolean _tokenIncomplete = false;
+ protected boolean _tokenIncomplete;
+
+ /**
+ * Value of {@link #_inputPtr} at the time when the first character of
+ * name token was read. Used for calculating token location when requested;
+ * combined with {@link #_currInputProcessed}, may be updated appropriately
+ * as needed.
+ *
+ * @since 2.7
+ */
+ protected long _nameStartOffset;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartRow;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartCol;
/*
/**********************************************************
@@ -85,7 +105,7 @@
/**
* Method called when caller wants to provide input buffer directly,
* and it may or may not be recyclable use standard recycle context.
- *
+ *
* @since 2.4
*/
public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
@@ -130,7 +150,7 @@
@Override public ObjectCodec getCodec() { return _objectCodec; }
@Override public void setCodec(ObjectCodec c) { _objectCodec = c; }
-
+
@Override
public int releaseBuffered(Writer w) throws IOException {
int count = _inputEnd - _inputPtr;
@@ -146,8 +166,15 @@
@Override
protected boolean loadMore() throws IOException
{
- _currInputProcessed += _inputEnd;
- _currInputRowStart -= _inputEnd;
+ final int bufSize = _inputEnd;
+
+ _currInputProcessed += bufSize;
+ _currInputRowStart -= bufSize;
+
+ // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+ // this increase to avoid "moving" name-offset, resulting most likely
+ // in negative value, which is fine as combine value remains unchanged.
+ _nameStartOffset -= bufSize;
if (_reader != null) {
int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
@@ -210,13 +237,13 @@
}
}
}
-
+
/*
/**********************************************************
/* Public API, data access
/**********************************************************
*/
-
+
/**
* Method for accessing textual representation of the current event;
* if no current event (before first call to {@link #nextToken}, or
@@ -238,7 +265,7 @@
}
// // // Let's override default impls for improved performance
-
+
// @since 2.1
@Override
public final String getValueAsString() throws IOException
@@ -255,7 +282,7 @@
}
return super.getValueAsString(null);
}
-
+
// @since 2.1
@Override
public final String getValueAsString(String defValue) throws IOException {
@@ -308,7 +335,6 @@
_nameCopied = true;
}
return _nameCopyBuffer;
-
case ID_STRING:
if (_tokenIncomplete) {
_tokenIncomplete = false;
@@ -318,7 +344,6 @@
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.getTextBuffer();
-
default:
return _currToken.asCharArray();
}
@@ -331,7 +356,6 @@
{
if (_currToken != null) { // null only before/after document
switch (_currToken.id()) {
-
case ID_FIELD_NAME:
return _parsingContext.getCurrentName().length();
case ID_STRING:
@@ -343,7 +367,6 @@
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.size();
-
default:
return _currToken.asCharArray().length;
}
@@ -404,7 +427,7 @@
}
return _binaryValue;
}
-
+
@Override
public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
{
@@ -562,8 +585,6 @@
@Override
public final JsonToken nextToken() throws IOException
{
- _numTypesValid = NR_UNKNOWN;
-
/* First: field names are special -- we will always tokenize
* (part of) value along with field name to simplify
* state handling. If so, can and need to use secondary token:
@@ -571,6 +592,9 @@
if (_currToken == JsonToken.FIELD_NAME) {
return _nextAfterName();
}
+ // But if we didn't already have a name, and (partially?) decode number,
+ // need to ensure no numeric information is leaked
+ _numTypesValid = NR_UNKNOWN;
if (_tokenIncomplete) {
_skipString(); // only strings can be partial
}
@@ -582,30 +606,24 @@
close();
return (_currToken = null);
}
-
- /* First, need to ensure we know the starting location of token
- * after skipping leading white space
- */
- _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
- _tokenInputRow = _currInputRow;
- _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
- // finally: clear any data retained so far
+ // clear any data retained so far
_binaryValue = null;
// Closing scope?
if (i == INT_RBRACKET) {
+ _updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
+ _updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_OBJECT);
}
@@ -614,18 +632,19 @@
i = _skipComma(i);
}
- /* And should we now have a name? Always true for
- * Object contexts, since the intermediate 'expect-value'
- * state is never retained.
+ /* And should we now have a name? Always true for Object contexts, since
+ * the intermediate 'expect-value' state is never retained.
*/
boolean inObject = _parsingContext.inObject();
if (inObject) {
- // First, field name itself:
+ // First, field name itself:
+ _updateNameLocation();
String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
_parsingContext.setCurrentName(name);
_currToken = JsonToken.FIELD_NAME;
i = _skipColon();
}
+ _updateLocation();
// Ok: we must have a value... what is it?
@@ -703,6 +722,9 @@
_nameCopied = false; // need to invalidate if it was copied
JsonToken t = _nextToken;
_nextToken = null;
+
+// !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
+
// Also: may need to start new context?
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
@@ -718,14 +740,86 @@
/**********************************************************
*/
- /*
+ // Implemented since 2.7
@Override
- public boolean nextFieldName(SerializableString str)
- throws IOException
+ public boolean nextFieldName(SerializableString sstr) throws IOException
{
-
+ // // // Note: most of code below is copied from nextToken()
+
+ _numTypesValid = NR_UNKNOWN;
+ if (_currToken == JsonToken.FIELD_NAME) {
+ _nextAfterName();
+ return false;
+ }
+ if (_tokenIncomplete) {
+ _skipString();
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) {
+ close();
+ _currToken = null;
+ return false;
+ }
+ _binaryValue = null;
+
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_ARRAY;
+ return false;
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_OBJECT;
+ return false;
+ }
+ if (_parsingContext.expectComma()) {
+ i = _skipComma(i);
+ }
+
+ if (!_parsingContext.inObject()) {
+ _updateLocation();
+ _nextTokenNotInObject(i);
+ return false;
+ }
+
+ _updateNameLocation();
+ if (i == INT_QUOTE) {
+ // when doing literal match, must consider escaping:
+ char[] nameChars = sstr.asQuotedChars();
+ final int len = nameChars.length;
+
+ // Require 4 more bytes for faster skipping of colon that follows name
+ if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
+ // first check length match by
+ final int end = _inputPtr+len;
+ if (_inputBuffer[end] == '"') {
+ int offset = 0;
+ int ptr = _inputPtr;
+ while (true) {
+ if (ptr == end) { // yes, match!
+ _parsingContext.setCurrentName(sstr.getValue());
+ _isNextTokenNameYes(_skipColonFast(ptr+1));
+ return true;
+ }
+ if (nameChars[offset] != _inputBuffer[ptr]) {
+ break;
+ }
+ ++offset;
+ ++ptr;
+ }
+ }
+ }
+ }
+ return _isNextTokenNameMaybe(i, sstr.getValue());
}
- */
@Override
public String nextFieldName() throws IOException
@@ -746,40 +840,41 @@
_currToken = null;
return null;
}
- _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
- _tokenInputRow = _currInputRow;
- _tokenInputCol = _inputPtr - _currInputRowStart - 1;
_binaryValue = null;
if (i == INT_RBRACKET) {
+ _updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
return null;
}
if (i == INT_RCURLY) {
+ _updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
return null;
}
if (_parsingContext.expectComma()) {
i = _skipComma(i);
}
-
if (!_parsingContext.inObject()) {
+ _updateLocation();
_nextTokenNotInObject(i);
return null;
}
+ _updateNameLocation();
String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
_parsingContext.setCurrentName(name);
_currToken = JsonToken.FIELD_NAME;
i = _skipColon();
+ _updateLocation();
if (i == INT_QUOTE) {
_tokenIncomplete = true;
_nextToken = JsonToken.VALUE_STRING;
@@ -832,6 +927,110 @@
return name;
}
+ private final void _isNextTokenNameYes(int i) throws IOException
+ {
+ _currToken = JsonToken.FIELD_NAME;
+ _updateLocation();
+
+ switch (i) {
+ case '"':
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return;
+ case '[':
+ _nextToken = JsonToken.START_ARRAY;
+ return;
+ case '{':
+ _nextToken = JsonToken.START_OBJECT;
+ return;
+ case 't':
+ _matchToken("true", 1);
+ _nextToken = JsonToken.VALUE_TRUE;
+ return;
+ case 'f':
+ _matchToken("false", 1);
+ _nextToken = JsonToken.VALUE_FALSE;
+ return;
+ case 'n':
+ _matchToken("null", 1);
+ _nextToken = JsonToken.VALUE_NULL;
+ return;
+ case '-':
+ _nextToken = _parseNegNumber();
+ return;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ _nextToken = _parsePosNumber(i);
+ return;
+ }
+ _nextToken = _handleOddValue(i);
+ }
+
+ protected boolean _isNextTokenNameMaybe(int i, String nameToMatch) throws IOException
+ {
+ // // // and this is back to standard nextToken()
+ String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
+ _parsingContext.setCurrentName(name);
+ _currToken = JsonToken.FIELD_NAME;
+ i = _skipColon();
+ _updateLocation();
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return nameToMatch.equals(name);
+ }
+ // Ok: we must have a value... what is it?
+ JsonToken t;
+ switch (i) {
+ case '-':
+ t = _parseNegNumber();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ case 'f':
+ _matchFalse();
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchNull();
+ t = JsonToken.VALUE_NULL;
+ break;
+ case 't':
+ _matchTrue();
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case '[':
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ t = JsonToken.START_OBJECT;
+ break;
+ default:
+ t = _handleOddValue(i);
+ break;
+ }
+ _nextToken = t;
+ return nameToMatch.equals(name);
+ }
+
private final JsonToken _nextTokenNotInObject(int i) throws IOException
{
if (i == INT_QUOTE) {
@@ -874,7 +1073,7 @@
}
return (_currToken = _handleOddValue(i));
}
-
+
// note: identical to one in UTF8StreamJsonParser
@Override
public final String nextTextValue() throws IOException
@@ -1015,15 +1214,15 @@
if (ch == INT_0) {
return _parseNumber2(false, startPtr);
}
-
+
/* First, let's see if the whole number is contained within
* the input buffer unsplit. This should be the common case;
* and to simplify processing, we will just reparse contents
* in the alternative case (number split on buffer boundary)
*/
-
+
int intLen = 1; // already got one
-
+
// First let's get the obligatory integer part:
int_loop:
while (true) {
@@ -1137,7 +1336,7 @@
return _parseNumber2(true, startPtr);
}
int intLen = 1; // already got one
-
+
// First let's get the obligatory integer part:
int_loop:
while (true) {
@@ -1312,7 +1511,7 @@
// and offline the less common case
return _verifyNLZ2();
}
-
+
private char _verifyNLZ2() throws IOException
{
if (_inputPtr >= _inputEnd && !loadMore()) {
@@ -1334,7 +1533,7 @@
return '0';
}
++_inputPtr; // skip previous zero
- if (ch != '0') { // followed by other number; return
+ if (ch != '0') { // followed by other number; return
break;
}
}
@@ -1398,7 +1597,7 @@
}
_reportMissingRootWS(ch);
}
-
+
/*
/**********************************************************
/* Internal methods, secondary parsing
@@ -1624,7 +1823,7 @@
_reportUnexpectedChar(i, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
return null;
}
-
+
protected JsonToken _handleApos() throws IOException
{
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
@@ -1665,7 +1864,7 @@
_textBuffer.setCurrentLength(outPtr);
return JsonToken.VALUE_STRING;
}
-
+
private String _handleOddName2(int startPtr, int hash, int[] codes) throws IOException
{
_textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
@@ -1709,7 +1908,7 @@
return _symbols.findSymbol(buf, start, len, hash);
}
}
-
+
@Override
protected final void _finishString() throws IOException
{
@@ -1839,7 +2038,7 @@
/* Internal methods, other parsing
/**********************************************************
*/
-
+
/**
* We actually need to check the character value here
* (to see if we have \n following \r).
@@ -1853,7 +2052,7 @@
++_currInputRow;
_currInputRowStart = _inputPtr;
}
-
+
private final int _skipColon() throws IOException
{
if ((_inputPtr + 4) >= _inputEnd) {
@@ -1875,7 +2074,7 @@
if (i == INT_SLASH || i == INT_HASH) {
return _skipColon2(true);
}
- ++_inputPtr;
+ ++_inputPtr;
return i;
}
}
@@ -1949,7 +2148,55 @@
}
}
}
-
+
+ // Variant called when we know there's at least 4 more bytes available
+ private final int _skipColonFast(int ptr) throws IOException
+ {
+ int i = (int) _inputBuffer[ptr++];
+ if (i == INT_COLON) { // common case, no leading space
+ i = _inputBuffer[ptr++];
+ if (i > INT_SPACE) { // nor trailing
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ } else if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ }
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(true); // true -> skipped colon
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = _inputBuffer[ptr++];
+ }
+ boolean gotColon = (i == INT_COLON);
+ if (gotColon) {
+ i = _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ } else if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ }
+ }
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(gotColon);
+ }
+
// Primary loop: no reloading, comment handling
private final int _skipComma(int i) throws IOException
{
@@ -2008,7 +2255,7 @@
}
throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
}
-
+
private final int _skipWSOrEnd() throws IOException
{
// Let's handle first character separately since it is likely that
@@ -2036,7 +2283,7 @@
_throwInvalidSpace(i);
}
}
-
+
while (_inputPtr < _inputEnd) {
i = (int) _inputBuffer[_inputPtr++];
if (i > INT_SPACE) {
@@ -2092,7 +2339,7 @@
}
}
}
-
+
private void _skipComment() throws IOException
{
if (!isEnabled(Feature.ALLOW_COMMENTS)) {
@@ -2151,7 +2398,7 @@
_skipLine();
return true;
}
-
+
private void _skipLine() throws IOException
{
// Ok: need to find EOF or linefeed
@@ -2225,7 +2472,7 @@
}
return (char) value;
}
-
+
private final void _matchTrue() throws IOException {
int ptr = _inputPtr;
if ((ptr + 3) < _inputEnd) {
@@ -2346,9 +2593,9 @@
}
}
int decodedData = bits;
-
+
// then second base64 char; can't get padding yet, nor ws
-
+
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
@@ -2358,7 +2605,7 @@
bits = _decodeBase64Escape(b64variant, ch, 1);
}
decodedData = (decodedData << 6) | bits;
-
+
// third base64 char; can be padding, but not ws
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
@@ -2431,6 +2678,51 @@
/*
/**********************************************************
+ /* Internal methods, location updating (refactored in 2.7)
+ /**********************************************************
+ */
+
+ @Override
+ public JsonLocation getTokenLocation()
+ {
+ final Object src = _ioContext.getSourceReference();
+ if (_currToken == JsonToken.FIELD_NAME) {
+ long total = _currInputProcessed + (_nameStartOffset-1);
+ return new JsonLocation(src,
+ -1L, total, _nameStartRow, _nameStartCol);
+ }
+ return new JsonLocation(src,
+ -1L, _tokenInputTotal-1, _tokenInputRow, _tokenInputCol);
+ }
+
+ @Override
+ public JsonLocation getCurrentLocation() {
+ int col = _inputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_ioContext.getSourceReference(),
+ -1L, _currInputProcessed + _inputPtr,
+ _currInputRow, col);
+ }
+
+ // @since 2.7
+ private final void _updateLocation()
+ {
+ int ptr = _inputPtr;
+ _tokenInputTotal = _currInputProcessed + ptr;
+ _tokenInputRow = _currInputRow;
+ _tokenInputCol = ptr - _currInputRowStart;
+ }
+
+ // @since 2.7
+ private final void _updateNameLocation()
+ {
+ int ptr = _inputPtr;
+ _nameStartOffset = ptr;
+ _nameStartRow = _currInputRow;
+ _nameStartCol = ptr - _currInputRowStart;
+ }
+
+ /*
+ /**********************************************************
/* Error reporting
/**********************************************************
*/
@@ -2438,7 +2730,7 @@
protected void _reportInvalidToken(String matchedPart) throws IOException {
_reportInvalidToken(matchedPart, "'null', 'true', 'false' or NaN");
}
-
+
protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
{
StringBuilder sb = new StringBuilder(matchedPart);
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
index 6d32010..84a6af2 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
@@ -27,7 +27,7 @@
// intermediate copies only made up to certain length...
private final static int MAX_BYTES_TO_BUFFER = 512;
- final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
+ private final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
private final static byte[] NULL_BYTES = { 'n', 'u', 'l', 'l' };
private final static byte[] TRUE_BYTES = { 't', 'r', 'u', 'e' };
@@ -54,7 +54,7 @@
* Pointer to the position right beyond the last character to output
* (end marker; may be past the buffer)
*/
- protected int _outputTail = 0;
+ protected int _outputTail;
/**
* End marker of the output buffer; one past the last valid position
@@ -305,7 +305,7 @@
}
_outputBuffer[_outputTail++] = BYTE_RBRACKET;
}
- _writeContext = _writeContext.getParent();
+ _writeContext = _writeContext.clearAndGetParent();
}
@Override
@@ -337,7 +337,7 @@
}
_outputBuffer[_outputTail++] = BYTE_RCURLY;
}
- _writeContext = _writeContext.getParent();
+ _writeContext = _writeContext.clearAndGetParent();
}
/**
@@ -747,8 +747,7 @@
*/
@Override
- public void writeNumber(short s)
- throws IOException, JsonGenerationException
+ public void writeNumber(short s) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
// up to 5 digits and possible minus sign
@@ -772,8 +771,7 @@
}
@Override
- public void writeNumber(int i)
- throws IOException, JsonGenerationException
+ public void writeNumber(int i) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
// up to 10 digits and possible minus sign
@@ -798,8 +796,7 @@
}
@Override
- public void writeNumber(long l)
- throws IOException, JsonGenerationException
+ public void writeNumber(long l) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (_cfgNumbersAsStrings) {
@@ -824,8 +821,7 @@
}
@Override
- public void writeNumber(BigInteger value)
- throws IOException, JsonGenerationException
+ public void writeNumber(BigInteger value) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (value == null) {
@@ -839,13 +835,11 @@
@Override
- public void writeNumber(double d)
- throws IOException, JsonGenerationException
+ public void writeNumber(double d) throws IOException
{
if (_cfgNumbersAsStrings ||
- // [JACKSON-139]
(((Double.isNaN(d) || Double.isInfinite(d))
- && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) {
+ && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
writeString(String.valueOf(d));
return;
}
@@ -855,13 +849,12 @@
}
@Override
- public void writeNumber(float f)
- throws IOException, JsonGenerationException
+ public void writeNumber(float f) throws IOException
{
if (_cfgNumbersAsStrings ||
// [JACKSON-139]
(((Float.isNaN(f) || Float.isInfinite(f))
- && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) {
+ && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
writeString(String.valueOf(f));
return;
}
@@ -871,17 +864,17 @@
}
@Override
- public void writeNumber(BigDecimal value)
- throws IOException, JsonGenerationException
+ public void writeNumber(BigDecimal value) throws IOException
{
// Don't really know max length for big decimal, no point checking
_verifyValueWrite(WRITE_NUMBER);
if (value == null) {
_writeNull();
} else if (_cfgNumbersAsStrings) {
- String raw = isEnabled(Feature.WRITE_BIGDECIMAL_AS_PLAIN) ? value.toPlainString() : value.toString();
+ String raw = Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)
+ ? value.toPlainString() : value.toString();
_writeQuotedRaw(raw);
- } else if (isEnabled(Feature.WRITE_BIGDECIMAL_AS_PLAIN)) {
+ } else if (Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)) {
writeRaw(value.toPlainString());
} else {
writeRaw(value.toString());
@@ -889,8 +882,7 @@
}
@Override
- public void writeNumber(String encodedValue)
- throws IOException, JsonGenerationException
+ public void writeNumber(String encodedValue) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (_cfgNumbersAsStrings) {
@@ -914,8 +906,7 @@
}
@Override
- public void writeBoolean(boolean state)
- throws IOException, JsonGenerationException
+ public void writeBoolean(boolean state) throws IOException
{
_verifyValueWrite(WRITE_BOOLEAN);
if ((_outputTail + 5) >= _outputEnd) {
@@ -928,8 +919,7 @@
}
@Override
- public void writeNull()
- throws IOException, JsonGenerationException
+ public void writeNull() throws IOException
{
_verifyValueWrite(WRITE_NULL);
_writeNull();
@@ -1918,8 +1908,7 @@
return inputOffset;
}
- protected final void _outputSurrogates(int surr1, int surr2)
- throws IOException
+ protected final void _outputSurrogates(int surr1, int surr2) throws IOException
{
int c = _decodeSurrogate(surr1, surr2);
if ((_outputTail + 4) > _outputEnd) {
@@ -1945,13 +1934,18 @@
{
byte[] bbuf = _outputBuffer;
if (ch >= SURR1_FIRST && ch <= SURR2_LAST) { // yes, outside of BMP; add an escape
- bbuf[outputPtr++] = BYTE_BACKSLASH;
- bbuf[outputPtr++] = BYTE_u;
-
- bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
- bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
- bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
- bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
+ // 23-Nov-2015, tatu: As per [core#223], may or may not want escapes;
+ // it would be added here... but as things are, we do not have proper
+ // access yet...
+// if (Feature.ESCAPE_UTF8_SURROGATES.enabledIn(_features)) {
+ bbuf[outputPtr++] = BYTE_BACKSLASH;
+ bbuf[outputPtr++] = BYTE_u;
+
+ bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
+ bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
+ bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
+ bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
+// } else { ... }
} else {
bbuf[outputPtr++] = (byte) (0xe0 | (ch >> 12));
bbuf[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
@@ -1959,7 +1953,7 @@
}
return outputPtr;
}
-
+
private final void _writeNull() throws IOException
{
if ((_outputTail + 4) >= _outputEnd) {
@@ -1974,8 +1968,7 @@
*
* @param charToEscape Character to escape using escape sequence (\\uXXXX)
*/
- private int _writeGenericEscape(int charToEscape, int outputPtr)
- throws IOException
+ private int _writeGenericEscape(int charToEscape, int outputPtr) throws IOException
{
final byte[] bbuf = _outputBuffer;
bbuf[outputPtr++] = BYTE_BACKSLASH;
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
index cc04868..cc2c927 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
@@ -64,13 +64,33 @@
* been fully processed, and needs to be finished for
* some access (or skipped to obtain the next token)
*/
- protected boolean _tokenIncomplete = false;
+ protected boolean _tokenIncomplete;
/**
* Temporary storage for partially parsed name bytes.
*/
private int _quad1;
+ /**
+ * Value of {@link #_inputPtr} at the time when the first character of
+ * name token was read. Used for calculating token location when requested;
+ * combined with {@link #_currInputProcessed}, may be updated appropriately
+ * as needed.
+ *
+ * @since 2.7
+ */
+ protected int _nameStartOffset;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartRow;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartCol;
+
/*
/**********************************************************
/* Input buffering (from former 'StreamBasedParserBase')
@@ -168,9 +188,16 @@
@Override
protected final boolean loadMore() throws IOException
{
+ final int bufSize = _inputEnd;
+
_currInputProcessed += _inputEnd;
_currInputRowStart -= _inputEnd;
-
+
+ // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+ // this increase to avoid "moving" name-offset, resulting most likely
+ // in negative value, which is fine as combine value remains unchanged.
+ _nameStartOffset -= bufSize;
+
if (_inputStream != null) {
int space = _inputBuffer.length;
if (space == 0) { // only occurs when we've been closed
@@ -206,9 +233,15 @@
// Need to move remaining data in front?
int amount = _inputEnd - _inputPtr;
if (amount > 0 && _inputPtr > 0) {
- _currInputProcessed += _inputPtr;
- _currInputRowStart -= _inputPtr;
- System.arraycopy(_inputBuffer, _inputPtr, _inputBuffer, 0, amount);
+ final int ptr = _inputPtr;
+
+ _currInputProcessed += ptr;
+ _currInputRowStart -= ptr;
+ // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+ // (note: probably has little effect here but just in case)
+ _nameStartOffset -= ptr;
+
+ System.arraycopy(_inputBuffer, ptr, _inputBuffer, 0, amount);
_inputEnd = amount;
} else {
_inputEnd = 0;
@@ -645,26 +678,6 @@
return outputCount;
}
- // As per [Issue#108], must ensure we call the right method
- @Override
- public JsonLocation getTokenLocation()
- {
- return new JsonLocation(_ioContext.getSourceReference(),
- getTokenCharacterOffset(), -1L, // bytes, chars
- getTokenLineNr(),
- getTokenColumnNr());
- }
-
- // As per [Issue#108], must ensure we call the right method
- @Override
- public JsonLocation getCurrentLocation()
- {
- int col = _inputPtr - _currInputRowStart + 1; // 1-based
- return new JsonLocation(_ioContext.getSourceReference(),
- _currInputProcessed + _inputPtr, -1L, // bytes, chars
- _currInputRow, col);
- }
-
/*
/**********************************************************
/* Public API, traversal, basic
@@ -678,7 +691,6 @@
@Override
public JsonToken nextToken() throws IOException
{
- _numTypesValid = NR_UNKNOWN;
/* First: field names are special -- we will always tokenize
* (part of) value along with field name to simplify
* state handling. If so, can and need to use secondary token:
@@ -686,6 +698,9 @@
if (_currToken == JsonToken.FIELD_NAME) {
return _nextAfterName();
}
+ // But if we didn't already have a name, and (partially?) decode number,
+ // need to ensure no numeric information is leaked
+ _numTypesValid = NR_UNKNOWN;
if (_tokenIncomplete) {
_skipString(); // only strings can be partial
}
@@ -695,29 +710,24 @@
close();
return (_currToken = null);
}
-
- // First, need to ensure we know the starting location of token
- // after skipping leading white space
- _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
- _tokenInputRow = _currInputRow;
- _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
- // finally: clear any data retained so far
+ // clear any data retained so far
_binaryValue = null;
// Closing scope?
if (i == INT_RBRACKET) {
+ _updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
+ _updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_OBJECT);
}
@@ -734,14 +744,17 @@
* state is never retained.
*/
if (!_parsingContext.inObject()) {
+ _updateLocation();
return _nextTokenNotInObject(i);
}
// So first parse the field name itself:
+ _updateNameLocation();
String n = _parseName(i);
_parsingContext.setCurrentName(n);
_currToken = JsonToken.FIELD_NAME;
i = _skipColon();
+ _updateLocation();
// Ok: we must have a value... what is it? Strings are very common, check first:
if (i == INT_QUOTE) {
@@ -846,6 +859,9 @@
_nameCopied = false; // need to invalidate if it was copied
JsonToken t = _nextToken;
_nextToken = null;
+
+ // !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
+
// Also: may need to start new context?
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
@@ -865,7 +881,6 @@
public boolean nextFieldName(SerializableString str) throws IOException
{
// // // Note: most of code below is copied from nextToken()
-
_numTypesValid = NR_UNKNOWN;
if (_currToken == JsonToken.FIELD_NAME) { // can't have name right after name
_nextAfterName();
@@ -880,27 +895,24 @@
_currToken = null;
return false;
}
- _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
- _tokenInputRow = _currInputRow;
- _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
- // finally: clear any data retained so far
_binaryValue = null;
// Closing scope?
if (i == INT_RBRACKET) {
+ _updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
return false;
}
if (i == INT_RCURLY) {
+ _updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
return false;
}
@@ -914,11 +926,13 @@
}
if (!_parsingContext.inObject()) {
+ _updateLocation();
_nextTokenNotInObject(i);
return false;
}
// // // This part differs, name parsing
+ _updateNameLocation();
if (i == INT_QUOTE) {
// when doing literal match, must consider escaping:
byte[] nameBytes = str.asQuotedUTF8();
@@ -969,25 +983,23 @@
_currToken = null;
return null;
}
- _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
- _tokenInputRow = _currInputRow;
- _tokenInputCol = _inputPtr - _currInputRowStart - 1;
-
_binaryValue = null;
if (i == INT_RBRACKET) {
+ _updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
return null;
}
if (i == INT_RCURLY) {
+ _updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
- _parsingContext = _parsingContext.getParent();
+ _parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
return null;
}
@@ -999,17 +1011,19 @@
}
i = _skipWS();
}
-
if (!_parsingContext.inObject()) {
+ _updateLocation();
_nextTokenNotInObject(i);
return null;
}
+ _updateNameLocation();
final String nameStr = _parseName(i);
_parsingContext.setCurrentName(nameStr);
_currToken = JsonToken.FIELD_NAME;
i = _skipColon();
+ _updateLocation();
if (i == INT_QUOTE) {
_tokenIncomplete = true;
_nextToken = JsonToken.VALUE_STRING;
@@ -1110,6 +1124,7 @@
private final void _isNextTokenNameYes(int i) throws IOException
{
_currToken = JsonToken.FIELD_NAME;
+ _updateLocation();
switch (i) {
case '"':
@@ -1152,8 +1167,7 @@
}
_nextToken = _handleUnexpectedValue(i);
}
-
-
+
private final boolean _isNextTokenNameMaybe(int i, SerializableString str) throws IOException
{
// // // and this is back to standard nextToken()
@@ -1163,6 +1177,7 @@
final boolean match = n.equals(str.getValue());
_currToken = JsonToken.FIELD_NAME;
i = _skipColon();
+ _updateLocation();
// Ok: we must have a value... what is it? Strings are very common, check first:
if (i == INT_QUOTE) {
@@ -1853,7 +1868,7 @@
/**
* Method called when not even first 8 bytes are guaranteed
- * to come consequtively. Happens rarely, so this is offlined;
+ * to come consecutively. Happens rarely, so this is offlined;
* plus we'll also do full checks for escaping etc.
*/
protected String slowParseName() throws IOException
@@ -1988,7 +2003,7 @@
/**
* Method called when we see non-white space character other
* than double quote, when expecting a field name.
- * In standard mode will just throw an expection; but
+ * In standard mode will just throw an exception; but
* in non-standard modes may be able to parse name.
*/
protected String _handleOddName(int ch) throws IOException
@@ -3608,6 +3623,54 @@
/*
/**********************************************************
+ /* Improved location updating (refactored in 2.7)
+ /**********************************************************
+ */
+
+ // As per [core#108], must ensure we call the right method
+ @Override
+ public JsonLocation getTokenLocation()
+ {
+ final Object src = _ioContext.getSourceReference();
+ if (_currToken == JsonToken.FIELD_NAME) {
+ long total = _currInputProcessed + (_nameStartOffset-1);
+ return new JsonLocation(src,
+ total, -1L, _nameStartRow, _nameStartCol);
+ }
+ return new JsonLocation(src,
+ _tokenInputTotal-1, -1L, _tokenInputRow, _tokenInputCol);
+ }
+
+ // As per [core#108], must ensure we call the right method
+ @Override
+ public JsonLocation getCurrentLocation()
+ {
+ int col = _inputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_ioContext.getSourceReference(),
+ _currInputProcessed + _inputPtr, -1L, // bytes, chars
+ _currInputRow, col);
+ }
+
+ // @since 2.7
+ private final void _updateLocation()
+ {
+ _tokenInputRow = _currInputRow;
+ final int ptr = _inputPtr;
+ _tokenInputTotal = _currInputProcessed + ptr;
+ _tokenInputCol = ptr - _currInputRowStart;
+ }
+
+ // @since 2.7
+ private final void _updateNameLocation()
+ {
+ _nameStartRow = _currInputRow;
+ final int ptr = _inputPtr;
+ _nameStartOffset = ptr;
+ _nameStartCol = ptr - _currInputRowStart;
+ }
+
+ /*
+ /**********************************************************
/* Internal methods, other
/**********************************************************
*/
diff --git a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
index 4e91969..af871ce 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
@@ -17,7 +17,7 @@
final protected static int SHORT_WRITE = 32;
final protected static char[] HEX_CHARS = CharTypes.copyHexChars();
-
+
/*
/**********************************************************
/* Output buffering
@@ -25,7 +25,7 @@
*/
final protected Writer _writer;
-
+
/**
* Intermediate buffer in which contents are buffered before
* being written using {@link #_writer}.
@@ -35,13 +35,13 @@
/**
* Pointer to the first buffered character to output
*/
- protected int _outputHead = 0;
+ protected int _outputHead;
/**
* Pointer to the position right beyond the last character to output
* (end marker; may point to position right beyond the end of the buffer)
*/
- protected int _outputTail = 0;
+ protected int _outputTail;
/**
* End marker of the output buffer; one past the last valid position
@@ -121,6 +121,72 @@
}
_writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
}
+
+ protected void _writeFieldName(String name, boolean commaBefore) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ _writePPFieldName(name, commaBefore);
+ return;
+ }
+ // for fast+std case, need to output up to 2 chars, comma, dquote
+ if ((_outputTail + 1) >= _outputEnd) {
+ _flushBuffer();
+ }
+ if (commaBefore) {
+ _outputBuffer[_outputTail++] = ',';
+ }
+ // Alternate mode, in which quoting of field names disabled?
+ if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
+ _writeString(name);
+ return;
+ }
+ // we know there's room for at least one more char
+ _outputBuffer[_outputTail++] = '"';
+ // The beef:
+ _writeString(name);
+ // and closing quotes; need room for one more char:
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ _writePPFieldName(name, commaBefore);
+ return;
+ }
+ // for fast+std case, need to output up to 2 chars, comma, dquote
+ if ((_outputTail + 1) >= _outputEnd) {
+ _flushBuffer();
+ }
+ if (commaBefore) {
+ _outputBuffer[_outputTail++] = ',';
+ }
+ // Alternate mode, in which quoting of field names disabled?
+ final char[] quoted = name.asQuotedChars();
+ if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
+ writeRaw(quoted, 0, quoted.length);
+ return;
+ }
+ // we know there's room for at least one more char
+ _outputBuffer[_outputTail++] = '"';
+ // The beef:
+ final int qlen = quoted.length;
+ if ((_outputTail + qlen + 1) >= _outputEnd) {
+ writeRaw(quoted, 0, qlen);
+ // and closing quotes; need room for one more char:
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ } else {
+ System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
+ _outputTail += qlen;
+ _outputBuffer[_outputTail++] = '"';
+ }
+ }
/*
/**********************************************************
@@ -157,7 +223,7 @@
}
_outputBuffer[_outputTail++] = ']';
}
- _writeContext = _writeContext.getParent();
+ _writeContext = _writeContext.clearAndGetParent();
}
@Override
@@ -189,87 +255,14 @@
}
_outputBuffer[_outputTail++] = '}';
}
- _writeContext = _writeContext.getParent();
+ _writeContext = _writeContext.clearAndGetParent();
}
- protected void _writeFieldName(String name, boolean commaBefore) throws IOException
- {
- if (_cfgPrettyPrinter != null) {
- _writePPFieldName(name, commaBefore);
- return;
- }
- // for fast+std case, need to output up to 2 chars, comma, dquote
- if ((_outputTail + 1) >= _outputEnd) {
- _flushBuffer();
- }
- if (commaBefore) {
- _outputBuffer[_outputTail++] = ',';
- }
-
- /* To support [JACKSON-46], we'll do this:
- * (Question: should quoting of spaces (etc) still be enabled?)
- */
- if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
- _writeString(name);
- return;
- }
-
- // we know there's room for at least one more char
- _outputBuffer[_outputTail++] = '"';
- // The beef:
- _writeString(name);
- // and closing quotes; need room for one more char:
- if (_outputTail >= _outputEnd) {
- _flushBuffer();
- }
- _outputBuffer[_outputTail++] = '"';
- }
-
- protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
- {
- if (_cfgPrettyPrinter != null) {
- _writePPFieldName(name, commaBefore);
- return;
- }
- // for fast+std case, need to output up to 2 chars, comma, dquote
- if ((_outputTail + 1) >= _outputEnd) {
- _flushBuffer();
- }
- if (commaBefore) {
- _outputBuffer[_outputTail++] = ',';
- }
- /* To support [JACKSON-46], we'll do this:
- * (Question: should quoting of spaces (etc) still be enabled?)
- */
- final char[] quoted = name.asQuotedChars();
- if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) {
- writeRaw(quoted, 0, quoted.length);
- return;
- }
- // we know there's room for at least one more char
- _outputBuffer[_outputTail++] = '"';
- // The beef:
- final int qlen = quoted.length;
- if ((_outputTail + qlen + 1) >= _outputEnd) {
- writeRaw(quoted, 0, qlen);
- // and closing quotes; need room for one more char:
- if (_outputTail >= _outputEnd) {
- _flushBuffer();
- }
- _outputBuffer[_outputTail++] = '"';
- } else {
- System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
- _outputTail += qlen;
- _outputBuffer[_outputTail++] = '"';
- }
- }
-
/**
* Specialized version of <code>_writeFieldName</code>, off-lined
* to keep the "fast path" as simple (and hopefully fast) as possible.
*/
- protected void _writePPFieldName(String name, boolean commaBefore)
- throws IOException, JsonGenerationException
+ protected void _writePPFieldName(String name, boolean commaBefore) throws IOException
{
if (commaBefore) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
@@ -292,8 +285,7 @@
}
}
- protected void _writePPFieldName(SerializableString name, boolean commaBefore)
- throws IOException, JsonGenerationException
+ protected void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
{
if (commaBefore) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
diff --git a/src/main/java/com/fasterxml/jackson/core/sym/BytesToNameCanonicalizer.java b/src/main/java/com/fasterxml/jackson/core/sym/BytesToNameCanonicalizer.java
deleted file mode 100644
index 7d610c1..0000000
--- a/src/main/java/com/fasterxml/jackson/core/sym/BytesToNameCanonicalizer.java
+++ /dev/null
@@ -1,1322 +0,0 @@
-package com.fasterxml.jackson.core.sym;
-
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.concurrent.atomic.AtomicReference;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.util.InternCache;
-
-/**
- * A caching symbol table implementation used for canonicalizing JSON field
- * names (as {@link Name}s which are constructed directly from a byte-based
- * input source).
- * Complications arise from trying to do efficient reuse and merging of
- * symbol tables, to be able to make use of usually shared vocabulary
- * of subsequent parsing runs.
- *
- * @deprecated Since 2.6, replaced by {@link ByteQuadsCanonicalizer}
- */
-@Deprecated
-public final class BytesToNameCanonicalizer
-{
- private static final int DEFAULT_T_SIZE = 64;
-
- /**
- * Let's not expand symbol tables past some maximum size;
- * this should protected against OOMEs caused by large documents
- * with unique (~= random) names.
- */
- private static final int MAX_T_SIZE = 0x10000; // 64k entries == 256k mem
-
- /**
- * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k;
- * this corresponds to 64k main hash index. This should allow for enough distinct
- * names for almost any case.
- */
- final static int MAX_ENTRIES_FOR_REUSE = 6000;
-
- /**
- * Also: to thwart attacks based on hash collisions (which may or may not
- * be cheap to calculate), we will need to detect "too long"
- * collision chains.
- *<p>
- * Note: longest chain we have been able to produce without malicious
- * intent has been 10 (with "com.fasterxml.jackson.core.sym.TestSymbolTables");
- * our setting should be reasonable here. Also note that overflow
- * chains are shared between multiple primary cells, which could cause
- * problems for lower values.
- *<p>
- * Also note that value was lowered from 255 (2.3 and earlier) to 100 for 2.4,
- * but raised again to 200 for 2.5.2 (as per [core#187])
- *
- * @since 2.1
- */
- private final static int MAX_COLL_CHAIN_LENGTH = 200;
-
- /**
- * No point in trying to construct tiny tables, just need to resize soon.
- */
- final static int MIN_HASH_SIZE = 16;
-
- /**
- * We will also need to define initial size for collision list,
- * when copying it.
- */
- final static int INITIAL_COLLISION_LEN = 32;
-
- /**
- * Bucket index is 8 bits, and value 0 is reserved to represent
- * 'empty' status.
- */
- final static int LAST_VALID_BUCKET = 0xFE;
-
- /*
- /**********************************************************
- /* Linkage, needed for merging symbol tables
- /**********************************************************
- */
-
- /**
- * Reference to the root symbol table, for child tables, so
- * that they can merge table information back as necessary.
- */
- final protected BytesToNameCanonicalizer _parent;
-
- /**
- * Member that is only used by the root table instance: root
- * passes immutable state into child instances, and children
- * may return new state if they add entries to the table.
- * Child tables do NOT use the reference.
- */
- final protected AtomicReference<TableInfo> _tableInfo;
-
- /**
- * Seed value we use as the base to make hash codes non-static between
- * different runs, but still stable for lifetime of a single symbol table
- * instance.
- * This is done for security reasons, to avoid potential DoS attack via
- * hash collisions.
- *
- * @since 2.1
- */
- final private int _seed;
-
- /*
- /**********************************************************
- /* Configuration
- /**********************************************************
- */
-
- /**
- * Whether canonical symbol Strings are to be intern()ed before added
- * to the table or not.
- *<p>
- * NOTE: non-final to allow disabling intern()ing in case of excessive
- * collisions.
- */
- protected boolean _intern;
-
- /**
- * Flag that indicates whether we should throw an exception if enough
- * hash collisions are detected (true); or just worked around (false).
- *
- * @since 2.4
- */
- protected final boolean _failOnDoS;
-
- /*
- /**********************************************************
- /* Main table state
- /**********************************************************
- */
-
- // // // First, global information
-
- /**
- * Total number of Names in the symbol table;
- * only used for child tables.
- */
- protected int _count;
-
- /**
- * We need to keep track of the longest collision list; this is needed
- * both to indicate problems with attacks and to allow flushing for
- * other cases.
- *
- * @since 2.1
- */
- protected int _longestCollisionList;
-
- // // // Then information regarding primary hash array and its
- // // // matching Name array
-
- /**
- * Mask used to truncate 32-bit hash value to current hash array
- * size; essentially, hash array size - 1 (since hash array sizes
- * are 2^N).
- */
- protected int _hashMask;
-
- /**
- * Array of 2^N size, which contains combination
- * of 24-bits of hash (0 to indicate 'empty' slot),
- * and 8-bit collision bucket index (0 to indicate empty
- * collision bucket chain; otherwise subtract one from index)
- */
- protected int[] _hash;
-
- /**
- * Array that contains <code>Name</code> instances matching
- * entries in <code>_mainHash</code>. Contains nulls for unused
- * entries.
- */
- protected Name[] _mainNames;
-
- // // // Then the collision/spill-over area info
-
- /**
- * Array of heads of collision bucket chains; size dynamically
- */
- protected Bucket[] _collList;
-
- /**
- * Total number of Names in collision buckets (included in
- * <code>_count</code> along with primary entries)
- */
- protected int _collCount;
-
- /**
- * Index of the first unused collision bucket entry (== size of
- * the used portion of collision list): less than
- * or equal to 0xFF (255), since max number of entries is 255
- * (8-bit, minus 0 used as 'empty' marker)
- */
- protected int _collEnd;
-
- // // // Info regarding pending rehashing...
-
- /**
- * This flag is set if, after adding a new entry, it is deemed
- * that a rehash is warranted if any more entries are to be added.
- */
- private transient boolean _needRehash;
-
- /*
- /**********************************************************
- /* Sharing, versioning
- /**********************************************************
- */
-
- // // // Which of the buffers may be shared (and are copy-on-write)?
-
- /**
- * Flag that indicates whether underlying data structures for
- * the main hash area are shared or not. If they are, then they
- * need to be handled in copy-on-write way, i.e. if they need
- * to be modified, a copy needs to be made first; at this point
- * it will not be shared any more, and can be modified.
- *<p>
- * This flag needs to be checked both when adding new main entries,
- * and when adding new collision list queues (i.e. creating a new
- * collision list head entry)
- */
- private boolean _hashShared;
-
- private boolean _namesShared;
-
- /**
- * Flag that indicates whether underlying data structures for
- * the collision list are shared or not. If they are, then they
- * need to be handled in copy-on-write way, i.e. if they need
- * to be modified, a copy needs to be made first; at this point
- * it will not be shared any more, and can be modified.
- *<p>
- * This flag needs to be checked when adding new collision entries.
- */
- private boolean _collListShared;
-
- /*
- /**********************************************************
- /* Bit of DoS detection goodness
- /**********************************************************
- */
-
- /**
- * Lazily constructed structure that is used to keep track of
- * collision buckets that have overflowed once: this is used
- * to detect likely attempts at denial-of-service attacks that
- * uses hash collisions.
- *
- * @since 2.4
- */
- protected BitSet _overflows;
-
- /*
- /**********************************************************
- /* Life-cycle: constructors
- /**********************************************************
- */
-
- /**
- * Constructor used for creating per-<code>JsonFactory</code> "root"
- * symbol tables: ones used for merging and sharing common symbols
- *
- * @param sz Initial hash area size
- * @param intern Whether Strings contained should be {@link String#intern}ed
- * @param seed Random seed valued used to make it more difficult to cause
- * collisions (used for collision-based DoS attacks).
- */
- private BytesToNameCanonicalizer(int sz, boolean intern, int seed, boolean failOnDoS) {
- _parent = null;
- _seed = seed;
- _intern = intern;
- _failOnDoS = failOnDoS;
- // Sanity check: let's now allow hash sizes below certain minimum value
- if (sz < MIN_HASH_SIZE) {
- sz = MIN_HASH_SIZE;
- } else {
- /* Also; size must be 2^N; otherwise hash algorithm won't
- * work... so let's just pad it up, if so
- */
- if ((sz & (sz - 1)) != 0) { // only true if it's 2^N
- int curr = MIN_HASH_SIZE;
- while (curr < sz) {
- curr += curr;
- }
- sz = curr;
- }
- }
- _tableInfo = new AtomicReference<TableInfo>(initTableInfo(sz));
- }
-
- /**
- * Constructor used when creating a child instance
- */
- private BytesToNameCanonicalizer(BytesToNameCanonicalizer parent, boolean intern,
- int seed, boolean failOnDoS, TableInfo state)
- {
- _parent = parent;
- _seed = seed;
- _intern = intern;
- _failOnDoS = failOnDoS;
- _tableInfo = null; // not used by child tables
-
- // Then copy shared state
- _count = state.count;
- _hashMask = state.mainHashMask;
- _hash = state.mainHash;
- _mainNames = state.mainNames;
- _collList = state.collList;
- _collCount = state.collCount;
- _collEnd = state.collEnd;
- _longestCollisionList = state.longestCollisionList;
-
- // and then set other state to reflect sharing status
- _needRehash = false;
- _hashShared = true;
- _namesShared = true;
- _collListShared = true;
- }
-
- /*
- public TableInfo(int count, int mainHashMask, int[] mainHash, Name[] mainNames,
- Bucket[] collList, int collCount, int collEnd, int longestCollisionList)
- */
- private TableInfo initTableInfo(int sz) {
- return new TableInfo(0, // count
- sz - 1, // mainHashMask
- new int[sz], // mainHash
- new Name[sz], // mainNames
- null, // collList
- 0, // collCount,
- 0, // collEnd
- 0 // longestCollisionList
- );
- }
-
- /*
- /**********************************************************
- /* Life-cycle: factory methods, merging
- /**********************************************************
- */
-
- /**
- * Factory method to call to create a symbol table instance with a
- * randomized seed value.
- */
- public static BytesToNameCanonicalizer createRoot() {
- /* [Issue-21]: Need to use a variable seed, to thwart hash-collision
- * based attacks.
- */
- long now = System.currentTimeMillis();
- // ensure it's not 0; and might as well require to be odd so:
- int seed = (((int) now) + ((int) (now >>> 32))) | 1;
- return createRoot(seed);
- }
-
- /**
- * Factory method that should only be called from unit tests, where seed
- * value should remain the same.
- */
- protected static BytesToNameCanonicalizer createRoot(int seed) {
- return new BytesToNameCanonicalizer(DEFAULT_T_SIZE, true, seed, true);
- }
-
- /**
- * Factory method used to create actual symbol table instance to
- * use for parsing.
- */
- public BytesToNameCanonicalizer makeChild(int flags) {
- return new BytesToNameCanonicalizer(this,
- JsonFactory.Feature.INTERN_FIELD_NAMES.enabledIn(flags),
- _seed,
- JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW.enabledIn(flags),
- _tableInfo.get());
- }
-
- @Deprecated // since 2.4
- public BytesToNameCanonicalizer makeChild(boolean canonicalize, boolean intern) {
- return new BytesToNameCanonicalizer(this, intern, _seed,
- true, // JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW
- _tableInfo.get());
- }
-
- /**
- * Method called by the using code to indicate it is done
- * with this instance. This lets instance merge accumulated
- * changes into parent (if need be), safely and efficiently,
- * and without calling code having to know about parent
- * information
- */
- public void release()
- {
- // we will try to merge if child table has new entries
- if (_parent != null && maybeDirty()) {
- _parent.mergeChild(new TableInfo(this));
- /* Let's also mark this instance as dirty, so that just in
- * case release was too early, there's no corruption of possibly shared data.
- */
- _hashShared = true;
- _namesShared = true;
- _collListShared = true;
- }
- }
-
- private void mergeChild(TableInfo childState)
- {
- final int childCount = childState.count;
- TableInfo currState = _tableInfo.get();
-
- /* Should usually grow; but occasionally could also shrink if
- * (but only if) collision list overflow ends up clearing
- * some collision lists.
- */
- if (childCount == currState.count) {
- return;
- }
-
- /* One caveat: let's try to avoid problems with
- * degenerate cases of documents with generated "random"
- * names: for these, symbol tables would bloat indefinitely.
- * One way to do this is to just purge tables if they grow
- * too large, and that's what we'll do here.
- */
- if (childCount > MAX_ENTRIES_FOR_REUSE) {
- /* Should there be a way to get notified about this
- * event, to log it or such? (as it's somewhat abnormal
- * thing to happen)
- */
- // At any rate, need to clean up the tables
- childState = initTableInfo(DEFAULT_T_SIZE);
- }
- _tableInfo.compareAndSet(currState, childState);
- }
-
- /*
- /**********************************************************
- /* API, accessors
- /**********************************************************
- */
-
- public int size()
- {
- if (_tableInfo != null) { // root table
- return _tableInfo.get().count;
- }
- // nope, child table
- return _count;
- }
-
- /**
- * @since 2.1
- */
- public int bucketCount() { return _hash.length; }
-
- /**
- * Method called to check to quickly see if a child symbol table
- * may have gotten additional entries. Used for checking to see
- * if a child table should be merged into shared table.
- */
- public boolean maybeDirty() { return !_hashShared; }
-
- /**
- * @since 2.1
- */
- public int hashSeed() { return _seed; }
-
- /**
- * Method mostly needed by unit tests; calculates number of
- * entries that are in collision list. Value can be at most
- * ({@link #size} - 1), but should usually be much lower, ideally 0.
- *
- * @since 2.1
- */
- public int collisionCount() { return _collCount; }
-
- /**
- * Method mostly needed by unit tests; calculates length of the
- * longest collision chain. This should typically be a low number,
- * but may be up to {@link #size} - 1 in the pathological case
- *
- * @since 2.1
- */
- public int maxCollisionLength() {
- return _longestCollisionList;
- }
-
- /*
- /**********************************************************
- /* Public API, accessing symbols:
- /**********************************************************
- */
-
- public static Name getEmptyName() {
- return Name1.getEmptyName();
- }
-
- /**
- * Finds and returns name matching the specified symbol, if such
- * name already exists in the table.
- * If not, will return null.
- *<p>
- * Note: separate methods to optimize common case of
- * short element/attribute names (4 or less ascii characters)
- *
- * @param q1 int32 containing first 4 bytes of the name;
- * if the whole name less than 4 bytes, padded with zero bytes
- * in front (zero MSBs, ie. right aligned)
- *
- * @return Name matching the symbol passed (or constructed for
- * it)
- */
- public Name findName(int q1)
- {
- int hash = calcHash(q1);
- int ix = (hash & _hashMask);
- int val = _hash[ix];
-
- /* High 24 bits of the value are low 24 bits of hash (low 8 bits
- * are bucket index)... match?
- */
- if ((((val >> 8) ^ hash) << 8) == 0) { // match
- // Ok, but do we have an actual match?
- Name name = _mainNames[ix];
- if (name == null) { // main slot empty; can't find
- return null;
- }
- if (name.equals(q1)) {
- return name;
- }
- } else if (val == 0) { // empty slot? no match
- return null;
- }
- // Maybe a spill-over?
- val &= 0xFF;
- if (val > 0) { // 0 means 'empty'
- val -= 1; // to convert from 1-based to 0...
- Bucket bucket = _collList[val];
- if (bucket != null) {
- return bucket.find(hash, q1, 0);
- }
- }
- // Nope, no match whatsoever
- return null;
- }
-
- /**
- * Finds and returns name matching the specified symbol, if such
- * name already exists in the table.
- * If not, will return null.
- *<p>
- * Note: separate methods to optimize common case of relatively
- * short element/attribute names (8 or less ascii characters)
- *
- * @param q1 int32 containing first 4 bytes of the name.
- * @param q2 int32 containing bytes 5 through 8 of the
- * name; if less than 8 bytes, padded with up to 3 zero bytes
- * in front (zero MSBs, ie. right aligned)
- *
- * @return Name matching the symbol passed (or constructed for it)
- */
- public Name findName(int q1, int q2)
- {
- int hash = (q2 == 0) ? calcHash(q1) : calcHash(q1, q2);
- int ix = (hash & _hashMask);
- int val = _hash[ix];
-
- /* High 24 bits of the value are low 24 bits of hash (low 8 bits
- * are bucket index)... match?
- */
- if ((((val >> 8) ^ hash) << 8) == 0) { // match
- // Ok, but do we have an actual match?
- Name name = _mainNames[ix];
- if (name == null) { // main slot empty; can't find
- return null;
- }
- if (name.equals(q1, q2)) {
- return name;
- }
- } else if (val == 0) { // empty slot? no match
- return null;
- }
- // Maybe a spill-over?
- val &= 0xFF;
- if (val > 0) { // 0 means 'empty'
- val -= 1; // to convert from 1-based to 0...
- Bucket bucket = _collList[val];
- if (bucket != null) {
- return bucket.find(hash, q1, q2);
- }
- }
- // Nope, no match whatsoever
- return null;
- }
-
- public Name findName(int q1, int q2, int q3)
- {
- int hash = calcHash(q1, q2, q3);
- int ix = (hash & _hashMask);
- int val = _hash[ix];
-
- if ((((val >> 8) ^ hash) << 8) == 0) { // match
- // Ok, but do we have an actual match?
- Name name = _mainNames[ix];
- if (name == null) { // main slot empty; can't find
- return null;
- }
- if (name.equals(q1, q2, q3)) {
- return name;
- }
- } else if (val == 0) { // empty slot? no match
- return null;
- }
- // Maybe a spill-over?
- val &= 0xFF;
- if (val > 0) { // 0 means 'empty'
- val -= 1; // to convert from 1-based to 0...
- Bucket bucket = _collList[val];
- if (bucket != null) {
- return bucket.find(hash, q1, q2, q3);
- }
- }
- // Nope, no match whatsoever
- return null;
- }
-
- /**
- * Finds and returns name matching the specified symbol, if such
- * name already exists in the table; or if not, creates name object,
- * adds to the table, and returns it.
- *<p>
- * Note: this is the general purpose method that can be called for
- * names of any length. However, if name is less than 9 bytes long,
- * it is preferable to call the version optimized for short
- * names.
- *
- * @param q Array of int32s, each of which contain 4 bytes of
- * encoded name
- * @param qlen Number of int32s, starting from index 0, in quads
- * parameter
- *
- * @return Name matching the symbol passed (or constructed for it)
- */
- public Name findName(int[] q, int qlen)
- {
- if (qlen < 4) { // another sanity check
- if (qlen == 3) {
- return findName(q[0], q[1], q[2]);
- }
- return findName(q[0], (qlen < 2) ? 0 : q[1]);
- }
- int hash = calcHash(q, qlen);
- // (for rest of comments regarding logic, see method above)
- int ix = (hash & _hashMask);
- int val = _hash[ix];
- if ((((val >> 8) ^ hash) << 8) == 0) {
- Name name = _mainNames[ix];
- if (name == null // main slot empty; no collision list then either
- || name.equals(q, qlen)) { // should be match, let's verify
- return name;
- }
- } else if (val == 0) { // empty slot? no match
- return null;
- }
- val &= 0xFF;
- if (val > 0) { // 0 means 'empty'
- val -= 1; // to convert from 1-based to 0...
- Bucket bucket = _collList[val];
- if (bucket != null) {
- return bucket.find(hash, q, qlen);
- }
- }
- return null;
- }
-
- /*
- /**********************************************************
- /* API, mutators
- /**********************************************************
- */
-
- public Name addName(String name, int q1, int q2)
- {
- if (_intern) {
- name = InternCache.instance.intern(name);
- }
- int hash = (q2 == 0) ? calcHash(q1) : calcHash(q1, q2);
- Name symbol = constructName(hash, name, q1, q2);
- _addSymbol(hash, symbol);
- return symbol;
- }
-
- public Name addName(String name, int[] q, int qlen)
- {
- if (_intern) {
- name = InternCache.instance.intern(name);
- }
- int hash;
- if (qlen < 4) {
- if (qlen == 1) {
- hash = calcHash(q[0]);
- } else if (qlen == 2) {
- hash = calcHash(q[0], q[1]);
- } else {
- hash = calcHash(q[0], q[1], q[2]);
- }
- } else {
- hash = calcHash(q, qlen);
- }
- Name symbol = constructName(hash, name, q, qlen);
- _addSymbol(hash, symbol);
- return symbol;
- }
-
- /*
- /**********************************************************
- /* Helper methods
- /**********************************************************
- */
-
- /* Note on hash calculation: we try to make it more difficult to
- * generate collisions automatically; part of this is to avoid
- * simple "multiply-add" algorithm (like JDK String.hashCode()),
- * and add bit of shifting. And other part is to make this
- * non-linear, at least for shorter symbols.
- */
-
- // JDK uses 31; other fine choices are 33 and 65599, let's use 33
- // as it seems to give fewest collisions for us
- // (see [http://www.cse.yorku.ca/~oz/hash.html] for details)
- private final static int MULT = 33;
- private final static int MULT2 = 65599;
- private final static int MULT3 = 31;
-
- public int calcHash(int q1)
- {
- int hash = q1 ^ _seed;
- hash += (hash >>> 15); // to xor hi- and low- 16-bits
- hash ^= (hash >>> 9); // as well as lowest 2 bytes
- return hash;
- }
-
- public int calcHash(int q1, int q2)
- {
- // For two quads, let's change algorithm a bit, to spice
- // things up (can do bit more processing anyway)
- int hash = q1;
- hash ^= (hash >>> 15); // try mixing first and second byte pairs first
- hash += (q2 * MULT); // then add second quad
- hash ^= _seed;
- hash += (hash >>> 7); // and shuffle some more
- // 26-Mar-2015, tatu: As per [core#187] need bit more shuffling. This may
- // seem like a magical number (and in a way, it is), but it was the sweet
- // spot for some reason (5 and 3 work ok but converges for 4, for tested case)
- hash ^= (hash >>> 4);
- return hash;
- }
-
- public int calcHash(int q1, int q2, int q3)
- {
- // use same algorithm as multi-byte, tested to work well
- int hash = q1 ^ _seed;
- hash += (hash >>> 9);
- hash *= MULT;
- hash += q2;
- hash *= MULT2;
- hash += (hash >>> 15);
- hash ^= q3;
- hash += (hash >>> 17);
-
- // and finally shuffle some more once done
- hash += (hash >>> 15); // to get high-order bits to mix more
- hash ^= (hash << 9); // as well as lowest 2 bytes
-
- return hash;
- }
-
- public int calcHash(int[] q, int qlen)
- {
- if (qlen < 4) {
- throw new IllegalArgumentException();
- }
-
- /* And then change handling again for "multi-quad" case; mostly
- * to make calculation of collisions less fun. For example,
- * add seed bit later in the game, and switch plus/xor around,
- * use different shift lengths.
- */
- int hash = q[0] ^ _seed;
- hash += (hash >>> 9);
- hash *= MULT;
- hash += q[1];
- hash *= MULT2;
- hash += (hash >>> 15);
- hash ^= q[2];
- hash += (hash >>> 17);
-
- for (int i = 3; i < qlen; ++i) {
- hash = (hash * MULT3) ^ q[i];
- // for longer entries, mess a bit in-between too
- hash += (hash >>> 3);
- hash ^= (hash << 7);
- }
- // and finally shuffle some more once done
- hash += (hash >>> 15); // to get high-order bits to mix more
- hash ^= (hash << 9); // as well as lowest 2 bytes
- return hash;
- }
-
- // Method only used by unit tests
- protected static int[] calcQuads(byte[] wordBytes) {
- int blen = wordBytes.length;
- int[] result = new int[(blen + 3) / 4];
- for (int i = 0; i < blen; ++i) {
- int x = wordBytes[i] & 0xFF;
-
- if (++i < blen) {
- x = (x << 8) | (wordBytes[i] & 0xFF);
- if (++i < blen) {
- x = (x << 8) | (wordBytes[i] & 0xFF);
- if (++i < blen) {
- x = (x << 8) | (wordBytes[i] & 0xFF);
- }
- }
- }
- result[i >> 2] = x;
- }
- return result;
- }
-
- /*
- /**********************************************************
- /* Standard methods
- /**********************************************************
- */
-
- /*
- @Override
- public String toString()
- {
- StringBuilder sb = new StringBuilder();
- sb.append("[BytesToNameCanonicalizer, size: ");
- sb.append(_count);
- sb.append('/');
- sb.append(_mainHash.length);
- sb.append(", ");
- sb.append(_collCount);
- sb.append(" coll; avg length: ");
-
- // Average length: minimum of 1 for all (1 == primary hit);
- // and then 1 per each traversal for collisions/buckets
- //int maxDist = 1;
- int pathCount = _count;
- for (int i = 0; i < _collEnd; ++i) {
- int spillLen = _collList[i].length();
- for (int j = 1; j <= spillLen; ++j) {
- pathCount += j;
- }
- }
- double avgLength;
-
- if (_count == 0) {
- avgLength = 0.0;
- } else {
- avgLength = (double) pathCount / (double) _count;
- }
- // let's round up a bit (two 2 decimal places)
- //avgLength -= (avgLength % 0.01);
-
- sb.append(avgLength);
- sb.append(']');
- return sb.toString();
- }
- */
-
- /*
- /**********************************************************
- /* Internal methods
- /**********************************************************
- */
-
- private void _addSymbol(int hash, Name symbol)
- {
- if (_hashShared) { // always have to modify main entry
- unshareMain();
- }
- // First, do we need to rehash?
- if (_needRehash) {
- rehash();
- }
-
- ++_count;
-
- /* Ok, enough about set up: now we need to find the slot to add
- * symbol in:
- */
- int ix = (hash & _hashMask);
- if (_mainNames[ix] == null) { // primary empty?
- _hash[ix] = (hash << 8);
- if (_namesShared) {
- unshareNames();
- }
- _mainNames[ix] = symbol;
- } else { // nope, it's a collision, need to spill over
- /* How about spill-over area... do we already know the bucket
- * (is the case if it's not the first collision)
- */
- if (_collListShared) {
- unshareCollision(); // also allocates if list was null
- }
- ++_collCount;
- int entryValue = _hash[ix];
- int bucket = entryValue & 0xFF;
- if (bucket == 0) { // first spill over?
- if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket
- bucket = _collEnd;
- ++_collEnd;
- // need to expand?
- if (bucket >= _collList.length) {
- expandCollision();
- }
- } else { // nope, have to share... let's find shortest?
- bucket = findBestBucket();
- }
- // Need to mark the entry... and the spill index is 1-based
- _hash[ix] = (entryValue & ~0xFF) | (bucket + 1);
- } else {
- --bucket; // 1-based index in value
- }
-
- // And then just need to link the new bucket entry in
- Bucket newB = new Bucket(symbol, _collList[bucket]);
- int collLen = newB.length;
- if (collLen > MAX_COLL_CHAIN_LENGTH) {
- /* 23-May-2014, tatu: Instead of throwing an exception right away, let's handle
- * in bit smarter way.
- */
- _handleSpillOverflow(bucket, newB);
- } else {
- _collList[bucket] = newB;
- // but, be careful wrt attacks
- _longestCollisionList = Math.max(newB.length, _longestCollisionList);
- }
- }
-
- /* Ok. Now, do we need a rehash next time? Need to have at least
- * 50% fill rate no matter what:
- */
- {
- int hashSize = _hash.length;
- if (_count > (hashSize >> 1)) {
- int hashQuarter = (hashSize >> 2);
- /* And either strictly above 75% (the usual) or
- * just 50%, and collision count >= 25% of total hash size
- */
- if (_count > (hashSize - hashQuarter)) {
- _needRehash = true;
- } else if (_collCount >= hashQuarter) {
- _needRehash = true;
- }
- }
- }
- }
-
- private void _handleSpillOverflow(int bindex, Bucket newBucket)
- {
- if (_overflows == null) {
- _overflows = new BitSet();
- _overflows.set(bindex);
- } else {
- if (_overflows.get(bindex)) {
- // Has happened once already, so not a coincident...
- if (_failOnDoS) {
- reportTooManyCollisions(MAX_COLL_CHAIN_LENGTH);
- }
- // but even if we don't fail, we will stop intern()ing
- _intern = false;
- } else {
- _overflows.set(bindex);
- }
- }
- // regardless, if we get this far, clear up the bucket, adjust size appropriately.
- _collList[bindex] = null;
- _count -= (newBucket.length);
- // we could calculate longest; but for now just mark as invalid
- _longestCollisionList = -1;
- }
-
- private void rehash()
- {
- _needRehash = false;
- // Note: since we'll make copies, no need to unshare, can just mark as such:
- _namesShared = false;
-
- /* And then we can first deal with the main hash area. Since we
- * are expanding linearly (double up), we know there'll be no
- * collisions during this phase.
- */
- int[] oldMainHash = _hash;
- int len = oldMainHash.length;
- int newLen = len+len;
-
- /* 13-Mar-2010, tatu: Let's guard against OOME that could be caused by
- * large documents with unique (or mostly so) names
- */
- if (newLen > MAX_T_SIZE) {
- nukeSymbols();
- return;
- }
-
- _hash = new int[newLen];
- _hashMask = (newLen - 1);
- Name[] oldNames = _mainNames;
- _mainNames = new Name[newLen];
- int symbolsSeen = 0; // let's do a sanity check
- for (int i = 0; i < len; ++i) {
- Name symbol = oldNames[i];
- if (symbol != null) {
- ++symbolsSeen;
- int hash = symbol.hashCode();
- int ix = (hash & _hashMask);
- _mainNames[ix] = symbol;
- _hash[ix] = hash << 8; // will clear spill index
- }
- }
-
- /* And then the spill area. This may cause collisions, although
- * not necessarily as many as there were earlier. Let's allocate
- * same amount of space, however
- */
- int oldEnd = _collEnd;
- if (oldEnd == 0) { // no prior collisions...
- _longestCollisionList = 0;
- return;
- }
-
- _collCount = 0;
- _collEnd = 0;
- _collListShared = false;
-
- int maxColl = 0;
-
- Bucket[] oldBuckets = _collList;
- _collList = new Bucket[oldBuckets.length];
- for (int i = 0; i < oldEnd; ++i) {
- for (Bucket curr = oldBuckets[i]; curr != null; curr = curr.next) {
- ++symbolsSeen;
- Name symbol = curr.name;
- int hash = symbol.hashCode();
- int ix = (hash & _hashMask);
- int val = _hash[ix];
- if (_mainNames[ix] == null) { // no primary entry?
- _hash[ix] = (hash << 8);
- _mainNames[ix] = symbol;
- } else { // nope, it's a collision, need to spill over
- ++_collCount;
- int bucket = val & 0xFF;
- if (bucket == 0) { // first spill over?
- if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket
- bucket = _collEnd;
- ++_collEnd;
- // need to expand?
- if (bucket >= _collList.length) {
- expandCollision();
- }
- } else { // nope, have to share... let's find shortest?
- bucket = findBestBucket();
- }
- // Need to mark the entry... and the spill index is 1-based
- _hash[ix] = (val & ~0xFF) | (bucket + 1);
- } else {
- --bucket; // 1-based index in value
- }
- // And then just need to link the new bucket entry in
- Bucket newB = new Bucket(symbol, _collList[bucket]);
- _collList[bucket] = newB;
- maxColl = Math.max(maxColl, newB.length);
- }
- } // for (... buckets in the chain ...)
- } // for (... list of bucket heads ... )
-
- _longestCollisionList = maxColl;
-
- if (symbolsSeen != _count) { // sanity check
- throw new RuntimeException("Internal error: count after rehash "+symbolsSeen+"; should be "+_count);
- }
- }
-
- /**
- * Helper method called to empty all shared symbols, but to leave
- * arrays allocated
- */
- private void nukeSymbols() {
- _count = 0;
- _longestCollisionList = 0;
- Arrays.fill(_hash, 0);
- Arrays.fill(_mainNames, null);
- Arrays.fill(_collList, null);
- _collCount = 0;
- _collEnd = 0;
- }
-
- /**
- * Method called to find the best bucket to spill a Name over to:
- * usually the first bucket that has only one entry, but in general
- * first one of the buckets with least number of entries
- */
- private int findBestBucket() {
- Bucket[] buckets = _collList;
- int bestCount = Integer.MAX_VALUE;
- int bestIx = -1;
-
- for (int i = 0, len = _collEnd; i < len; ++i) {
- Bucket b = buckets[i];
- // [#145] may become null due to long overflow chain
- if (b == null) {
- return i;
- }
- int count = b.length;
- if (count < bestCount) {
- if (count == 1) { // best possible
- return i;
- }
- bestCount = count;
- bestIx = i;
- }
- }
- return bestIx;
- }
-
- /**
- * Method that needs to be called, if the main hash structure
- * is (may be) shared. This happens every time something is added,
- * even if addition is to the collision list (since collision list
- * index comes from lowest 8 bits of the primary hash entry)
- */
- private void unshareMain() {
- final int[] old = _hash;
- _hash = Arrays.copyOf(old, old.length);
- _hashShared = false;
- }
-
- private void unshareCollision() {
- Bucket[] old = _collList;
- if (old == null) {
- _collList = new Bucket[INITIAL_COLLISION_LEN];
- } else {
- _collList = Arrays.copyOf(old, old.length);
- }
- _collListShared = false;
- }
-
- private void unshareNames() {
- final Name[] old = _mainNames;
- _mainNames = Arrays.copyOf(old, old.length);
- _namesShared = false;
- }
-
- private void expandCollision() {
- final Bucket[] old = _collList;
- _collList = Arrays.copyOf(old, old.length * 2);
- }
-
- /*
- /**********************************************************
- /* Constructing name objects
- /**********************************************************
- */
-
- private static Name constructName(int hash, String name, int q1, int q2) {
- if (q2 == 0) { // one quad only?
- return new Name1(name, hash, q1);
- }
- return new Name2(name, hash, q1, q2);
- }
-
- private static Name constructName(int hash, String name, int[] quads, int qlen) {
- if (qlen < 4) { // Need to check for 3 quad one, can do others too
- switch (qlen) {
- case 1:
- return new Name1(name, hash, quads[0]);
- case 2:
- return new Name2(name, hash, quads[0], quads[1]);
- case 3:
- default:
- return new Name3(name, hash, quads[0], quads[1], quads[2]);
- }
- }
- return NameN.construct(name, hash, quads, qlen);
- }
-
- /*
- /**********************************************************
- /* Other helper methods
- /**********************************************************
- */
-
- /**
- * @since 2.1
- */
- protected void reportTooManyCollisions(int maxLen)
- {
- throw new IllegalStateException("Longest collision chain in symbol table (of size "+_count
- +") now exceeds maximum, "+maxLen+" -- suspect a DoS attack based on hash collisions");
- }
-
- /*
- /**********************************************************
- /* Helper classes
- /**********************************************************
- */
-
- /**
- * Immutable value class used for sharing information as efficiently
- * as possible, by only require synchronization of reference manipulation
- * but not access to contents.
- *
- * @since 2.1
- */
- private final static class TableInfo
- {
- public final int count;
- public final int mainHashMask;
- public final int[] mainHash;
- public final Name[] mainNames;
- public final Bucket[] collList;
- public final int collCount;
- public final int collEnd;
- public final int longestCollisionList;
-
- public TableInfo(int count, int mainHashMask, int[] mainHash, Name[] mainNames,
- Bucket[] collList, int collCount, int collEnd, int longestCollisionList)
- {
- this.count = count;
- this.mainHashMask = mainHashMask;
- this.mainHash = mainHash;
- this.mainNames = mainNames;
- this.collList = collList;
- this.collCount = collCount;
- this.collEnd = collEnd;
- this.longestCollisionList = longestCollisionList;
- }
-
- public TableInfo(BytesToNameCanonicalizer src)
- {
- count = src._count;
- mainHashMask = src._hashMask;
- mainHash = src._hash;
- mainNames = src._mainNames;
- collList = src._collList;
- collCount = src._collCount;
- collEnd = src._collEnd;
- longestCollisionList = src._longestCollisionList;
- }
- }
-
- final private static class Bucket
- {
- public final Name name;
- public final Bucket next;
- public final int hash;
- public final int length;
-
- Bucket(Name name, Bucket next) {
- this.name = name;
- this.next = next;
- length = (next == null) ? 1 : next.length+1;
- hash = name.hashCode();
- }
-
- public Name find(int h, int firstQuad, int secondQuad) {
- if (hash == h) {
- if (name.equals(firstQuad, secondQuad)) {
- return name;
- }
- }
- for (Bucket curr = next; curr != null; curr = curr.next) {
- if (curr.hash == h) {
- Name currName = curr.name;
- if (currName.equals(firstQuad, secondQuad)) {
- return currName;
- }
- }
- }
- return null;
- }
-
- public Name find(int h, int q1, int q2, int q3) {
- if (hash == h) {
- if (name.equals(q1, q2, q3)) {
- return name;
- }
- }
- for (Bucket curr = next; curr != null; curr = curr.next) {
- if (curr.hash == h) {
- Name currName = curr.name;
- if (currName.equals(q1, q2, q3)) {
- return currName;
- }
- }
- }
- return null;
- }
-
- public Name find(int h, int[] quads, int qlen) {
- if (hash == h) {
- if (name.equals(quads, qlen)) {
- return name;
- }
- }
- for (Bucket curr = next; curr != null; curr = curr.next) {
- if (curr.hash == h) {
- Name currName = curr.name;
- if (currName.equals(quads, qlen)) {
- return currName;
- }
- }
- }
- return null;
- }
- }
-}
diff --git a/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java b/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java
index 2c57157..a668c7e 100644
--- a/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java
+++ b/src/main/java/com/fasterxml/jackson/core/type/ResolvedType.java
@@ -88,7 +88,11 @@
* subtypes they may be different parameters or possibly none at all).
*
* @since 2.5
+ *
+ * @deprecated Since 2.7: does not have meaning as parameters depend on type
+ * resolved.
*/
+ @Deprecated // since 2.7
public Class<?> getParameterSource() {
return null;
}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java b/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
index 0a004c5..510d2fd 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
@@ -79,7 +79,7 @@
* Number of open levels of nesting. Used to determine amount of
* indentation to use.
*/
- protected transient int _nesting = 0;
+ protected transient int _nesting;
/*
/**********************************************************
@@ -245,8 +245,7 @@
*/
@Override
- public void writeRootValueSeparator(JsonGenerator jg)
- throws IOException, JsonGenerationException
+ public void writeRootValueSeparator(JsonGenerator jg) throws IOException
{
if (_rootSeparator != null) {
jg.writeRaw(_rootSeparator);
@@ -254,8 +253,7 @@
}
@Override
- public void writeStartObject(JsonGenerator jg)
- throws IOException, JsonGenerationException
+ public void writeStartObject(JsonGenerator jg) throws IOException
{
jg.writeRaw('{');
if (!_objectIndenter.isInline()) {
@@ -264,8 +262,7 @@
}
@Override
- public void beforeObjectEntries(JsonGenerator jg)
- throws IOException, JsonGenerationException
+ public void beforeObjectEntries(JsonGenerator jg) throws IOException
{
_objectIndenter.writeIndentation(jg, _nesting);
}
@@ -280,8 +277,7 @@
* (white-space) decoration.
*/
@Override
- public void writeObjectFieldValueSeparator(JsonGenerator jg)
- throws IOException, JsonGenerationException
+ public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException
{
if (_spacesInObjectEntries) {
jg.writeRaw(" : ");
@@ -300,16 +296,14 @@
* (white-space) decoration.
*/
@Override
- public void writeObjectEntrySeparator(JsonGenerator jg)
- throws IOException, JsonGenerationException
+ public void writeObjectEntrySeparator(JsonGenerator jg) throws IOException
{
jg.writeRaw(',');
_objectIndenter.writeIndentation(jg, _nesting);
}
@Override
- public void writeEndObject(JsonGenerator jg, int nrOfEntries)
- throws IOException, JsonGenerationException
+ public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException
{
if (!_objectIndenter.isInline()) {
--_nesting;
@@ -323,8 +317,7 @@
}
@Override
- public void writeStartArray(JsonGenerator jg)
- throws IOException, JsonGenerationException
+ public void writeStartArray(JsonGenerator jg) throws IOException
{
if (!_arrayIndenter.isInline()) {
++_nesting;
@@ -333,9 +326,7 @@
}
@Override
- public void beforeArrayValues(JsonGenerator jg)
- throws IOException, JsonGenerationException
- {
+ public void beforeArrayValues(JsonGenerator jg) throws IOException {
_arrayIndenter.writeIndentation(jg, _nesting);
}
@@ -409,43 +400,4 @@
@Override
public boolean isInline() { return true; }
}
-
- /**
- * @deprecated Since 2.5 use {@link DefaultIndenter} instead
- */
- @Deprecated
- public static class Lf2SpacesIndenter extends DefaultIndenter
- {
- /** @deprecated Use {@link DefaultIndenter#SYSTEM_LINEFEED_INSTANCE} instead.
- */
- @SuppressWarnings("hiding")
- @Deprecated
- public static final Lf2SpacesIndenter instance = new Lf2SpacesIndenter();
-
- /** @deprecated Use {@code new DefaultIndenter(" ", DefaultIndenter.SYS_LF)} instead
- */
- @Deprecated
- public Lf2SpacesIndenter() {
- super(" ", DefaultIndenter.SYS_LF);
- }
-
- /** @deprecated Use {@code new DefaultIndenter(" ", lf)} instead
- */
- @Deprecated
- public Lf2SpacesIndenter(String lf) {
- super(" ", lf);
- }
-
- /**
- * Note: method was accidentally missing from 2.5.0; put back for 2.5.1 and
- * later 2.5.x versions.
- */
- @Override
- public Lf2SpacesIndenter withLinefeed(String lf) {
- if (lf.equals(getEol())) {
- return this;
- }
- return new Lf2SpacesIndenter(lf);
- }
- }
}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
index 9d53afa..f8c31ca 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
@@ -128,11 +128,24 @@
public int getFeatureMask() { return delegate.getFeatureMask(); }
@Override
+ @Deprecated
public JsonGenerator setFeatureMask(int mask) {
delegate.setFeatureMask(mask);
return this;
}
+ @Override
+ public JsonGenerator overrideStdFeatures(int values, int mask) {
+ delegate.overrideStdFeatures(values, mask);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator overrideFormatFeatures(int values, int mask) {
+ delegate.overrideFormatFeatures(values, mask);
+ return this;
+ }
+
/*
/**********************************************************
/* Configuring generator
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
index 7f4241d..c96d239 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
@@ -60,11 +60,24 @@
@Override public int getFeatureMask() { return delegate.getFeatureMask(); }
@Override
+ @Deprecated // since 2.7
public JsonParser setFeatureMask(int mask) {
delegate.setFeatureMask(mask);
return this;
}
+ @Override
+ public JsonParser overrideStdFeatures(int values, int mask) {
+ delegate.overrideStdFeatures(values, mask);
+ return this;
+ }
+
+ @Override
+ public JsonParser overrideFormatFeatures(int values, int mask) {
+ delegate.overrideFormatFeatures(values, mask);
+ return this;
+ }
+
@Override public FormatSchema getSchema() { return delegate.getSchema(); }
@Override public void setSchema(FormatSchema schema) { delegate.setSchema(schema); }
@Override public boolean canUseSchema(FormatSchema schema) { return delegate.canUseSchema(schema); }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
index 68ba240..85250b1 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
@@ -82,7 +82,7 @@
/**
* Flag that indicates whether _seqments is non-empty
*/
- private boolean _hasSegments = false;
+ private boolean _hasSegments;
// // // Currently used segment; not (yet) contained in _seqments
diff --git a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
index 5d14f71..d5a2ae0 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
+++ b/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
@@ -1,15 +1,45 @@
package com.fasterxml.jackson.core;
+import java.io.StringWriter;
public class TestExceptions extends BaseTest
{
- // For [Issue#10]
+ private final JsonFactory JSON_F = new JsonFactory();
+
+ // For [core#10]
public void testOriginalMesssage()
{
- JsonProcessingException exc = new JsonParseException("Foobar", JsonLocation.NA);
+ JsonProcessingException exc = new JsonParseException(null, "Foobar", JsonLocation.NA);
String msg = exc.getMessage();
String orig = exc.getOriginalMessage();
assertEquals("Foobar", orig);
assertTrue(msg.length() > orig.length());
}
+
+ // [core#198]
+ public void testAccessToParser() throws Exception
+ {
+ JsonParser p = JSON_F.createParser("{}");
+ assertToken(JsonToken.START_OBJECT, p.nextToken());
+ JsonParseException e = new JsonParseException(p, "Test!");
+ assertSame(p, e.getProcessor());
+ assertEquals("Test!", e.getOriginalMessage());
+ JsonLocation loc = e.getLocation();
+ assertNotNull(loc);
+ assertEquals(2, loc.getColumnNr());
+ assertEquals(1, loc.getLineNr());
+ p.close();
+ }
+
+ // [core#198]
+ public void testAccessToGenerator() throws Exception
+ {
+ StringWriter w = new StringWriter();
+ JsonGenerator g = JSON_F.createGenerator(w);
+ g.writeStartObject();
+ JsonGenerationException e = new JsonGenerationException("Test!", g);
+ assertSame(g, e.getProcessor());
+ assertEquals("Test!", e.getOriginalMessage());
+ g.close();
+ }
}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/LocationInArrayTest.java b/src/test/java/com/fasterxml/jackson/core/json/LocationInArrayTest.java
new file mode 100644
index 0000000..6883523
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/LocationInArrayTest.java
@@ -0,0 +1,66 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+
+// Tests mostly for [core#229]
+public class LocationInArrayTest extends com.fasterxml.jackson.core.BaseTest
+{
+ final JsonFactory JSON_F = new JsonFactory();
+
+ // for [core#229]
+ public void testOffsetInArraysBytes() throws Exception {
+ _testOffsetInArrays(true);
+ }
+
+ // for [core#229]
+ public void testOffsetInArraysChars() throws Exception {
+ _testOffsetInArrays(false);
+ }
+
+ private void _testOffsetInArrays(boolean useBytes) throws Exception
+ {
+ JsonParser p;
+ final String DOC = " [10, 251,\n 3 ]";
+
+ // first, char based:
+ p = useBytes ? JSON_F.createParser(DOC.getBytes("UTF-8"))
+ : JSON_F.createParser(DOC.toCharArray());
+ assertToken(JsonToken.START_ARRAY, p.nextToken());
+ _assertLocation(useBytes, p.getTokenLocation(), 2L, 1, 3);
+ _assertLocation(useBytes, p.getCurrentLocation(), 3L, 1, 4);
+
+ assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+ _assertLocation(useBytes, p.getTokenLocation(), 3L, 1, 4);
+ assertEquals(10, p.getIntValue()); // just to ensure read proceeds to end
+ // 2-digits so
+ _assertLocation(useBytes, p.getCurrentLocation(), 5L, 1, 6);
+
+ assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+ _assertLocation(useBytes, p.getTokenLocation(), 7L, 1, 8);
+ assertEquals(251, p.getIntValue()); // just to ensure read proceeds to end
+ _assertLocation(useBytes, p.getCurrentLocation(), 10L, 1, 11);
+
+ assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+ _assertLocation(useBytes, p.getTokenLocation(), 15L, 2, 4);
+ assertEquals(3, p.getIntValue());
+ _assertLocation(useBytes, p.getCurrentLocation(), 16L, 2, 5);
+
+ assertToken(JsonToken.END_ARRAY, p.nextToken());
+ _assertLocation(useBytes, p.getTokenLocation(), 18L, 2, 7);
+ _assertLocation(useBytes, p.getCurrentLocation(), 19L, 2, 8);
+
+ p.close();
+ }
+
+ private void _assertLocation(boolean useBytes, JsonLocation loc, long offset, int row, int col)
+ {
+ assertEquals(row, loc.getLineNr());
+ assertEquals(col, loc.getColumnNr());
+
+ if (useBytes) {
+ assertEquals(offset, loc.getByteOffset());
+ } else {
+ assertEquals(offset, loc.getCharOffset());
+ }
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/LocationInObjectTest.java b/src/test/java/com/fasterxml/jackson/core/json/LocationInObjectTest.java
new file mode 100644
index 0000000..eb317d4
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/LocationInObjectTest.java
@@ -0,0 +1,99 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+
+// tests for [core#37]
+public class LocationInObjectTest extends BaseTest
+{
+ public void testOffsetWithObjectFieldsUsingUTF8() throws Exception
+ {
+ final JsonFactory f = new JsonFactory();
+ byte[] b = "{\"f1\":\"v1\",\"f2\":{\"f3\":\"v3\"},\"f4\":[true,false],\"f5\":5}".getBytes("UTF-8");
+ // 1 6 11 16 17 22 28 33 34 39 46 51
+ JsonParser p = f.createParser(b);
+
+ assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+ assertEquals(JsonToken.FIELD_NAME, p.nextToken());
+ assertEquals(1L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.VALUE_STRING, p.nextToken());
+ assertEquals(6L, p.getTokenLocation().getByteOffset());
+
+ assertEquals("f2", p.nextFieldName());
+ assertEquals(11L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.START_OBJECT, p.nextValue());
+ assertEquals(16L, p.getTokenLocation().getByteOffset());
+
+ assertEquals("f3", p.nextFieldName());
+ assertEquals(17L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.VALUE_STRING, p.nextValue());
+ assertEquals(22L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+ assertEquals("f4", p.nextFieldName());
+ assertEquals(28L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.START_ARRAY, p.nextValue());
+ assertEquals(33L, p.getTokenLocation().getByteOffset());
+
+ assertEquals(JsonToken.VALUE_TRUE, p.nextValue());
+ assertEquals(34L, p.getTokenLocation().getByteOffset());
+
+ assertEquals(JsonToken.VALUE_FALSE, p.nextValue());
+ assertEquals(39L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.END_ARRAY, p.nextToken());
+
+ assertEquals("f5", p.nextFieldName());
+ assertEquals(46L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+ assertEquals(51L, p.getTokenLocation().getByteOffset());
+ assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+ p.close();
+ }
+
+ public void testOffsetWithObjectFieldsUsingReader() throws Exception
+ {
+ final JsonFactory f = new JsonFactory();
+ char[] c = "{\"f1\":\"v1\",\"f2\":{\"f3\":\"v3\"},\"f4\":[true,false],\"f5\":5}".toCharArray();
+ // 1 6 11 16 17 22 28 33 34 39 46 51
+ JsonParser p = f.createParser(c);
+
+ assertEquals(JsonToken.START_OBJECT, p.nextToken());
+
+ assertEquals(JsonToken.FIELD_NAME, p.nextToken());
+ assertEquals(1L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.VALUE_STRING, p.nextToken());
+ assertEquals(6L, p.getTokenLocation().getCharOffset());
+
+ assertEquals("f2", p.nextFieldName());
+ assertEquals(11L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.START_OBJECT, p.nextValue());
+ assertEquals(16L, p.getTokenLocation().getCharOffset());
+
+ assertEquals("f3", p.nextFieldName());
+ assertEquals(17L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.VALUE_STRING, p.nextValue());
+ assertEquals(22L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+ assertEquals("f4", p.nextFieldName());
+ assertEquals(28L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.START_ARRAY, p.nextValue());
+ assertEquals(33L, p.getTokenLocation().getCharOffset());
+
+ assertEquals(JsonToken.VALUE_TRUE, p.nextValue());
+ assertEquals(34L, p.getTokenLocation().getCharOffset());
+
+ assertEquals(JsonToken.VALUE_FALSE, p.nextValue());
+ assertEquals(39L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.END_ARRAY, p.nextToken());
+
+ assertEquals("f5", p.nextFieldName());
+ assertEquals(46L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken());
+ assertEquals(51L, p.getTokenLocation().getCharOffset());
+ assertEquals(JsonToken.END_OBJECT, p.nextToken());
+
+ p.close();
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java b/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java
index a42c800..f3192e6 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestLocation.java
@@ -5,16 +5,17 @@
// NOTE: just a stub so for, fill me!
public class TestLocation extends com.fasterxml.jackson.core.BaseTest
{
+ final JsonFactory JSON_F = new JsonFactory();
+
// Trivially simple unit test for basics wrt offsets
public void testSimpleInitialOffsets() throws Exception
{
- final JsonFactory f = new JsonFactory();
JsonLocation loc;
JsonParser p;
final String DOC = "{ }";
// first, char based:
- p = f.createParser(DOC);
+ p = JSON_F.createParser(DOC);
assertToken(JsonToken.START_OBJECT, p.nextToken());
loc = p.getTokenLocation();
@@ -33,7 +34,7 @@
// then byte-based
- p = f.createParser(DOC.getBytes("UTF-8"));
+ p = JSON_F.createParser(DOC.getBytes("UTF-8"));
assertToken(JsonToken.START_OBJECT, p.nextToken());
loc = p.getTokenLocation();
@@ -51,17 +52,16 @@
p.close();
}
- // for [Issue#111]
+ // for [core#111]
public void testOffsetWithInputOffset() throws Exception
{
- final JsonFactory f = new JsonFactory();
JsonLocation loc;
JsonParser p;
// 3 spaces before, 2 after, just for padding
byte[] b = " { } ".getBytes("UTF-8");
// and then peel them off
- p = f.createParser(b, 3, b.length-5);
+ p = JSON_F.createParser(b, 3, b.length-5);
assertToken(JsonToken.START_OBJECT, p.nextToken());
loc = p.getTokenLocation();
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java b/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
index feb8560..2aaeeb1 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestNextXxx.java
@@ -25,12 +25,23 @@
{
_testIsNextTokenName1(false);
_testIsNextTokenName1(true);
+ }
+
+ public void testIsNextTokenName2() throws Exception {
_testIsNextTokenName2(false);
_testIsNextTokenName2(true);
+ }
+
+ public void testIsNextTokenName3() throws Exception {
_testIsNextTokenName3(false);
_testIsNextTokenName3(true);
}
+ public void testIsNextTokenName4() throws Exception {
+ _testIsNextTokenName4(false);
+ _testIsNextTokenName4(true);
+ }
+
// [jackson-core#34]
public void testIssue34() throws Exception
{
@@ -110,6 +121,7 @@
assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
assertEquals("name2", jp.getCurrentName());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+ // do NOT check number value, to enforce skipping
assertFalse(jp.nextFieldName(NAME));
assertToken(JsonToken.FIELD_NAME, jp.getCurrentToken());
@@ -234,6 +246,27 @@
p.close();
}
+ private void _testIsNextTokenName4(boolean useStream) throws Exception
+ {
+ final String DOC = "{\"name\":-123,\"name2\":99}";
+ JsonParser jp = useStream ?
+ JSON_F.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8")))
+ : JSON_F.createParser(new StringReader(DOC));
+ assertToken(JsonToken.START_OBJECT, jp.nextToken());
+
+ assertTrue(jp.nextFieldName(new SerializedString("name")));
+ assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+ assertEquals(-123, jp.getIntValue());
+
+ assertTrue(jp.nextFieldName(new SerializedString("name2")));
+ assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
+ assertEquals(99, jp.getIntValue());
+ assertToken(JsonToken.END_OBJECT, jp.nextToken());
+ assertNull(jp.nextToken());
+
+ jp.close();
+ }
+
private void _testNextFieldNameIndent(boolean useStream) throws Exception
{
final String DOC = "{\n \"name\" : \n [\n ]\n }";
@@ -251,7 +284,7 @@
p.close();
}
-
+
private void _textNextText(boolean useStream) throws Exception
{
final String DOC = aposToQuotes("{'a':'123','b':5,'c':[false,'foo']}");
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java b/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
index ceea01a..fb99205 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestNumericValues.java
@@ -389,7 +389,7 @@
}
sb.append(segment);
sb.append('\n');
- // let's add somewhat arbitray number of spaces
+ // let's add somewhat arbitrary number of spaces
int x = (i & 3);
if (i > 300) {
x += i % 5;
diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
index 3fed2d5..3cf4020 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java
@@ -37,7 +37,7 @@
p.close();
}
- // for [Issue#115]
+ // for [core#115]
public void testSurrogatesWithRaw() throws Exception
{
final String VALUE = quote("\ud83d\ude0c");
diff --git a/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java b/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java
index 045a943..9fa5871 100644
--- a/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java
+++ b/src/test/java/com/fasterxml/jackson/core/sym/TestSymbolTables.java
@@ -38,33 +38,6 @@
assertEquals(6, symbols.maxCollisionLength());
}
- // Test for verifying stability of hashCode, wrt collisions, using
- // synthetic field name generation and byte-based input (UTF-8)
- @SuppressWarnings("deprecation")
- public void testSyntheticWithBytesOld() throws IOException
- {
- // pass seed, to keep results consistent:
- final int SEED = 33333;
- BytesToNameCanonicalizer symbols =
- BytesToNameCanonicalizer.createRoot(SEED).makeChild(JsonFactory.Feature.collectDefaults());
-
- final int COUNT = 12000;
- for (int i = 0; i < COUNT; ++i) {
- String id = fieldNameFor(i);
- int[] quads = calcQuads(id.getBytes("UTF-8"));
- symbols.addName(id, quads, quads.length);
- }
- assertEquals(COUNT, symbols.size());
- assertEquals(16384, symbols.bucketCount());
-
-//System.out.printf("Byte stuff: collisions %d, max-coll %d\n", symbols.collisionCount(), symbols.maxCollisionLength());
- assertEquals(3476, symbols.collisionCount());
- // longest collision chain not optimal but ok:
- assertEquals(15, symbols.maxCollisionLength());
-
- // But also verify entries are actually found?
- }
-
public void testSyntheticWithBytesNew() throws IOException
{
// pass seed, to keep results consistent:
@@ -119,35 +92,6 @@
}
}
- @SuppressWarnings("deprecation")
- public void testThousandsOfSymbolsWithOldBytes() throws IOException
- {
- final int SEED = 33333;
-
- BytesToNameCanonicalizer symbolsBRoot = BytesToNameCanonicalizer.createRoot(SEED);
- final Charset utf8 = Charset.forName("UTF-8");
- int exp = 0;
-
- for (int doc = 0; doc < 100; ++doc) {
- BytesToNameCanonicalizer symbolsB =
- symbolsBRoot.makeChild(JsonFactory.Feature.collectDefaults());
- for (int i = 0; i < 250; ++i) {
- String name = "f_"+doc+"_"+i;
-
- int[] quads = BytesToNameCanonicalizer.calcQuads(name.getBytes(utf8));
- symbolsB.addName(name, quads, quads.length);
- Name n = symbolsB.findName(quads, quads.length);
- assertEquals(name, n.getName());
- }
- symbolsB.release();
- exp += 250;
- if (exp > BytesToNameCanonicalizer.MAX_ENTRIES_FOR_REUSE) {
- exp = 0;
- }
- assertEquals(exp, symbolsBRoot.size());
- }
- }
-
// Since 2.6
public void testThousandsOfSymbolsWithNew() throws IOException
{
@@ -234,30 +178,6 @@
}
// [core#187]: unexpectedly high number of collisions for straight numbers
- @SuppressWarnings("deprecation")
- public void testCollisionsWithBytes187() throws IOException
- {
- BytesToNameCanonicalizer symbols =
- BytesToNameCanonicalizer.createRoot(1).makeChild(JsonFactory.Feature.collectDefaults());
- final int COUNT = 30000;
- for (int i = 0; i < COUNT; ++i) {
- String id = String.valueOf(10000 + i);
- int[] quads = BytesToNameCanonicalizer.calcQuads(id.getBytes("UTF-8"));
- symbols.addName(id, quads, quads.length);
- }
-
-//System.out.printf("Byte stuff: collisions %d, max-coll %d\n", symbols.collisionCount(), symbols.maxCollisionLength());
-
- assertEquals(COUNT, symbols.size());
- assertEquals(65536, symbols.bucketCount());
-
- // collision count acceptable
- assertEquals(5782, symbols.collisionCount());
- // as well as collision counts
- assertEquals(24, symbols.maxCollisionLength());
- }
-
- // [core#187]: unexpectedly high number of collisions for straight numbers
public void testCollisionsWithChars187() throws IOException
{
CharsToNameCanonicalizer symbols = CharsToNameCanonicalizer.createRoot(1);
@@ -386,24 +306,6 @@
assertEquals(2, symbols.maxCollisionLength());
}
- @SuppressWarnings("deprecation")
- public void testShortQuotedDirectBytesOld() throws IOException
- {
- final int COUNT = 400;
- BytesToNameCanonicalizer symbols =
- BytesToNameCanonicalizer.createRoot(1).makeChild(JsonFactory.Feature.collectDefaults());
- for (int i = 0; i < COUNT; ++i) {
- String id = String.format("\\u%04x", i);
- int[] quads = BytesToNameCanonicalizer.calcQuads(id.getBytes("UTF-8"));
- symbols.addName(id, quads, quads.length);
- }
- assertEquals(COUNT, symbols.size());
- assertEquals(1024, symbols.bucketCount());
-
- assertEquals(44, symbols.collisionCount());
- assertEquals(2, symbols.maxCollisionLength());
- }
-
public void testShortQuotedDirectBytes() throws IOException
{
final int COUNT = 400;
@@ -424,7 +326,6 @@
}
// [core#191]
- @SuppressWarnings("deprecation")
public void testShortNameCollisionsDirect() throws IOException
{
final int COUNT = 600;
@@ -443,22 +344,6 @@
assertEquals(16, symbols.collisionCount());
assertEquals(1, symbols.maxCollisionLength());
}
-
- // then byte-based
- {
- BytesToNameCanonicalizer symbols =
- BytesToNameCanonicalizer.createRoot(1).makeChild(JsonFactory.Feature.collectDefaults());
- for (int i = 0; i < COUNT; ++i) {
- String id = String.valueOf((char) i);
- int[] quads = calcQuads(id.getBytes("UTF-8"));
- symbols.addName(id, quads, quads.length);
- }
- assertEquals(COUNT, symbols.size());
- assertEquals(1024, symbols.bucketCount());
-
- assertEquals(209, symbols.collisionCount());
- assertEquals(1, symbols.maxCollisionLength());
- }
}
public void testShortNameCollisionsDirectNew() throws IOException
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java b/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
index 2ce3917..4f467fe 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
+++ b/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
@@ -6,7 +6,7 @@
/**
* Set of basic unit tests for verifying that the low-level number
- * printingg methods work as expected.
+ * printing methods work as expected.
*/
public class TestNumberPrinting
extends com.fasterxml.jackson.core.BaseTest
diff --git a/src/test/java/com/fasterxml/jackson/failing/Surrogate223Test.java b/src/test/java/com/fasterxml/jackson/failing/Surrogate223Test.java
new file mode 100644
index 0000000..33dd2ae
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/failing/Surrogate223Test.java
@@ -0,0 +1,90 @@
+package com.fasterxml.jackson.failing;
+
+import java.io.ByteArrayOutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+
+public class Surrogate223Test extends BaseTest
+{
+ private final JsonFactory JSON_F = new JsonFactory();
+
+ // for [core#223]
+ public void testSurrogatesByteBacked() throws Exception
+ {
+ ByteArrayOutputStream out;
+ JsonGenerator g;
+ final String toQuote = new String(Character.toChars(0x1F602));
+ assertEquals(2, toQuote.length()); // just sanity check
+
+ // default should be disabled:
+// assertFalse(JSON_F.isEnabled(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES));
+
+ out = new ByteArrayOutputStream();
+ g = JSON_F.createGenerator(out);
+ g.writeStartArray();
+ g.writeString(toQuote);
+ g.writeEndArray();
+ g.close();
+ assertEquals(2 + 2 + 4, out.size()); // brackets, quotes, 4-byte encoding
+
+ // Also parse back to ensure correctness
+ JsonParser p = JSON_F.createParser(out.toByteArray());
+ assertToken(JsonToken.START_ARRAY, p.nextToken());
+ assertToken(JsonToken.VALUE_STRING, p.nextToken());
+ assertToken(JsonToken.END_ARRAY, p.nextToken());
+ p.close();
+
+ // but may revert back to original behavior
+ out = new ByteArrayOutputStream();
+ g = JSON_F.createGenerator(out);
+// g.enable(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES);
+ g.writeStartArray();
+ g.writeString(toQuote);
+ g.writeEndArray();
+ g.close();
+ assertEquals(2 + 2 + 12, out.size()); // brackets, quotes, 2 x 6 byte JSON escape
+ }
+
+ // for [core#223]
+ public void testSurrogatesCharBacked() throws Exception
+ {
+ Writer out;
+ JsonGenerator g;
+ final String toQuote = new String(Character.toChars(0x1F602));
+ assertEquals(2, toQuote.length()); // just sanity check
+
+ // default should be disabled:
+// assertFalse(JSON_F.isEnabled(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES));
+
+ out = new StringWriter();
+ g = JSON_F.createGenerator(out);
+ g.writeStartArray();
+ g.writeString(toQuote);
+ g.writeEndArray();
+ g.close();
+ assertEquals(2 + 2 + 2, out.toString().length()); // brackets, quotes, 2 chars as is
+
+ // Also parse back to ensure correctness
+ JsonParser p = JSON_F.createParser(out.toString());
+ assertToken(JsonToken.START_ARRAY, p.nextToken());
+ assertToken(JsonToken.VALUE_STRING, p.nextToken());
+ assertToken(JsonToken.END_ARRAY, p.nextToken());
+ p.close();
+
+ // but may revert back to original behavior
+ out = new StringWriter();
+ g = JSON_F.createGenerator(out);
+// g.enable(JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES);
+ g.writeStartArray();
+ g.writeString(toQuote);
+ g.writeEndArray();
+ g.close();
+ assertEquals(2 + 2 + 12, out.toString().length()); // brackets, quotes, 2 x 6 byte JSON escape
+ }
+}