+ * NOTE: non-final since 2.17 due to need to re-create if
+ * {@link StreamReadConstraints} re-configured for factory.
*/
- protected final transient CharsToNameCanonicalizer _rootCharSymbols;
+ protected transient CharsToNameCanonicalizer _rootCharSymbols;
/**
* Alternative to the basic symbol table, some stream-based
@@ -260,6 +262,9 @@ public static int collectDefaults() {
*/
/**
+ * {@link RecyclerPool} configured for use by this factory: used for
+ * recycling underlying read and/or write buffers via {@link BufferRecycler}.
+ *
* @since 2.16
*/
protected RecyclerPool _recyclerPool;
@@ -539,7 +544,7 @@ protected static List _copy(List src) {
if (src == null) {
return src;
}
- return new ArrayList(src);
+ return new ArrayList<>(src);
}
/*
@@ -867,7 +872,13 @@ public StreamWriteConstraints streamWriteConstraints() {
* @since 2.15
*/
public JsonFactory setStreamReadConstraints(StreamReadConstraints src) {
+ final int maxNameLen = _streamReadConstraints.getMaxNameLength();
_streamReadConstraints = Objects.requireNonNull(src);
+ // 30-Jan-2024, tatu: [core#1207] Need to recreate if max-name-length
+ // setting changes
+ if (_streamReadConstraints.getMaxNameLength() != maxNameLen) {
+ _rootCharSymbols = CharsToNameCanonicalizer.createRoot(this);
+ }
return this;
}
@@ -887,7 +898,7 @@ public JsonFactory setStreamReadConstraints(StreamReadConstraints src) {
* @since 2.16
*/
public JsonFactory setErrorReportConfiguration(ErrorReportConfiguration src) {
- _errorReportConfiguration = Objects.requireNonNull(src, "Cannot pass null ErrorReportConfiguration");;
+ _errorReportConfiguration = Objects.requireNonNull(src, "Cannot pass null ErrorReportConfiguration");
return this;
}
@@ -2181,12 +2192,29 @@ public RecyclerPool _getRecyclerPool() {
* @return I/O context created
*/
protected IOContext _createContext(ContentReference contentRef, boolean resourceManaged) {
- // 21-Mar-2021, tatu: Bit of defensive coding for backwards compatibility
+ BufferRecycler br = null;
+ boolean recyclerExternal = false;
+
if (contentRef == null) {
contentRef = ContentReference.unknown();
+ } else {
+ Object content = contentRef.getRawContent();
+ // 18-Jan-2024, tatu: [core#1195] Let's see if we can reuse already allocated recycler
+ // (is the case when SegmentedStringWriter / ByteArrayBuilder passed)
+ if (content instanceof BufferRecycler.Gettable) {
+ br = ((BufferRecycler.Gettable) content).bufferRecycler();
+ recyclerExternal = (br != null);
+ }
}
- return new IOContext(_streamReadConstraints, _streamWriteConstraints, _errorReportConfiguration,
- _getBufferRecycler(), contentRef, resourceManaged);
+ if (br == null) {
+ br = _getBufferRecycler();
+ }
+ IOContext ctxt = new IOContext(_streamReadConstraints, _streamWriteConstraints, _errorReportConfiguration,
+ br, contentRef, resourceManaged);
+ if (recyclerExternal) {
+ ctxt.markBufferRecyclerReleased();
+ }
+ return ctxt;
}
/**
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
index d524939aef..42ff2a9d82 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
@@ -12,6 +12,7 @@
import java.util.concurrent.atomic.AtomicLong;
import com.fasterxml.jackson.core.JsonParser.NumberType;
+import com.fasterxml.jackson.core.exc.StreamWriteException;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.core.type.WritableTypeId.Inclusion;
@@ -265,7 +266,23 @@ public enum Feature {
* @deprecated Use {@link com.fasterxml.jackson.core.json.JsonWriteFeature#WRITE_HEX_UPPER_CASE} instead
*/
@Deprecated
- WRITE_HEX_UPPER_CASE(true);
+ WRITE_HEX_UPPER_CASE(true),
+
+ /**
+ * See {@link com.fasterxml.jackson.core.json.JsonWriteFeature#ESCAPE_FORWARD_SLASHES}.
+ *
+ * @since 2.17
+ */
+ ESCAPE_FORWARD_SLASHES(false),
+
+ /**
+ * See {@link com.fasterxml.jackson.core.json.JsonWriteFeature#COMBINE_UNICODE_SURROGATES_IN_UTF8}.
+ *
+ * @since 2.18
+ */
+ COMBINE_UNICODE_SURROGATES_IN_UTF8(false),
+
+ ;
private final boolean _defaultState;
private final int _mask;
@@ -344,6 +361,8 @@ protected JsonGenerator() { }
/**
* Get the constraints to apply when performing streaming writes.
*
+ * @return StreamWriteConstraints used by this generator
+ *
* @since 2.16
*/
public StreamWriteConstraints streamWriteConstraints() {
@@ -410,8 +429,8 @@ public Object getOutputTarget() {
* @since 2.13 (added as replacement for older {@link #getCurrentValue()}
*/
public Object currentValue() {
- // TODO: implement directly in 2.14 or later, make getCurrentValue() call this
- return getCurrentValue();
+ JsonStreamContext ctxt = getOutputContext();
+ return (ctxt == null) ? null : ctxt.getCurrentValue();
}
/**
@@ -425,34 +444,36 @@ public Object currentValue() {
* @since 2.13 (added as replacement for older {@link #setCurrentValue}
*/
public void assignCurrentValue(Object v) {
- // TODO: implement directly in 2.14 or later, make setCurrentValue() call this
- setCurrentValue(v);
+ JsonStreamContext ctxt = getOutputContext();
+ if (ctxt != null) {
+ ctxt.setCurrentValue(v);
+ }
}
- // TODO: deprecate in 2.14 or later
/**
* Alias for {@link #currentValue()}, to be deprecated in later
* Jackson 2.x versions (and removed from Jackson 3.0).
*
* @return Location of the last processed input unit (byte or character)
+ *
+ * @deprecated Since 2.17 use {@link #currentValue()} instead
*/
+ @Deprecated
public Object getCurrentValue() {
- JsonStreamContext ctxt = getOutputContext();
- return (ctxt == null) ? null : ctxt.getCurrentValue();
+ return currentValue();
}
- // TODO: deprecate in 2.14 or later
/**
* Alias for {@link #assignCurrentValue}, to be deprecated in later
* Jackson 2.x versions (and removed from Jackson 3.0).
*
* @param v Current value to assign for the current context of this generator
+ *
+ * @deprecated Since 2.17 use {@link #currentValue()} instead
*/
+ @Deprecated
public void setCurrentValue(Object v) {
- JsonStreamContext ctxt = getOutputContext();
- if (ctxt != null) {
- ctxt.setCurrentValue(v);
- }
+ assignCurrentValue(v);
}
/*
@@ -1760,7 +1781,7 @@ public abstract int writeBinary(Base64Variant bv,
* If implementation does not implement this method,
* it needs to throw {@link UnsupportedOperationException}.
*
- * @param encodedValue Textual (possibly format) number representation to write
+ * @param encodedValue Textual (possibly formatted) number representation to write
*
* @throws IOException if there is either an underlying I/O problem or encoding
* issue at format layer
@@ -2463,8 +2484,7 @@ public void copyCurrentEvent(JsonParser p) throws IOException
final int token = (t == null) ? ID_NOT_AVAILABLE : t.id();
switch (token) {
case ID_NOT_AVAILABLE:
- _reportError("No current event to copy");
- break; // never gets here
+ throw _constructWriteException("No current event to copy");
case ID_START_OBJECT:
writeStartObject();
break;
@@ -2478,7 +2498,7 @@ public void copyCurrentEvent(JsonParser p) throws IOException
writeEndArray();
break;
case ID_FIELD_NAME:
- writeFieldName(p.getCurrentName());
+ writeFieldName(p.currentName());
break;
case ID_STRING:
_copyCurrentStringValue(p);
@@ -2527,8 +2547,7 @@ public void copyCurrentEventExact(JsonParser p) throws IOException
final int token = (t == null) ? ID_NOT_AVAILABLE : t.id();
switch (token) {
case ID_NOT_AVAILABLE:
- _reportError("No current event to copy");
- break; // never gets here
+ throw _constructWriteException("No current event to copy");
case ID_START_OBJECT:
writeStartObject();
break;
@@ -2542,7 +2561,7 @@ public void copyCurrentEventExact(JsonParser p) throws IOException
writeEndArray();
break;
case ID_FIELD_NAME:
- writeFieldName(p.getCurrentName());
+ writeFieldName(p.currentName());
break;
case ID_STRING:
_copyCurrentStringValue(p);
@@ -2617,7 +2636,7 @@ public void copyCurrentStructure(JsonParser p) throws IOException
// Let's handle field-name separately first
int id = (t == null) ? ID_NOT_AVAILABLE : t.id();
if (id == ID_FIELD_NAME) {
- writeFieldName(p.getCurrentName());
+ writeFieldName(p.currentName());
t = p.nextToken();
id = (t == null) ? ID_NOT_AVAILABLE : t.id();
// fall-through to copy the associated value
@@ -2647,7 +2666,7 @@ protected void _copyCurrentContents(JsonParser p) throws IOException
while ((t = p.nextToken()) != null) {
switch (t.id()) {
case ID_FIELD_NAME:
- writeFieldName(p.getCurrentName());
+ writeFieldName(p.currentName());
break;
case ID_START_ARRAY:
@@ -2707,11 +2726,13 @@ protected void _copyCurrentContents(JsonParser p) throws IOException
* {@link JsonParser#getNumberType()} for declared type and uses matching
* accessors: this may cause inexact conversion for some textual formats
* (depending on settings). If this is problematic, use
- * {@lnik #_copyCurrentFloatValueExact} instead (note that doing so may add
+ * {@link #_copyCurrentFloatValueExact} instead (note that doing so may add
* overhead).
*
* @param p Parser that points to the value to copy
*
+ * @throws IOException exception thrown by write method called to copy value, if any
+ *
* @since 2.15
*/
protected void _copyCurrentFloatValue(JsonParser p) throws IOException
@@ -2738,6 +2759,8 @@ protected void _copyCurrentFloatValue(JsonParser p) throws IOException
*
* @param p Parser that points to the value to copy
*
+ * @throws IOException exception thrown by write method called to copy value, if any
+ *
* @since 2.15
*/
protected void _copyCurrentFloatValueExact(JsonParser p) throws IOException
@@ -2758,6 +2781,8 @@ protected void _copyCurrentFloatValueExact(JsonParser p) throws IOException
*
* @param p Parser that points to the value to copy
*
+ * @throws IOException exception thrown by write method called to copy value, if any
+ *
* @since 2.15
*/
protected void _copyCurrentIntValue(JsonParser p) throws IOException
@@ -2778,6 +2803,8 @@ protected void _copyCurrentIntValue(JsonParser p) throws IOException
*
* @param p Parser that points to the value to copy
*
+ * @throws IOException exception thrown by write method called to copy value, if any
+ *
* @since 2.15
*/
protected void _copyCurrentStringValue(JsonParser p) throws IOException
@@ -2839,7 +2866,7 @@ protected void _copyCurrentStringValue(JsonParser p) throws IOException
/*
/**********************************************************************
- /* Helper methods for sub-classes
+ /* Helper methods for sub-classes, error reporting
/**********************************************************************
*/
@@ -2855,15 +2882,46 @@ protected void _copyCurrentStringValue(JsonParser p) throws IOException
* @throws JsonGenerationException constructed
*/
protected void _reportError(String msg) throws JsonGenerationException {
- throw new JsonGenerationException(msg, this);
+ throw (JsonGenerationException) _constructWriteException(msg);
}
protected final void _throwInternal() { VersionUtil.throwInternal(); }
protected void _reportUnsupportedOperation() {
- throw new UnsupportedOperationException("Operation not supported by generator of type "+getClass().getName());
+ _reportUnsupportedOperation("Operation not supported by `JsonGenerator` of type "+getClass().getName());
+ }
+
+ // @since 2.17
+ protected void _reportUnsupportedOperation(String msg) {
+ throw new UnsupportedOperationException(msg);
+ }
+
+ // @since 2.17
+ protected StreamWriteException _constructWriteException(String msg) {
+ return new JsonGenerationException(msg, this);
}
+ // @since 2.17
+ protected StreamWriteException _constructWriteException(String msg, Object arg) {
+ return _constructWriteException(String.format(msg, arg));
+ }
+
+ // @since 2.17
+ protected StreamWriteException _constructWriteException(String msg, Object arg1, Object arg2) {
+ return _constructWriteException(String.format(msg, arg1, arg2));
+ }
+
+ // @since 2.17
+ protected StreamWriteException _constructWriteException(String msg, Throwable t) {
+ return new JsonGenerationException(msg, t, this);
+ }
+
+ /*
+ /**********************************************************************
+ /* Helper methods for sub-classes, other
+ /**********************************************************************
+ */
+
// @since 2.8
protected final void _verifyOffsets(int arrayLength, int offset, int length)
{
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonLocation.java b/src/main/java/com/fasterxml/jackson/core/JsonLocation.java
index 589410e3d3..ce95f5cc05 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonLocation.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonLocation.java
@@ -152,10 +152,16 @@ public Object getSourceRef() {
public int getLineNr() { return _lineNr; }
/**
- * Access for getting column position of this location, if available.
+ * Access for getting column offset of this location, if available.
* Note that column position is typically not available for binary formats.
+ * Note: this returns an offset that is in units of input, so for {@code byte}-based
+ * input sources (like {@link java.io.InputStream}) this does not take into
+ * account multi-byte characters: one logical character can be 1, 2 or 3 bytes long.
+ * To calculate column position in characters either {@code char}-based input
+ * source (like {@link java.io.Reader}) needs to be used, or content needs to be
+ * explicitly decoded.
*
- * @return Column position of the location (1-based), if available; {@code -1} if not.
+ * @return Column offset of the location (1-based), if available; {@code -1} if not.
*/
public int getColumnNr() { return _columnNr; }
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
index a5eb101dcd..a84f83d89c 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParseException.java
@@ -18,14 +18,9 @@ public class JsonParseException
{
private static final long serialVersionUID = 2L; // 2.7
- @Deprecated // since 2.7
- public JsonParseException(String msg, JsonLocation loc) {
- super(msg, loc, null);
- }
-
- @Deprecated // since 2.7
- public JsonParseException(String msg, JsonLocation loc, Throwable root) {
- super(msg, loc, root);
+ // @since 2.15
+ public JsonParseException(String msg) {
+ this(null, msg, null, null);
}
/**
@@ -39,27 +34,33 @@ public JsonParseException(String msg, JsonLocation loc, Throwable root) {
* @since 2.7
*/
public JsonParseException(JsonParser p, String msg) {
- super(p, msg);
+ this(p, msg, _currentLocation(p), null);
}
// @since 2.7
- public JsonParseException(JsonParser p, String msg, Throwable root) {
- super(p, msg, root);
+ public JsonParseException(JsonParser p, String msg, Throwable rootCause) {
+ this(p, msg, _currentLocation(p), rootCause);
}
// @since 2.7
public JsonParseException(JsonParser p, String msg, JsonLocation loc) {
- super(p, msg, loc);
+ this(p, msg, loc, null);
}
+ // Canonical constructor
// @since 2.7
- public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable root) {
- super(p, msg, loc, root);
+ public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable rootCause) {
+ super(p, msg, loc, rootCause);
}
- // @since 2.15
- public JsonParseException(String msg) {
- super(msg);
+ @Deprecated // since 2.7
+ public JsonParseException(String msg, JsonLocation loc) {
+ this(null, msg, loc, null);
+ }
+
+ @Deprecated // since 2.7
+ public JsonParseException(String msg, JsonLocation loc, Throwable rootCause) {
+ this(null, msg, loc, rootCause);
}
/**
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
index 50f454063c..5916d88a6f 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
@@ -12,9 +12,9 @@
import com.fasterxml.jackson.core.async.NonBlockingInputFeeder;
import com.fasterxml.jackson.core.exc.InputCoercionException;
+import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.core.util.JacksonFeatureSet;
-import com.fasterxml.jackson.core.util.RequestPayload;
+import com.fasterxml.jackson.core.util.*;
/**
* Base class that defines public API for reading JSON content.
@@ -26,12 +26,12 @@
public abstract class JsonParser
implements Closeable, Versioned
{
- private final static int MIN_BYTE_I = (int) Byte.MIN_VALUE;
+ private final static int MIN_BYTE_I = Byte.MIN_VALUE;
// as per [JACKSON-804], allow range up to and including 255
- private final static int MAX_BYTE_I = (int) 255;
+ private final static int MAX_BYTE_I = 255;
- private final static int MIN_SHORT_I = (int) Short.MIN_VALUE;
- private final static int MAX_SHORT_I = (int) Short.MAX_VALUE;
+ private final static int MIN_SHORT_I = Short.MIN_VALUE;
+ private final static int MAX_SHORT_I = Short.MAX_VALUE;
/**
* Enumeration of possible "native" (optimal) types that can be
@@ -39,7 +39,47 @@ public abstract class JsonParser
*/
public enum NumberType {
INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL
- };
+ }
+
+ /**
+ * Enumeration of possible physical Floating-Point types that
+ * underlying format uses. Used to indicate most accurate (and
+ * efficient) representation if known (if not known,
+ * {@link NumberTypeFP#UNKNOWN} is used).
+ *
+ * @since 2.17
+ */
+ public enum NumberTypeFP {
+ /**
+ * Special "mini-float" that some binary formats support.
+ */
+ FLOAT16,
+
+ /**
+ * Standard IEEE-754 single-precision 32-bit binary value
+ */
+ FLOAT32,
+
+ /**
+ * Standard IEEE-754 double-precision 64-bit binary value
+ */
+ DOUBLE64,
+
+ /**
+ * Unlimited precision, decimal (10-based) values
+ */
+ BIG_DECIMAL,
+
+ /**
+ * Constant used when type is not known, or there is no specific
+ * type to match: most commonly used for textual formats like JSON
+ * where representation does not necessarily have single easily detectable
+ * optimal representation (for example, value {@code 0.1} has no
+ * exact binary representation whereas {@code 0.25} has exact representation
+ * in every binary type supported)
+ */
+ UNKNOWN
+ }
/**
* Default set of {@link StreamReadCapability}ies that may be used as
@@ -321,7 +361,7 @@ public enum Feature {
* with reference to source or not. If source reference is included, its type and contents
* are included when `toString()` method is called (most notably when printing out parse
* exception with that location information). If feature is disabled, no source reference
- * is passed and source is only indicated as "UNKNOWN".
+ * is passed and source is only indicated as "REDACTED".
*
* Most common reason for disabling this feature is to avoid leaking information about
* internal information; this may be done for security reasons.
@@ -352,7 +392,7 @@ public enum Feature {
/**
* Feature that determines whether to use the built-in Java code for parsing
- * BigDecimals and BigIntegerss or to use
+ * BigDecimals and BigIntegers or to use
* specifically optimized custom implementation instead.
*
* This setting is disabled by default for backwards compatibility.
@@ -741,22 +781,36 @@ public JsonLocation currentTokenLocation() {
return getTokenLocation();
}
- // TODO: deprecate in 2.14 or later
/**
- * Alias for {@link #currentLocation()}, to be deprecated in later
- * Jackson 2.x versions (and removed from Jackson 3.0).
+ * Get an approximate count of the number of tokens that have been read.
+ * This count is likely to be only updated if {@link StreamReadConstraints.Builder#maxTokenCount(long)}
+ * has been used to set a limit on the number of tokens that can be read.
+ *
+ * @return the number of tokens that have been read (-1 if the count is not available)
+ * @since 2.18
+ */
+ public long currentTokenCount() {
+ return -1L;
+ }
+
+ /**
+ * Deprecated alias for {@link #currentLocation()} (removed from Jackson 3.0).
*
* @return Location of the last processed input unit (byte or character)
+ *
+ * @deprecated Since 2.17 use {@link #currentLocation()} instead
*/
+ @Deprecated // since 2.17
public abstract JsonLocation getCurrentLocation();
- // TODO: deprecate in 2.14 or later
/**
- * Alias for {@link #currentTokenLocation()}, to be deprecated in later
- * Jackson 2.x versions (and removed from Jackson 3.0).
+ * Deprecated alias for {@link #currentTokenLocation()} (removed from Jackson 3.0).
*
* @return Starting location of the token parser currently points to
+ *
+ * @deprecated Since 2.17 use {@link #currentTokenLocation()} instead
*/
+ @Deprecated // since 2.17
public abstract JsonLocation getTokenLocation();
/**
@@ -775,8 +829,21 @@ public JsonLocation currentTokenLocation() {
* @since 2.13 (added as replacement for older {@link #getCurrentValue()}
*/
public Object currentValue() {
- // TODO: implement directly in 2.14 or later, make getCurrentValue() call this
- return getCurrentValue();
+ // Note: implemented directly in 2.17, no longer delegating to getCurrentValue()
+ JsonStreamContext ctxt = getParsingContext();
+ return (ctxt == null) ? null : ctxt.getCurrentValue();
+ }
+
+ /**
+ * Deprecated alias for {@link #currentValue()} (removed from Jackson 3.0).
+ *
+ * @return Location of the last processed input unit (byte or character)
+ *
+ * @deprecated Since 2.17 use {@link #currentValue()} instead
+ */
+ @Deprecated // since 2.17
+ public Object getCurrentValue() {
+ return currentValue();
}
/**
@@ -790,34 +857,23 @@ public Object currentValue() {
* @since 2.13 (added as replacement for older {@link #setCurrentValue}
*/
public void assignCurrentValue(Object v) {
- // TODO: implement directly in 2.14 or later, make setCurrentValue() call this
- setCurrentValue(v);
- }
-
- // TODO: deprecate in 2.14 or later
- /**
- * Alias for {@link #currentValue()}, to be deprecated in later
- * Jackson 2.x versions (and removed from Jackson 3.0).
- *
- * @return Location of the last processed input unit (byte or character)
- */
- public Object getCurrentValue() {
+ // Note: implemented directly in 2.17, no longer delegating to setCurrentValue()
JsonStreamContext ctxt = getParsingContext();
- return (ctxt == null) ? null : ctxt.getCurrentValue();
+ if (ctxt != null) {
+ ctxt.setCurrentValue(v);
+ }
}
- // TODO: deprecate in 2.14 or later
/**
- * Alias for {@link #assignCurrentValue}, to be deprecated in later
- * Jackson 2.x versions (and removed from Jackson 3.0).
+ * Deprecated alias for {@link #assignCurrentValue(Object)} (removed from Jackson 3.0).
*
* @param v Current value to assign for the current input context of this parser
+ *
+ * @deprecated Since 2.17 use {@link #assignCurrentValue} instead
*/
+ @Deprecated // since 2.17
public void setCurrentValue(Object v) {
- JsonStreamContext ctxt = getParsingContext();
- if (ctxt != null) {
- ctxt.setCurrentValue(v);
- }
+ assignCurrentValue(v);
}
/*
@@ -1041,7 +1097,7 @@ public JsonParser overrideFormatFeatures(int values, int mask) {
* time to get the value for the field.
* Method is most useful for iterating over value entries
* of JSON objects; field name will still be available
- * by calling {@link #getCurrentName} when parser points to
+ * by calling {@link #currentName} when parser points to
* the value.
*
* @return Next non-field-name token from the stream, if any found,
@@ -1060,7 +1116,7 @@ public JsonParser overrideFormatFeatures(int values, int mask) {
* and returns result of that comparison.
* It is functionally equivalent to:
*
* but may be faster for parser to verify, and can therefore be used if caller
* expects to get such a property name from input next.
@@ -1075,13 +1131,13 @@ public JsonParser overrideFormatFeatures(int values, int mask) {
* {@link JsonParseException} for decoding problems
*/
public boolean nextFieldName(SerializableString str) throws IOException {
- return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
+ return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(currentName());
}
/**
* Method that fetches next token (as if calling {@link #nextToken}) and
* verifies whether it is {@link JsonToken#FIELD_NAME}; if it is,
- * returns same as {@link #getCurrentName()}, otherwise null.
+ * returns same as {@link #currentName()}, otherwise null.
*
* @return Name of the the {@code JsonToken.FIELD_NAME} parser advanced to, if any;
* {@code null} if next token is of some other type
@@ -1092,7 +1148,7 @@ public boolean nextFieldName(SerializableString str) throws IOException {
* @since 2.5
*/
public String nextFieldName() throws IOException {
- return (nextToken() == JsonToken.FIELD_NAME) ? getCurrentName() : null;
+ return (nextToken() == JsonToken.FIELD_NAME) ? currentName() : null;
}
/**
@@ -1198,7 +1254,7 @@ public Boolean nextBooleanValue() throws IOException {
/**
* Method that will skip all child tokens of an array or
* object token that the parser currently points to,
- * iff stream points to
+ * if (and only if) stream points to
* {@link JsonToken#START_OBJECT} or {@link JsonToken#START_ARRAY}.
* If not, it will do nothing.
* After skipping, stream will point to matching
@@ -1234,7 +1290,7 @@ public Boolean nextBooleanValue() throws IOException {
* @since 2.8
*/
public void finishToken() throws IOException {
- ; // nothing
+ // nothing to do
}
/*
@@ -1257,6 +1313,7 @@ public void finishToken() throws IOException {
* @since 2.8
*/
public JsonToken currentToken() {
+ // !!! TODO: switch direction in 2.18 or later
return getCurrentToken();
}
@@ -1397,21 +1454,26 @@ public int currentTokenId() {
public boolean isExpectedNumberIntToken() { return currentToken() == JsonToken.VALUE_NUMBER_INT; }
/**
- * Access for checking whether current token is a numeric value token, but
- * one that is of "not-a-number" (NaN) variety (including both "NaN" AND
- * positive/negative infinity!): not supported by all formats,
- * but often supported for {@link JsonToken#VALUE_NUMBER_FLOAT}.
- * NOTE: roughly equivalent to calling !Double.isFinite()
- * on value you would get from calling {@link #getDoubleValue()}.
+ * Accessor for checking whether current token is a special
+ * "not-a-number" (NaN) token (including both "NaN" AND
+ * positive/negative infinity!). These values are not supported by all formats:
+ * JSON, for example, only supports them if
+ * {@link JsonReadFeature#ALLOW_NON_NUMERIC_NUMBERS} is enabled.
+ *
+ * NOTE: in case where numeric value is outside range of requested type --
+ * most notably {@link java.lang.Float} or {@link java.lang.Double} -- and
+ * decoding results effectively in a NaN value, this method DOES NOT return
+ * {@code true}: only explicit incoming markers do.
+ * This is because value could still be accessed as a valid {@link BigDecimal}.
*
- * @return {@code True} if the current token is of type {@link JsonToken#VALUE_NUMBER_FLOAT}
- * but represents a "Not a Number"; {@code false} for other tokens and regular
- * floating-point numbers
+ * @return {@code True} if the current token is reported as {@link JsonToken#VALUE_NUMBER_FLOAT}
+ * and represents a "Not a Number" value; {@code false} for other tokens and regular
+ * floating-point numbers.
*
* @throws IOException for low-level read issues, or
* {@link JsonParseException} for decoding problems
*
- * @since 2.9
+ * @since 2.9 (slight change in semantics in 2.17)
*/
public boolean isNaN() throws IOException {
return false;
@@ -1467,15 +1529,17 @@ public boolean isNaN() throws IOException {
/**********************************************************
*/
- // TODO: deprecate in 2.14 or later
/**
- * Alias of {@link #currentName()}.
+ * Deprecated alias of {@link #currentName()}.
*
* @return Name of the current field in the parsing context
*
* @throws IOException for low-level read issues, or
* {@link JsonParseException} for decoding problems
+ *
+ * @deprecated Since 2.17 use {@link #currentName} instead.
*/
+ @Deprecated
public abstract String getCurrentName() throws IOException;
/**
@@ -1493,6 +1557,7 @@ public boolean isNaN() throws IOException {
* @since 2.10
*/
public String currentName() throws IOException {
+ // !!! TODO: switch direction in 2.18 or later
return getCurrentName();
}
@@ -1521,6 +1586,12 @@ public String currentName() throws IOException {
* but should typically be more efficient as longer content does need to
* be combined into a single String to return, and write
* can occur directly from intermediate buffers Jackson uses.
+ *
+ * NOTE: textual content will still be buffered (usually
+ * using {@link TextBuffer}) and will be accessible with
+ * other {@code getText()} calls (that is, it will not be consumed).
+ * So this accessor only avoids construction of {@link java.lang.String}
+ * compared to plain {@link #getText()} method.
*
* @param writer Writer to write textual content to
*
@@ -1701,7 +1772,7 @@ public Object getNumberValueDeferred() throws IOException {
* If current token is of type
* {@link JsonToken#VALUE_NUMBER_INT} or
* {@link JsonToken#VALUE_NUMBER_FLOAT}, returns
- * one of {@link NumberType} constants; otherwise returns null.
+ * one of {@link NumberType} constants; otherwise returns {@code null}.
*
* @return Type of current number, if parser points to numeric token; {@code null} otherwise
*
@@ -1710,6 +1781,38 @@ public Object getNumberValueDeferred() throws IOException {
*/
public abstract NumberType getNumberType() throws IOException;
+ /**
+ * If current token is of type
+ * {@link JsonToken#VALUE_NUMBER_FLOAT}, returns
+ * one of {@link NumberTypeFP} constants; otherwise returns
+ * {@link NumberTypeFP#UNKNOWN}.
+ *
+ * Default implementation as of Jackson 2.x will call {@link #getNumberType()}
+ * and translate types -- this needs to be overriden actual implementations
+ * if this is not sufficient (which it usually is not for textual formats).
+ *
+ * @return Type of current floating-point number, if parser points to numeric token;
+ * {@link NumberTypeFP#UNKNOWN} otherwise.
+ *
+ * @throws IOException for low-level read issues, or
+ * {@link JsonParseException} for decoding problems
+ *
+ * @since 2.17
+ */
+ public NumberTypeFP getNumberTypeFP() throws IOException {
+ NumberType nt = getNumberType();
+ if (nt == NumberType.BIG_DECIMAL) {
+ return NumberTypeFP.BIG_DECIMAL;
+ }
+ if (nt == NumberType.DOUBLE) {
+ return NumberTypeFP.DOUBLE64;
+ }
+ if (nt == NumberType.FLOAT) {
+ return NumberTypeFP.FLOAT32;
+ }
+ return NumberTypeFP.UNKNOWN;
+ }
+
/**
* Numeric accessor that can be called when the current
* token is of type {@link JsonToken#VALUE_NUMBER_INT} and
@@ -2539,4 +2642,25 @@ protected JsonParseException _constructReadException(String msg, Throwable t) {
}
return e;
}
+
+ /**
+ * Helper method for constructing {@link JsonParseException}
+ * based on current state of the parser, except for specified
+ * {@link JsonLocation} for problem location (which may not be
+ * the exact current location)
+ *
+ * @param msg Base exception message to construct exception with
+ * @param loc Error location to report
+ *
+ * @return Read exception (of type {@link JsonParseException}) constructed
+ *
+ * @since 2.13
+ */
+ protected JsonParseException _constructReadException(String msg, JsonLocation loc) {
+ JsonParseException e = new JsonParseException(this, msg, loc);
+ if (_requestPayload != null) {
+ e = e.withRequestPayload(_requestPayload);
+ }
+ return e;
+ }
}
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
index 17c0cbcb08..51f1978a65 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonPointer.java
@@ -25,10 +25,46 @@
*/
public class JsonPointer implements Serializable
{
+ /**
+ * Escape character {@value #ESC} per RFC6901.
+ *
+ *
+ * @since 2.17
+ */
+ public static final String ESC_TILDE = "~0";
+
private static final long serialVersionUID = 1L;
/**
* Character used to separate segments.
+ *
+ * json-pointer = *( "/" reference-token )
+ *
*
* @since 2.9
*/
@@ -158,7 +194,7 @@ public static JsonPointer compile(String expr) throws IllegalArgumentException
return EMPTY;
}
// And then quick validity check:
- if (expr.charAt(0) != '/') {
+ if (expr.charAt(0) != SEPARATOR) {
throw new IllegalArgumentException("Invalid input: JSON Pointer expression must start with '/': "+"\""+expr+"\"");
}
return _parseTail(expr);
@@ -249,7 +285,7 @@ public static JsonPointer forPath(JsonStreamContext context,
// Let's find the last segment as well, for reverse traversal
last = next;
next.pathOffset = pathBuilder.length();
- pathBuilder.append('/');
+ pathBuilder.append(SEPARATOR);
if (next.property != null) {
_appendEscaped(pathBuilder, next.property);
} else {
@@ -281,15 +317,15 @@ private static void _appendEscaped(StringBuilder sb, String segment)
{
for (int i = 0, end = segment.length(); i < end; ++i) {
char c = segment.charAt(i);
- if (c == '/') {
- sb.append("~1");
- continue;
- }
- if (c == '~') {
- sb.append("~0");
- continue;
- }
- sb.append(c);
+ if (c == SEPARATOR) {
+ sb.append(ESC_SLASH);
+ continue;
+ }
+ if (c == ESC) {
+ sb.append(ESC_TILDE);
+ continue;
+ }
+ sb.append(c);
}
}
@@ -374,51 +410,59 @@ public JsonPointer append(JsonPointer tail) {
// 21-Mar-2017, tatu: Not superbly efficient; could probably improve by not concatenating,
// re-decoding -- by stitching together segments -- but for now should be fine.
- String currentJsonPointer = _asString;
+ String currentJsonPointer = toString();
+
+ // 14-Dec-2023, tatu: Pre-2.17 had special handling which makes no sense:
+ /*
if (currentJsonPointer.endsWith("/")) {
//removes final slash
currentJsonPointer = currentJsonPointer.substring(0, currentJsonPointer.length()-1);
}
- return compile(currentJsonPointer + tail._asString);
+ */
+ return compile(currentJsonPointer + tail.toString());
}
/**
- * ATTENTION! {@link JsonPointer} is head centric, tail appending is much costlier than head appending.
- * It is not recommended to overuse the method.
+ * ATTENTION! {@link JsonPointer} is head-centric, tail appending is much costlier
+ * than head appending.
+ * It is recommended that this method is used sparingly due to possible
+ * sub-par performance.
*
- * Mutant factory method that will return
+ * Mutant factory method that will return:
*
- *
`this` instance if `property` is null or empty String, OR
+ *
`this` instance if `property` is null, OR
*
*
Newly constructed {@link JsonPointer} instance that starts with all segments
* of `this`, followed by new segment of 'property' name.
*
*
- *
- * 'property' format is starting separator (optional, added automatically if not provided) and new segment name.
+ * 'property' is name to match: value is escaped as necessary (for any contained
+ * slashes or tildes).
+ *
+ * NOTE! Before Jackson 2.17, no escaping was performed, and leading slash was
+ * dropped if passed. This was incorrect implementation. Empty {@code property}
+ * was also ignored (similar to {@code null}).
*
* @param property new segment property name
*
* @return Either `this` instance, or a newly created combination, as per description above.
*/
public JsonPointer appendProperty(String property) {
- if (property == null || property.isEmpty()) {
+ if (property == null) {
return this;
}
- if (property.charAt(0) != SEPARATOR) {
- property = SEPARATOR + property;
- }
- String currentJsonPointer = _asString;
- if (currentJsonPointer.endsWith("/")) {
- //removes final slash
- currentJsonPointer = currentJsonPointer.substring(0, currentJsonPointer.length()-1);
- }
- return compile(currentJsonPointer + property);
+ // 14-Dec-2023, tatu: [core#1145] Must escape `property`; accept empty String
+ // as valid segment to match as well
+ StringBuilder sb = toStringBuilder(property.length() + 2).append(SEPARATOR);
+ _appendEscaped(sb, property);
+ return compile(sb.toString());
}
/**
- * ATTENTION! {@link JsonPointer} is head centric, tail appending is much costlier than head appending.
- * It is not recommended to overuse the method.
+ * ATTENTION! {@link JsonPointer} is head-centric, tail appending is much costlier
+ * than head appending.
+ * It is recommended that this method is used sparingly due to possible
+ * sub-par performance.
*
* Mutant factory method that will return newly constructed {@link JsonPointer} instance that starts with all
* segments of `this`, followed by new segment of element 'index'. Element 'index' should be non-negative.
@@ -432,12 +476,9 @@ public JsonPointer appendIndex(int index) {
if (index < 0) {
throw new IllegalArgumentException("Negative index cannot be appended");
}
- String currentJsonPointer = _asString;
- if (currentJsonPointer.endsWith("/")) {
- //removes final slash
- currentJsonPointer = currentJsonPointer.substring(0, currentJsonPointer.length()-1);
- }
- return compile(currentJsonPointer + SEPARATOR + index);
+ // 14-Dec-2024, tatu: Used to have odd logic for removing "trailing" slash;
+ // removed from 2.17
+ return compile(toStringBuilder(8).append(SEPARATOR).append(index).toString());
}
/**
@@ -556,14 +597,39 @@ public JsonPointer head() {
/**********************************************************
*/
- @Override public String toString() {
+ @Override
+ public String toString() {
if (_asStringOffset <= 0) {
return _asString;
}
return _asString.substring(_asStringOffset);
}
- @Override public int hashCode() {
+ /**
+ * Functionally equivalent to:
+ *
+ * new StringBuilder(toString());
+ *
+ * but possibly more efficient
+ *
+ * @param slack Number of characters to reserve in StringBuilder beyond
+ * minimum copied
+ * @return a new StringBuilder
+ *
+ * @since 2.17
+ */
+ protected StringBuilder toStringBuilder(int slack) {
+ if (_asStringOffset <= 0) {
+ return new StringBuilder(_asString);
+ }
+ final int len = _asString.length();
+ StringBuilder sb = new StringBuilder(len - _asStringOffset + slack);
+ sb.append(_asString, _asStringOffset, len);
+ return sb;
+ }
+
+ @Override
+ public int hashCode() {
int h = _hashCode;
if (h == 0) {
// Alas, this is bit wasteful, creating temporary String, but
@@ -578,7 +644,8 @@ public JsonPointer head() {
return h;
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (o == this) return true;
if (o == null) return false;
if (!(o instanceof JsonPointer)) return false;
@@ -636,10 +703,11 @@ private final static int _parseIndex(String str) {
}
}
if (len == 10) {
- long l = NumberInput.parseLong(str);
+ long l = Long.parseLong(str);
if (l > Integer.MAX_VALUE) {
return -1;
}
+ return (int) l;
}
return NumberInput.parseInt(str);
}
@@ -655,7 +723,7 @@ protected static JsonPointer _parseTail(final String fullPath)
while (i < end) {
char c = fullPath.charAt(i);
- if (c == '/') { // common case, got a segment
+ if (c == SEPARATOR) { // common case, got a segment
parent = new PointerParent(parent, startOffset,
fullPath.substring(startOffset + 1, i));
startOffset = i;
@@ -664,7 +732,7 @@ protected static JsonPointer _parseTail(final String fullPath)
}
++i;
// quoting is different; offline this case
- if (c == '~' && i < end) { // possibly, quote
+ if (c == ESC && i < end) { // possibly, quote
// 04-Oct-2022, tatu: Let's decode escaped segment
// instead of recursive call
StringBuilder sb = new StringBuilder(32);
@@ -719,11 +787,11 @@ protected static int _extractEscapedSegment(String input, int firstCharOffset,
_appendEscape(sb, input.charAt(i++));
while (i < end) {
char c = input.charAt(i);
- if (c == '/') { // end is nigh!
+ if (c == SEPARATOR) { // end is nigh!
return i;
}
++i;
- if (c == '~' && i < end) {
+ if (c == ESC && i < end) {
_appendEscape(sb, input.charAt(i++));
continue;
}
@@ -735,11 +803,11 @@ protected static int _extractEscapedSegment(String input, int firstCharOffset,
private static void _appendEscape(StringBuilder sb, char c) {
if (c == '0') {
- c = '~';
+ c = ESC;
} else if (c == '1') {
- c = '/';
+ c = SEPARATOR;
} else {
- sb.append('~');
+ sb.append(ESC);
}
sb.append(c);
}
@@ -754,7 +822,6 @@ protected JsonPointer _constructHead()
// and from that, length of suffix to drop
int suffixLength = last.length();
JsonPointer next = _nextSegment;
- // !!! TODO 07-Oct-2022, tatu: change to iterative, not recursive
String fullString = toString();
return new JsonPointer(fullString.substring(0, fullString.length() - suffixLength), 0,
_matchingPropertyName,
diff --git a/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java b/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java
index b703fa11a7..a1aa43314e 100644
--- a/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java
+++ b/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java
@@ -23,6 +23,9 @@
*
Maximum Document length: default {@code unlimited} (coded as {@code -1},
* (see {@link #DEFAULT_MAX_DOC_LEN})
*
+ *
Maximum Token count: default {@code unlimited} (coded as {@code -1},
+ * (see {@link #DEFAULT_MAX_TOKEN_COUNT})
+ *
*
*
* @since 2.15
@@ -43,6 +46,12 @@ public class StreamReadConstraints
*/
public static final long DEFAULT_MAX_DOC_LEN = -1L;
+ /**
+ * Default setting for maximum token count:
+ * see {@link Builder#maxTokenCount} for details.
+ */
+ public static final long DEFAULT_MAX_TOKEN_COUNT = -1L;
+
/**
* @since 2.16
*/
@@ -74,6 +83,7 @@ public class StreamReadConstraints
protected final int _maxNestingDepth;
protected final long _maxDocLen;
+ protected final long _maxTokenCount;
protected final int _maxNumLen;
protected final int _maxStringLen;
@@ -112,6 +122,7 @@ public static void overrideDefaultStreamReadConstraints(final StreamReadConstrai
public static final class Builder {
private long maxDocLen;
+ private long maxTokenCount;
private int maxNestingDepth;
private int maxNumLen;
private int maxStringLen;
@@ -140,7 +151,7 @@ public Builder maxNestingDepth(final int maxNestingDepth) {
* The length is in input units of the input source, that is, in
* {@code byte}s or {@code char}s.
*
- * @param maxDocLen the maximum allowed document if positive number above 0; otherwise
+ * @param maxDocLen the maximum allowed document length if positive number above 0; otherwise
* ({@code 0} or negative number) means "unlimited".
*
* @return this builder
@@ -156,6 +167,31 @@ public Builder maxDocumentLength(long maxDocLen) {
return this;
}
+ /**
+ * Sets the maximum allowed token count (for positive values over 0) or
+ * indicate that any count is acceptable ({@code 0} or negative number).
+ *
+ *
+ * A token is a single unit of input, such as a number, a string, an object
+ * start or end, or an array start or end.
+ *
+ *
+ * @param maxTokenCount the maximum allowed token count if positive number above 0; otherwise
+ * ({@code 0} or negative number) means "unlimited".
+ *
+ * @return this builder
+ *
+ * @since 2.18
+ */
+ public Builder maxTokenCount(long maxTokenCount) {
+ // Negative values and 0 mean "unlimited", mark with -1L
+ if (maxTokenCount <= 0L) {
+ maxTokenCount = -1L;
+ }
+ this.maxTokenCount = maxTokenCount;
+ return this;
+ }
+
/**
* Sets the maximum number length (in chars or bytes, depending on input context).
* The default is 1000.
@@ -220,14 +256,15 @@ public Builder maxNameLength(final int maxNameLen) {
}
Builder() {
- this(DEFAULT_MAX_DEPTH, DEFAULT_MAX_DOC_LEN,
+ this(DEFAULT_MAX_DEPTH, DEFAULT_MAX_DOC_LEN, DEFAULT_MAX_TOKEN_COUNT,
DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN, DEFAULT_MAX_NAME_LEN);
}
- Builder(final int maxNestingDepth, final long maxDocLen,
+ Builder(final int maxNestingDepth, final long maxDocLen, final long maxTokenCount,
final int maxNumLen, final int maxStringLen, final int maxNameLen) {
this.maxNestingDepth = maxNestingDepth;
this.maxDocLen = maxDocLen;
+ this.maxTokenCount = maxTokenCount;
this.maxNumLen = maxNumLen;
this.maxStringLen = maxStringLen;
this.maxNameLen = maxNameLen;
@@ -236,6 +273,7 @@ public Builder maxNameLength(final int maxNameLen) {
Builder(StreamReadConstraints src) {
maxNestingDepth = src._maxNestingDepth;
maxDocLen = src._maxDocLen;
+ maxTokenCount = src._maxTokenCount;
maxNumLen = src._maxNumLen;
maxStringLen = src._maxStringLen;
maxNameLen = src._maxNameLen;
@@ -243,7 +281,7 @@ public Builder maxNameLength(final int maxNameLen) {
public StreamReadConstraints build() {
return new StreamReadConstraints(maxNestingDepth, maxDocLen,
- maxNumLen, maxStringLen, maxNameLen);
+ maxNumLen, maxStringLen, maxNameLen, maxTokenCount);
}
}
@@ -256,8 +294,8 @@ public StreamReadConstraints build() {
@Deprecated // since 2.16
protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
final int maxNumLen, final int maxStringLen) {
- this(maxNestingDepth, DEFAULT_MAX_DOC_LEN,
- maxNumLen, maxStringLen, DEFAULT_MAX_NAME_LEN);
+ this(maxNestingDepth, maxDocLen,
+ maxNumLen, maxStringLen, DEFAULT_MAX_NAME_LEN, DEFAULT_MAX_TOKEN_COUNT);
}
/**
@@ -269,13 +307,30 @@ protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
*
* @since 2.16
*/
+ @Deprecated // since 2.18
+ protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
+ final int maxNumLen, final int maxStringLen, final int maxNameLen) {
+ this(maxNestingDepth, maxDocLen, maxNumLen, maxStringLen, maxNameLen, DEFAULT_MAX_TOKEN_COUNT);
+ }
+
+ /**
+ * @param maxNestingDepth Maximum input document nesting to allow
+ * @param maxDocLen Maximum input document length to allow
+ * @param maxNumLen Maximum number representation length to allow
+ * @param maxStringLen Maximum String value length to allow
+ * @param maxNameLen Maximum Object property name length to allow
+ * @param maxTokenCount Maximum number of tokens to allow
+ *
+ * @since 2.18
+ */
protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
- final int maxNumLen, final int maxStringLen, final int maxNameLen) {
+ final int maxNumLen, final int maxStringLen, final int maxNameLen, final long maxTokenCount) {
_maxNestingDepth = maxNestingDepth;
_maxDocLen = maxDocLen;
_maxNumLen = maxNumLen;
_maxStringLen = maxStringLen;
_maxNameLen = maxNameLen;
+ _maxTokenCount = maxTokenCount;
}
public static Builder builder() {
@@ -337,6 +392,31 @@ public boolean hasMaxDocumentLength() {
return _maxDocLen > 0L;
}
+ /**
+ * Accessor for maximum token count.
+ * see {@link Builder#maxTokenCount(long)} for details.
+ *
+ * @return Maximum allowed token count
+ * @since 2.18
+ */
+ public long getMaxTokenCount() {
+ return _maxTokenCount;
+ }
+
+ /**
+ * Convenience method, basically same as:
+ *
+ * getMaxTokenCount() > 0L
+ *
+ *
+ * @return {@code True} if this constraints instance has a limit for maximum
+ * token count to enforce; {@code false} otherwise.
+ * @since 2.18
+ */
+ public boolean hasMaxTokenCount() {
+ return _maxTokenCount > 0L;
+ }
+
/**
* Accessor for maximum length of numbers to decode.
* see {@link Builder#maxNumberLength(int)} for details.
@@ -419,6 +499,31 @@ public void validateDocumentLength(long len) throws StreamConstraintsException
}
}
+ /**
+ * Convenience method that can be used to verify that the
+ * token count does not exceed the maximum specified by this
+ * constraints object (if any): if it does, a
+ * {@link StreamConstraintsException}
+ * is thrown.
+ *
+ * @param count Current token count for processed document content
+ *
+ * @throws StreamConstraintsException If length exceeds maximum
+ *
+ * @since 2.18
+ */
+ public void validateTokenCount(long count) throws StreamConstraintsException
+ {
+ // for performance reasons, it is assumed that users check hasMaxTokenCount()
+ // before calling this method - this method will not work properly if hasMaxTokenCount() is false
+ if (count > _maxTokenCount) {
+ throw _constructException(
+ "Token count (%d) exceeds the maximum allowed (%d, from %s)",
+ count, _maxTokenCount,
+ _constrainRef("getMaxTokenCount"));
+ }
+ }
+
/*
/**********************************************************************
/* Convenience methods for validation, token lengths
diff --git a/src/main/java/com/fasterxml/jackson/core/StreamReadFeature.java b/src/main/java/com/fasterxml/jackson/core/StreamReadFeature.java
index d49a132db0..eb22be4832 100644
--- a/src/main/java/com/fasterxml/jackson/core/StreamReadFeature.java
+++ b/src/main/java/com/fasterxml/jackson/core/StreamReadFeature.java
@@ -104,7 +104,7 @@ public enum StreamReadFeature
/**
* Feature that determines whether to use the built-in Java code for parsing
- * BigDecimals and BigIntegerss or to use
+ * BigDecimals and BigIntegers or to use
* {@code FastDoubleParser} instead.
*
* This setting is disabled by default.
diff --git a/src/main/java/com/fasterxml/jackson/core/StreamWriteFeature.java b/src/main/java/com/fasterxml/jackson/core/StreamWriteFeature.java
index a30c23ea9b..7a10fb21a7 100644
--- a/src/main/java/com/fasterxml/jackson/core/StreamWriteFeature.java
+++ b/src/main/java/com/fasterxml/jackson/core/StreamWriteFeature.java
@@ -115,11 +115,17 @@ public enum StreamWriteFeature
/**
* Feature that determines whether to use standard Java code to write floats/doubles
- * (default) or use the Schubfach algorithm which is faster.
- * The latter approach may lead to small differences in the precision of the
- * float/double that is written to the JSON output.
+ * (default) or use the Schubfach algorithm which may be faster (but see the next
+ * paragraph for details).
+ * Schubfach algorithm output may have small differences in the precision of the
+ * float/double that compared to JDK default processing.
*
- * Feature is disabled by default, meaning that slower JDK default conversions are used.
+ * NOTE! Enabling this feature appears to improve performance significantly
+ * up to and including JDK 17, but NOT when using JDK 21
+ * and above -- in fact, it seems that JDK implementation is slightly faster.
+ * Because of this,enabling this feature is only recommended for JDKs 17 and below.
+ *
+ * Feature is disabled by default, meaning that JDK default conversions are used.
*
* @since 2.14
*/
diff --git a/src/main/java/com/fasterxml/jackson/core/TSFBuilder.java b/src/main/java/com/fasterxml/jackson/core/TSFBuilder.java
index 63a4589160..c255b59b47 100644
--- a/src/main/java/com/fasterxml/jackson/core/TSFBuilder.java
+++ b/src/main/java/com/fasterxml/jackson/core/TSFBuilder.java
@@ -162,7 +162,7 @@ protected static List _copy(List src) {
if (src == null) {
return src;
}
- return new ArrayList(src);
+ return new ArrayList<>(src);
}
// // // Accessors
diff --git a/src/main/java/com/fasterxml/jackson/core/TreeNode.java b/src/main/java/com/fasterxml/jackson/core/TreeNode.java
index 242ec3d322..c2c64fc559 100644
--- a/src/main/java/com/fasterxml/jackson/core/TreeNode.java
+++ b/src/main/java/com/fasterxml/jackson/core/TreeNode.java
@@ -228,7 +228,7 @@ public interface TreeNode
TreeNode path(int index);
/**
- * Method for accessing names of all fields for this node, iff
+ * Method for accessing names of all fields for this node, if (and only if)
* this node is an Object node. Number of field names accessible
* will be {@link #size}.
*
diff --git a/src/main/java/com/fasterxml/jackson/core/Version.java b/src/main/java/com/fasterxml/jackson/core/Version.java
index d70e5e193b..464acdb797 100644
--- a/src/main/java/com/fasterxml/jackson/core/Version.java
+++ b/src/main/java/com/fasterxml/jackson/core/Version.java
@@ -5,6 +5,8 @@
package com.fasterxml.jackson.core;
+import java.util.Objects;
+
/**
* Object that encapsulates versioning information of a component.
* Version information includes not just version number but also
@@ -79,7 +81,9 @@ public Version(int major, int minor, int patchLevel, String snapshotInfo,
*/
public boolean isUnknownVersion() { return (this == UNKNOWN_VERSION); }
- public boolean isSnapshot() { return (_snapshotInfo != null && _snapshotInfo.length() > 0); }
+ public boolean isSnapshot() {
+ return (_snapshotInfo != null) && !_snapshotInfo.isEmpty();
+ }
/**
* @return {@code True} if this instance is the one returned by
@@ -101,7 +105,8 @@ public String toFullString() {
return _groupId + '/' + _artifactId + '/' + toString();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(_majorVersion).append('.');
sb.append(_minorVersion).append('.');
@@ -112,9 +117,11 @@ public String toFullString() {
return sb.toString();
}
- @Override public int hashCode() {
- return _artifactId.hashCode() ^ _groupId.hashCode() ^ _snapshotInfo.hashCode()
- + _majorVersion - _minorVersion + _patchLevel;
+ @Override
+ public int hashCode() {
+ return _artifactId.hashCode() ^ _groupId.hashCode()
+ ^ Objects.hashCode(_snapshotInfo)
+ + _majorVersion - _minorVersion + _patchLevel;
}
@Override
@@ -127,7 +134,7 @@ public boolean equals(Object o)
return (other._majorVersion == _majorVersion)
&& (other._minorVersion == _minorVersion)
&& (other._patchLevel == _patchLevel)
- && other._snapshotInfo.equals(_snapshotInfo)
+ && Objects.equals(other._snapshotInfo, _snapshotInfo)
&& other._artifactId.equals(_artifactId)
&& other._groupId.equals(_groupId)
;
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 75b87d2539..db136e28b4 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/GeneratorBase.java
@@ -1,16 +1,17 @@
package com.fasterxml.jackson.core.base;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.io.UTF8Writer;
import com.fasterxml.jackson.core.json.DupDetector;
import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.json.PackageVersion;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigDecimal;
-
/**
* This base class implements part of API that a JSON generator exposes
* to applications, adds shared internal methods that sub-classes
@@ -150,13 +151,15 @@ protected GeneratorBase(int features, ObjectCodec codec, IOContext ioContext, Js
*/
@Override public Version version() { return PackageVersion.VERSION; }
+ // Overridden from JsonGenerator for direct context access:
@Override
- public Object getCurrentValue() {
+ public Object currentValue() {
return _writeContext.getCurrentValue();
}
@Override
- public void setCurrentValue(Object v) {
+ // Overridden from JsonGenerator for direct context access:
+ public void assignCurrentValue(Object v) {
if (_writeContext != null) {
_writeContext.setCurrentValue(v);
}
@@ -294,7 +297,19 @@ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
* base type in 2.8 to allow for overriding by subtypes that use
* custom context type.
*/
- @Override public JsonStreamContext getOutputContext() { return _writeContext; }
+ @Override
+ public JsonStreamContext getOutputContext() { return _writeContext; }
+
+ /**
+ * Accessor for use by {@code jackson-core} itself (tests in particular).
+ *
+ * @return {@link IOContext} in use by this generator
+ *
+ * @since 2.17
+ */
+ public IOContext ioContext() {
+ return _ioContext;
+ }
/*
/**********************************************************
@@ -312,7 +327,7 @@ public void writeStartObject(Object forValue) throws IOException
{
writeStartObject();
if (forValue != null) {
- setCurrentValue(forValue);
+ assignCurrentValue(forValue);
}
}
@@ -519,8 +534,7 @@ protected final int _decodeSurrogate(int surr1, int surr2) throws IOException
"Incomplete surrogate pair: first char 0x%04X, second 0x%04X", surr1, surr2);
_reportError(msg);
}
- int c = 0x10000 + ((surr1 - SURR1_FIRST) << 10) + (surr2 - SURR2_FIRST);
- return c;
+ return (surr1 << 10) + surr2 + UTF8Writer.SURROGATE_BASE;
}
/*
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 8188d31fb8..65f169badc 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
@@ -41,11 +41,9 @@ public abstract class ParserBase extends ParserMinimalBase
*/
protected final IOContext _ioContext;
- /**
- * @since 2.15
- */
- protected final StreamReadConstraints _streamReadConstraints;
-
+ // Demoted to ParserMinimalBase in 2.18
+ //protected final StreamReadConstraints _streamReadConstraints;
+
/**
* Flag that indicates whether parser is closed or not. Gets
* set when parser is either closed by explicit call
@@ -217,6 +215,21 @@ public abstract class ParserBase extends ParserMinimalBase
*/
protected String _numberString;
+ /**
+ * Marker for explicit "Not a Number" (NaN) values that may be read
+ * by some formats: this includes positive and negative infinity,
+ * as well as "NaN" result for some arithmetic operations.
+ *
+ * In case of JSON, such values can only be handled with non-standard
+ * processing: for some other formats they can be passed normally.
+ *
+ * NOTE: this marker is NOT set in case of value overflow/underflow for
+ * {@code double} or {@code float} values.
+ *
+ * @since 2.17
+ */
+ protected boolean _numberIsNaN;
+
// And then other information about value itself
/**
@@ -252,26 +265,24 @@ public abstract class ParserBase extends ParserMinimalBase
*/
protected ParserBase(IOContext ctxt, int features) {
- super(features);
+ super(features, ctxt.streamReadConstraints());
_ioContext = ctxt;
- final StreamReadConstraints streamReadConstraints = ctxt.streamReadConstraints();
- _streamReadConstraints = streamReadConstraints == null ?
- StreamReadConstraints.defaults() : streamReadConstraints;
_textBuffer = ctxt.constructReadConstrainedTextBuffer();
DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
? DupDetector.rootDetector(this) : null;
_parsingContext = JsonReadContext.createRootContext(dups);
}
- @Override public Version version() { return PackageVersion.VERSION; }
+ @Override
+ public Version version() { return PackageVersion.VERSION; }
@Override
- public Object getCurrentValue() {
+ public Object currentValue() {
return _parsingContext.getCurrentValue();
}
@Override
- public void setCurrentValue(Object v) {
+ public void assignCurrentValue(Object v) {
_parsingContext.setCurrentValue(v);
}
@@ -358,7 +369,9 @@ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
* Method that can be called to get the name associated with
* the current event.
*/
- @Override public String getCurrentName() throws IOException {
+ @Deprecated // since 2.17
+ @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();
@@ -369,7 +382,8 @@ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
return _parsingContext.getCurrentName();
}
- @Override public void overrideCurrentName(String name) {
+ @Override
+ public void overrideCurrentName(String name) {
// Simple, but need to look for START_OBJECT/ARRAY's "off-by-one" thing:
JsonReadContext ctxt = _parsingContext;
if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
@@ -409,6 +423,7 @@ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures)
* that starts the current token.
*/
@Override
+ @Deprecated // since 2.17
public JsonLocation getTokenLocation() {
return new JsonLocation(_contentReference(),
-1L, getTokenCharacterOffset(), // bytes, chars
@@ -421,6 +436,7 @@ public JsonLocation getTokenLocation() {
* usually for error reporting purposes
*/
@Override
+ @Deprecated // since 2.17
public JsonLocation getCurrentLocation() {
int col = _inputPtr - _currInputRowStart + 1; // 1-based
return new JsonLocation(_contentReference(),
@@ -504,7 +520,7 @@ protected void _releaseBuffers() throws IOException {
/**
* Method called when an EOF is encountered between tokens.
- * If so, it may be a legitimate EOF, but only iff there
+ * If so, it may be a legitimate EOF, but only if there
* is no open non-root context.
*/
@Override
@@ -571,6 +587,7 @@ protected final JsonToken resetInt(boolean negative, int intLen)
// May throw StreamConstraintsException:
_streamReadConstraints.validateIntegerLength(intLen);
_numberNegative = negative;
+ _numberIsNaN = false;
_intLength = intLen;
_fractLength = 0;
_expLength = 0;
@@ -584,6 +601,7 @@ protected final JsonToken resetFloat(boolean negative, int intLen, int fractLen,
// May throw StreamConstraintsException:
_streamReadConstraints.validateFPLength(intLen + fractLen + expLen);
_numberNegative = negative;
+ _numberIsNaN = false;
_intLength = intLen;
_fractLength = fractLen;
_expLength = expLen;
@@ -597,17 +615,15 @@ protected final JsonToken resetAsNaN(String valueStr, double value)
_textBuffer.resetWithString(valueStr);
_numberDouble = value;
_numTypesValid = NR_DOUBLE;
+ _numberIsNaN = true;
return JsonToken.VALUE_NUMBER_FLOAT;
}
@Override
public boolean isNaN() throws IOException {
- if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) {
- if ((_numTypesValid & NR_DOUBLE) != 0) {
- return !Double.isFinite(_getNumberDouble());
- }
- }
- return false;
+ // 01-Dec-2023, tatu: [core#1137] Only return explicit NaN
+ return (_currToken == JsonToken.VALUE_NUMBER_FLOAT)
+ && _numberIsNaN;
}
/*
@@ -831,6 +847,7 @@ public double getDoubleValue() throws IOException
if (_numTypesValid == NR_UNKNOWN) {
_parseNumericValue(NR_DOUBLE);
}
+ // if underlying type not FP, need conversion:
if ((_numTypesValid & NR_DOUBLE) == 0) {
convertNumberToDouble();
}
@@ -852,11 +869,6 @@ public BigDecimal getDecimalValue() throws IOException
return _getBigDecimal();
}
- @Override // @since 2.15
- public StreamReadConstraints streamReadConstraints() {
- return _streamReadConstraints;
- }
-
/*
/**********************************************************
/* Conversion from textual to numeric representation
@@ -976,17 +988,19 @@ private void _parseSlowFloat(int expType) throws IOException
if (expType == NR_BIGDECIMAL) {
// 04-Dec-2022, tatu: Let's defer actual decoding until it is certain
// value is actually needed.
- _numberBigDecimal = null;
- _numberString = _textBuffer.contentsAsString();
+ // 24-Jun-2024, tatu: No; we shouldn't have to defer unless specifically
+ // request w/ `getNumberValueDeferred()` or so
+ _numberBigDecimal = _textBuffer.contentsAsDecimal(isEnabled(StreamReadFeature.USE_FAST_BIG_NUMBER_PARSER));
_numTypesValid = NR_BIGDECIMAL;
+ } else if (expType == NR_DOUBLE) {
+ _numberDouble = _textBuffer.contentsAsDouble(isEnabled(StreamReadFeature.USE_FAST_DOUBLE_PARSER));
+ _numTypesValid = NR_DOUBLE;
} else if (expType == NR_FLOAT) {
- _numberFloat = 0.0f;
- _numberString = _textBuffer.contentsAsString();
+ _numberFloat = _textBuffer.contentsAsFloat(isEnabled(StreamReadFeature.USE_FAST_DOUBLE_PARSER));
_numTypesValid = NR_FLOAT;
- } else {
- // Otherwise double has to do
- // 04-Dec-2022, tatu: We can get all kinds of values here, NR_DOUBLE
- // but also NR_INT or even NR_UNKNOWN. Shouldn't we try further
+ } else { // NR_UNKOWN, or one of int types
+ // 04-Dec-2022, tatu: We can get all kinds of values here
+ // (NR_INT, NR_LONG or even NR_UNKNOWN). Should we try further
// deferring some typing?
_numberDouble = 0.0;
_numberString = _textBuffer.contentsAsString();
@@ -1034,7 +1048,7 @@ protected void convertNumberToInt() throws IOException
if ((_numTypesValid & NR_LONG) != 0) {
// Let's verify its lossless conversion by simple roundtrip
int result = (int) _numberLong;
- if (((long) result) != _numberLong) {
+ if (result != _numberLong) {
reportOverflowInt(getText(), currentToken());
}
_numberInt = result;
@@ -1068,7 +1082,7 @@ protected void convertNumberToInt() throws IOException
protected void convertNumberToLong() throws IOException
{
if ((_numTypesValid & NR_INT) != 0) {
- _numberLong = (long) _numberInt;
+ _numberLong = _numberInt;
} else if ((_numTypesValid & NR_BIGINT) != 0) {
final BigInteger bigInteger = _getBigInteger();
if (BI_MIN_LONG.compareTo(bigInteger) > 0
@@ -1138,14 +1152,14 @@ protected void convertNumberToDouble() throws IOException
_numberDouble = _getBigInteger().doubleValue();
}
} else if ((_numTypesValid & NR_LONG) != 0) {
- _numberDouble = (double) _numberLong;
+ _numberDouble = _numberLong;
} else if ((_numTypesValid & NR_INT) != 0) {
- _numberDouble = (double) _numberInt;
+ _numberDouble = _numberInt;
} else if ((_numTypesValid & NR_FLOAT) != 0) {
if (_numberString != null) {
_numberDouble = _getNumberDouble();
} else {
- _numberDouble = (double) _getNumberFloat();
+ _numberDouble = _getNumberFloat();
}
} else {
_throwInternal();
@@ -1174,9 +1188,9 @@ protected void convertNumberToFloat() throws IOException
_numberFloat = _getBigInteger().floatValue();
}
} else if ((_numTypesValid & NR_LONG) != 0) {
- _numberFloat = (float) _numberLong;
+ _numberFloat = _numberLong;
} else if ((_numTypesValid & NR_INT) != 0) {
- _numberFloat = (float) _numberInt;
+ _numberFloat = _numberInt;
} else if ((_numTypesValid & NR_DOUBLE) != 0) {
if (_numberString != null) {
_numberFloat = _getNumberFloat();
@@ -1230,12 +1244,15 @@ protected BigInteger _convertBigDecimalToBigInteger(BigDecimal bigDec) throws IO
*
* @return {@link BigInteger} value of the current token
*
+ * @throws JsonParseException If parsing fails
+ *
* @since 2.14
*/
protected BigInteger _getBigInteger() throws JsonParseException {
if (_numberBigInt != null) {
return _numberBigInt;
- } else if (_numberString == null) {
+ }
+ if (_numberString == null) {
throw new IllegalStateException("cannot get BigInteger from current parser state");
}
try {
@@ -1256,12 +1273,15 @@ protected BigInteger _getBigInteger() throws JsonParseException {
*
* @return {@link BigDecimal} value of the current token
*
+ * @throws JsonParseException If parsing fails
+ *
* @since 2.14
*/
protected BigDecimal _getBigDecimal() throws JsonParseException {
if (_numberBigDecimal != null) {
return _numberBigDecimal;
- } else if (_numberString == null) {
+ }
+ if (_numberString == null) {
throw new IllegalStateException("cannot get BigDecimal from current parser state");
}
try {
@@ -1282,6 +1302,8 @@ protected BigDecimal _getBigDecimal() throws JsonParseException {
*
* @return {@code double} value of the current token
*
+ * @throws JsonParseException If parsing fails
+ *
* @since 2.15
*/
protected double _getNumberDouble() throws JsonParseException {
@@ -1303,6 +1325,8 @@ protected double _getNumberDouble() throws JsonParseException {
*
* @return {@code float} value of the current token
*
+ * @throws JsonParseException If parsing fails
+ *
* @since 2.15
*/
protected float _getNumberFloat() throws JsonParseException {
@@ -1342,14 +1366,6 @@ protected void createChildObjectContext(final int lineNr, final int colNr) throw
/**********************************************************
*/
- protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException {
- JsonReadContext ctxt = getParsingContext();
- _reportError(String.format(
- "Unexpected close marker '%s': expected '%c' (for %s starting at %s)",
- (char) actCh, expCh, ctxt.typeDesc(),
- ctxt.startLocation(_contentReference())));
- }
-
@SuppressWarnings("deprecation")
protected char _handleUnrecognizedCharacterEscape(char ch) throws JsonProcessingException {
// as per [JACKSON-300]
@@ -1360,8 +1376,17 @@ protected char _handleUnrecognizedCharacterEscape(char ch) throws JsonProcessing
if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
return ch;
}
- _reportError("Unrecognized character escape "+_getCharDesc(ch));
- return ch;
+ throw _constructReadException("Unrecognized character escape "+_getCharDesc(ch),
+ _currentLocationMinusOne());
+ }
+
+ protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException {
+ final JsonReadContext ctxt = getParsingContext();
+ final String msg = String.format(
+ "Unexpected close marker '%s': expected '%c' (for %s starting at %s)",
+ (char) actCh, expCh, ctxt.typeDesc(),
+ ctxt.startLocation(_contentReference()));
+ throw _constructReadException(msg, _currentLocationMinusOne());
}
/**
@@ -1381,7 +1406,7 @@ protected void _throwUnquotedSpace(int i, String ctxtDesc) throws JsonParseExcep
if (!isEnabled(Feature.ALLOW_UNQUOTED_CONTROL_CHARS) || i > INT_SPACE) {
char c = (char) i;
String msg = "Illegal unquoted character ("+_getCharDesc(c)+"): has to be escaped using backslash to be included in "+ctxtDesc;
- _reportError(msg);
+ throw _constructReadException(msg, _currentLocationMinusOne());
}
}
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 2f37c22a73..5f2dc7ff00 100644
--- a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java
@@ -3,9 +3,11 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.exc.InputCoercionException;
+import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.JsonEOFException;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
@@ -106,16 +108,16 @@ public abstract class ParserMinimalBase extends JsonParser
protected final static BigDecimal BD_MIN_INT = new BigDecimal(BI_MIN_INT);
protected final static BigDecimal BD_MAX_INT = new BigDecimal(BI_MAX_INT);
- protected final static long MIN_INT_L = (long) Integer.MIN_VALUE;
- protected final static long MAX_INT_L = (long) Integer.MAX_VALUE;
+ protected final static long MIN_INT_L = Integer.MIN_VALUE;
+ protected final static long MAX_INT_L = Integer.MAX_VALUE;
// These are not very accurate, but have to do... (for bounds checks)
- protected final static double MIN_LONG_D = (double) Long.MIN_VALUE;
- protected final static double MAX_LONG_D = (double) Long.MAX_VALUE;
+ protected final static double MIN_LONG_D = Long.MIN_VALUE;
+ protected final static double MAX_LONG_D = Long.MAX_VALUE;
- protected final static double MIN_INT_D = (double) Integer.MIN_VALUE;
- protected final static double MAX_INT_D = (double) Integer.MAX_VALUE;
+ protected final static double MIN_INT_D = Integer.MIN_VALUE;
+ protected final static double MAX_INT_D = Integer.MAX_VALUE;
/*
/**********************************************************
@@ -133,6 +135,17 @@ public abstract class ParserMinimalBase extends JsonParser
@Deprecated
protected final static int MAX_ERROR_TOKEN_LENGTH = 256;
+ /*
+ /**********************************************************
+ /* Minimal configuration
+ /**********************************************************
+ */
+
+ /**
+ * @since 2.18 (was higher up in {@code ParserBase} before)
+ */
+ protected final StreamReadConstraints _streamReadConstraints;
+
/*
/**********************************************************
/* Minimal generally useful state
@@ -146,6 +159,20 @@ public abstract class ParserMinimalBase extends JsonParser
*/
protected JsonToken _currToken;
+ /**
+ * Current count of tokens, if tracked (see {@link #_trackMaxTokenCount})
+ *
+ * @since 2.18
+ */
+ protected long _tokenCount;
+
+ /**
+ * Whether or not to track the token count due a {@link StreamReadConstraints} maxTokenCount > 0.
+ *
+ * @since 2.18
+ */
+ protected final boolean _trackMaxTokenCount;
+
/**
* Last cleared token, if any: that is, value that was in
* effect when {@link #clearCurrentToken} was called.
@@ -158,8 +185,31 @@ public abstract class ParserMinimalBase extends JsonParser
/**********************************************************
*/
- protected ParserMinimalBase() { super(); }
- protected ParserMinimalBase(int features) { super(features); }
+ @Deprecated // since 2.18
+ protected ParserMinimalBase() {
+ super();
+ _streamReadConstraints = StreamReadConstraints.defaults();
+ _trackMaxTokenCount = _streamReadConstraints.hasMaxTokenCount();
+ }
+
+ @Deprecated // since 2.18
+ protected ParserMinimalBase(int features) {
+ this(features, null);
+ }
+
+ // @since 2.18
+ protected ParserMinimalBase(StreamReadConstraints src) {
+ super();
+ _streamReadConstraints = (src == null) ? StreamReadConstraints.defaults() : src;
+ _trackMaxTokenCount = _streamReadConstraints.hasMaxTokenCount();
+ }
+
+ // @since 2.18
+ protected ParserMinimalBase(int features, StreamReadConstraints src) {
+ super(features);
+ _streamReadConstraints = (src == null) ? StreamReadConstraints.defaults() : src;
+ _trackMaxTokenCount = _streamReadConstraints.hasMaxTokenCount();
+ }
// NOTE: had base impl in 2.3 and before; but shouldn't
// public abstract Version version();
@@ -177,6 +227,11 @@ public abstract class ParserMinimalBase extends JsonParser
//public void setFeature(Feature f, boolean state)
//public boolean isFeatureEnabled(Feature f)
+ @Override // @since 2.18 (demoted from ParserBase)
+ public StreamReadConstraints streamReadConstraints() {
+ return _streamReadConstraints;
+ }
+
/*
/**********************************************************
/* JsonParser impl
@@ -273,10 +328,10 @@ public JsonParser skipChildren() throws IOException
*/
protected abstract void _handleEOF() throws JsonParseException;
- //public JsonToken getCurrentToken()
- //public boolean hasCurrentToken()
+ @Deprecated // since 2.17 -- still need to implement
+ @Override
+ public abstract String getCurrentName() throws IOException;
- @Override public abstract String getCurrentName() throws IOException;
@Override public abstract void close() throws IOException;
@Override public abstract boolean isClosed();
@@ -286,6 +341,11 @@ public JsonParser skipChildren() throws IOException
// public abstract JsonLocation getCurrentLocation();
+ @Override // since 2.18
+ public long currentTokenCount() {
+ return _tokenCount;
+ }
+
/*
/**********************************************************
/* Public API, token state overrides
@@ -458,7 +518,7 @@ public double getValueAsDouble(double defaultValue) throws IOException
if (_hasTextualNull(str)) {
return 0L;
}
- streamReadConstraints().validateFPLength(str.length());
+ _streamReadConstraints.validateFPLength(str.length());
return NumberInput.parseAsDouble(str, defaultValue);
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
@@ -490,7 +550,7 @@ public String getValueAsString(String defaultValue) throws IOException {
return getText();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
if (_currToken == null || _currToken == JsonToken.VALUE_NULL || !_currToken.isScalarValue()) {
return defaultValue;
@@ -552,26 +612,33 @@ protected void _decodeBase64(String str, ByteArrayBuilder builder, Base64Variant
/**********************************************************
*/
- /**
- * @since 2.14
- *
- * @param ch Character that was unexpected
- * @param comment Additional failure comment to add, if any
- *
- * @throws JsonParseException
- */
- protected T _reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException {
- String msg = String.format("Unexpected character (%s) in numeric value", _getCharDesc(ch));
- if (comment != null) {
- msg += ": "+comment;
+ // @since 2.10
+ protected void _reportInputCoercion(String msg, JsonToken inputType, Class> targetType)
+ throws InputCoercionException {
+ throw new InputCoercionException(this, msg, inputType, targetType);
+ }
+
+ protected void _reportInvalidEOF() throws JsonParseException {
+ _reportInvalidEOF(" in "+_currToken, _currToken);
+ }
+
+ // @since 2.8
+ protected void _reportInvalidEOFInValue(JsonToken type) throws JsonParseException {
+ String msg;
+ if (type == JsonToken.VALUE_STRING) {
+ msg = " in a String value";
+ } else if ((type == JsonToken.VALUE_NUMBER_INT)
+ || (type == JsonToken.VALUE_NUMBER_FLOAT)) {
+ msg = " in a Number value";
+ } else {
+ msg = " in a value";
}
- _reportError(msg);
- return null; // never gets here
+ _reportInvalidEOF(msg, type);
}
- @Deprecated // @since 2.14
- protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException {
- _reportUnexpectedNumberChar(ch, comment);
+ // @since 2.8
+ protected void _reportInvalidEOF(String msg, JsonToken currToken) throws JsonParseException {
+ throw new JsonEOFException(this, currToken, "Unexpected end-of-input"+msg);
}
/**
@@ -585,7 +652,11 @@ protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonPar
* @throws JsonParseException Exception that describes problem with number validity
*/
protected void reportInvalidNumber(String msg) throws JsonParseException {
- _reportError("Invalid numeric value: "+msg);
+ throw _constructReadException("Invalid numeric value: "+msg);
+ }
+
+ protected void _reportMissingRootWS(int ch) throws JsonParseException {
+ _reportUnexpectedChar(ch, "Expected space separating root-level values");
}
/**
@@ -634,12 +705,6 @@ protected void reportOverflowLong(String numDesc, JsonToken inputType) throws IO
inputType, Long.TYPE);
}
- // @since 2.10
- protected void _reportInputCoercion(String msg, JsonToken inputType, Class> targetType)
- throws InputCoercionException {
- throw new InputCoercionException(this, msg, inputType, targetType);
- }
-
// @since 2.9.8
protected String _longIntegerDesc(String rawNum) {
int rawLen = rawNum.length();
@@ -673,61 +738,38 @@ protected void _reportUnexpectedChar(int ch, String comment) throws JsonParseExc
if (comment != null) {
msg += ": "+comment;
}
- _reportError(msg);
- }
-
- protected void _reportInvalidEOF() throws JsonParseException {
- _reportInvalidEOF(" in "+_currToken, _currToken);
- }
-
- // @since 2.8
- protected void _reportInvalidEOFInValue(JsonToken type) throws JsonParseException {
- String msg;
- if (type == JsonToken.VALUE_STRING) {
- msg = " in a String value";
- } else if ((type == JsonToken.VALUE_NUMBER_INT)
- || (type == JsonToken.VALUE_NUMBER_FLOAT)) {
- msg = " in a Number value";
- } else {
- msg = " in a value";
- }
- _reportInvalidEOF(msg, type);
- }
-
- // @since 2.8
- protected void _reportInvalidEOF(String msg, JsonToken currToken) throws JsonParseException {
- throw new JsonEOFException(this, currToken, "Unexpected end-of-input"+msg);
+ throw _constructReadException(msg, _currentLocationMinusOne());
}
/**
- * @deprecated Since 2.8 use {@link #_reportInvalidEOF(String, JsonToken)} instead
+ * @since 2.14
*
- * @throws JsonParseException Exception that describes problem with end-of-content within value
- */
- @Deprecated // since 2.8
- protected void _reportInvalidEOFInValue() throws JsonParseException {
- _reportInvalidEOF(" in a value");
- }
-
- /**
- * @param msg Addition message snippet to append to base exception message
- * @deprecated Since 2.8 use {@link #_reportInvalidEOF(String, JsonToken)} instead
+ * @param ch Character that was unexpected
+ * @param comment Additional failure comment to add, if any
+ * @param Nominal type for bogus return value
*
- * @throws JsonParseException Exception that describes problem with end-of-content within value
+ * @return Nothing, just declared to let caller use {@code return} when
+ * calling this method, to keep compiler happy.
+ *
+ * @throws JsonParseException constructed with {@link #_constructReadException(String, JsonLocation)}
*/
- @Deprecated // since 2.8
- protected void _reportInvalidEOF(String msg) throws JsonParseException {
- throw new JsonEOFException(this, null, "Unexpected end-of-input"+msg);
+ protected T _reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException {
+ String msg = String.format("Unexpected character (%s) in numeric value", _getCharDesc(ch));
+ if (comment != null) {
+ msg += ": "+comment;
+ }
+ throw _constructReadException(msg, _currentLocationMinusOne());
}
- protected void _reportMissingRootWS(int ch) throws JsonParseException {
- _reportUnexpectedChar(ch, "Expected space separating root-level values");
+ @Deprecated // @since 2.14
+ protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException {
+ _reportUnexpectedNumberChar(ch, comment);
}
-
+
protected void _throwInvalidSpace(int i) throws JsonParseException {
char c = (char) i;
String msg = "Illegal character ("+_getCharDesc(c)+"): only regular white space (\\r, \\n, \\t) is allowed between tokens";
- _reportError(msg);
+ throw _constructReadException(msg);
}
/*
@@ -736,6 +778,27 @@ protected void _throwInvalidSpace(int i) throws JsonParseException {
/**********************************************************
*/
+ protected final JsonParseException _constructError(String msg, Throwable t) {
+ return _constructReadException(msg, t);
+ }
+
+ /**
+ * Factory method used to provide location for cases where we must read
+ * and consume a single "wrong" character (to possibly allow error recovery),
+ * but need to report accurate location for that character: if so, the
+ * current location is past location we want, and location we want will be
+ * "one location earlier".
+ *
+ * Default implementation simply returns {@link #currentLocation()}
+ *
+ * @since 2.17
+ *
+ * @return Same as {@link #currentLocation()} except offset by -1
+ */
+ protected JsonLocation _currentLocationMinusOne() {
+ return currentLocation();
+ }
+
protected final static String _getCharDesc(int ch)
{
char c = (char) ch;
@@ -749,29 +812,62 @@ protected final static String _getCharDesc(int ch)
}
protected final void _reportError(String msg) throws JsonParseException {
- throw _constructError(msg);
+ throw _constructReadException(msg);
}
// @since 2.9
protected final void _reportError(String msg, Object arg) throws JsonParseException {
- throw _constructError(String.format(msg, arg));
+ throw _constructReadException(msg, arg);
}
// @since 2.9
protected final void _reportError(String msg, Object arg1, Object arg2) throws JsonParseException {
- throw _constructError(String.format(msg, arg1, arg2));
+ throw _constructReadException(msg, arg1, arg2);
+ }
+
+ protected final void _throwInternal() {
+ VersionUtil.throwInternal();
+ }
+
+ // @since 2.17
+ protected final T _throwInternalReturnAny() {
+ return VersionUtil.throwInternalReturnAny();
}
protected final void _wrapError(String msg, Throwable t) throws JsonParseException {
- throw _constructError(msg, t);
+ throw _constructReadException(msg, t);
}
- protected final void _throwInternal() {
- VersionUtil.throwInternal();
+ /*
+ /**********************************************************
+ /* Helper methods, other
+ /**********************************************************
+ */
+
+ // for performance reasons, this method assumes that the input token is non-null
+ protected final JsonToken _updateToken(final JsonToken token) throws StreamConstraintsException {
+ _currToken = token;
+ if (_trackMaxTokenCount) {
+ _streamReadConstraints.validateTokenCount(++_tokenCount);
+ }
+ return token;
}
- protected final JsonParseException _constructError(String msg, Throwable t) {
- return new JsonParseException(this, msg, t);
+ // only updates the token count if input token is non-null
+ protected final JsonToken _nullSafeUpdateToken(final JsonToken token) throws StreamConstraintsException {
+ _currToken = token;
+ if (_trackMaxTokenCount && token != null) {
+ _streamReadConstraints.validateTokenCount(++_tokenCount);
+ }
+ return token;
+ }
+
+ protected final JsonToken _updateTokenToNull() {
+ return (_currToken = null);
+ }
+
+ protected final JsonToken _updateTokenToNA() {
+ return (_currToken = JsonToken.NOT_AVAILABLE);
}
@Deprecated // since 2.11
@@ -785,10 +881,6 @@ protected static byte[] _asciiBytes(String str) {
@Deprecated // since 2.11
protected static String _ascii(byte[] b) {
- try {
- return new String(b, "US-ASCII");
- } catch (IOException e) { // never occurs
- throw new RuntimeException(e);
- }
+ return new String(b, StandardCharsets.US_ASCII);
}
}
diff --git a/src/main/java/com/fasterxml/jackson/core/exc/StreamReadException.java b/src/main/java/com/fasterxml/jackson/core/exc/StreamReadException.java
index 8971bf704c..ee5591b00a 100644
--- a/src/main/java/com/fasterxml/jackson/core/exc/StreamReadException.java
+++ b/src/main/java/com/fasterxml/jackson/core/exc/StreamReadException.java
@@ -26,21 +26,28 @@ public abstract class StreamReadException
*/
protected RequestPayload _requestPayload;
+ // @since 2.15
+ protected StreamReadException(String msg) {
+ this(null, msg, null, null);
+ }
+
protected StreamReadException(JsonParser p, String msg) {
- super(msg, (p == null) ? null : p.getCurrentLocation());
- _processor = p;
+ this(p, msg, _currentLocation(p), null);
}
- protected StreamReadException(JsonParser p, String msg, Throwable root) {
- super(msg, (p == null) ? null : p.getCurrentLocation(), root);
- _processor = p;
+ protected StreamReadException(JsonParser p, String msg, Throwable rootCause) {
+ this(p, msg, _currentLocation(p), rootCause);
}
protected StreamReadException(JsonParser p, String msg, JsonLocation loc) {
- super(msg, loc, null);
- _processor = p;
+ this(p, msg, loc, null);
+ }
+
+ protected StreamReadException(String msg, JsonLocation loc, Throwable rootCause) {
+ this(null, msg, loc, rootCause);
}
+ // Canonical constructor
// @since 2.13
protected StreamReadException(JsonParser p, String msg, JsonLocation loc,
Throwable rootCause) {
@@ -48,15 +55,6 @@ protected StreamReadException(JsonParser p, String msg, JsonLocation loc,
_processor = p;
}
- protected StreamReadException(String msg, JsonLocation loc, Throwable rootCause) {
- super(msg, loc, rootCause);
- }
-
- // @since 2.15
- protected StreamReadException(String msg) {
- super(msg);
- }
-
/**
* Fluent method that may be used to assign originating {@link JsonParser},
* to be accessed using {@link #getProcessor()}.
@@ -117,4 +115,9 @@ public String getMessage() {
}
return msg;
}
+
+ // @since 2.17
+ protected static JsonLocation _currentLocation(JsonParser p) {
+ return (p == null) ? null : p.currentLocation();
+ }
}
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 64276c5fd8..759482a671 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
@@ -150,17 +150,20 @@ public int getMatchCount() {
/**********************************************************
*/
- @Override public JsonToken getCurrentToken() { return _currToken; }
@Override public JsonToken currentToken() { return _currToken; }
- @Deprecated // since 2.12
- @Override public final int getCurrentTokenId() {
- return currentTokenId();
- }
+ @Override
+ @Deprecated // since 2.17
+ public JsonToken getCurrentToken() { return _currToken; }
+
@Override public final int currentTokenId() {
final JsonToken t = _currToken;
return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
}
+ @Deprecated // since 2.12
+ @Override public final int getCurrentTokenId() {
+ return currentTokenId();
+ }
@Override public boolean hasCurrentToken() { return _currToken != null; }
@Override public boolean hasTokenId(int id) {
@@ -178,15 +181,31 @@ public int getMatchCount() {
@Override public boolean isExpectedStartArrayToken() { return _currToken == JsonToken.START_ARRAY; }
@Override public boolean isExpectedStartObjectToken() { return _currToken == JsonToken.START_OBJECT; }
- @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
+ @Override
+ public JsonLocation currentLocation() {
+ return delegate.currentLocation();
+ }
+ @Override
+ @Deprecated // since 2.17
+ public JsonLocation getCurrentLocation() {
+ return delegate.getCurrentLocation();
+ }
+
+ @Override
+ public JsonLocation currentTokenLocation() { return delegate.currentTokenLocation(); }
+
+ @Override
+ @Deprecated // since 2.17
+ public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
+
@Override
public JsonStreamContext getParsingContext() {
return _filterContext();
}
- // !!! TODO: Verify it works as expected: copied from standard JSON parser impl
@Override
+ @Deprecated // since 2.17
public String getCurrentName() throws IOException {
JsonStreamContext ctxt = _filterContext();
if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
@@ -419,7 +438,7 @@ public JsonToken nextToken() throws IOException
case ID_FIELD_NAME:
{
- final String name = delegate.getCurrentName();
+ final String name = delegate.currentName();
// note: this will also set 'needToHandleName'
f = _headContext.setFieldName(name);
if (f == TokenFilter.INCLUDE_ALL) {
@@ -609,7 +628,7 @@ protected final JsonToken _nextToken2() throws IOException
case ID_FIELD_NAME:
{
- final String name = delegate.getCurrentName();
+ final String name = delegate.currentName();
f = _headContext.setFieldName(name);
if (f == TokenFilter.INCLUDE_ALL) {
_itemFilter = f;
@@ -796,7 +815,7 @@ protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffR
case ID_FIELD_NAME:
{
- final String name = delegate.getCurrentName();
+ final String name = delegate.currentName();
f = _headContext.setFieldName(name);
if (f == TokenFilter.INCLUDE_ALL) {
_itemFilter = f;
@@ -1046,7 +1065,6 @@ public JsonParser skipChildren() throws IOException
@Override public Object getEmbeddedObject() throws IOException { return delegate.getEmbeddedObject(); }
@Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { return delegate.getBinaryValue(b64variant); }
@Override public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException { return delegate.readBinaryValue(b64variant, out); }
- @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
/*
/**********************************************************
diff --git a/src/main/java/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java b/src/main/java/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java
index 4ffd947a03..d2d8bfb5a7 100644
--- a/src/main/java/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java
+++ b/src/main/java/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java
@@ -54,6 +54,8 @@ public JsonPointerBasedFilter(JsonPointer pathToMatch, boolean includeAllElement
* @param includeAllElements Whether to just include all array elements
* of matching Array-valued path automatically
*
+ * @return Constructed filter
+ *
* @since 2.16
*/
protected JsonPointerBasedFilter construct(JsonPointer pathToMatch, boolean includeAllElements) {
diff --git a/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java b/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java
index 0e42d163e2..2be42744c8 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java
@@ -3,212 +3,178 @@
import ch.randelshofer.fastdoubleparser.JavaBigDecimalParser;
import java.math.BigDecimal;
-import java.util.Arrays;
-
-// Based on a great idea of Eric ObermĂĽhlner to use a tree of smaller BigDecimals for parsing
-// really big numbers with O(n^1.5) complexity instead of O(n^2) when using the constructor
-// for a decimal representation from JDK 8/11:
-//
-// https://github.com/eobermuhlner/big-math/commit/7a5419aac8b2adba2aa700ccf00197f97b2ad89f
/**
- * Helper class used to implement more optimized parsing of {@link BigDecimal} for REALLY
- * big values (over 500 characters)
+ * Internal Jackson Helper class used to implement more optimized parsing of {@link BigDecimal} for REALLY
+ * big values (over 500 characters).
+ *
+ * This class is not meant to be used directly. It is designed to be used by Jackson JSON parsers (and parsers
+ * for other Jackson supported data formats). The parsers check for invalid characters and the length of the number.
+ * Without these checks, this parser is susceptible to performing badly with invalid inputs. If you need to parse
+ * numbers directly, please use JavaBigDecimalParser in fastdoubleparser
+ * instead.
+ *
*
* @since 2.13
*/
public final class BigDecimalParser
{
final static int MAX_CHARS_TO_REPORT = 1000;
+ private final static int SIZE_FOR_SWITCH_TO_FASTDOUBLEPARSER = 500;
private BigDecimalParser() {}
+ /**
+ * Internal Jackson method. Please do not use.
+ *
+ * Note: Caller MUST pre-validate that given String represents a valid representation
+ * of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
+ * code must do the same.
+ *
+ * @param valueStr
+ * @return BigDecimal value
+ * @throws NumberFormatException
+ */
public static BigDecimal parse(String valueStr) {
- return parse(valueStr.toCharArray());
+ try {
+ if (valueStr.length() < SIZE_FOR_SWITCH_TO_FASTDOUBLEPARSER) {
+ return new BigDecimal(valueStr);
+ }
+ return JavaBigDecimalParser.parseBigDecimal(valueStr);
+
+ // 20-Aug-2022, tatu: Although "new BigDecimal(...)" only throws NumberFormatException
+ // operations by "parseBigDecimal()" can throw "ArithmeticException", so handle both:
+ } catch (ArithmeticException | NumberFormatException e) {
+ throw _parseFailure(e, valueStr);
+ }
}
+ /**
+ * Internal Jackson method. Please do not use.
+ *
+ * Note: Caller MUST pre-validate that given String represents a valid representation
+ * of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
+ * code must do the same.
+ *
+ * @return BigDecimal value
+ * @throws NumberFormatException
+ */
public static BigDecimal parse(final char[] chars, final int off, final int len) {
try {
- if (len < 500) {
+ if (len < SIZE_FOR_SWITCH_TO_FASTDOUBLEPARSER) {
return new BigDecimal(chars, off, len);
}
- return parseBigDecimal(chars, off, len, len / 10);
+ return JavaBigDecimalParser.parseBigDecimal(chars, off, len);
// 20-Aug-2022, tatu: Although "new BigDecimal(...)" only throws NumberFormatException
// operations by "parseBigDecimal()" can throw "ArithmeticException", so handle both:
} catch (ArithmeticException | NumberFormatException e) {
- String desc = e.getMessage();
- // 05-Feb-2021, tatu: Alas, JDK mostly has null message so:
- if (desc == null) {
- desc = "Not a valid number representation";
- }
- String stringToReport;
- if (len <= MAX_CHARS_TO_REPORT) {
- stringToReport = new String(chars, off, len);
- } else {
- stringToReport = new String(Arrays.copyOfRange(chars, off, MAX_CHARS_TO_REPORT))
- + "(truncated, full length is " + chars.length + " chars)";
- }
- throw new NumberFormatException("Value \"" + stringToReport
- + "\" can not be represented as `java.math.BigDecimal`, reason: " + desc);
+ throw _parseFailure(e, chars, off, len);
}
}
-
+
+ /**
+ * Internal Jackson method. Please do not use.
+ *
+ * Note: Caller MUST pre-validate that given String represents a valid representation
+ * of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
+ * code must do the same.
+ *
+ * @param chars
+ * @return BigDecimal value
+ * @throws NumberFormatException
+ */
public static BigDecimal parse(char[] chars) {
return parse(chars, 0, chars.length);
}
+ /**
+ * Internal Jackson method. Please do not use.
+ *
+ * Note: Caller MUST pre-validate that given String represents a valid representation
+ * of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
+ * code must do the same.
+ *
+ * @param valueStr
+ * @return BigDecimal value
+ * @throws NumberFormatException
+ */
public static BigDecimal parseWithFastParser(final String valueStr) {
try {
return JavaBigDecimalParser.parseBigDecimal(valueStr);
- } catch (NumberFormatException nfe) {
- final String reportNum = valueStr.length() <= MAX_CHARS_TO_REPORT ?
- valueStr : valueStr.substring(0, MAX_CHARS_TO_REPORT) + " [truncated]";
- throw new NumberFormatException("Value \"" + reportNum
- + "\" can not be represented as `java.math.BigDecimal`, reason: " + nfe.getMessage());
+ } catch (ArithmeticException | NumberFormatException e) {
+ throw _parseFailure(e, valueStr);
}
}
+ /**
+ * Internal Jackson method. Please do not use.
+ *
+ * Note: Caller MUST pre-validate that given String represents a valid representation
+ * of {@link BigDecimal} value: parsers in {@code jackson-core} do that; other
+ * code must do the same.
+ *
+ * @return BigDecimal value
+ * @throws NumberFormatException
+ */
public static BigDecimal parseWithFastParser(final char[] ch, final int off, final int len) {
try {
return JavaBigDecimalParser.parseBigDecimal(ch, off, len);
- } catch (NumberFormatException nfe) {
- final String reportNum = len <= MAX_CHARS_TO_REPORT ?
- new String(ch, off, len) : new String(ch, off, MAX_CHARS_TO_REPORT) + " [truncated]";
- throw new NumberFormatException("Value \"" + reportNum
- + "\" can not be represented as `java.math.BigDecimal`, reason: " + nfe.getMessage());
+ } catch (ArithmeticException | NumberFormatException e) {
+ throw _parseFailure(e, ch, off, len);
}
}
- private static BigDecimal parseBigDecimal(final char[] chars, final int off, final int len, final int splitLen) {
- boolean numHasSign = false;
- boolean expHasSign = false;
- boolean neg = false;
- int numIdx = off;
- int expIdx = -1;
- int dotIdx = -1;
- int scale = 0;
- final int endIdx = off + len;
-
- for (int i = off; i < endIdx; i++) {
- char c = chars[i];
- switch (c) {
- case '+':
- if (expIdx >= 0) {
- if (expHasSign) {
- throw new NumberFormatException("Multiple signs in exponent");
- }
- expHasSign = true;
- } else {
- if (numHasSign) {
- throw new NumberFormatException("Multiple signs in number");
- }
- numHasSign = true;
- numIdx = i + 1;
- }
- break;
- case '-':
- if (expIdx >= 0) {
- if (expHasSign) {
- throw new NumberFormatException("Multiple signs in exponent");
- }
- expHasSign = true;
- } else {
- if (numHasSign) {
- throw new NumberFormatException("Multiple signs in number");
- }
- numHasSign = true;
- neg = true;
- numIdx = i + 1;
- }
- break;
- case 'e':
- case 'E':
- if (expIdx >= 0) {
- throw new NumberFormatException("Multiple exponent markers");
- }
- expIdx = i;
- break;
- case '.':
- if (dotIdx >= 0) {
- throw new NumberFormatException("Multiple decimal points");
- }
- dotIdx = i;
- break;
- default:
- if (dotIdx >= 0 && expIdx == -1) {
- scale++;
- }
- }
- }
-
- int numEndIdx;
- int exp = 0;
- if (expIdx >= 0) {
- numEndIdx = expIdx;
- String expStr = new String(chars, expIdx + 1, endIdx - expIdx - 1);
- exp = Integer.parseInt(expStr);
- scale = adjustScale(scale, exp);
- } else {
- numEndIdx = endIdx;
- }
-
- BigDecimal res;
-
- if (dotIdx >= 0) {
- int leftLen = dotIdx - numIdx;
- BigDecimal left = toBigDecimalRec(chars, numIdx, leftLen, exp, splitLen);
-
- int rightLen = numEndIdx - dotIdx - 1;
- BigDecimal right = toBigDecimalRec(chars, dotIdx + 1, rightLen, exp - rightLen, splitLen);
-
- res = left.add(right);
- } else {
- res = toBigDecimalRec(chars, numIdx, numEndIdx - numIdx, exp, splitLen);
- }
-
- if (scale != 0) {
- res = res.setScale(scale);
+ private static NumberFormatException _parseFailure(Exception e, String fullValue) {
+ String desc = e.getMessage();
+ // 05-Feb-2021, tatu: Alas, JDK mostly has null message so:
+ if (desc == null) {
+ desc = "Not a valid number representation";
}
+ String valueToReport = _getValueDesc(fullValue);
+ return new NumberFormatException(_generateExceptionMessage(valueToReport, desc));
+ }
- if (neg) {
- res = res.negate();
+ private static NumberFormatException _parseFailure(final Exception e,
+ final char[] array,
+ final int offset,
+ final int len) {
+ String desc = e.getMessage();
+ // 05-Feb-2021, tatu: Alas, JDK mostly has null message so:
+ if (desc == null) {
+ desc = "Not a valid number representation";
}
-
- return res;
+ String valueToReport = _getValueDesc(array, offset, len);
+ return new NumberFormatException(_generateExceptionMessage(valueToReport, desc));
}
- private static int adjustScale(int scale, long exp) {
- long adjScale = scale - exp;
- if (adjScale > Integer.MAX_VALUE || adjScale < Integer.MIN_VALUE) {
- throw new NumberFormatException(
- "Scale out of range: " + adjScale + " while adjusting scale " + scale + " to exponent " + exp);
+ private static String _getValueDesc(final String fullValue) {
+ final int len = fullValue.length();
+ if (len <= MAX_CHARS_TO_REPORT) {
+ return String.format("\"%s\"", fullValue);
}
-
- return (int) adjScale;
+ return String.format("\"%s\" (truncated to %d chars (from %d))",
+ fullValue.substring(0, MAX_CHARS_TO_REPORT),
+ MAX_CHARS_TO_REPORT, len);
}
- private static BigDecimal toBigDecimalRec(final char[] chars, final int off, final int len,
- final int scale, final int splitLen) {
- if (len > splitLen) {
- int mid = len / 2;
- BigDecimal left = toBigDecimalRec(chars, off, mid, scale + len - mid, splitLen);
- BigDecimal right = toBigDecimalRec(chars, off + mid, len - mid, scale, splitLen);
-
- return left.add(right);
+ private static String _getValueDesc(final char[] array, final int offset, final int len) {
+ if (len <= MAX_CHARS_TO_REPORT) {
+ return String.format("\"%s\"", new String(array, offset, len));
}
+ return String.format("\"%s\" (truncated to %d chars (from %d))",
+ new String(array, offset, MAX_CHARS_TO_REPORT),
+ MAX_CHARS_TO_REPORT, len);
+ }
- if (len == 0) {
- return BigDecimal.ZERO;
- }
- // 02-Apr-2023, tatu: [core#967] Looks like "scaleByPowerOfThen" avoids performance issue
- // there would be with "movePointRight" (both doing about same thing), so)
- return new BigDecimal(chars, off, len)
-// .movePointRight(scale);
- .scaleByPowerOfTen(scale);
+ private static String _generateExceptionMessage(final String valueToReport, final String desc) {
+ return String.format("Value %s can not be deserialized as `java.math.BigDecimal`, reason: %s" ,
+ valueToReport, desc);
}
+
}
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 abd2d2ea8b..2b2305e1eb 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java
@@ -176,6 +176,16 @@ public final class CharTypes
sOutputEscapes128 = table;
}
+ /**
+ * Lookup table same as {@link #sOutputEscapes128} except that
+ * forward slash ('/') is also escaped
+ */
+ protected final static int[] sOutputEscapes128WithSlash;
+ static {
+ sOutputEscapes128WithSlash = Arrays.copyOf(sOutputEscapes128, sOutputEscapes128.length);
+ sOutputEscapes128WithSlash['/'] = '/';
+ }
+
/**
* Lookup table for the first 256 Unicode characters (ASCII / UTF-8)
* range. For actual hex digits, contains corresponding value;
@@ -233,6 +243,28 @@ public static int[] get7BitOutputEscapes(int quoteChar) {
return AltEscapes.instance.escapesFor(quoteChar);
}
+ /**
+ * Alternative to {@link #get7BitOutputEscapes()} when either a non-standard
+ * quote character is used, or forward slash is to be escaped.
+ *
+ * @param quoteChar Character used for quoting textual values and property names;
+ * usually double-quote but sometimes changed to single-quote (apostrophe)
+ * @param escapeSlash
+ *
+ * @return 128-entry {@code int[]} that contains escape definitions
+ *
+ * @since 2.17
+ */
+ public static int[] get7BitOutputEscapes(int quoteChar, boolean escapeSlash) {
+ if (quoteChar == '"') {
+ if (escapeSlash) {
+ return sOutputEscapes128WithSlash;
+ }
+ return sOutputEscapes128;
+ }
+ return AltEscapes.instance.escapesFor(quoteChar, escapeSlash);
+ }
+
public static int charToHex(int ch)
{
// 08-Nov-2019, tatu: As per [core#540] and [core#578], changed to
@@ -246,7 +278,6 @@ public static char hexToChar(int ch)
return HC[ch];
}
-
/**
* Helper method for appending JSON-escaped version of contents
* into specific {@link StringBuilder}, using default JSON specification
@@ -328,6 +359,9 @@ private static class AltEscapes {
private int[][] _altEscapes = new int[128][];
+ // @since 2.17
+ private int[][] _altEscapesWithSlash = new int[128][];
+
public int[] escapesFor(int quoteChar) {
int[] esc = _altEscapes[quoteChar];
if (esc == null) {
@@ -340,6 +374,20 @@ public int[] escapesFor(int quoteChar) {
}
return esc;
}
+
+ // @since 2.17
+ public int[] escapesFor(int quoteChar, boolean escapeSlash)
+ {
+ if (!escapeSlash) {
+ return escapesFor(quoteChar);
+ }
+ int[] esc = _altEscapesWithSlash[quoteChar];
+ if (esc == null) {
+ esc = escapesFor(quoteChar);
+ esc['/'] = '/';
+ _altEscapesWithSlash[quoteChar] = esc;
+ }
+ return esc;
+ }
}
}
-
diff --git a/src/main/java/com/fasterxml/jackson/core/io/ContentReference.java b/src/main/java/com/fasterxml/jackson/core/io/ContentReference.java
index 6884661b7b..9186d8dcfd 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/ContentReference.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/ContentReference.java
@@ -96,6 +96,9 @@ public class ContentReference
*/
/**
+ * @param isContentTextual Whether content is textual (not binary)
+ * @param rawContent Contents being referenced
+ *
* @deprecated Since 2.16. Use {@link #ContentReference(boolean, Object, ErrorReportConfiguration)} instead.
*/
@Deprecated
@@ -104,6 +107,11 @@ protected ContentReference(boolean isContentTextual, Object rawContent) {
}
/**
+ * @param isContentTextual Whether content is textual (not binary)
+ * @param rawContent Contents being referenced
+ * @param offset Offset of content within {@code rawContent}
+ * @param length Length of content within {@code rawContent}
+ *
* @deprecated Since 2.16. Use {@link #ContentReference(boolean, Object, int, int, ErrorReportConfiguration)} instead.
*/
@Deprecated
@@ -113,17 +121,14 @@ protected ContentReference(boolean isContentTextual, Object rawContent,
this(isContentTextual, rawContent, offset, length, ErrorReportConfiguration.defaults());
}
- /**
- * @since 2.16
- */
+
+ // @since 2.16
protected ContentReference(boolean isContentTextual, Object rawContent, ErrorReportConfiguration errorReportConfiguration)
{
this(isContentTextual, rawContent, -1, -1, errorReportConfiguration);
}
- /**
- * @since 2.16
- */
+ // @since 2.16
protected ContentReference(boolean isContentTextual, Object rawContent,
int offset, int length, ErrorReportConfiguration errorReportConfiguration)
{
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 3a5985664c..41ffe23e76 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java
@@ -64,6 +64,16 @@ public class IOContext implements AutoCloseable
*/
protected final BufferRecycler _bufferRecycler;
+ /**
+ * Flag that indicates whether this context instance should release
+ * configured {@code _bufferRecycler} or not: if it does, it needs to call
+ * (via {@link BufferRecycler#releaseToPool()} when closed; if not,
+ * should do nothing (recycler life-cycle is externally managed)
+ *
+ * @since 2.17
+ */
+ protected boolean _releaseRecycler = true;
+
/**
* @since 2.15
*/
@@ -194,6 +204,20 @@ public IOContext(BufferRecycler br, Object rawContent, boolean managedResource)
this(br, ContentReference.rawReference(rawContent), managedResource);
}
+ /**
+ * Method to call to prevent {@link #_bufferRecycler} release upon
+ * {@link #close()}: called when {@link #_bufferRecycler} life-cycle is
+ * externally managed.
+ *
+ * @return This context instance, for call chaining
+ *
+ * @since 2.17
+ */
+ public IOContext markBufferRecyclerReleased() {
+ _releaseRecycler = false;
+ return this;
+ }
+
/*
/**********************************************************************
/* Public API, accessors
@@ -201,7 +225,7 @@ public IOContext(BufferRecycler br, Object rawContent, boolean managedResource)
*/
/**
- * @return constraints for streaming reads
+ * @return Constraints to use for streaming reads
* @since 2.15
*/
public StreamReadConstraints streamReadConstraints() {
@@ -257,6 +281,11 @@ public ContentReference contentReference() {
@Deprecated
public Object getSourceReference() { return _sourceRef; }
+ // @since 2.17
+ public BufferRecycler bufferRecycler() {
+ return _bufferRecycler;
+ }
+
/*
/**********************************************************************
/* Public API, buffer management
@@ -464,8 +493,11 @@ private IllegalArgumentException wrongBuf() {
@Override
public void close() {
if (!_closed) {
- _bufferRecycler.releaseToPool();
_closed = true;
+ if (_releaseRecycler) {
+ _releaseRecycler = false;
+ _bufferRecycler.releaseToPool();
+ }
}
}
}
diff --git a/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java b/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java
index 87487459af..2095fb08d1 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/JsonStringEncoder.java
@@ -120,7 +120,7 @@ public char[] quoteAsString(String input)
int length = (escCode < 0)
? _appendNumeric(d, qbuf)
: _appendNamed(escCode, qbuf);
- ;
+
if ((outPtr + length) > outputBuffer.length) {
int first = outputBuffer.length - outPtr;
if (first > 0) {
@@ -216,7 +216,7 @@ public char[] quoteAsString(CharSequence input)
int length = (escCode < 0)
? _appendNumeric(d, qbuf)
: _appendNamed(escCode, qbuf);
- ;
+
if ((outPtr + length) > outputBuffer.length) {
int first = outputBuffer.length - outPtr;
if (first > 0) {
@@ -344,7 +344,7 @@ public byte[] quoteAsUTF8(String text)
outputPtr = 0;
}
// Ok, so what did we hit?
- int ch = (int) text.charAt(inputPtr++);
+ int ch = text.charAt(inputPtr++);
if (ch <= 0x7F) { // needs quoting
int escape = escCodes[ch];
// ctrl-char, 6-byte escape...
@@ -659,7 +659,7 @@ private static int _convert(int p1, int p2) {
if (p2 < SURR2_FIRST || p2 > SURR2_LAST) {
throw new IllegalArgumentException("Broken surrogate pair: first char 0x"+Integer.toHexString(p1)+", second 0x"+Integer.toHexString(p2)+"; illegal combination");
}
- return 0x10000 + ((p1 - SURR1_FIRST) << 10) + (p2 - SURR2_FIRST);
+ return (p1 << 10) + p2 + UTF8Writer.SURROGATE_BASE;
}
private static void _illegal(int c) {
diff --git a/src/main/java/com/fasterxml/jackson/core/io/NumberInput.java b/src/main/java/com/fasterxml/jackson/core/io/NumberInput.java
index e216f48a0f..5cef8dbb33 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/NumberInput.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/NumberInput.java
@@ -5,6 +5,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.util.regex.Pattern;
/**
* Helper class for efficient parsing of various JSON numbers.
@@ -31,6 +32,25 @@ public final class NumberInput
final static String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE).substring(1);
final static String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
+ /**
+ * Regexp used to pre-validate "Stringified Numbers": slightly looser than
+ * JSON Number definition (allows leading zeroes, positive sign).
+ *
+ * @since 2.17
+ */
+ private final static Pattern PATTERN_FLOAT = Pattern.compile(
+ "[+-]?[0-9]*[\\.]?[0-9]+([eE][+-]?[0-9]+)?");
+
+
+ /**
+ * Secondary regexp used along with {@code PATTERN_FLOAT} to cover
+ * case where number ends with dot, like {@code "+12."}
+ *
+ * @since 2.17.2
+ */
+ private final static Pattern PATTERN_FLOAT_TRAILING_DOT = Pattern.compile(
+ "[+-]?[0-9]+[\\.]");
+
/**
* Fast method for parsing unsigned integers that are known to fit into
* regular 32-bit signed int type. This means that length is
@@ -146,7 +166,7 @@ public static long parseLong(char[] ch, int off, int len)
// Note: caller must ensure length is [10, 18]
int len1 = len-9;
long val = parseInt(ch, off, len1) * L_BILLION;
- return val + (long) parseInt(ch, off+len1, 9);
+ return val + parseInt(ch, off+len1, 9);
}
/**
@@ -190,7 +210,7 @@ public static long parseLong(String s)
// that is, if we know they must be ints, call int parsing
int length = s.length();
if (length <= 9) {
- return (long) parseInt(s);
+ return parseInt(s);
}
// !!! TODO: implement efficient 2-int parsing...
return Long.parseLong(s);
@@ -357,8 +377,7 @@ public static double parseAsDouble(String s, final double def, final boolean use
{
if (s == null) { return def; }
s = s.trim();
- int len = s.length();
- if (len == 0) {
+ if (s.isEmpty()) {
return def;
}
try {
@@ -372,7 +391,10 @@ public static double parseAsDouble(String s, final double def, final boolean use
* @return closest matching double
* @throws NumberFormatException if string cannot be represented by a double where useFastParser=false
* @see #parseDouble(String, boolean)
+ *
+ * @deprecated Since 2.17 use {@link #parseDouble(String, boolean)} instead
*/
+ @Deprecated // since 2.17
public static double parseDouble(final String s) throws NumberFormatException {
return parseDouble(s, false);
}
@@ -388,13 +410,42 @@ public static double parseDouble(final String s, final boolean useFastParser) th
return useFastParser ? JavaDoubleParser.parseDouble(s) : Double.parseDouble(s);
}
+ /**
+ * @param array a char array containing a number to parse
+ * @param useFastParser whether to use {@code FastDoubleParser}
+ * @return closest matching double
+ * @throws NumberFormatException if value cannot be represented by a double
+ * @since 2.18
+ */
+ public static double parseDouble(final char[] array, final boolean useFastParser) throws NumberFormatException {
+ return parseDouble(array, 0, array.length, useFastParser);
+ }
+
+ /**
+ * @param array a char array containing a number to parse
+ * @param offset the offset to apply when parsing the number in the char array
+ * @param len the length of the number in the char array
+ * @param useFastParser whether to use {@code FastDoubleParser}
+ * @return closest matching double
+ * @throws NumberFormatException if value cannot be represented by a double
+ * @since 2.18
+ */
+ public static double parseDouble(final char[] array, final int offset,
+ final int len, final boolean useFastParser) throws NumberFormatException {
+ return useFastParser ? JavaDoubleParser.parseDouble(array, offset, len) :
+ Double.parseDouble(new String(array, offset, len));
+ }
+
/**
* @param s a string representing a number to parse
* @return closest matching float
* @throws NumberFormatException if string cannot be represented by a float where useFastParser=false
* @see #parseFloat(String, boolean)
* @since v2.14
+ *
+ * @deprecated Since 2.17 use {@link #parseFloat(String, boolean)} instead
*/
+ @Deprecated // since 2.17
public static float parseFloat(final String s) throws NumberFormatException {
return parseFloat(s, false);
}
@@ -407,16 +458,48 @@ public static float parseFloat(final String s) throws NumberFormatException {
* @since v2.14
*/
public static float parseFloat(final String s, final boolean useFastParser) throws NumberFormatException {
- return useFastParser ? JavaFloatParser.parseFloat(s) : Float.parseFloat(s);
+ if (useFastParser) {
+ return JavaFloatParser.parseFloat(s);
+ }
+ return Float.parseFloat(s);
+ }
+
+ /**
+ * @param array a char array containing a number to parse
+ * @param useFastParser whether to use {@code FastDoubleParser}
+ * @return closest matching float
+ * @throws NumberFormatException if value cannot be represented by a float
+ * @since 2.18
+ */
+ public static float parseFloat(final char[] array, final boolean useFastParser) throws NumberFormatException {
+ return parseFloat(array, 0, array.length, useFastParser);
+ }
+
+ /**
+ * @param array a char array containing a number to parse
+ * @param offset the offset to apply when parsing the number in the char array
+ * @param len the length of the number in the char array
+ * @param useFastParser whether to use {@code FastDoubleParser}
+ * @return closest matching float
+ * @throws NumberFormatException if value cannot be represented by a float
+ * @since 2.18
+ */
+ public static float parseFloat(final char[] array, final int offset,
+ final int len, final boolean useFastParser) throws NumberFormatException {
+ return useFastParser ? JavaFloatParser.parseFloat(array, offset, len) :
+ Float.parseFloat(new String(array, offset, len));
}
/**
* @param s a string representing a number to parse
* @return a BigDecimal
* @throws NumberFormatException if the char array cannot be represented by a BigDecimal
+ *
+ * @deprecated Since 2.17 use {@link #parseBigDecimal(String, boolean)} instead
*/
+ @Deprecated // since 2.17
public static BigDecimal parseBigDecimal(final String s) throws NumberFormatException {
- return BigDecimalParser.parse(s);
+ return parseBigDecimal(s, false);
}
/**
@@ -427,9 +510,10 @@ public static BigDecimal parseBigDecimal(final String s) throws NumberFormatExce
* @since v2.15
*/
public static BigDecimal parseBigDecimal(final String s, final boolean useFastParser) throws NumberFormatException {
- return useFastParser ?
- BigDecimalParser.parseWithFastParser(s) :
- BigDecimalParser.parse(s);
+ if (useFastParser) {
+ return BigDecimalParser.parseWithFastParser(s);
+ }
+ return BigDecimalParser.parse(s);
}
/**
@@ -438,7 +522,10 @@ public static BigDecimal parseBigDecimal(final String s, final boolean useFastPa
* @param len the length of the number in the char array
* @return a BigDecimal
* @throws NumberFormatException if the char array cannot be represented by a BigDecimal
+ *
+ * @deprecated Since 2.17 use {@link #parseBigDecimal(char[], int, int, boolean)} instead
*/
+ @Deprecated // since 2.17
public static BigDecimal parseBigDecimal(final char[] ch, final int off, final int len) throws NumberFormatException {
return BigDecimalParser.parse(ch, off, len);
}
@@ -454,17 +541,22 @@ public static BigDecimal parseBigDecimal(final char[] ch, final int off, final i
*/
public static BigDecimal parseBigDecimal(final char[] ch, final int off, final int len,
final boolean useFastParser)
- throws NumberFormatException {
- return useFastParser ?
- BigDecimalParser.parseWithFastParser(ch, off, len) :
- BigDecimalParser.parse(ch, off, len);
+ throws NumberFormatException
+ {
+ if (useFastParser) {
+ return BigDecimalParser.parseWithFastParser(ch, off, len);
+ }
+ return BigDecimalParser.parse(ch, off, len);
}
/**
* @param ch a char array with text that makes up a number
* @return a BigDecimal
* @throws NumberFormatException if the char array cannot be represented by a BigDecimal
+ *
+ * @deprecated Since 2.17 use {@link #parseBigDecimal(char[], boolean)} instead
*/
+ @Deprecated // since 2.17
public static BigDecimal parseBigDecimal(final char[] ch) throws NumberFormatException {
return BigDecimalParser.parse(ch);
}
@@ -477,9 +569,10 @@ public static BigDecimal parseBigDecimal(final char[] ch) throws NumberFormatExc
* @since v2.15
*/
public static BigDecimal parseBigDecimal(final char[] ch, final boolean useFastParser) throws NumberFormatException {
- return useFastParser ?
- BigDecimalParser.parseWithFastParser(ch, 0, ch.length) :
- BigDecimalParser.parse(ch);
+ if (useFastParser) {
+ return BigDecimalParser.parseWithFastParser(ch, 0, ch.length);
+ }
+ return BigDecimalParser.parse(ch);
}
/**
@@ -487,9 +580,12 @@ public static BigDecimal parseBigDecimal(final char[] ch, final boolean useFastP
* @return a BigInteger
* @throws NumberFormatException if string cannot be represented by a BigInteger
* @since v2.14
+ *
+ * @deprecated Since 2.17 use {@link #parseBigInteger(String, boolean)} instead
*/
+ @Deprecated // since 2.17
public static BigInteger parseBigInteger(final String s) throws NumberFormatException {
- return new BigInteger(s);
+ return parseBigInteger(s, false);
}
/**
@@ -502,9 +598,8 @@ public static BigInteger parseBigInteger(final String s) throws NumberFormatExce
public static BigInteger parseBigInteger(final String s, final boolean useFastParser) throws NumberFormatException {
if (useFastParser) {
return BigIntegerParser.parseWithFastParser(s);
- } else {
- return parseBigInteger(s);
}
+ return new BigInteger(s);
}
/**
@@ -516,11 +611,48 @@ public static BigInteger parseBigInteger(final String s, final boolean useFastPa
* @since v2.15
*/
public static BigInteger parseBigIntegerWithRadix(final String s, final int radix,
- final boolean useFastParser) throws NumberFormatException {
+ final boolean useFastParser) throws NumberFormatException {
if (useFastParser) {
return BigIntegerParser.parseWithFastParser(s, radix);
- } else {
- return new BigInteger(s, radix);
}
+ return new BigInteger(s, radix);
+ }
+
+ /**
+ * Method called to check whether given pattern looks like a valid Java
+ * Number (which is bit looser definition than valid JSON Number).
+ * Used as pre-parsing check when parsing "Stringified numbers".
+ *
+ * The differences to stricter JSON Number are:
+ *
+ *
Positive sign is allowed
+ *
+ *
Leading zeroes are allowed
+ *
+ *
+ *
+ * Note: no trimming ({@code String.trim()}) nor null checks are performed
+ * on String passed.
+ *
+ * Note: this method returning {@code true} DOES NOT GUARANTEE String is valid
+ * number but just that it looks close enough.
+ *
+ * @param s String to validate
+ *
+ * @return True if String looks like valid Java number; false otherwise.
+ *
+ * @since 2.17
+ */
+ public static boolean looksLikeValidNumber(final String s) {
+ // While PATTERN_FLOAT handles most cases we can optimize some simple ones:
+ if (s == null || s.isEmpty()) {
+ return false;
+ }
+ if (s.length() == 1) {
+ char c = s.charAt(0);
+ return (c <= '9') && (c >= '0');
+ }
+ return PATTERN_FLOAT.matcher(s).matches()
+ || PATTERN_FLOAT_TRAILING_DOT.matcher(s).matches();
}
}
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 c78c610de1..844692bf85 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/NumberOutput.java
@@ -9,8 +9,8 @@ public final class NumberOutput
private static int BILLION = 1000000000;
private static long BILLION_L = 1000000000L;
- private static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE;
- private static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE;
+ private static long MIN_INT_AS_LONG = Integer.MIN_VALUE;
+ private static long MAX_INT_AS_LONG = Integer.MAX_VALUE;
final static String SMALLEST_INT = String.valueOf(Integer.MIN_VALUE);
final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE);
@@ -85,7 +85,7 @@ public static int outputInt(int v, char[] b, int off)
}
return _leading3(v, b, off);
}
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
v -= (thousands * 1000); // == value % 1000
off = _leading3(thousands, b, off);
off = _full3(v, b, off);
@@ -107,10 +107,10 @@ public static int outputInt(int v, char[] b, int off)
}
return _outputFullBillion(v, b, off);
}
- int newValue = v / 1000;
+ int newValue = divBy1000(v);
int ones = (v - (newValue * 1000)); // == value % 1000
v = newValue;
- newValue /= 1000;
+ newValue = divBy1000(newValue);
int thousands = (v - (newValue * 1000));
off = _leading3(newValue, b, off);
@@ -136,7 +136,7 @@ public static int outputInt(int v, byte[] b, int off)
off = _leading3(v, b, off);
}
} else {
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
v -= (thousands * 1000); // == value % 1000
off = _leading3(thousands, b, off);
off = _full3(v, b, off);
@@ -153,10 +153,10 @@ public static int outputInt(int v, byte[] b, int off)
}
return _outputFullBillion(v, b, off);
}
- int newValue = v / 1000;
+ int newValue = divBy1000(v);
int ones = (v - (newValue * 1000)); // == value % 1000
v = newValue;
- newValue /= 1000;
+ newValue = divBy1000(newValue);
int thousands = (v - (newValue * 1000));
off = _leading3(newValue, b, off);
off = _full3(thousands, b, off);
@@ -245,6 +245,16 @@ public static int outputLong(long v, byte[] b, int off)
return _outputFullBillion((int) v, b, off);
}
+ /**
+ * Optimized code for integer division by 1000; typically 50% higher
+ * throughput for calculation
+ *
+ * @since 2.17
+ */
+ static int divBy1000(int number) {
+ return (int) (number * 274_877_907L >>> 38);
+ }
+
/*
/**********************************************************
/* Convenience serialization methods
@@ -359,13 +369,13 @@ private static int _outputUptoBillion(int v, char[] b, int off)
if (v < 1000) {
return _leading3(v, b, off);
}
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
int ones = v - (thousands * 1000); // == value % 1000
return _outputUptoMillion(b, off, thousands, ones);
}
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
int ones = (v - (thousands * 1000)); // == value % 1000
- int millions = thousands / 1000;
+ int millions = divBy1000(thousands);
thousands -= (millions * 1000);
off = _leading3(millions, b, off);
@@ -385,9 +395,9 @@ private static int _outputUptoBillion(int v, char[] b, int off)
private static int _outputFullBillion(int v, char[] b, int off)
{
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
int ones = (v - (thousands * 1000)); // == value % 1000
- int millions = thousands / 1000;
+ int millions = divBy1000(thousands);
int enc = TRIPLET_TO_CHARS[millions];
b[off++] = (char) (enc >> 16);
@@ -414,13 +424,13 @@ private static int _outputUptoBillion(int v, byte[] b, int off)
if (v < 1000) {
return _leading3(v, b, off);
}
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
int ones = v - (thousands * 1000); // == value % 1000
return _outputUptoMillion(b, off, thousands, ones);
}
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
int ones = (v - (thousands * 1000)); // == value % 1000
- int millions = thousands / 1000;
+ int millions = divBy1000(thousands);
thousands -= (millions * 1000);
off = _leading3(millions, b, off);
@@ -440,9 +450,9 @@ private static int _outputUptoBillion(int v, byte[] b, int off)
private static int _outputFullBillion(int v, byte[] b, int off)
{
- int thousands = v / 1000;
+ int thousands = divBy1000(v);
int ones = (v - (thousands * 1000)); // == value % 1000
- int millions = thousands / 1000;
+ int millions = divBy1000(thousands);
thousands -= (millions * 1000);
int enc = TRIPLET_TO_CHARS[millions];
diff --git a/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java b/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
index 7c5285ed6e..b4db03dc60 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
@@ -13,7 +13,10 @@
* if so, instance of this class can be given as the writer to
* JsonGenerator.
*/
-public final class SegmentedStringWriter extends Writer {
+public final class SegmentedStringWriter
+ extends Writer
+ implements BufferRecycler.Gettable
+{
final private TextBuffer _buffer;
public SegmentedStringWriter(BufferRecycler br) {
@@ -22,9 +25,20 @@ public SegmentedStringWriter(BufferRecycler br) {
}
/*
- /**********************************************************
+ /**********************************************************************
+ /* BufferRecycler.Gettable implementation
+ /**********************************************************************
+ */
+
+ @Override
+ public BufferRecycler bufferRecycler() {
+ return _buffer.bufferRecycler();
+ }
+
+ /*
+ /**********************************************************************
/* java.io.Writer implementation
- /**********************************************************
+ /**********************************************************************
*/
@Override
@@ -59,6 +73,7 @@ public void write(char[] cbuf) throws IOException {
}
@Override
+
public void write(char[] cbuf, int off, int len) throws IOException {
_buffer.append(cbuf, off, len);
}
@@ -79,9 +94,9 @@ public void write(String str, int off, int len) throws IOException {
}
/*
- /**********************************************************
+ /**********************************************************************
/* Extended API
- /**********************************************************
+ /**********************************************************************
*/
/**
diff --git a/src/main/java/com/fasterxml/jackson/core/io/SerializedString.java b/src/main/java/com/fasterxml/jackson/core/io/SerializedString.java
index 4bed330dda..ff0db775cc 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/SerializedString.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/SerializedString.java
@@ -2,6 +2,7 @@
import java.io.*;
import java.nio.ByteBuffer;
+import java.util.Objects;
import com.fasterxml.jackson.core.SerializableString;
@@ -36,23 +37,20 @@ public class SerializedString
* search framework; and they believed this is an important optimization for
* heaviest, multi-core deployed use cases.
*/
- /*
- * 22-Sep-2013, tatu: FWIW, there have been no reports of problems in this
- * area, or anything pointing to it. So I think we are safe up to JDK7
- * and hopefully beyond.
- */
+ // 22-Sep-2013, tatu: FWIW, there have been no reports of problems in this
+ // area, or anything pointing to it. So I think we are safe up to JDK7
+ // and hopefully beyond.
+ // 09-Jun-2024, tatu: Until we are not. As per [core#1274] there are reasons to
+ // believe `volatile` is actually needed, so will be added in 2.18.0
- protected /*volatile*/ byte[] _quotedUTF8Ref;
+ protected volatile byte[] _quotedUTF8Ref;
- protected /*volatile*/ byte[] _unquotedUTF8Ref;
+ protected volatile byte[] _unquotedUTF8Ref;
- protected /*volatile*/ char[] _quotedChars;
+ protected volatile char[] _quotedChars;
public SerializedString(String v) {
- if (v == null) {
- throw new IllegalStateException("Null String illegal for SerializedString");
- }
- _value = v;
+ _value = Objects.requireNonNull(v, "Null String illegal for SerializedString");
}
/*
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 b7561839d1..b2c43c2667 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/UTF8Writer.java
@@ -9,6 +9,11 @@ public final class UTF8Writer extends Writer
final static int SURR2_FIRST = 0xDC00;
final static int SURR2_LAST = 0xDFFF;
+ /**
+ * @since 2.17
+ */
+ public static final int SURROGATE_BASE = 0x10000 - UTF8Writer.SURR2_FIRST - (UTF8Writer.SURR1_FIRST << 10);
+
final private IOContext _context;
private OutputStream _out;
@@ -369,7 +374,7 @@ protected int convertSurrogate(int secondPart)
if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) {
throw new IOException("Broken surrogate pair: first char 0x"+Integer.toHexString(firstPart)+", second 0x"+Integer.toHexString(secondPart)+"; illegal combination");
}
- return 0x10000 + ((firstPart - SURR1_FIRST) << 10) + (secondPart - SURR2_FIRST);
+ return (firstPart << 10) + secondPart + UTF8Writer.SURROGATE_BASE;
}
protected static void illegalSurrogate(int code) throws IOException {
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 f6efe43ffe..f829171cff 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
@@ -411,7 +411,7 @@ private static int skipSpace(InputAccessor acc) throws IOException
private static int skipSpace(InputAccessor acc, byte b) throws IOException
{
while (true) {
- int ch = (int) b & 0xFF;
+ int ch = b & 0xFF;
if (!(ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t')) {
return ch;
}
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 f8e028021d..33b3b921a5 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/DupDetector.java
@@ -58,7 +58,7 @@ public void reset() {
public JsonLocation findLocation() {
// ugly but:
if (_source instanceof JsonParser) {
- return ((JsonParser)_source).getCurrentLocation();
+ return ((JsonParser)_source).currentLocation();
}
// do generators have a way to provide Location? Apparently not...
return null;
@@ -102,7 +102,7 @@ public boolean isDup(String name) throws JsonParseException
return true;
}
if (_seen == null) {
- _seen = new HashSet(16); // 16 is default, seems reasonable
+ _seen = new HashSet<>(16); // 16 is default, seems reasonable
_seen.add(_firstName);
_seen.add(_secondName);
}
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 3c8a2923d2..04288ced6b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonGeneratorImpl.java
@@ -234,23 +234,6 @@ public JacksonFeatureSet getWriteCapabilities() {
return JSON_WRITE_CAPABILITIES;
}
- /*
- /**********************************************************
- /* Misc other accessors
- /**********************************************************
- */
-
- /**
- * Accessor for use by {@code jackson-core} itself (tests in particular).
- *
- * @return {@link IOContext} in use by this generator
- *
- * @since 2.16
- */
- public IOContext ioContext() {
- return _ioContext;
- }
-
/*
/**********************************************************
/* Shared helper methods
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonParserBase.java b/src/main/java/com/fasterxml/jackson/core/json/JsonParserBase.java
new file mode 100644
index 0000000000..07227ca55f
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonParserBase.java
@@ -0,0 +1,133 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.JsonParser.NumberTypeFP;
+import com.fasterxml.jackson.core.base.ParserBase;
+import com.fasterxml.jackson.core.io.CharTypes;
+import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.util.JacksonFeatureSet;
+
+/**
+ * Another intermediate base class, only used by actual JSON-backed parser
+ * implementations.
+ *
+ * @since 2.17
+ */
+public abstract class JsonParserBase
+ extends ParserBase
+{
+ @SuppressWarnings("deprecation")
+ protected final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
+ @SuppressWarnings("deprecation")
+ protected final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
+ @SuppressWarnings("deprecation")
+ protected final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
+ @SuppressWarnings("deprecation")
+ protected final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
+ protected final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
+ protected final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
+ protected final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
+ protected final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
+
+ // Latin1 encoding is not supported, but we do use 8-bit subset for
+ // pre-processing task, to simplify first pass, keep it fast.
+ protected final static int[] INPUT_CODES_LATIN1 = CharTypes.getInputCodeLatin1();
+
+ // This is the main input-code lookup table, fetched eagerly
+ protected final static int[] INPUT_CODES_UTF8 = CharTypes.getInputCodeUtf8();
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Codec used for data binding when (if) requested; typically full
+ * ObjectMapper, but that abstract is not part of core
+ * package.
+ */
+ protected ObjectCodec _objectCodec;
+
+ /*
+ /**********************************************************************
+ /* Life-cycle
+ /**********************************************************************
+ */
+
+ protected JsonParserBase(IOContext ioCtxt, int features, ObjectCodec codec) {
+ super(ioCtxt, features);
+ _objectCodec = codec;
+ }
+
+ @Override
+ public ObjectCodec getCodec() {
+ return _objectCodec;
+ }
+
+ @Override
+ public void setCodec(ObjectCodec c) {
+ _objectCodec = c;
+ }
+
+ /*
+ /**********************************************************************
+ /* Capability introspection
+ /**********************************************************************
+ */
+
+ @Override
+ public final JacksonFeatureSet getReadCapabilities() {
+ return JSON_READ_CAPABILITIES;
+ }
+
+ /*
+ /**********************************************************************
+ /* Overrides
+ /**********************************************************************
+ */
+
+ /**
+ * JSON format does not have native information on "correct" floating-point
+ * type to use, unlike some formats (most binary formats), so it needs to
+ * indicate this as {@link NumberTypeFP#UNKNOWN}.
+ *
+ * @return Natural floating-point type if known; {@link NumberTypeFP#UNKNOWN} for
+ * all JSON-backed parsers.
+ */
+ @Override // added in 2.17
+ public NumberTypeFP getNumberTypeFP() throws IOException {
+ return NumberTypeFP.UNKNOWN;
+ }
+
+ /*
+ /**********************************************************************
+ /* Location handling
+ /**********************************************************************
+ */
+
+ // First: override some methods as abstract to force definition by subclasses
+
+ @Override
+ public abstract JsonLocation currentLocation();
+
+ @Override
+ public abstract JsonLocation currentTokenLocation();
+
+ @Override
+ protected abstract JsonLocation _currentLocationMinusOne();
+
+ @Deprecated // since 2.17
+ @Override
+ public final JsonLocation getCurrentLocation() {
+ return currentLocation();
+ }
+
+ @Deprecated // since 2.17
+ @Override
+ public final JsonLocation getTokenLocation() {
+ return currentTokenLocation();
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteFeature.java b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteFeature.java
index 64f22b0372..356a95f27e 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/JsonWriteFeature.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/JsonWriteFeature.java
@@ -12,7 +12,7 @@ public enum JsonWriteFeature
{
// // // Support for non-standard data format constructs: comments
- // // Quoting/ecsaping-related features
+ // // Quoting/escaping-related features
/**
* Feature that determines whether JSON Object field names are
@@ -108,6 +108,37 @@ public enum JsonWriteFeature
*/
// ESCAPE_UTF8_SURROGATES(false, JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES),
+ /**
+ * Feature that specifies whether {@link JsonGenerator} should escape forward slashes.
+ *
+ * Feature is disabled by default for Jackson 2.x version, and enabled by default in Jackson 3.0.
+ *
+ * @since 2.17
+ */
+ ESCAPE_FORWARD_SLASHES(false, JsonGenerator.Feature.ESCAPE_FORWARD_SLASHES),
+
+ /**
+ * Feature that specifies how characters outside "Basic Multilingual Plane" (BMP) -- ones encoded
+ * as 4-byte UTF-8 sequences but represented in JVM memory as 2 16-bit "surrogate" {@code chars} --
+ * should be encoded as UTF-8 by {@link JsonGenerator}.
+ * If enabled, surrogate pairs are combined and flushed as a
+ * single, 4-byte UTF-8 character.
+ * If disabled, each {@code char} of pair is written as 2 separate characters: that is, as 2
+ * separate 3-byte UTF-8 characters with values in Surrogate character ranges
+ * ({@code 0xD800} - {@code 0xDBFF} and {@code 0xDC00} - {@code 0xDFFF})
+ *
+ * Note that this feature only has effect for {@link JsonGenerator}s that directly encode
+ * {@code byte}-based output, as UTF-8 (target {@link java.io.OutputStream}, {@code byte[]}
+ * and so on); it will not (can not) change handling of
+ * {@code char}-based output (like {@link java.io.Writer} or {@link java.lang.String}).
+ *
+ * Feature is disabled by default in 2.x for backwards-compatibility (will be enabled
+ * in 3.0).
+ *
+ * @since 2.18
+ */
+ COMBINE_UNICODE_SURROGATES_IN_UTF8(false, JsonGenerator.Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8),
+
;
final private boolean _defaultState;
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 27b5cfec2a..4e72b90fb6 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
@@ -3,7 +3,6 @@
import java.io.*;
import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.io.CharTypes;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
@@ -17,29 +16,8 @@
* conversion tasks.
*/
public class ReaderBasedJsonParser
- extends ParserBase
+ extends JsonParserBase
{
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
-
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
-
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
-
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
- private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
- private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
-
- private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
- private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
-
- // Latin1 encoding is not supported, but we do use 8-bit subset for
- // pre-processing task, to simplify first pass, keep it fast.
- protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
-
/*
/**********************************************************
/* Input configuration
@@ -76,9 +54,9 @@ public class ReaderBasedJsonParser
protected ObjectCodec _objectCodec;
- final protected CharsToNameCanonicalizer _symbols;
+ protected final CharsToNameCanonicalizer _symbols;
- final protected int _hashSeed;
+ protected final int _hashSeed;
/*
/**********************************************************
@@ -142,9 +120,8 @@ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
char[] inputBuffer, int start, int end,
boolean bufferRecyclable)
{
- super(ctxt, features);
+ super(ctxt, features, codec);
_reader = r;
- _objectCodec = codec;
_inputBuffer = inputBuffer;
_inputPtr = start;
_inputEnd = end;
@@ -169,12 +146,11 @@ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
ObjectCodec codec, CharsToNameCanonicalizer st)
{
- super(ctxt, features);
+ super(ctxt, features, codec);
_reader = r;
_inputBuffer = ctxt.allocTokenBuffer();
_inputPtr = 0;
_inputEnd = 0;
- _objectCodec = codec;
_symbols = st;
_hashSeed = st.hashSeed();
_bufferRecyclable = true;
@@ -186,14 +162,6 @@ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
/**********************************************************
*/
- @Override public ObjectCodec getCodec() { return _objectCodec; }
- @Override public void setCodec(ObjectCodec c) { _objectCodec = c; }
-
- @Override // @since 2.12
- public JacksonFeatureSet getReadCapabilities() {
- return JSON_READ_CAPABILITIES;
- }
-
@Override
public int releaseBuffered(Writer w) throws IOException {
int count = _inputEnd - _inputPtr;
@@ -277,7 +245,7 @@ protected boolean _loadMore() throws IOException
_currInputProcessed += bufSize;
_currInputRowStart -= bufSize;
// 06-Sep-2023, tatu: [core#1046] Enforce max doc length limit
- streamReadConstraints().validateDocumentLength(_currInputProcessed);
+ _streamReadConstraints.validateDocumentLength(_currInputProcessed);
int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
if (count > 0) {
@@ -372,7 +340,7 @@ public final String getValueAsString() throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(null);
}
@@ -388,7 +356,7 @@ public final String getValueAsString(String defValue) throws IOException {
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(defValue);
}
@@ -707,13 +675,13 @@ public final JsonToken nextToken() throws IOException
// Should actually close/release things
// like input source, symbol table and recyclable buffers now.
close();
- return (_currToken = null);
+ return _updateTokenToNull();
}
// clear any data retained so far
_binaryValue = null;
// Closing scope?
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return _currToken;
}
@@ -724,7 +692,7 @@ public final JsonToken nextToken() throws IOException
// Was that a trailing comma?
if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
- if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return _currToken;
}
@@ -740,7 +708,7 @@ public final JsonToken nextToken() throws IOException
_updateNameLocation();
String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
_parsingContext.setCurrentName(name);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
}
_updateLocation();
@@ -817,8 +785,7 @@ public final JsonToken nextToken() throws IOException
_nextToken = t;
return _currToken;
}
- _currToken = t;
- return t;
+ return _updateToken(t);
}
private final JsonToken _nextAfterName() throws IOException
@@ -835,7 +802,7 @@ private final JsonToken _nextAfterName() throws IOException
} else if (t == JsonToken.START_OBJECT) {
createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
- return (_currToken = t);
+ return _updateToken(t);
}
@Override
@@ -869,13 +836,13 @@ public boolean nextFieldName(SerializableString sstr) throws IOException
int i = _skipWSOrEnd();
if (i < 0) {
close();
- _currToken = null;
+ _updateTokenToNull();
return false;
}
_binaryValue = null;
// Closing scope?
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return false;
}
@@ -885,7 +852,7 @@ public boolean nextFieldName(SerializableString sstr) throws IOException
// Was that a trailing comma?
if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
- if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return false;
}
@@ -945,18 +912,18 @@ public String nextFieldName() throws IOException
int i = _skipWSOrEnd();
if (i < 0) {
close();
- _currToken = null;
+ _updateTokenToNull();
return null;
}
_binaryValue = null;
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return null;
}
if (_parsingContext.expectComma()) {
i = _skipComma(i);
if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
- if ((i == INT_RBRACKET) || (i == INT_RCURLY)) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return null;
}
@@ -971,7 +938,7 @@ public String nextFieldName() throws IOException
_updateNameLocation();
String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
_parsingContext.setCurrentName(name);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
_updateLocation();
@@ -1039,7 +1006,7 @@ public String nextFieldName() throws IOException
private final void _isNextTokenNameYes(int i) throws IOException
{
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
_updateLocation();
switch (i) {
@@ -1099,7 +1066,7 @@ protected boolean _isNextTokenNameMaybe(int i, String nameToMatch) throws IOExce
// // // and this is back to standard nextToken()
String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
_parsingContext.setCurrentName(name);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
_updateLocation();
if (i == INT_QUOTE) {
@@ -1165,32 +1132,32 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
{
if (i == INT_QUOTE) {
_tokenIncomplete = true;
- return (_currToken = JsonToken.VALUE_STRING);
+ return _updateToken(JsonToken.VALUE_STRING);
}
switch (i) {
case '[':
createChildArrayContext(_tokenInputRow, _tokenInputCol);
- return (_currToken = JsonToken.START_ARRAY);
+ return _updateToken(JsonToken.START_ARRAY);
case '{':
createChildObjectContext(_tokenInputRow, _tokenInputCol);
- return (_currToken = JsonToken.START_OBJECT);
+ return _updateToken(JsonToken.START_OBJECT);
case 't':
_matchToken("true", 1);
- return (_currToken = JsonToken.VALUE_TRUE);
+ return _updateToken(JsonToken.VALUE_TRUE);
case 'f':
_matchToken("false", 1);
- return (_currToken = JsonToken.VALUE_FALSE);
+ return _updateToken(JsonToken.VALUE_FALSE);
case 'n':
_matchToken("null", 1);
- return (_currToken = JsonToken.VALUE_NULL);
+ return _updateToken(JsonToken.VALUE_NULL);
case '-':
- return (_currToken = _parseSignedNumber(true));
+ return _updateToken(_parseSignedNumber(true));
/* Should we have separate handling for plus? Although
* it is not allowed per se, it may be erroneously used,
* and could be indicated by a more specific error message.
*/
case '.': // [core#61]]
- return (_currToken = _parseFloatThatStartsWithPeriod(false));
+ return _updateToken(_parseFloatThatStartsWithPeriod(false));
case '0':
case '1':
case '2':
@@ -1201,7 +1168,7 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
case '7':
case '8':
case '9':
- return (_currToken = _parseUnsignedNumber(i));
+ return _updateToken(_parseUnsignedNumber(i));
/*
* This check proceeds only if the Feature.ALLOW_MISSING_VALUES is enabled
* The Check is for missing values. In case of missing values in an array, the next token will be either ',' or ']'.
@@ -1216,11 +1183,11 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
if (!_parsingContext.inRoot()) {
if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) {
--_inputPtr;
- return (_currToken = JsonToken.VALUE_NULL);
+ return _updateToken(JsonToken.VALUE_NULL);
}
}
}
- return (_currToken = _handleOddValue(i));
+ return _updateToken(_handleOddValue(i));
}
// note: identical to one in UTF8StreamJsonParser
@Override
@@ -1230,7 +1197,7 @@ public final String nextTextValue() throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
@@ -1257,7 +1224,7 @@ public final int nextIntValue(int defaultValue) throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_NUMBER_INT) {
return getIntValue();
}
@@ -1280,7 +1247,7 @@ public final long nextLongValue(long defaultValue) throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_NUMBER_INT) {
return getLongValue();
}
@@ -1303,7 +1270,7 @@ public final Boolean nextBooleanValue() throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
@@ -1411,13 +1378,13 @@ protected final JsonToken _parseUnsignedNumber(int ch) throws IOException
_inputPtr = startPtr;
return _parseNumber2(false, startPtr);
}
- ch = (int) _inputBuffer[ptr++];
+ ch = _inputBuffer[ptr++];
if (ch < INT_0 || ch > INT_9) {
break int_loop;
}
++intLen;
}
- if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
+ if (ch == INT_PERIOD || (ch | 0x20) == INT_e) { // ~ '.eE'
_inputPtr = ptr;
return _parseFloat(ch, startPtr, ptr, false, intLen);
}
@@ -1446,7 +1413,7 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg,
if (ptr >= inputLen) {
return _parseNumber2(neg, startPtr);
}
- ch = (int) _inputBuffer[ptr++];
+ ch = _inputBuffer[ptr++];
if (ch < INT_0 || ch > INT_9) {
break fract_loop;
}
@@ -1460,19 +1427,19 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg,
}
}
int expLen = 0;
- if (ch == 'e' || ch == 'E') { // and/or exponent
+ if ((ch | 0x20) == INT_e) { // ~ 'eE' and/or exponent
if (ptr >= inputLen) {
_inputPtr = startPtr;
return _parseNumber2(neg, startPtr);
}
// Sign indicator?
- ch = (int) _inputBuffer[ptr++];
+ ch = _inputBuffer[ptr++];
if (ch == INT_MINUS || ch == INT_PLUS) { // yup, skip for now
if (ptr >= inputLen) {
_inputPtr = startPtr;
return _parseNumber2(neg, startPtr);
}
- ch = (int) _inputBuffer[ptr++];
+ ch = _inputBuffer[ptr++];
}
while (ch <= INT_9 && ch >= INT_0) {
++expLen;
@@ -1480,7 +1447,7 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg,
_inputPtr = startPtr;
return _parseNumber2(neg, startPtr);
}
- ch = (int) _inputBuffer[ptr++];
+ ch = _inputBuffer[ptr++];
}
// must be followed by sequence of ints, one minimum
if (expLen == 0) {
@@ -1531,14 +1498,14 @@ private final JsonToken _parseSignedNumber(final boolean negative) throws IOExce
if (ptr >= inputEnd) {
return _parseNumber2(negative, startPtr);
}
- ch = (int) _inputBuffer[ptr++];
+ ch = _inputBuffer[ptr++];
if (ch < INT_0 || ch > INT_9) {
break int_loop;
}
++intLen;
}
- if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
+ if (ch == INT_PERIOD || (ch | 0x20) == INT_e) { // ~ '.eE'
_inputPtr = ptr;
return _parseFloat(ch, startPtr, ptr, negative, intLen);
}
@@ -1582,8 +1549,7 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOExcept
// This is the place to do leading-zero check(s) too:
int intLen = 0;
char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
- : getNextChar("No digit following minus sign", JsonToken.VALUE_NUMBER_INT);
-
+ : getNextChar("No digit following sign", JsonToken.VALUE_NUMBER_INT);
if (c == '0') {
c = _verifyNoLeadingZeroes();
}
@@ -1609,7 +1575,7 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOExcept
// Also, integer part is not optional
if (intLen == 0) {
// [core#611]: allow optionally leading decimal point
- if (!isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
+ if ((c != '.') || !isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
return _handleInvalidNumberStart(c, neg);
}
}
@@ -1650,7 +1616,7 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOExcept
}
int expLen = -1;
- if (c == 'e' || c == 'E') { // exponent?
+ if ((c | 0x20) == INT_e) { // ~ 'eE' exponent?
expLen = 0;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
@@ -1846,7 +1812,7 @@ protected final String _parseName() throws IOException
// not cross input buffer boundary, and does not contain escape sequences.
int ptr = _inputPtr;
int hash = _hashSeed;
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
while (ptr < _inputEnd) {
int ch = _inputBuffer[ptr];
@@ -1883,7 +1849,7 @@ private String _parseName2(int startPtr, int hash, int endChar) throws IOExcepti
}
}
char c = _inputBuffer[_inputPtr++];
- int i = (int) c;
+ int i = c;
if (i <= INT_BACKSLASH) {
if (i == INT_BACKSLASH) {
/* Although chars outside of BMP are to be escaped as
@@ -1991,7 +1957,7 @@ protected String _parseAposName() throws IOException
final int inputLen = _inputEnd;
if (ptr < inputLen) {
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
final int maxCode = codes.length;
do {
@@ -2102,7 +2068,7 @@ protected JsonToken _handleApos() throws IOException
}
}
char c = _inputBuffer[_inputPtr++];
- int i = (int) c;
+ int i = c;
if (i <= '\\') {
if (i == '\\') {
// Although chars outside of BMP are to be escaped as
@@ -2144,7 +2110,7 @@ private String _handleOddName2(int startPtr, int hash, int[] codes) throws IOExc
}
}
char c = _inputBuffer[_inputPtr];
- int i = (int) c;
+ int i = c;
if (i < maxCode) {
if (codes[i] != 0) {
break;
@@ -2183,7 +2149,7 @@ protected final void _finishString() throws IOException
final int inputLen = _inputEnd;
if (ptr < inputLen) {
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
final int maxCode = codes.length;
do {
@@ -2211,7 +2177,7 @@ protected void _finishString2() throws IOException
{
char[] outBuf = _textBuffer.getCurrentSegment();
int outPtr = _textBuffer.getCurrentSegmentSize();
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
final int maxCode = codes.length;
while (true) {
@@ -2222,7 +2188,7 @@ protected void _finishString2() throws IOException
}
}
char c = _inputBuffer[_inputPtr++];
- int i = (int) c;
+ int i = c;
if (i < maxCode && codes[i] != 0) {
if (i == INT_QUOTE) {
break;
@@ -2274,7 +2240,7 @@ protected final void _skipString() throws IOException
inLen = _inputEnd;
}
char c = inBuf[inPtr++];
- int i = (int) c;
+ int i = c;
if (i <= INT_BACKSLASH) {
if (i == INT_BACKSLASH) {
// Although chars outside of BMP are to be escaped as an UTF-16 surrogate pair,
@@ -2331,7 +2297,7 @@ private final int _skipColon() throws IOException
return i;
}
if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[++_inputPtr];
+ i = _inputBuffer[++_inputPtr];
if (i > INT_SPACE) {
if (i == INT_SLASH || i == INT_HASH) {
return _skipColon2(true);
@@ -2355,7 +2321,7 @@ private final int _skipColon() throws IOException
return i;
}
if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[++_inputPtr];
+ i = _inputBuffer[++_inputPtr];
if (i > INT_SPACE) {
if (i == INT_SLASH || i == INT_HASH) {
return _skipColon2(true);
@@ -2372,7 +2338,7 @@ private final int _skipColon() throws IOException
private final int _skipColon2(boolean gotColon) throws IOException
{
while (_inputPtr < _inputEnd || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++];
+ int i = _inputBuffer[_inputPtr++];
if (i > INT_SPACE) {
if (i == INT_SLASH) {
_skipComment();
@@ -2411,7 +2377,7 @@ private final int _skipColon2(boolean gotColon) throws IOException
// 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++];
+ int i = _inputBuffer[ptr++];
if (i == INT_COLON) { // common case, no leading space
i = _inputBuffer[ptr++];
if (i > INT_SPACE) { // nor trailing
@@ -2420,7 +2386,7 @@ private final int _skipColonFast(int ptr) throws IOException
return i;
}
} else if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[ptr++];
+ i = _inputBuffer[ptr++];
if (i > INT_SPACE) {
if (i != INT_SLASH && i != INT_HASH) {
_inputPtr = ptr;
@@ -2443,7 +2409,7 @@ private final int _skipColonFast(int ptr) throws IOException
return i;
}
} else if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[ptr++];
+ i = _inputBuffer[ptr++];
if (i > INT_SPACE) {
if (i != INT_SLASH && i != INT_HASH) {
_inputPtr = ptr;
@@ -2463,7 +2429,7 @@ private final int _skipComma(int i) throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
}
while (_inputPtr < _inputEnd) {
- i = (int) _inputBuffer[_inputPtr++];
+ i = _inputBuffer[_inputPtr++];
if (i > INT_SPACE) {
if (i == INT_SLASH || i == INT_HASH) {
--_inputPtr;
@@ -2488,7 +2454,7 @@ private final int _skipComma(int i) throws IOException
private final int _skipAfterComma2() throws IOException
{
while (_inputPtr < _inputEnd || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++];
+ int i = _inputBuffer[_inputPtr++];
if (i > INT_SPACE) {
if (i == INT_SLASH) {
_skipComment();
@@ -2544,7 +2510,7 @@ private final int _skipWSOrEnd() throws IOException
}
while (_inputPtr < _inputEnd) {
- i = (int) _inputBuffer[_inputPtr++];
+ i = _inputBuffer[_inputPtr++];
if (i > INT_SPACE) {
if (i == INT_SLASH || i == INT_HASH) {
--_inputPtr;
@@ -2574,7 +2540,7 @@ private int _skipWSOrEnd2() throws IOException
return _eofAsNextChar();
}
}
- int i = (int) _inputBuffer[_inputPtr++];
+ int i = _inputBuffer[_inputPtr++];
if (i > INT_SPACE) {
if (i == INT_SLASH) {
_skipComment();
@@ -2622,7 +2588,7 @@ private void _skipCComment() throws IOException
{
// Ok: need the matching '*/'
while ((_inputPtr < _inputEnd) || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++];
+ int i = _inputBuffer[_inputPtr++];
if (i <= '*') {
if (i == '*') { // end?
if ((_inputPtr >= _inputEnd) && !_loadMore()) {
@@ -2662,7 +2628,7 @@ private void _skipLine() throws IOException
{
// Ok: need to find EOF or linefeed
while ((_inputPtr < _inputEnd) || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++];
+ int i = _inputBuffer[_inputPtr++];
if (i < INT_SPACE) {
if (i == INT_LF) {
++_currInputRow;
@@ -2688,7 +2654,7 @@ protected char _decodeEscaped() throws IOException
}
char c = _inputBuffer[_inputPtr++];
- switch ((int) c) {
+ switch (c) {
// First, ones that are mapped
case 'b':
return '\b';
@@ -2722,7 +2688,7 @@ protected char _decodeEscaped() throws IOException
_reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
}
}
- int ch = (int) _inputBuffer[_inputPtr++];
+ int ch = _inputBuffer[_inputPtr++];
int digit = CharTypes.charToHex(ch);
if (digit < 0) {
_reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence");
@@ -2973,7 +2939,24 @@ protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException
*/
@Override
- public JsonLocation getTokenLocation()
+ public JsonLocation currentLocation() {
+ final int col = _inputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_contentReference(),
+ -1L, _currInputProcessed + _inputPtr,
+ _currInputRow, col);
+ }
+
+ @Override // @since 2.17
+ protected JsonLocation _currentLocationMinusOne() {
+ final int prevInputPtr = _inputPtr - 1;
+ final int col = prevInputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_contentReference(),
+ -1L, _currInputProcessed + prevInputPtr,
+ _currInputRow, col);
+ }
+
+ @Override
+ public JsonLocation currentTokenLocation()
{
if (_currToken == JsonToken.FIELD_NAME) {
long total = _currInputProcessed + (_nameStartOffset-1);
@@ -2984,14 +2967,6 @@ public JsonLocation getTokenLocation()
-1L, _tokenInputTotal-1, _tokenInputRow, _tokenInputCol);
}
- @Override
- public JsonLocation getCurrentLocation() {
- final int col = _inputPtr - _currInputRowStart + 1; // 1-based
- return new JsonLocation(_contentReference(),
- -1L, _currInputProcessed + _inputPtr,
- _currInputRow, col);
- }
-
// @since 2.7
private final void _updateLocation()
{
@@ -3048,14 +3023,15 @@ protected void _reportInvalidToken(String matchedPart, String msg) throws IOExce
/**********************************************************
*/
- private void _closeScope(int i) throws JsonParseException {
+ private void _closeScope(int i) throws IOException
+ {
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
- _currToken = JsonToken.END_ARRAY;
+ _updateToken(JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
_updateLocation();
@@ -3063,7 +3039,7 @@ private void _closeScope(int i) throws JsonParseException {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
- _currToken = JsonToken.END_OBJECT;
+ _updateToken(JsonToken.END_OBJECT);
}
}
}
diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
index 25c026763a..57dc66b7ab 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java
@@ -3,7 +3,6 @@
import java.io.*;
import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.CharTypes;
import com.fasterxml.jackson.core.io.IOContext;
@@ -36,45 +35,18 @@
* @since 2.8
*/
public class UTF8DataInputJsonParser
- extends ParserBase
+ extends JsonParserBase
{
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
- private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
- private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
- private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
- private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
-
- // This is the main input-code lookup table, fetched eagerly
- private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8();
-
- // Latin1 encoding is not supported, but we do use 8-bit subset for
- // pre-processing task, to simplify first pass, keep it fast.
- protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
-
/*
/**********************************************************
/* Configuration
/**********************************************************
*/
- /**
- * Codec used for data binding when (if) requested; typically full
- * ObjectMapper, but that abstract is not part of core
- * package.
- */
- protected ObjectCodec _objectCodec;
-
/**
* Symbol table that contains field names encountered so far
*/
- final protected ByteQuadsCanonicalizer _symbols;
+ protected final ByteQuadsCanonicalizer _symbols;
/*
/**********************************************************
@@ -123,28 +95,12 @@ public UTF8DataInputJsonParser(IOContext ctxt, int features, DataInput inputData
ObjectCodec codec, ByteQuadsCanonicalizer sym,
int firstByte)
{
- super(ctxt, features);
- _objectCodec = codec;
+ super(ctxt, features, codec);
_symbols = sym;
_inputData = inputData;
_nextByte = firstByte;
}
- @Override
- public ObjectCodec getCodec() {
- return _objectCodec;
- }
-
- @Override
- public void setCodec(ObjectCodec c) {
- _objectCodec = c;
- }
-
- @Override // @since 2.12
- public JacksonFeatureSet getReadCapabilities() {
- return JSON_READ_CAPABILITIES;
- }
-
/*
/**********************************************************
/* Overrides for life-cycle
@@ -242,7 +198,7 @@ public String getValueAsString() throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(null);
}
@@ -258,7 +214,7 @@ public String getValueAsString(String defValue) throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(defValue);
}
@@ -604,14 +560,14 @@ public JsonToken nextToken() throws IOException
if (i < 0) { // end-of-input
// Close/release things like input source, symbol table and recyclable buffers
close();
- return (_currToken = null);
+ return _updateTokenToNull();
}
// clear any data retained so far
_binaryValue = null;
_tokenInputRow = _currInputRow;
// Closing scope?
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return _currToken;
}
@@ -625,7 +581,7 @@ public JsonToken nextToken() throws IOException
// Was that a trailing comma?
if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return _currToken;
}
@@ -642,7 +598,7 @@ public JsonToken nextToken() throws IOException
// So first parse the field name itself:
String n = _parseName(i);
_parsingContext.setCurrentName(n);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
@@ -710,33 +666,33 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
{
if (i == INT_QUOTE) {
_tokenIncomplete = true;
- return (_currToken = JsonToken.VALUE_STRING);
+ return _updateToken(JsonToken.VALUE_STRING);
}
switch (i) {
case '[':
createChildArrayContext(_tokenInputRow, _tokenInputCol);
- return (_currToken = JsonToken.START_ARRAY);
+ return _updateToken(JsonToken.START_ARRAY);
case '{':
createChildObjectContext(_tokenInputRow, _tokenInputCol);
- return (_currToken = JsonToken.START_OBJECT);
+ return _updateToken(JsonToken.START_OBJECT);
case 't':
_matchToken("true", 1);
- return (_currToken = JsonToken.VALUE_TRUE);
+ return _updateToken(JsonToken.VALUE_TRUE);
case 'f':
_matchToken("false", 1);
- return (_currToken = JsonToken.VALUE_FALSE);
+ return _updateToken(JsonToken.VALUE_FALSE);
case 'n':
_matchToken("null", 1);
- return (_currToken = JsonToken.VALUE_NULL);
+ return _updateToken(JsonToken.VALUE_NULL);
case '-':
- return (_currToken = _parseNegNumber());
+ return _updateToken(_parseNegNumber());
case '+':
if (isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) {
- return (_currToken = _parsePosNumber());
+ return _updateToken(_parsePosNumber());
}
- return (_currToken = _handleUnexpectedValue(i));
+ return _updateToken(_handleUnexpectedValue(i));
case '.': // as per [core#611]
- return (_currToken = _parseFloatThatStartsWithPeriod(false, false));
+ return _updateToken(_parseFloatThatStartsWithPeriod(false, false));
case '0':
case '1':
case '2':
@@ -747,9 +703,9 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
case '7':
case '8':
case '9':
- return (_currToken = _parseUnsignedNumber(i));
+ return _updateToken(_parseUnsignedNumber(i));
}
- return (_currToken = _handleUnexpectedValue(i));
+ return _updateToken(_handleUnexpectedValue(i));
}
private final JsonToken _nextAfterName() throws IOException
@@ -764,7 +720,7 @@ private final JsonToken _nextAfterName() throws IOException
} else if (t == JsonToken.START_OBJECT) {
createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
- return (_currToken = t);
+ return _updateToken(t);
}
@Override
@@ -801,7 +757,7 @@ public String nextFieldName() throws IOException
_binaryValue = null;
_tokenInputRow = _currInputRow;
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return null;
}
@@ -815,7 +771,7 @@ public String nextFieldName() throws IOException
// Was that a trailing comma?
if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) {
- if (i == INT_RBRACKET || i == INT_RCURLY) {
+ if ((i | 0x20) == INT_RCURLY) { // ~ '}]'
_closeScope(i);
return null;
}
@@ -829,7 +785,7 @@ public String nextFieldName() throws IOException
final String nameStr = _parseName(i);
_parsingContext.setCurrentName(nameStr);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
if (i == INT_QUOTE) {
@@ -897,7 +853,7 @@ public String nextTextValue() throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
@@ -923,7 +879,7 @@ public int nextIntValue(int defaultValue) throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_NUMBER_INT) {
return getIntValue();
}
@@ -945,7 +901,7 @@ public long nextLongValue(long defaultValue) throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_NUMBER_INT) {
return getLongValue();
}
@@ -967,7 +923,7 @@ public Boolean nextBooleanValue() throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
@@ -1077,7 +1033,7 @@ protected JsonToken _parseUnsignedNumber(int c) throws IOException
outBuf[outPtr++] = (char) c;
c = _inputData.readUnsignedByte();
}
- if (c == '.' || c == 'e' || c == 'E') {
+ if (c == '.' || (c | 0x20) == INT_e) { // ~ '.eE'
return _parseFloat(outBuf, outPtr, c, false, intLen);
}
_textBuffer.setCurrentLength(outPtr);
@@ -1140,7 +1096,7 @@ private final JsonToken _parseSignedNumber(boolean negative) throws IOException
outBuf[outPtr++] = (char) c;
c = _inputData.readUnsignedByte();
}
- if (c == '.' || c == 'e' || c == 'E') {
+ if (c == '.' || (c | 0x20) == INT_e) { // ~ '.eE'
return _parseFloat(outBuf, outPtr, c, negative, intLen);
}
_textBuffer.setCurrentLength(outPtr);
@@ -1217,7 +1173,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
}
int expLen = 0;
- if (c == INT_e || c == INT_E) { // exponent?
+ if ((c | 0x20) == INT_e) { // ~ 'eE' exponent?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
@@ -1298,7 +1254,7 @@ protected final String _parseName(int i) throws IOException
* assume that part is ok (if not it will get caught
* later on), and just handle quotes and backslashes here.
*/
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
int q = _inputData.readUnsignedByte();
@@ -1345,7 +1301,7 @@ protected final String _parseName(int i) throws IOException
private final String _parseMediumName(int q2) throws IOException
{
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
// Ok, got 5 name bytes so far
int i = _inputData.readUnsignedByte();
@@ -1384,7 +1340,7 @@ private final String _parseMediumName(int q2) throws IOException
private final String _parseMediumName2(int q3, final int q2) throws IOException
{
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
// Got 9 name bytes so far
int i = _inputData.readUnsignedByte();
@@ -1428,7 +1384,7 @@ private final String _parseLongName(int q, final int q2, int q3) throws IOExcept
_quadBuffer[2] = q3;
// As explained above, will ignore UTF-8 encoding at this point
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
int qlen = 3;
while (true) {
@@ -1504,7 +1460,7 @@ protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int
* UTF-8 decoding yet. Rather, we'll assume that part is ok (if not it will get
* caught later on), and just handle quotes and backslashes here.
*/
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
while (true) {
if (codes[ch] != 0) {
@@ -1678,7 +1634,7 @@ protected String _parseAposName() throws IOException
// Copied from parseEscapedFieldName, with minor mods:
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
while (true) {
if (ch == '\'') {
@@ -1953,7 +1909,7 @@ protected void _finishString() throws IOException
{
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final int outEnd = outBuf.length;
do {
@@ -1975,7 +1931,7 @@ private String _finishAndReturnString() throws IOException
{
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final int outEnd = outBuf.length;
do {
@@ -1997,7 +1953,7 @@ private final void _finishString2(char[] outBuf, int outPtr, int c)
throws IOException
{
// Here we do want to do full decoding, hence:
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
int outEnd = outBuf.length;
main_loop:
@@ -2071,7 +2027,7 @@ protected void _skipString() throws IOException
_tokenIncomplete = false;
// Need to be fully UTF-8 aware here:
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
main_loop:
while (true) {
@@ -2190,7 +2146,7 @@ protected JsonToken _handleApos() throws IOException
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
// Here we do want to do full decoding, hence:
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
main_loop:
while (true) {
@@ -2968,7 +2924,21 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio
*/
@Override
- public JsonLocation getTokenLocation() {
+ public JsonLocation currentLocation() {
+ // No column tracking since we do not have pointers, DataInput has no offset
+ final int col = -1;
+ return new JsonLocation(_contentReference(), -1L, -1L,
+ _currInputRow, col);
+ }
+
+ // Since we only know row, may as well return currentLocation()
+ @Override // @since 2.17
+ protected JsonLocation _currentLocationMinusOne() {
+ return currentLocation();
+ }
+
+ @Override
+ public JsonLocation currentTokenLocation() {
// 03-Jan-2020, tatu: Should probably track this, similar to how
// streaming parsers do it, but... not done yet
@@ -2982,39 +2952,32 @@ public JsonLocation getTokenLocation() {
return new JsonLocation(_contentReference(), -1L, -1L, _tokenInputRow, -1);
}
- @Override
- public JsonLocation getCurrentLocation() {
- // No column tracking since we do not have pointers, DataInput has no offset
- final int col = -1;
- return new JsonLocation(_contentReference(), -1L, -1L,
- _currInputRow, col);
- }
-
/*
/**********************************************************
/* Internal methods, other
/**********************************************************
*/
- private void _closeScope(int i) throws JsonParseException {
+ private void _closeScope(int i) throws IOException
+ {
if (i == INT_RBRACKET) {
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
- _currToken = JsonToken.END_ARRAY;
+ _updateToken(JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
- _currToken = JsonToken.END_OBJECT;
+ _updateToken(JsonToken.END_OBJECT);
}
}
/**
- * Helper method needed to fix [Issue#148], masking of 0x00 character
+ * Helper method needed to fix [core#148], masking of 0x00 character
*/
private final static int pad(int q, int bytes) {
return (bytes == 4) ? q : (q | (-1 << (bytes << 3)));
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 553fb7be93..31076e752b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
@@ -122,10 +122,11 @@ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
super(ctxt, features, codec);
_outputStream = out;
_quoteChar = (byte) quoteChar;
- if (quoteChar != '"') { // since 2.10
- _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar);
- }
+ boolean escapeSlash = isEnabled(JsonWriteFeature.ESCAPE_FORWARD_SLASHES.mappedFeature());
+ if (quoteChar != '"' || escapeSlash) {
+ _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar, escapeSlash);
+ }
_bufferRecyclable = true;
_outputBuffer = ctxt.allocWriteEncodingBuffer();
_outputEnd = _outputBuffer.length;
@@ -153,8 +154,9 @@ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
super(ctxt, features, codec);
_outputStream = out;
_quoteChar = (byte) quoteChar;
- if (quoteChar != '"') { // since 2.10
- _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar);
+ boolean escapeSlash = isEnabled(JsonWriteFeature.ESCAPE_FORWARD_SLASHES.mappedFeature());
+ if (quoteChar != '"' || escapeSlash) {
+ _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar, escapeSlash);
}
_bufferRecyclable = bufferRecyclable;
@@ -769,7 +771,7 @@ public final void writeRaw(char[] cbuf, int offset, int len) throws IOException
while (offset < len) {
inner_loop:
while (true) {
- int ch = (int) cbuf[offset];
+ int ch = cbuf[offset];
if (ch > 0x7F) {
break inner_loop;
}
@@ -819,8 +821,8 @@ private final void _writeSegmentedRaw(char[] cbuf, int offset, int len) throws I
while (offset < inputEnd) {
inner_loop:
while (true) {
- int ch = (int) cbuf[offset];
- if (ch >= 0x80) {
+ int ch = cbuf[offset];
+ if (ch > 0x7F) {
break inner_loop;
}
// !!! TODO: fast(er) writes (roll input, output checks in one)
@@ -860,7 +862,7 @@ private void _writeRawSegment(char[] cbuf, int offset, int end) throws IOExcepti
while (offset < end) {
inner_loop:
while (true) {
- int ch = (int) cbuf[offset];
+ int ch = cbuf[offset];
if (ch > 0x7F) {
break inner_loop;
}
@@ -1508,6 +1510,16 @@ private final void _writeStringSegment2(final char[] cbuf, int offset, final int
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
+ // 3- or 4-byte character
+ if (_isSurrogateChar(ch)) {
+ final boolean combineSurrogates = Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8.enabledIn(_features);
+ if (combineSurrogates && offset < end) {
+ char highSurrogate = (char) ch;
+ char lowSurrogate = cbuf[offset++];
+ outputPtr = _outputSurrogatePair(highSurrogate, lowSurrogate, outputPtr);
+ continue;
+ }
+ }
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
@@ -1546,6 +1558,16 @@ private final void _writeStringSegment2(final String text, int offset, final int
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
+ // 3- or 4-byte character
+ if (_isSurrogateChar(ch)) {
+ final boolean combineSurrogates = Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8.enabledIn(_features);
+ if (combineSurrogates && offset < end) {
+ char highSurrogate = (char) ch;
+ char lowSurrogate = text.charAt(offset++);
+ outputPtr = _outputSurrogatePair(highSurrogate, lowSurrogate, outputPtr);
+ continue;
+ }
+ }
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
@@ -1914,9 +1936,9 @@ protected final void _writeBinary(Base64Variant b64variant,
_flushBuffer();
}
// First, mash 3 bytes into lsb of 32-bit int
- int b24 = ((int) input[inputPtr++]) << 8;
- b24 |= ((int) input[inputPtr++]) & 0xFF;
- b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
+ int b24 = (input[inputPtr++]) << 8;
+ b24 |= (input[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | ((input[inputPtr++]) & 0xFF);
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
// note: must quote in JSON value
@@ -1932,9 +1954,9 @@ protected final void _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
- int b24 = ((int) input[inputPtr++]) << 16;
+ int b24 = (input[inputPtr++]) << 16;
if (inputLeft == 2) {
- b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
+ b24 |= ((input[inputPtr++]) & 0xFF) << 8;
}
_outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
}
@@ -1965,9 +1987,9 @@ protected final int _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // need to flush
_flushBuffer();
}
- int b24 = ((int) readBuffer[inputPtr++]) << 8;
- b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
- b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ int b24 = (readBuffer[inputPtr++]) << 8;
+ b24 |= (readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | ((readBuffer[inputPtr++]) & 0xFF);
bytesLeft -= 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
@@ -1985,10 +2007,10 @@ protected final int _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
- int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int b24 = (readBuffer[inputPtr++]) << 16;
int amount;
if (inputPtr < inputEnd) {
- b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ b24 |= ((readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
} else {
amount = 1;
@@ -2028,9 +2050,9 @@ protected final int _writeBinary(Base64Variant b64variant,
_flushBuffer();
}
// First, mash 3 bytes into lsb of 32-bit int
- int b24 = ((int) readBuffer[inputPtr++]) << 8;
- b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
- b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ int b24 = (readBuffer[inputPtr++]) << 8;
+ b24 |= (readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | ((readBuffer[inputPtr++]) & 0xFF);
bytesDone += 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
@@ -2045,10 +2067,10 @@ protected final int _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
- int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int b24 = (readBuffer[inputPtr++]) << 16;
int amount = 1;
if (inputPtr < inputEnd) {
- b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ b24 |= ((readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
}
bytesDone += amount;
@@ -2131,6 +2153,19 @@ protected final void _outputSurrogates(int surr1, int surr2) throws IOException
bbuf[_outputTail++] = (byte) (0x80 | (c & 0x3f));
}
+ // @since 2.18
+ private int _outputSurrogatePair(char highSurrogate, char lowSurrogate, int outputPtr) {
+ final int unicode = 0x10000 + ((highSurrogate & 0x03FF) << 10)
+ + (lowSurrogate & 0x03FF);
+
+ _outputBuffer[outputPtr++] = (byte) (0xF0 + ((unicode >> 18) & 0x07));
+ _outputBuffer[outputPtr++] = (byte) (0x80 + ((unicode >> 12) & 0x3F));
+ _outputBuffer[outputPtr++] = (byte) (0x80 + ((unicode >> 6) & 0x3F));
+ _outputBuffer[outputPtr++] = (byte) (0x80 + (unicode & 0x3F));
+
+ return outputPtr;
+ }
+
/**
*
* @param ch
@@ -2212,5 +2247,10 @@ protected final void _flushBuffer() throws IOException
private byte[] getHexBytes() {
return _cfgWriteHexUppercase ? HEX_BYTES_UPPER : HEX_BYTES_LOWER;
}
+
+ // @since 2.18
+ private boolean _isSurrogateChar(int ch) {
+ return (ch & 0xD800) == 0xD800;
+ }
}
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 4f43c7eeb9..5d4e7e870b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
@@ -3,7 +3,6 @@
import java.io.*;
import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.CharTypes;
import com.fasterxml.jackson.core.io.IOContext;
@@ -17,29 +16,9 @@
* based on a {@link java.io.InputStream} as the input source.
*/
public class UTF8StreamJsonParser
- extends ParserBase
+ extends JsonParserBase
{
- final static byte BYTE_LF = (byte) '\n';
-
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask();
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask();
- @SuppressWarnings("deprecation")
- private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask();
- private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask();
- private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask();
- private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask();
- private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask();
-
- // This is the main input-code lookup table, fetched eagerly
- private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8();
-
- // Latin1 encoding is not supported, but we do use 8-bit subset for
- // pre-processing task, to simplify first pass, keep it fast.
- protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
+ protected final static byte BYTE_LF = (byte) '\n';
/*
/**********************************************************
@@ -47,17 +26,10 @@ public class UTF8StreamJsonParser
/**********************************************************
*/
- /**
- * Codec used for data binding when (if) requested; typically full
- * ObjectMapper, but that abstract is not part of core
- * package.
- */
- protected ObjectCodec _objectCodec;
-
/**
* Symbol table that contains field names encountered so far
*/
- final protected ByteQuadsCanonicalizer _symbols;
+ protected final ByteQuadsCanonicalizer _symbols;
/*
/**********************************************************
@@ -188,9 +160,8 @@ public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
byte[] inputBuffer, int start, int end, int bytesPreProcessed,
boolean bufferRecyclable)
{
- super(ctxt, features);
+ super(ctxt, features, codec);
_inputStream = in;
- _objectCodec = codec;
_symbols = sym;
_inputBuffer = inputBuffer;
_inputPtr = start;
@@ -201,21 +172,6 @@ public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
_bufferRecyclable = bufferRecyclable;
}
- @Override
- public ObjectCodec getCodec() {
- return _objectCodec;
- }
-
- @Override
- public void setCodec(ObjectCodec c) {
- _objectCodec = c;
- }
-
- @Override // @since 2.12
- public JacksonFeatureSet getReadCapabilities() {
- return JSON_READ_CAPABILITIES;
- }
-
/*
/**********************************************************
/* Overrides for life-cycle
@@ -259,7 +215,7 @@ protected final boolean _loadMore() throws IOException
_currInputProcessed += bufSize;
_currInputRowStart -= bufSize;
// 06-Sep-2023, tatu: [core#1046] Enforce max doc length limit
- streamReadConstraints().validateDocumentLength(_currInputProcessed);
+ _streamReadConstraints.validateDocumentLength(_currInputProcessed);
int count = _inputStream.read(_inputBuffer, 0, space);
if (count > 0) {
@@ -383,7 +339,7 @@ public String getValueAsString() throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(null);
}
@@ -400,7 +356,7 @@ public String getValueAsString(String defValue) throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(defValue);
}
@@ -608,7 +564,7 @@ protected int _readBinary(Base64Variant b64variant, OutputStream out,
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
} while (ch <= INT_SPACE);
int bits = b64variant.decodeBase64Char(ch);
if (bits < 0) { // reached the end, fair and square?
@@ -761,7 +717,7 @@ public JsonToken nextToken() throws IOException
if (i < 0) { // end-of-input
// Close/release things like input source, symbol table and recyclable buffers
close();
- return (_currToken = null);
+ return _updateTokenToNull();
}
// clear any data retained so far
_binaryValue = null;
@@ -769,11 +725,11 @@ public JsonToken nextToken() throws IOException
// Closing scope?
if (i == INT_RBRACKET) {
_closeArrayScope();
- return (_currToken = JsonToken.END_ARRAY);
+ return _updateToken(JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
_closeObjectScope();
- return (_currToken = JsonToken.END_OBJECT);
+ return _updateToken(JsonToken.END_OBJECT);
}
// Nope: do we then expect a comma?
@@ -800,7 +756,7 @@ public JsonToken nextToken() throws IOException
_updateNameLocation();
String n = _parseName(i);
_parsingContext.setCurrentName(n);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
_updateLocation();
@@ -869,33 +825,33 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
{
if (i == INT_QUOTE) {
_tokenIncomplete = true;
- return (_currToken = JsonToken.VALUE_STRING);
+ return _updateToken(JsonToken.VALUE_STRING);
}
switch (i) {
case '[':
createChildArrayContext(_tokenInputRow, _tokenInputCol);
- return (_currToken = JsonToken.START_ARRAY);
+ return _updateToken(JsonToken.START_ARRAY);
case '{':
createChildObjectContext(_tokenInputRow, _tokenInputCol);
- return (_currToken = JsonToken.START_OBJECT);
+ return _updateToken(JsonToken.START_OBJECT);
case 't':
_matchTrue();
- return (_currToken = JsonToken.VALUE_TRUE);
+ return _updateToken(JsonToken.VALUE_TRUE);
case 'f':
_matchFalse();
- return (_currToken = JsonToken.VALUE_FALSE);
+ return _updateToken(JsonToken.VALUE_FALSE);
case 'n':
_matchNull();
- return (_currToken = JsonToken.VALUE_NULL);
+ return _updateToken(JsonToken.VALUE_NULL);
case '-':
- return (_currToken = _parseSignedNumber(true));
+ return _updateToken(_parseSignedNumber(true));
case '+':
if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) {
- return (_currToken = _handleUnexpectedValue(i));
+ return _updateToken(_handleUnexpectedValue(i));
}
- return (_currToken = _parseSignedNumber(false));
+ return _updateToken(_parseSignedNumber(false));
case '.': // [core#611]:
- return (_currToken = _parseFloatThatStartsWithPeriod(false, false));
+ return _updateToken(_parseFloatThatStartsWithPeriod(false, false));
case '0':
case '1':
case '2':
@@ -906,9 +862,9 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
case '7':
case '8':
case '9':
- return (_currToken = _parseUnsignedNumber(i));
+ return _updateToken(_parseUnsignedNumber(i));
}
- return (_currToken = _handleUnexpectedValue(i));
+ return _updateToken(_handleUnexpectedValue(i));
}
private final JsonToken _nextAfterName() throws IOException
@@ -925,7 +881,7 @@ private final JsonToken _nextAfterName() throws IOException
} else if (t == JsonToken.START_OBJECT) {
createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
- return (_currToken = t);
+ return _updateToken(t);
}
@Override
@@ -957,7 +913,7 @@ public boolean nextFieldName(SerializableString str) throws IOException
int i = _skipWSOrEnd();
if (i < 0) { // end-of-input
close();
- _currToken = null;
+ _updateTokenToNull();
return false;
}
_binaryValue = null;
@@ -965,12 +921,12 @@ public boolean nextFieldName(SerializableString str) throws IOException
// Closing scope?
if (i == INT_RBRACKET) {
_closeArrayScope();
- _currToken = JsonToken.END_ARRAY;
+ _updateToken(JsonToken.END_ARRAY);
return false;
}
if (i == INT_RCURLY) {
_closeObjectScope();
- _currToken = JsonToken.END_OBJECT;
+ _updateToken(JsonToken.END_OBJECT);
return false;
}
@@ -1043,19 +999,19 @@ public String nextFieldName() throws IOException
int i = _skipWSOrEnd();
if (i < 0) {
close();
- _currToken = null;
+ _updateTokenToNull();
return null;
}
_binaryValue = null;
if (i == INT_RBRACKET) {
_closeArrayScope();
- _currToken = JsonToken.END_ARRAY;
+ _updateToken(JsonToken.END_ARRAY);
return null;
}
if (i == INT_RCURLY) {
_closeObjectScope();
- _currToken = JsonToken.END_OBJECT;
+ _updateToken(JsonToken.END_OBJECT);
return null;
}
@@ -1083,7 +1039,7 @@ public String nextFieldName() throws IOException
_updateNameLocation();
final String nameStr = _parseName(i);
_parsingContext.setCurrentName(nameStr);
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
_updateLocation();
@@ -1157,7 +1113,7 @@ private final int _skipColonFast(int ptr) throws IOException
return i;
}
} else if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[ptr++];
+ i = _inputBuffer[ptr++];
if (i > INT_SPACE) {
if (i != INT_SLASH && i != INT_HASH) {
_inputPtr = ptr;
@@ -1179,7 +1135,7 @@ private final int _skipColonFast(int ptr) throws IOException
return i;
}
} else if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[ptr++];
+ i = _inputBuffer[ptr++];
if (i > INT_SPACE) {
if (i != INT_SLASH && i != INT_HASH) {
_inputPtr = ptr;
@@ -1196,7 +1152,7 @@ private final int _skipColonFast(int ptr) throws IOException
private final void _isNextTokenNameYes(int i) throws IOException
{
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
_updateLocation();
switch (i) {
@@ -1258,7 +1214,7 @@ private final boolean _isNextTokenNameMaybe(int i, SerializableString str) throw
String n = _parseName(i);
_parsingContext.setCurrentName(n);
final boolean match = n.equals(str.getValue());
- _currToken = JsonToken.FIELD_NAME;
+ _updateToken(JsonToken.FIELD_NAME);
i = _skipColon();
_updateLocation();
@@ -1329,7 +1285,7 @@ public String nextTextValue() throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
@@ -1356,7 +1312,7 @@ public int nextIntValue(int defaultValue) throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_NUMBER_INT) {
return getIntValue();
}
@@ -1379,7 +1335,7 @@ public long nextLongValue(long defaultValue) throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_NUMBER_INT) {
return getLongValue();
}
@@ -1402,7 +1358,7 @@ public Boolean nextBooleanValue() throws IOException
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
- _currToken = t;
+ _updateToken(t);
if (t == JsonToken.VALUE_TRUE) {
return Boolean.TRUE;
}
@@ -1497,14 +1453,14 @@ protected JsonToken _parseUnsignedNumber(int c) throws IOException
if (_inputPtr >= end) { // split across boundary, offline
return _parseNumber2(outBuf, outPtr, false, intLen);
}
- c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ c = _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break;
}
++intLen;
outBuf[outPtr++] = (char) c;
}
- if (c == INT_PERIOD || c == INT_e || c == INT_E) {
+ if (c == INT_PERIOD || (c | 0x20) == INT_e) { // ~ '.eE'
return _parseFloat(outBuf, outPtr, c, false, intLen);
}
--_inputPtr; // to push back trailing char (comma etc)
@@ -1530,7 +1486,7 @@ private final JsonToken _parseSignedNumber(boolean negative) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ int c = _inputBuffer[_inputPtr++] & 0xFF;
// Note: must be followed by a digit
if (c <= INT_0) {
// One special case: if first char is 0, must not be followed by a digit
@@ -1558,14 +1514,14 @@ private final JsonToken _parseSignedNumber(boolean negative) throws IOException
// Long enough to be split across boundary, so:
return _parseNumber2(outBuf, outPtr, negative, intLen);
}
- c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ c = _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break;
}
++intLen;
outBuf[outPtr++] = (char) c;
}
- if (c == INT_PERIOD || c == INT_e || c == INT_E) {
+ if (c == INT_PERIOD || (c | 0x20) == INT_e) { // ~ '.eE'
return _parseFloat(outBuf, outPtr, c, negative, intLen);
}
@@ -1591,9 +1547,9 @@ private final JsonToken _parseNumber2(char[] outBuf, int outPtr, boolean negativ
_textBuffer.setCurrentLength(outPtr);
return resetInt(negative, intPartLength);
}
- int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ int c = _inputBuffer[_inputPtr++] & 0xFF;
if (c > INT_9 || c < INT_0) {
- if (c == INT_PERIOD || c == INT_e || c == INT_E) {
+ if (c == INT_PERIOD || (c | 0x20) == INT_e) { // ~ '.eE'
return _parseFloat(outBuf, outPtr, c, negative, intPartLength);
}
break;
@@ -1671,7 +1627,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
eof = true;
break fract_loop;
}
- c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ c = _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
@@ -1691,7 +1647,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
}
int expLen = 0;
- if (c == INT_e || c == INT_E) { // exponent?
+ if ((c | 0x20) == INT_e) { // ~ 'eE' exponent?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
@@ -1701,7 +1657,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ c = _inputBuffer[_inputPtr++] & 0xFF;
// Sign indicator?
if (c == '-' || c == '+') {
if (outPtr >= outBuf.length) {
@@ -1713,7 +1669,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ c = _inputBuffer[_inputPtr++] & 0xFF;
}
exp_loop:
@@ -1728,7 +1684,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
eof = true;
break exp_loop;
}
- c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ c = _inputBuffer[_inputPtr++] & 0xFF;
}
// must be followed by sequence of ints, one minimum
if (expLen == 0) {
@@ -1808,7 +1764,7 @@ protected final String _parseName(int i) throws IOException
* later on), and just handle quotes and backslashes here.
*/
final byte[] input = _inputBuffer;
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
int q = input[_inputPtr++] & 0xFF;
@@ -1856,7 +1812,7 @@ protected final String _parseName(int i) throws IOException
protected final String parseMediumName(int q2) throws IOException
{
final byte[] input = _inputBuffer;
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
// Ok, got 5 name bytes so far
int i = input[_inputPtr++] & 0xFF;
@@ -1897,7 +1853,7 @@ protected final String parseMediumName(int q2) throws IOException
protected final String parseMediumName2(int q3, final int q2) throws IOException
{
final byte[] input = _inputBuffer;
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
// Got 9 name bytes so far
int i = input[_inputPtr++] & 0xFF;
@@ -1942,7 +1898,7 @@ protected final String parseLongName(int q, final int q2, int q3) throws IOExcep
// As explained above, will ignore UTF-8 encoding at this point
final byte[] input = _inputBuffer;
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
int qlen = 3;
while ((_inputPtr + 4) <= _inputEnd) {
@@ -2038,7 +1994,7 @@ protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int
// This may seem weird, but here we do not want to worry about
// UTF-8 decoding yet. Rather, we'll assume that part is ok (if not it will get
// caught later on), and just handle quotes and backslashes here.
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
while (true) {
if (codes[ch] != 0) {
@@ -2224,7 +2180,7 @@ protected String _parseAposName() throws IOException
// Copied from parseEscapedFieldName, with minor mods:
- final int[] codes = _icLatin1;
+ final int[] codes = INPUT_CODES_LATIN1;
while (true) {
if (ch == INT_APOS) {
@@ -2512,12 +2468,12 @@ protected void _finishString() throws IOException
}
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final int max = Math.min(_inputEnd, (ptr + outBuf.length));
final byte[] inputBuffer = _inputBuffer;
while (ptr < max) {
- int c = (int) inputBuffer[ptr] & 0xFF;
+ int c = inputBuffer[ptr] & 0xFF;
if (codes[c] != 0) {
if (c == INT_QUOTE) {
_inputPtr = ptr+1;
@@ -2544,12 +2500,12 @@ protected String _finishAndReturnString() throws IOException
}
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final int max = Math.min(_inputEnd, (ptr + outBuf.length));
final byte[] inputBuffer = _inputBuffer;
while (ptr < max) {
- int c = (int) inputBuffer[ptr] & 0xFF;
+ int c = inputBuffer[ptr] & 0xFF;
if (codes[c] != 0) {
if (c == INT_QUOTE) {
_inputPtr = ptr+1;
@@ -2571,7 +2527,7 @@ private final void _finishString2(char[] outBuf, int outPtr)
int c;
// Here we do want to do full decoding, hence:
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final byte[] inputBuffer = _inputBuffer;
main_loop:
@@ -2588,9 +2544,11 @@ private final void _finishString2(char[] outBuf, int outPtr)
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
- final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
+ final int max = Math.min(
+ _inputEnd,
+ InternalJacksonUtil.addOverflowSafe(ptr, outBuf.length - outPtr));
while (ptr < max) {
- c = (int) inputBuffer[ptr++] & 0xFF;
+ c = inputBuffer[ptr++] & 0xFF;
if (codes[c] != 0) {
_inputPtr = ptr;
break ascii_loop;
@@ -2662,7 +2620,7 @@ protected void _skipString() throws IOException
_tokenIncomplete = false;
// Need to be fully UTF-8 aware here:
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final byte[] inputBuffer = _inputBuffer;
main_loop:
@@ -2679,7 +2637,7 @@ protected void _skipString() throws IOException
max = _inputEnd;
}
while (ptr < max) {
- c = (int) inputBuffer[ptr++] & 0xFF;
+ c = inputBuffer[ptr++] & 0xFF;
if (codes[c] != 0) {
_inputPtr = ptr;
break ascii_loop;
@@ -2803,7 +2761,7 @@ protected JsonToken _handleApos() throws IOException
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
// Here we do want to do full decoding, hence:
- final int[] codes = _icUTF8;
+ final int[] codes = INPUT_CODES_UTF8;
final byte[] inputBuffer = _inputBuffer;
main_loop:
@@ -2820,13 +2778,14 @@ protected JsonToken _handleApos() throws IOException
}
int max = _inputEnd;
{
- int max2 = _inputPtr + (outBuf.length - outPtr);
+ final int max2 =
+ InternalJacksonUtil.addOverflowSafe(_inputPtr, outBuf.length - outPtr);
if (max2 < max) {
max = max2;
}
}
while (_inputPtr < max) {
- c = (int) inputBuffer[_inputPtr++] & 0xFF;
+ c = inputBuffer[_inputPtr++] & 0xFF;
if (c == INT_APOS) {
break main_loop;
}
@@ -2942,7 +2901,7 @@ protected final void _matchTrue() throws IOException
&& (buf[ptr++] == 'u')
&& (buf[ptr++] == 'e')) {
int ch = buf[ptr] & 0xFF;
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
_inputPtr = ptr;
return;
}
@@ -2961,7 +2920,7 @@ protected final void _matchFalse() throws IOException
&& (buf[ptr++] == 's')
&& (buf[ptr++] == 'e')) {
int ch = buf[ptr] & 0xFF;
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
_inputPtr = ptr;
return;
}
@@ -2979,7 +2938,7 @@ protected final void _matchNull() throws IOException
&& (buf[ptr++] == 'l')
&& (buf[ptr++] == 'l')) {
int ch = buf[ptr] & 0xFF;
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
_inputPtr = ptr;
return;
}
@@ -3196,7 +3155,7 @@ private final int _skipColon() throws IOException
return i;
}
if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[++_inputPtr];
+ i = _inputBuffer[++_inputPtr];
if (i > INT_SPACE) {
if (i == INT_SLASH || i == INT_HASH) {
return _skipColon2(true);
@@ -3220,7 +3179,7 @@ private final int _skipColon() throws IOException
return i;
}
if (i == INT_SPACE || i == INT_TAB) {
- i = (int) _inputBuffer[++_inputPtr];
+ i = _inputBuffer[++_inputPtr];
if (i > INT_SPACE) {
if (i == INT_SLASH || i == INT_HASH) {
return _skipColon2(true);
@@ -3299,7 +3258,7 @@ private final void _skipCComment() throws IOException
// Ok: need the matching '*/'
main_loop:
while ((_inputPtr < _inputEnd) || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
int code = codes[i];
if (code != 0) {
switch (code) {
@@ -3353,7 +3312,7 @@ private final void _skipLine() throws IOException
// Ok: need to find EOF or linefeed
final int[] codes = CharTypes.getInputCodeComment();
while ((_inputPtr < _inputEnd) || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
int code = codes[i];
if (code != 0) {
switch (code) {
@@ -3393,7 +3352,7 @@ protected char _decodeEscaped() throws IOException
_reportInvalidEOF(" in character escape sequence", JsonToken.VALUE_STRING);
}
}
- int c = (int) _inputBuffer[_inputPtr++];
+ int c = _inputBuffer[_inputPtr++];
switch (c) {
// First, ones that are mapped
@@ -3496,7 +3455,7 @@ private final int _decodeUtf8_2(int c) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- int d = (int) _inputBuffer[_inputPtr++];
+ int d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3509,7 +3468,7 @@ private final int _decodeUtf8_3(int c1) throws IOException
_loadMoreGuaranteed();
}
c1 &= 0x0F;
- int d = (int) _inputBuffer[_inputPtr++];
+ int d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3517,7 +3476,7 @@ private final int _decodeUtf8_3(int c1) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- d = (int) _inputBuffer[_inputPtr++];
+ d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3528,12 +3487,12 @@ private final int _decodeUtf8_3(int c1) throws IOException
private final int _decodeUtf8_3fast(int c1) throws IOException
{
c1 &= 0x0F;
- int d = (int) _inputBuffer[_inputPtr++];
+ int d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
int c = (c1 << 6) | (d & 0x3F);
- d = (int) _inputBuffer[_inputPtr++];
+ d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3548,7 +3507,7 @@ private final int _decodeUtf8_4(int c) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- int d = (int) _inputBuffer[_inputPtr++];
+ int d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3557,7 +3516,7 @@ private final int _decodeUtf8_4(int c) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- d = (int) _inputBuffer[_inputPtr++];
+ d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3565,7 +3524,7 @@ private final int _decodeUtf8_4(int c) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- d = (int) _inputBuffer[_inputPtr++];
+ d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3581,7 +3540,7 @@ private final void _skipUtf8_2() throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- int c = (int) _inputBuffer[_inputPtr++];
+ int c = _inputBuffer[_inputPtr++];
if ((c & 0xC0) != 0x080) {
_reportInvalidOther(c & 0xFF, _inputPtr);
}
@@ -3596,14 +3555,14 @@ private final void _skipUtf8_3() throws IOException
_loadMoreGuaranteed();
}
//c &= 0x0F;
- int c = (int) _inputBuffer[_inputPtr++];
+ int c = _inputBuffer[_inputPtr++];
if ((c & 0xC0) != 0x080) {
_reportInvalidOther(c & 0xFF, _inputPtr);
}
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- c = (int) _inputBuffer[_inputPtr++];
+ c = _inputBuffer[_inputPtr++];
if ((c & 0xC0) != 0x080) {
_reportInvalidOther(c & 0xFF, _inputPtr);
}
@@ -3614,21 +3573,21 @@ private final void _skipUtf8_4(int c) throws IOException
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- int d = (int) _inputBuffer[_inputPtr++];
+ int d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- d = (int) _inputBuffer[_inputPtr++];
+ d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- d = (int) _inputBuffer[_inputPtr++];
+ d = _inputBuffer[_inputPtr++];
if ((d & 0xC0) != 0x080) {
_reportInvalidOther(d & 0xFF, _inputPtr);
}
@@ -3684,7 +3643,7 @@ protected void _reportInvalidToken(String matchedPart, String msg) throws IOExce
*/
StringBuilder sb = new StringBuilder(matchedPart);
while ((_inputPtr < _inputEnd) || _loadMore()) {
- int i = (int) _inputBuffer[_inputPtr++];
+ int i = _inputBuffer[_inputPtr++];
char c = (char) _decodeCharForError(i);
if (!Character.isJavaIdentifierPart(c)) {
// 11-Jan-2016, tatu: note: we will fully consume the character,
@@ -3756,7 +3715,7 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio
if (_inputPtr >= _inputEnd) {
_loadMoreGuaranteed();
}
- ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
} while (ch <= INT_SPACE);
int bits = b64variant.decodeBase64Char(ch);
if (bits < 0) { // reached the end, fair and square?
@@ -3864,9 +3823,26 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio
/**********************************************************
*/
- // As per [core#108], must ensure we call the right method
@Override
- public JsonLocation getTokenLocation()
+ public JsonLocation currentLocation()
+ {
+ int col = _inputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_contentReference(),
+ _currInputProcessed + _inputPtr, -1L, // bytes, chars
+ _currInputRow, col);
+ }
+
+ @Override // @since 2.17
+ protected JsonLocation _currentLocationMinusOne() {
+ final int prevInputPtr = _inputPtr - 1;
+ final int col = prevInputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_contentReference(),
+ _currInputProcessed + prevInputPtr, -1L, // bytes, chars
+ _currInputRow, col);
+ }
+
+ @Override
+ public JsonLocation currentTokenLocation()
{
if (_currToken == JsonToken.FIELD_NAME) {
long total = _currInputProcessed + (_nameStartOffset-1);
@@ -3877,16 +3853,6 @@ public JsonLocation getTokenLocation()
_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(_contentReference(),
- _currInputProcessed + _inputPtr, -1L, // bytes, chars
- _currInputRow, col);
- }
-
// @since 2.7
private final void _updateLocation()
{
@@ -3911,16 +3877,16 @@ private final void _updateNameLocation()
/**********************************************************
*/
- private final JsonToken _closeScope(int i) throws JsonParseException {
+ private final JsonToken _closeScope(int i) throws IOException {
if (i == INT_RCURLY) {
_closeObjectScope();
- return (_currToken = JsonToken.END_OBJECT);
+ return _updateToken(JsonToken.END_OBJECT);
}
_closeArrayScope();
- return (_currToken = JsonToken.END_ARRAY);
+ return _updateToken(JsonToken.END_ARRAY);
}
- private final void _closeArrayScope() throws JsonParseException {
+ private final void _closeArrayScope() throws IOException {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(']', '}');
@@ -3928,7 +3894,7 @@ private final void _closeArrayScope() throws JsonParseException {
_parsingContext = _parsingContext.clearAndGetParent();
}
- private final void _closeObjectScope() throws JsonParseException {
+ private final void _closeObjectScope() throws IOException {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker('}', ']');
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 b1628c92b3..6bffd40e6b 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
@@ -105,15 +105,15 @@ public WriterBasedJsonGenerator(IOContext ctxt, int features,
public WriterBasedJsonGenerator(IOContext ctxt, int features,
ObjectCodec codec, Writer w,
char quoteChar)
-
{
super(ctxt, features, codec);
_writer = w;
_outputBuffer = ctxt.allocConcatBuffer();
_outputEnd = _outputBuffer.length;
_quoteChar = quoteChar;
- if (quoteChar != '"') { // since 2.10
- _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar);
+ boolean escapeSlash = isEnabled(JsonWriteFeature.ESCAPE_FORWARD_SLASHES.mappedFeature());
+ if (quoteChar != '"' || escapeSlash) {
+ _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar, escapeSlash);
}
}
@@ -166,7 +166,7 @@ public void writeFieldName(SerializableString name) throws IOException
_writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
}
- protected final void _writeFieldName(String name, boolean commaBefore) throws IOException
+ protected void _writeFieldName(String name, boolean commaBefore) throws IOException
{
if (_cfgPrettyPrinter != null) {
_writePPFieldName(name, commaBefore);
@@ -195,7 +195,7 @@ protected final void _writeFieldName(String name, boolean commaBefore) throws IO
_outputBuffer[_outputTail++] = _quoteChar;
}
- protected final void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
+ protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
{
if (_cfgPrettyPrinter != null) {
_writePPFieldName(name, commaBefore);
@@ -230,7 +230,7 @@ protected final void _writeFieldName(SerializableString name, boolean commaBefor
_outputBuffer[_outputTail++] = _quoteChar;
}
- private final void _writeFieldNameTail(SerializableString name) throws IOException
+ protected void _writeFieldNameTail(SerializableString name) throws IOException
{
final char[] quoted = name.asQuotedChars();
writeRaw(quoted, 0, quoted.length);
@@ -368,7 +368,7 @@ public void writeEndObject() throws IOException
// Specialized version of _writeFieldName, off-lined
// to keep the "fast path" as simple (and hopefully fast) as possible.
- protected final void _writePPFieldName(String name, boolean commaBefore) throws IOException
+ protected void _writePPFieldName(String name, boolean commaBefore) throws IOException
{
if (commaBefore) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
@@ -391,7 +391,7 @@ protected final void _writePPFieldName(String name, boolean commaBefore) throws
}
}
- protected final void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
+ protected void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
{
if (commaBefore) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
@@ -441,7 +441,7 @@ public void writeString(String text) throws IOException
}
@Override
- public void writeString(Reader reader, final int len) throws IOException
+ public void writeString(Reader reader, int len) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (reader == null) {
@@ -939,7 +939,7 @@ public void writeNull() throws IOException {
*/
@Override
- protected final void _verifyValueWrite(String typeMsg) throws IOException
+ protected void _verifyValueWrite(String typeMsg) throws IOException
{
final int status = _writeContext.writeValue();
if (_cfgPrettyPrinter != null) {
@@ -1586,7 +1586,7 @@ private void _writeStringCustom(char[] text, int offset, int len)
/**********************************************************
*/
- protected final void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd)
+ protected void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd)
throws IOException, JsonGenerationException
{
// Encoding is by chunks of 3 input, 4 output chars, so:
@@ -1601,9 +1601,9 @@ protected final void _writeBinary(Base64Variant b64variant, byte[] input, int in
_flushBuffer();
}
// First, mash 3 bytes into lsb of 32-bit int
- int b24 = ((int) input[inputPtr++]) << 8;
- b24 |= ((int) input[inputPtr++]) & 0xFF;
- b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
+ int b24 = (input[inputPtr++]) << 8;
+ b24 |= (input[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | ((input[inputPtr++]) & 0xFF);
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
// note: must quote in JSON value
@@ -1619,16 +1619,16 @@ protected final void _writeBinary(Base64Variant b64variant, byte[] input, int in
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
- int b24 = ((int) input[inputPtr++]) << 16;
+ int b24 = (input[inputPtr++]) << 16;
if (inputLeft == 2) {
- b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
+ b24 |= ((input[inputPtr++]) & 0xFF) << 8;
}
_outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
}
}
// write-method called when length is definitely known
- protected final int _writeBinary(Base64Variant b64variant,
+ protected int _writeBinary(Base64Variant b64variant,
InputStream data, byte[] readBuffer, int bytesLeft)
throws IOException, JsonGenerationException
{
@@ -1652,9 +1652,9 @@ protected final int _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // need to flush
_flushBuffer();
}
- int b24 = ((int) readBuffer[inputPtr++]) << 8;
- b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
- b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ int b24 = (readBuffer[inputPtr++]) << 8;
+ b24 |= (readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | ((readBuffer[inputPtr++]) & 0xFF);
bytesLeft -= 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
@@ -1672,10 +1672,10 @@ protected final int _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
- int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int b24 = (readBuffer[inputPtr++]) << 16;
int amount;
if (inputPtr < inputEnd) {
- b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ b24 |= ((readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
} else {
amount = 1;
@@ -1688,7 +1688,7 @@ protected final int _writeBinary(Base64Variant b64variant,
}
// write method when length is unknown
- protected final int _writeBinary(Base64Variant b64variant,
+ protected int _writeBinary(Base64Variant b64variant,
InputStream data, byte[] readBuffer)
throws IOException, JsonGenerationException
{
@@ -1715,9 +1715,9 @@ protected final int _writeBinary(Base64Variant b64variant,
_flushBuffer();
}
// First, mash 3 bytes into lsb of 32-bit int
- int b24 = ((int) readBuffer[inputPtr++]) << 8;
- b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
- b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ int b24 = (readBuffer[inputPtr++]) << 8;
+ b24 |= (readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | ((readBuffer[inputPtr++]) & 0xFF);
bytesDone += 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
@@ -1732,10 +1732,10 @@ protected final int _writeBinary(Base64Variant b64variant,
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
- int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int b24 = (readBuffer[inputPtr++]) << 16;
int amount = 1;
if (inputPtr < inputEnd) {
- b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ b24 |= ((readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
}
bytesDone += amount;
diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingByteBufferJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingByteBufferJsonParser.java
index ca66d78bf6..8d5c147dba 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingByteBufferJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingByteBufferJsonParser.java
@@ -57,7 +57,7 @@ public void feedInput(final ByteBuffer byteBuffer) throws IOException {
_currInputProcessed += _origBufferLen;
// 06-Sep-2023, tatu: [core#1046] Enforce max doc length limit
- streamReadConstraints().validateDocumentLength(_currInputProcessed);
+ _streamReadConstraints.validateDocumentLength(_currInputProcessed);
// Also need to adjust row start, to work as if it extended into the past wrt new buffer
_currInputRowStart = start - (_inputEnd - _currInputRowStart);
diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java
index fcd90b46fc..7de4ccf2ba 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java
@@ -49,7 +49,7 @@ public void feedInput(final byte[] buf, final int start, final int end) throws I
_currInputProcessed += _origBufferLen;
// 06-Sep-2023, tatu: [core#1046] Enforce max doc length limit
- streamReadConstraints().validateDocumentLength(_currInputProcessed);
+ _streamReadConstraints.validateDocumentLength(_currInputProcessed);
// Also need to adjust row start, to work as if it extended into the past wrt new buffer
_currInputRowStart = start - (_inputEnd - _currInputRowStart);
diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParserBase.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParserBase.java
index 4eeb24ee95..46ca776907 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParserBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParserBase.java
@@ -3,13 +3,12 @@
import java.io.*;
import com.fasterxml.jackson.core.*;
-import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.json.JsonParserBase;
import com.fasterxml.jackson.core.json.JsonReadContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
-import com.fasterxml.jackson.core.util.JacksonFeatureSet;
import static com.fasterxml.jackson.core.JsonTokenId.*;
@@ -19,7 +18,7 @@
* @since 2.9
*/
public abstract class NonBlockingJsonParserBase
- extends ParserBase
+ extends JsonParserBase
{
/*
/**********************************************************************
@@ -255,31 +254,27 @@ public abstract class NonBlockingJsonParserBase
public NonBlockingJsonParserBase(IOContext ctxt, int parserFeatures,
ByteQuadsCanonicalizer sym)
{
- super(ctxt, parserFeatures);
+ super(ctxt, parserFeatures, null);
_symbols = sym;
_currToken = null;
_majorState = MAJOR_INITIAL;
_majorStateAfterValue = MAJOR_ROOT;
}
- @Override
- public ObjectCodec getCodec() {
- return null;
- }
-
@Override
public void setCodec(ObjectCodec c) {
throw new UnsupportedOperationException("Can not use ObjectMapper with non-blocking parser");
}
+ /*
+ /**********************************************************
+ /* Capability introspection
+ /**********************************************************
+ */
+
@Override // since 2.9
public boolean canParseAsync() { return true; }
- @Override // @since 2.12
- public JacksonFeatureSet getReadCapabilities() {
- return JSON_READ_CAPABILITIES;
- }
-
/*
/**********************************************************
/* Test support
@@ -345,7 +340,7 @@ public boolean hasTextCharacters()
}
@Override
- public JsonLocation getCurrentLocation()
+ public JsonLocation currentLocation()
{
int col = _inputPtr - _currInputRowStart + 1; // 1-based
// Since we track CR and LF separately, max should gives us right answer
@@ -355,8 +350,18 @@ public JsonLocation getCurrentLocation()
row, col);
}
+ @Override // @since 2.17
+ protected JsonLocation _currentLocationMinusOne() {
+ final int prevInputPtr = _inputPtr - 1;
+ int row = Math.max(_currInputRow, _currInputRowAlt);
+ final int col = prevInputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_contentReference(),
+ _currInputProcessed + (prevInputPtr - _currBufferStart), -1L, // bytes, chars
+ row, col);
+ }
+
@Override
- public JsonLocation getTokenLocation()
+ public JsonLocation currentTokenLocation()
{
return new JsonLocation(_contentReference(),
_tokenInputTotal, -1L, _tokenInputRow, _tokenInputCol);
@@ -442,7 +447,7 @@ public String getValueAsString() throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(null);
}
@@ -455,7 +460,7 @@ public String getValueAsString(String defValue) throws IOException
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
- return getCurrentName();
+ return currentName();
}
return super.getValueAsString(defValue);
}
@@ -583,7 +588,7 @@ protected final JsonToken _startArrayScope() throws IOException
createChildArrayContext(-1, -1);
_majorState = MAJOR_ARRAY_ELEMENT_FIRST;
_majorStateAfterValue = MAJOR_ARRAY_ELEMENT_NEXT;
- return (_currToken = JsonToken.START_ARRAY);
+ return _updateToken(JsonToken.START_ARRAY);
}
protected final JsonToken _startObjectScope() throws IOException
@@ -591,7 +596,7 @@ protected final JsonToken _startObjectScope() throws IOException
createChildObjectContext(-1, -1);
_majorState = MAJOR_OBJECT_FIELD_FIRST;
_majorStateAfterValue = MAJOR_OBJECT_FIELD_NEXT;
- return (_currToken = JsonToken.START_OBJECT);
+ return _updateToken(JsonToken.START_OBJECT);
}
protected final JsonToken _closeArrayScope() throws IOException
@@ -611,7 +616,7 @@ protected final JsonToken _closeArrayScope() throws IOException
}
_majorState = st;
_majorStateAfterValue = st;
- return (_currToken = JsonToken.END_ARRAY);
+ return _updateToken(JsonToken.END_ARRAY);
}
protected final JsonToken _closeObjectScope() throws IOException
@@ -631,7 +636,7 @@ protected final JsonToken _closeObjectScope() throws IOException
}
_majorState = st;
_majorStateAfterValue = st;
- return (_currToken = JsonToken.END_OBJECT);
+ return _updateToken(JsonToken.END_OBJECT);
}
/*
@@ -821,21 +826,20 @@ protected final JsonToken _eofAsNextToken() throws IOException {
_handleEOF();
}
close();
- return (_currToken = null);
+ return _updateTokenToNull();
}
protected final JsonToken _fieldComplete(String name) throws IOException
{
_majorState = MAJOR_OBJECT_VALUE;
_parsingContext.setCurrentName(name);
- return (_currToken = JsonToken.FIELD_NAME);
+ return _updateToken(JsonToken.FIELD_NAME);
}
protected final JsonToken _valueComplete(JsonToken t) throws IOException
{
_majorState = _majorStateAfterValue;
- _currToken = t;
- return t;
+ return _updateToken(t);
}
protected final JsonToken _valueCompleteInt(int value, String asText) throws IOException
@@ -845,9 +849,7 @@ protected final JsonToken _valueCompleteInt(int value, String asText) throws IOE
_numTypesValid = NR_INT; // to force parsing
_numberInt = value;
_majorState = _majorStateAfterValue;
- JsonToken t = JsonToken.VALUE_NUMBER_INT;
- _currToken = t;
- return t;
+ return _updateToken(JsonToken.VALUE_NUMBER_INT);
}
@SuppressWarnings("deprecation")
@@ -863,7 +865,7 @@ protected final JsonToken _valueNonStdNumberComplete(int type) throws IOExceptio
_numTypesValid = NR_DOUBLE;
_numberDouble = NON_STD_TOKEN_VALUES[type];
_majorState = _majorStateAfterValue;
- return (_currToken = JsonToken.VALUE_NUMBER_FLOAT);
+ return _updateToken(JsonToken.VALUE_NUMBER_FLOAT);
}
protected final String _nonStdToken(int type) {
diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java
index de2f081380..9194b15955 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingUtf8JsonParserBase.java
@@ -6,6 +6,7 @@
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
+import com.fasterxml.jackson.core.util.InternalJacksonUtil;
import com.fasterxml.jackson.core.util.VersionUtil;
import java.io.IOException;
@@ -467,7 +468,7 @@ private final JsonToken _finishBOM(int bytesHandled) throws IOException
}
_pending32 = bytesHandled;
_minorState = MINOR_ROOT_BOM;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
/*
@@ -532,7 +533,7 @@ private final JsonToken _startFieldNameAfterComma(int ch) throws IOException
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
_minorState = MINOR_FIELD_LEADING_WS;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(ptr);
_inputPtr = ptr+1;
@@ -675,7 +676,7 @@ private final JsonToken _startValueExpectComma(int ch) throws IOException
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
_minorState = MINOR_VALUE_WS_AFTER_COMMA;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(ptr);
_inputPtr = ptr+1;
@@ -765,7 +766,7 @@ private final JsonToken _startValueExpectColon(int ch) throws IOException
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
_minorState = MINOR_VALUE_LEADING_WS;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(ptr);
_inputPtr = ptr+1;
@@ -946,7 +947,7 @@ private final int _skipWS(int ch) throws IOException
}
}
if (_inputPtr >= _inputEnd) {
- _currToken = JsonToken.NOT_AVAILABLE;
+ _updateTokenToNA();
return 0;
}
ch = getNextUnsignedByteFromBuffer();
@@ -964,7 +965,7 @@ private final JsonToken _startSlashComment(int fromMinorState) throws IOExceptio
if (_inputPtr >= _inputEnd) {
_pending32 = fromMinorState;
_minorState = MINOR_COMMENT_LEADING_SLASH;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextSignedByteFromBuffer();
if (ch == INT_ASTERISK) { // c-style
@@ -987,7 +988,7 @@ private final JsonToken _finishHashComment(int fromMinorState) throws IOExceptio
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_COMMENT_YAML;
_pending32 = fromMinorState;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch < 0x020) {
@@ -1013,7 +1014,7 @@ private final JsonToken _finishCppComment(int fromMinorState) throws IOException
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_COMMENT_CPP;
_pending32 = fromMinorState;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch < 0x020) {
@@ -1039,7 +1040,7 @@ private final JsonToken _finishCComment(int fromMinorState, boolean gotStar) thr
if (_inputPtr >= _inputEnd) {
_minorState = gotStar ? MINOR_COMMENT_CLOSING_ASTERISK : MINOR_COMMENT_C;
_pending32 = fromMinorState;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch < 0x020) {
@@ -1070,7 +1071,7 @@ private final JsonToken _startAfterComment(int fromMinorState) throws IOExceptio
// Ok, then, need one more character...
if (_inputPtr >= _inputEnd) {
_minorState = fromMinorState;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
switch (fromMinorState) {
@@ -1107,7 +1108,7 @@ protected JsonToken _startFalseToken() throws IOException
&& (getByteFromBuffer(ptr++) == 's')
&& (getByteFromBuffer(ptr++) == 'e')) {
int ch = getByteFromBuffer(ptr) & 0xFF;
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
_inputPtr = ptr;
return _valueComplete(JsonToken.VALUE_FALSE);
}
@@ -1125,7 +1126,7 @@ protected JsonToken _startTrueToken() throws IOException
&& (getByteFromBuffer(ptr++) == 'u')
&& (getByteFromBuffer(ptr++) == 'e')) {
int ch = getByteFromBuffer(ptr) & 0xFF;
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
_inputPtr = ptr;
return _valueComplete(JsonToken.VALUE_TRUE);
}
@@ -1143,7 +1144,7 @@ protected JsonToken _startNullToken() throws IOException
&& (getByteFromBuffer(ptr++) == 'l')
&& (getByteFromBuffer(ptr++) == 'l')) {
int ch = getByteFromBuffer(ptr) & 0xFF;
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
_inputPtr = ptr;
return _valueComplete(JsonToken.VALUE_NULL);
}
@@ -1161,11 +1162,11 @@ protected JsonToken _finishKeywordToken(String expToken, int matched,
while (true) {
if (_inputPtr >= _inputEnd) {
_pending32 = matched;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getByteFromBuffer(_inputPtr);
if (matched == end) { // need to verify trailing separator
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
return _valueComplete(result);
}
break;
@@ -1185,7 +1186,7 @@ protected JsonToken _finishKeywordTokenWithEOF(String expToken, int matched,
JsonToken result) throws IOException
{
if (matched == expToken.length()) {
- return (_currToken = result);
+ return _updateToken(result);
}
_textBuffer.resetWithCopy(expToken, 0, matched);
return _finishErrorTokenWithEOF();
@@ -1201,11 +1202,11 @@ protected JsonToken _finishNonStdToken(int type, int matched) throws IOException
_nonStdTokenType = type;
_pending32 = matched;
_minorState = MINOR_VALUE_TOKEN_NON_STD;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getByteFromBuffer(_inputPtr);
if (matched == end) { // need to verify trailing separator
- if (ch < INT_0 || (ch == INT_RBRACKET) || (ch == INT_RCURLY)) { // expected/allowed chars
+ if (ch < INT_0 || (ch | 0x20) == INT_RCURLY) { // < '0' || ~ '}]' expected/allowed chars
return _valueNonStdNumberComplete(type);
}
break;
@@ -1250,7 +1251,7 @@ protected JsonToken _finishErrorToken() throws IOException
}
return _reportErrorToken(_textBuffer.contentsAsString());
}
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
protected JsonToken _finishErrorTokenWithEOF() throws IOException
@@ -1290,7 +1291,7 @@ protected JsonToken _startPositiveNumber(int ch) throws IOException
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(1);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int outPtr = 1;
@@ -1306,7 +1307,7 @@ protected JsonToken _startPositiveNumber(int ch) throws IOException
break;
}
if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
_intLength = outPtr;
++_inputPtr;
return _startFloat(outBuf, outPtr, ch);
@@ -1322,7 +1323,7 @@ protected JsonToken _startPositiveNumber(int ch) throws IOException
if (++_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(_inputPtr) & 0xFF;
}
@@ -1336,7 +1337,7 @@ protected JsonToken _startNegativeNumber() throws IOException
_numberNegative = true;
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_MINUS;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch <= INT_0) {
@@ -1358,7 +1359,7 @@ protected JsonToken _startNegativeNumber() throws IOException
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(2);
_intLength = 1;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(_inputPtr);
int outPtr = 2;
@@ -1373,7 +1374,7 @@ protected JsonToken _startNegativeNumber() throws IOException
break;
}
if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
_intLength = outPtr-1;
++_inputPtr;
return _startFloat(outBuf, outPtr, ch);
@@ -1388,7 +1389,7 @@ protected JsonToken _startNegativeNumber() throws IOException
if (++_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(_inputPtr) & 0xFF;
}
@@ -1402,7 +1403,7 @@ protected JsonToken _startPositiveNumber() throws IOException
_numberNegative = false;
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_PLUS;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch <= INT_0) {
@@ -1430,7 +1431,7 @@ protected JsonToken _startPositiveNumber() throws IOException
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(2);
_intLength = 1;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(_inputPtr);
int outPtr = 2;
@@ -1445,7 +1446,7 @@ protected JsonToken _startPositiveNumber() throws IOException
break;
}
if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
_intLength = outPtr-1;
++_inputPtr;
return _startFloat(outBuf, outPtr, ch);
@@ -1460,7 +1461,7 @@ protected JsonToken _startPositiveNumber() throws IOException
if (++_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getByteFromBuffer(_inputPtr) & 0xFF;
}
@@ -1474,7 +1475,7 @@ protected JsonToken _startNumberLeadingZero() throws IOException
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
_minorState = MINOR_NUMBER_ZERO;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
// While we could call `_finishNumberLeadingZeroes()`, let's try checking
@@ -1492,7 +1493,7 @@ protected JsonToken _startNumberLeadingZero() throws IOException
return _startFloat(outBuf, 1, ch);
}
} else if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
_inputPtr = ptr;
_intLength = 1;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
@@ -1502,7 +1503,7 @@ protected JsonToken _startNumberLeadingZero() throws IOException
// Ok; unfortunately we have closing bracket/curly that are valid so need
// (colon not possible since this is within value, not after key)
//
- if ((ch != INT_RBRACKET) && (ch != INT_RCURLY)) {
+ if ((ch | 0x20) != INT_RCURLY) { // ~ '}]'
_reportUnexpectedNumberChar(ch,
"expected digit (0-9), decimal point (.) or exponent indicator (e/E) to follow '0'");
}
@@ -1579,7 +1580,7 @@ protected JsonToken _finishNumberLeadingZeroes() throws IOException
while (true) {
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_ZERO;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch < INT_0) {
@@ -1590,7 +1591,7 @@ protected JsonToken _finishNumberLeadingZeroes() throws IOException
return _startFloat(outBuf, 1, ch);
}
} else if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
outBuf[0] = '0';
_intLength = 1;
@@ -1599,7 +1600,7 @@ protected JsonToken _finishNumberLeadingZeroes() throws IOException
// Ok; unfortunately we have closing bracket/curly that are valid so need
// (colon not possible since this is within value, not after key)
//
- if ((ch != INT_RBRACKET) && (ch != INT_RCURLY)) {
+ if ((ch | 0x20) != INT_RCURLY) { // ~ '}]'
_reportUnexpectedNumberChar(ch,
"expected digit (0-9), decimal point (.) or exponent indicator (e/E) to follow '0'");
}
@@ -1637,7 +1638,7 @@ protected JsonToken _finishNumberLeadingPosNegZeroes(final boolean negative) thr
while (true) {
if (_inputPtr >= _inputEnd) {
_minorState = negative ? MINOR_NUMBER_MINUSZERO : MINOR_NUMBER_ZERO;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch < INT_0) {
@@ -1649,7 +1650,7 @@ protected JsonToken _finishNumberLeadingPosNegZeroes(final boolean negative) thr
return _startFloat(outBuf, 2, ch);
}
} else if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
outBuf[0] = negative ? '-' : '+';
outBuf[1] = '0';
@@ -1659,7 +1660,7 @@ protected JsonToken _finishNumberLeadingPosNegZeroes(final boolean negative) thr
// Ok; unfortunately we have closing bracket/curly that are valid so need
// (colon not possible since this is within value, not after key)
//
- if ((ch != INT_RBRACKET) && (ch != INT_RCURLY)) {
+ if ((ch | 0x20) != INT_RCURLY) { // ~ '}]'
_reportUnexpectedNumberChar(ch,
"expected digit (0-9), decimal point (.) or exponent indicator (e/E) to follow '0'");
}
@@ -1691,7 +1692,7 @@ protected JsonToken _finishNumberIntegralPart(char[] outBuf, int outPtr) throws
if (_inputPtr >= _inputEnd) {
_minorState = MINOR_NUMBER_INTEGER_DIGITS;
_textBuffer.setCurrentLength(outPtr);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getByteFromBuffer(_inputPtr) & 0xFF;
if (ch < INT_0) {
@@ -1703,7 +1704,7 @@ protected JsonToken _finishNumberIntegralPart(char[] outBuf, int outPtr) throws
break;
}
if (ch > INT_9) {
- if (ch == INT_e || ch == INT_E) {
+ if ((ch | 0x20) == INT_e) { // ~ 'eE'
_intLength = outPtr+negMod;
++_inputPtr;
return _startFloat(outBuf, outPtr, ch);
@@ -1736,7 +1737,7 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce
_textBuffer.setCurrentLength(outPtr);
_minorState = MINOR_NUMBER_FRACTION_DIGITS;
_fractLength = fractLen;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getNextSignedByteFromBuffer(); // ok to have sign extension for now
if (ch < INT_0 || ch > INT_9) {
@@ -1758,7 +1759,7 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce
}
_fractLength = fractLen;
int expLen = 0;
- if (ch == INT_e || ch == INT_E) { // exponent?
+ if ((ch | 0x20) == INT_e) { // ~ 'eE' exponent?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.expandCurrentSegment();
}
@@ -1767,7 +1768,7 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce
_textBuffer.setCurrentLength(outPtr);
_minorState = MINOR_NUMBER_EXPONENT_MARKER;
_expLength = 0;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getNextSignedByteFromBuffer(); // ok to have sign extension for now
if (ch == INT_MINUS || ch == INT_PLUS) {
@@ -1779,7 +1780,7 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce
_textBuffer.setCurrentLength(outPtr);
_minorState = MINOR_NUMBER_EXPONENT_DIGITS;
_expLength = 0;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getNextSignedByteFromBuffer();
}
@@ -1793,7 +1794,7 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce
_textBuffer.setCurrentLength(outPtr);
_minorState = MINOR_NUMBER_EXPONENT_DIGITS;
_expLength = expLen;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
ch = getNextSignedByteFromBuffer();
}
@@ -1833,7 +1834,7 @@ protected JsonToken _finishFloatFraction() throws IOException
return JsonToken.NOT_AVAILABLE;
}
ch = getNextSignedByteFromBuffer();
- } else if (ch == 'f' || ch == 'd' || ch == 'F' || ch == 'D') {
+ } else if ((ch | 0x22) == 'f') { // ~ fFdD
_reportUnexpectedNumberChar(ch, "JSON does not support parsing numbers that have 'f' or 'd' suffixes");
} else if (ch == INT_PERIOD) {
_reportUnexpectedNumberChar(ch, "Cannot parse number with more than one decimal point");
@@ -1853,7 +1854,7 @@ protected JsonToken _finishFloatFraction() throws IOException
_textBuffer.setCurrentLength(outPtr);
// Ok: end of floating point number or exponent?
- if (ch == INT_e || ch == INT_E) { // exponent?
+ if ((ch | 0x20) == INT_e) { // ~ 'eE' exponent?
_textBuffer.append((char) ch);
_expLength = 0;
if (_inputPtr >= _inputEnd) {
@@ -2086,7 +2087,7 @@ private final JsonToken _parseEscapedName(int qlen, int currQuad, int currQuadBy
_pending32 = currQuad;
_pendingBytes = currQuadBytes;
_minorState = MINOR_FIELD_NAME;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (codes[ch] == 0) {
@@ -2121,7 +2122,7 @@ private final JsonToken _parseEscapedName(int qlen, int currQuad, int currQuadBy
_quadLength = qlen;
_pending32 = currQuad;
_pendingBytes = currQuadBytes;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
}
@@ -2246,7 +2247,7 @@ private JsonToken _finishUnquotedName(int qlen, int currQuad, int currQuadBytes)
_pending32 = currQuad;
_pendingBytes = currQuadBytes;
_minorState = MINOR_FIELD_UNQUOTED_NAME;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getByteFromBuffer(_inputPtr) & 0xFF;
if (codes[ch] != 0) {
@@ -2292,7 +2293,7 @@ private JsonToken _finishAposName(int qlen, int currQuad, int currQuadBytes)
_pending32 = currQuad;
_pendingBytes = currQuadBytes;
_minorState = MINOR_FIELD_APOS_NAME;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
int ch = getNextUnsignedByteFromBuffer();
if (ch == INT_APOS) {
@@ -2312,7 +2313,7 @@ private JsonToken _finishAposName(int qlen, int currQuad, int currQuadBytes)
_quadLength = qlen;
_pending32 = currQuad;
_pendingBytes = currQuadBytes;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
}
if (ch > 127) {
@@ -2548,13 +2549,15 @@ private final JsonToken _finishRegularString() throws IOException
_inputPtr = ptr;
_minorState = MINOR_VALUE_STRING;
_textBuffer.setCurrentLength(outPtr);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
- final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
+ final int max = Math.min(
+ _inputEnd,
+ InternalJacksonUtil.addOverflowSafe(ptr, outBuf.length - outPtr));
while (ptr < max) {
c = getByteFromBuffer(ptr++) & 0xFF;
if (codes[c] != 0) {
@@ -2575,7 +2578,7 @@ private final JsonToken _finishRegularString() throws IOException
_textBuffer.setCurrentLength(outPtr);
if (!_decodeSplitMultiByte(c, codes[c], ptr < _inputEnd)) {
_minorStateAfterSplit = MINOR_VALUE_STRING;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
outBuf = _textBuffer.getBufferWithoutReset();
outPtr = _textBuffer.getCurrentSegmentSize();
@@ -2671,13 +2674,15 @@ private final JsonToken _finishAposString() throws IOException
_inputPtr = ptr;
_minorState = MINOR_VALUE_APOS_STRING;
_textBuffer.setCurrentLength(outPtr);
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
- final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
+ final int max = Math.min(
+ _inputEnd,
+ InternalJacksonUtil.addOverflowSafe(ptr, outBuf.length - outPtr));
while (ptr < max) {
c = getByteFromBuffer(ptr++) & 0xFF;
if ((codes[c] != 0) && (c != INT_QUOTE)) {
@@ -2698,7 +2703,7 @@ private final JsonToken _finishAposString() throws IOException
_textBuffer.setCurrentLength(outPtr);
if (!_decodeSplitMultiByte(c, codes[c], ptr < _inputEnd)) {
_minorStateAfterSplit = MINOR_VALUE_APOS_STRING;
- return (_currToken = JsonToken.NOT_AVAILABLE);
+ return _updateTokenToNA();
}
outBuf = _textBuffer.getBufferWithoutReset();
outPtr = _textBuffer.getCurrentSegmentSize();
diff --git a/src/main/java/com/fasterxml/jackson/core/package-info.java b/src/main/java/com/fasterxml/jackson/core/package-info.java
index cf300844b1..ca4128edb8 100644
--- a/src/main/java/com/fasterxml/jackson/core/package-info.java
+++ b/src/main/java/com/fasterxml/jackson/core/package-info.java
@@ -14,7 +14,7 @@
*
{@link com.fasterxml.jackson.core.TreeNode} is included
*within Streaming API to support integration of the Tree Model
*(which is based on JsonNode) with the basic
- *parsers and generators (iff using mapping-supporting factory: which
+ *parsers and generators (if and only if using mapping-supporting factory: which
*is part of Mapping API, not core)
*
*
{@link com.fasterxml.jackson.core.ObjectCodec} is included so that
diff --git a/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java b/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
index 1df0e03dd1..e705ab7c18 100644
--- a/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
+++ b/src/main/java/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
@@ -248,7 +248,7 @@ private ByteQuadsCanonicalizer(int sz, int seed)
sz = curr;
}
}
- _tableInfo = new AtomicReference(TableInfo.createInitial(sz));
+ _tableInfo = new AtomicReference<>(TableInfo.createInitial(sz));
}
/**
@@ -1096,13 +1096,18 @@ private int _resizeAndFindOffsetForAdd(int hash) throws StreamConstraintsExcepti
return offset;
}
+ // @since 2.17
+ static int multiplyByFourFifths(int number) {
+ return (int) (number * 3_435_973_837L >>> 32);
+ }
+
// Helper method for checking if we should simply rehash() before add
private boolean _checkNeedForRehash() {
// Yes if above 80%, or above 50% AND have ~1% spill-overs
if (_count > (_hashSize >> 1)) { // over 50%
int spillCount = (_spilloverEnd - _spilloverStart()) >> 2;
if ((spillCount > (1 + _count >> 7))
- || (_count > (_hashSize * 0.80))) {
+ || (_count > multiplyByFourFifths(_hashSize))) {
return true;
}
}
diff --git a/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java b/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java
index f5c39a61d7..27b777a541 100644
--- a/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java
+++ b/src/main/java/com/fasterxml/jackson/core/sym/CharsToNameCanonicalizer.java
@@ -257,7 +257,7 @@ private CharsToNameCanonicalizer(StreamReadConstraints src, int factoryFeatures,
_hashShared = false; // doesn't really matter for root instance
_longestCollisionList = 0;
- _tableInfo = new AtomicReference(TableInfo.createInitial(DEFAULT_T_SIZE));
+ _tableInfo = new AtomicReference<>(TableInfo.createInitial(DEFAULT_T_SIZE));
// and actually do NOT assign buffers so we'll find if anyone tried to
// use root instance
}
@@ -364,10 +364,9 @@ public static CharsToNameCanonicalizer createRoot(TokenStreamFactory owner, int
* read-only copy of parent's data, but when changes are needed, a
* copy will be created.
*
- * Note: while this method is synchronized, it is generally not
- * safe to both use makeChild/mergeChild, AND to use instance
- * actively. Instead, a separate 'root' instance should be used
- * on which only makeChild/mergeChild are called, but instance itself
+ * Note: It is generally not safe to both use makeChild/mergeChild, AND to
+ * use instance actively. Instead, a separate 'root' instance should be
+ * used on which only makeChild/mergeChild are called, but instance itself
* is not used as a symbol table.
*
* @return Actual canonicalizer instance that can be used by a parser
@@ -659,7 +658,7 @@ public int _hashToIndex(int rawHash) {
public int calcHash(char[] buffer, int start, int len) {
int hash = _seed;
for (int i = start, end = start+len; i < end; ++i) {
- hash = (hash * HASH_MULT) + (int) buffer[i];
+ hash = (hash * HASH_MULT) + buffer[i];
}
// NOTE: shuffling, if any, is done in 'findSymbol()', not here:
return (hash == 0) ? 1 : hash;
@@ -671,7 +670,7 @@ public int calcHash(String key)
int hash = _seed;
for (int i = 0; i < len; ++i) {
- hash = (hash * HASH_MULT) + (int) key.charAt(i);
+ hash = (hash * HASH_MULT) + key.charAt(i);
}
// NOTE: shuffling, if any, is done in 'findSymbol()', not here:
return (hash == 0) ? 1 : hash;
diff --git a/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java b/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java
index 4a8913161c..a76167f4a0 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/BufferRecycler.java
@@ -20,6 +20,20 @@
public class BufferRecycler
implements RecyclerPool.WithPool
{
+ /**
+ * Tag-on interface to allow various other types to expose {@link BufferRecycler}
+ * they are constructed with.
+ *
+ * @since 2.17
+ */
+ public interface Gettable {
+ /**
+ * @return Buffer recycler instance object is configured with, if any;
+ * whether this can be {@code null} depends on type of object
+ */
+ public BufferRecycler bufferRecycler();
+ }
+
/**
* Buffer used for reading byte-based input.
*/
@@ -91,7 +105,7 @@ public class BufferRecycler
/*
/**********************************************************
- /* Construction
+ /* Life-cycle
/**********************************************************
*/
@@ -113,8 +127,18 @@ public BufferRecycler() {
* @since 2.4
*/
protected BufferRecycler(int bbCount, int cbCount) {
- _byteBuffers = new AtomicReferenceArray(bbCount);
- _charBuffers = new AtomicReferenceArray(cbCount);
+ _byteBuffers = new AtomicReferenceArray<>(bbCount);
+ _charBuffers = new AtomicReferenceArray<>(cbCount);
+ }
+
+ /**
+ * @return True if this recycler is linked to pool and may be released
+ * with {@link #releaseToPool()}; false if no linkage exists.
+ *
+ * @since 2.17
+ */
+ public boolean isLinkedWithPool() {
+ return _pool != null;
}
/*
@@ -145,7 +169,12 @@ public byte[] allocByteBuffer(int ix, int minSize) {
}
public void releaseByteBuffer(int ix, byte[] buffer) {
- _byteBuffers.set(ix, buffer);
+ // 13-Jan-2024, tatu: [core#1186] Replace only if beneficial:
+ byte[] oldBuffer = _byteBuffers.get(ix);
+ if ((oldBuffer == null) || buffer.length > oldBuffer.length) {
+ // Could use CAS, but should not really matter
+ _byteBuffers.set(ix, buffer);
+ }
}
/*
@@ -171,7 +200,12 @@ public char[] allocCharBuffer(int ix, int minSize) {
}
public void releaseCharBuffer(int ix, char[] buffer) {
- _charBuffers.set(ix, buffer);
+ // 13-Jan-2024, tatu: [core#1186] Replace only if beneficial:
+ char[] oldBuffer = _charBuffers.get(ix);
+ if ((oldBuffer == null) || buffer.length > oldBuffer.length) {
+ // Could use CAS, but should not really matter
+ _charBuffers.set(ix, buffer);
+ }
}
/*
diff --git a/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclers.java b/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclers.java
index 2f49c9e45c..5078ccd783 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclers.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/BufferRecyclers.java
@@ -58,7 +58,7 @@ public class BufferRecyclers
* buffer recycling between reader and writer instances.
*/
final protected static ThreadLocal> _recyclerRef
- = new ThreadLocal>();
+ = new ThreadLocal<>();
/**
* Main accessor to call for accessing possibly recycled {@link BufferRecycler} instance.
@@ -79,7 +79,7 @@ public static BufferRecycler getBufferRecycler()
if (_bufferRecyclerTracker != null) {
ref = _bufferRecyclerTracker.wrapAndTrack(br);
} else {
- ref = new SoftReference(br);
+ ref = new SoftReference<>(br);
}
_recyclerRef.set(ref);
}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java b/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
index 85cbcd0e96..226932cf45 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
@@ -26,7 +26,9 @@
* theoretically this builder can aggregate more content it will not be usable
* as things are. Behavior may be improved if we solve the access problem.
*/
-public final class ByteArrayBuilder extends OutputStream
+public final class ByteArrayBuilder
+ extends OutputStream
+ implements BufferRecycler.Gettable
{
public final static byte[] NO_BYTES = new byte[0];
@@ -41,7 +43,7 @@ public final class ByteArrayBuilder extends OutputStream
// Optional buffer recycler instance that we can use for allocating the first block.
private final BufferRecycler _bufferRecycler;
- private final LinkedList _pastBlocks = new LinkedList();
+ private final LinkedList _pastBlocks = new LinkedList<>();
// Number of bytes within byte arrays in {@link _pastBlocks}.
private int _pastLen;
@@ -93,7 +95,7 @@ public int size() {
/**
* Clean up method to call to release all buffers this object may be
* using. After calling the method, no other accessors can be used (and
- * attempt to do so may result in an exception)
+ * attempt to do so may result in an exception).
*/
public void release() {
reset();
@@ -180,6 +182,39 @@ public byte[] toByteArray()
return result;
}
+ /**
+ * Method functionally same as calling:
+ *
+ * that is; aggregates output contained in the builder (if any),
+ * clear state; returns buffer(s) to {@link BufferRecycler} configured,
+ * if any, and returns output to caller.
+ *
+ * @return Content in byte array
+ *
+ * @since 2.17
+ */
+ public byte[] getClearAndRelease()
+ {
+ byte[] result = toByteArray();
+ release();
+ return result;
+ }
+
+ /*
+ /**********************************************************
+ /* BufferRecycler.Gettable implementation
+ /**********************************************************
+ */
+
+ @Override
+ public BufferRecycler bufferRecycler() {
+ return _bufferRecycler;
+ }
+
/*
/**********************************************************
/* Non-stream API (similar to TextBuffer)
@@ -260,7 +295,12 @@ public void write(int b) {
append(b);
}
- @Override public void close() { /* NOP */ }
+ @Override
+ public void close() {
+ // 18-Jan-2024, tatu: Ideally would call `release()` but currently
+ // not possible due to existing usage
+ }
+
@Override public void flush() { /* NOP */ }
/*
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 2e233306b8..dfaafdea17 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/DefaultPrettyPrinter.java
@@ -110,10 +110,26 @@ public interface Indenter
*/
protected String _objectEntrySeparator;
+ /**
+ * String to use in empty Object to separate start and end markers.
+ * Default is single space, resulting in output of {@code { }}.
+ *
+ * @since 2.17
+ */
+ protected String _objectEmptySeparator;
+
/**
* @since 2.16
*/
protected String _arrayValueSeparator;
+
+ /**
+ * String to use in empty Array to separate start and end markers.
+ * Default is single space, resulting in output of {@code [ ]}.
+ *
+ * @since 2.17
+ */
+ protected String _arrayEmptySeparator;
/*
/**********************************************************
@@ -135,7 +151,7 @@ public DefaultPrettyPrinter() {
* @param rootSeparator String to use as root value separator
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter(String rootSeparator) {
this((rootSeparator == null) ? null : new SerializedString(rootSeparator));
}
@@ -147,7 +163,7 @@ public DefaultPrettyPrinter(String rootSeparator) {
* @param rootSeparator String to use as root value separator
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter(SerializableString rootSeparator) {
this(DEFAULT_SEPARATORS.withRootSeparator(rootSeparator.getValue()));
}
@@ -155,7 +171,7 @@ public DefaultPrettyPrinter(SerializableString rootSeparator) {
/**
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter(DefaultPrettyPrinter base,
SerializableString rootSeparator)
{
@@ -167,7 +183,9 @@ public DefaultPrettyPrinter(DefaultPrettyPrinter base,
_separators = base._separators;
_objectFieldValueSeparatorWithSpaces = base._objectFieldValueSeparatorWithSpaces;
_objectEntrySeparator = base._objectEntrySeparator;
+ _objectEmptySeparator = base._objectEmptySeparator;
_arrayValueSeparator = base._arrayValueSeparator;
+ _arrayEmptySeparator = base._arrayEmptySeparator;
_rootSeparator = rootSeparator;
}
@@ -183,7 +201,9 @@ public DefaultPrettyPrinter(Separators separators)
_objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSpacing().apply(
separators.getObjectFieldValueSeparator());
_objectEntrySeparator = separators.getObjectEntrySpacing().apply(separators.getObjectEntrySeparator());
+ _objectEmptySeparator = separators.getObjectEmptySeparator();
_arrayValueSeparator = separators.getArrayValueSpacing().apply(separators.getArrayValueSeparator());
+ _arrayEmptySeparator = separators.getArrayEmptySeparator();
}
/**
@@ -202,13 +222,15 @@ public DefaultPrettyPrinter(DefaultPrettyPrinter base) {
_separators = base._separators;
_objectFieldValueSeparatorWithSpaces = base._objectFieldValueSeparatorWithSpaces;
_objectEntrySeparator = base._objectEntrySeparator;
+ _objectEmptySeparator = base._objectEmptySeparator;
_arrayValueSeparator = base._arrayValueSeparator;
+ _arrayEmptySeparator = base._arrayEmptySeparator;
}
/**
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter withRootSeparator(SerializableString rootSeparator)
{
if (_rootSeparator == rootSeparator ||
@@ -228,7 +250,7 @@ public DefaultPrettyPrinter withRootSeparator(SerializableString rootSeparator)
* @since 2.6
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter withRootSeparator(String rootSeparator) {
return withRootSeparator((rootSeparator == null) ? null : new SerializedString(rootSeparator));
}
@@ -278,7 +300,7 @@ public DefaultPrettyPrinter withObjectIndenter(Indenter i) {
* @since 2.3
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter withSpacesInObjectEntries() {
return _withSpaces(true);
}
@@ -294,7 +316,7 @@ public DefaultPrettyPrinter withSpacesInObjectEntries() {
* @since 2.3
* @deprecated in 2.16. Use the Separators API instead.
*/
- @Deprecated
+ @Deprecated // since 2.16
public DefaultPrettyPrinter withoutSpacesInObjectEntries() {
return _withSpaces(false);
}
@@ -328,7 +350,9 @@ public DefaultPrettyPrinter withSeparators(Separators separators) {
result._objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSpacing().apply(
separators.getObjectFieldValueSeparator());
result._objectEntrySeparator = separators.getObjectEntrySpacing().apply(separators.getObjectEntrySeparator());
+ result._objectEmptySeparator = separators.getObjectEmptySeparator();
result._arrayValueSeparator = separators.getArrayValueSpacing().apply(separators.getArrayValueSeparator());
+ result._arrayEmptySeparator = separators.getArrayEmptySeparator();
return result;
}
@@ -417,7 +441,7 @@ public void writeEndObject(JsonGenerator g, int nrOfEntries) throws IOException
if (nrOfEntries > 0) {
_objectIndenter.writeIndentation(g, _nesting);
} else {
- g.writeRaw(' ');
+ g.writeRaw(_objectEmptySeparator);
}
g.writeRaw('}');
}
@@ -461,7 +485,7 @@ public void writeEndArray(JsonGenerator g, int nrOfValues) throws IOException
if (nrOfValues > 0) {
_arrayIndenter.writeIndentation(g, _nesting);
} else {
- g.writeRaw(' ');
+ g.writeRaw(_arrayEmptySeparator);
}
g.writeRaw(']');
}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/InternCache.java b/src/main/java/com/fasterxml/jackson/core/util/InternCache.java
index ecf561d4ba..454d07d2ae 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/InternCache.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/InternCache.java
@@ -1,6 +1,7 @@
package com.fasterxml.jackson.core.util;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Singleton class that adds a simple first-level cache in front of
@@ -19,8 +20,10 @@ public final class InternCache
*
* One consideration is possible attack via colliding {@link String#hashCode};
* because of this, limit to reasonably low setting.
+ *
+ * Increased to 200 (from 100) in 2.18
*/
- private final static int MAX_ENTRIES = 180;
+ private final static int DEFAULT_MAX_ENTRIES = 280;
public final static InternCache instance = new InternCache();
@@ -29,9 +32,9 @@ public final class InternCache
* cases where multiple threads might try to concurrently
* flush the map.
*/
- private final Object lock = new Object();
+ private final ReentrantLock lock = new ReentrantLock();
- public InternCache() { this(MAX_ENTRIES, 0.8f, 4); }
+ public InternCache() { this(DEFAULT_MAX_ENTRIES, 0.8f, 4); }
public InternCache(int maxSize, float loadFactor, int concurrency) {
super(maxSize, loadFactor, concurrency);
@@ -46,14 +49,20 @@ public String intern(String input) {
* possible limitation: just clear all contents. This because otherwise
* we are simply likely to keep on clearing same, commonly used entries.
*/
- if (size() >= MAX_ENTRIES) {
- /* Not incorrect wrt well-known double-locking anti-pattern because underlying
- * storage gives close enough answer to real one here; and we are
- * more concerned with flooding than starvation.
+ if (size() >= DEFAULT_MAX_ENTRIES) {
+ /* As of 2.18, the limit is not strictly enforced, but we do try to
+ * clear entries if we have reached the limit. We do not expect to
+ * go too much over the limit, and if we do, it's not a huge problem.
+ * If some other thread has the lock, we will not clear but the lock should
+ * not be held for long, so another thread should be able to clear in the near future.
*/
- synchronized (lock) {
- if (size() >= MAX_ENTRIES) {
- clear();
+ if (lock.tryLock()) {
+ try {
+ if (size() >= DEFAULT_MAX_ENTRIES) {
+ clear();
+ }
+ } finally {
+ lock.unlock();
}
}
}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/InternalJacksonUtil.java b/src/main/java/com/fasterxml/jackson/core/util/InternalJacksonUtil.java
new file mode 100644
index 0000000000..4b356552b5
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/core/util/InternalJacksonUtil.java
@@ -0,0 +1,25 @@
+package com.fasterxml.jackson.core.util;
+
+/**
+ * Internal Use Only. Helper class used to contain some useful utility methods.
+ *
+ * @since 2.17.3 / 2.18.1
+ */
+public abstract class InternalJacksonUtil {
+ /**
+ * Internal Use Only.
+ *
+ * Method that will add two non-negative integers, and if result overflows, return
+ * {@link Integer#MAX_VALUE}. For performance reasons, does NOT check for
+ * the result being less than {@link Integer#MIN_VALUE}, nor whether arguments
+ * are actually non-negative.
+ * This is usually used to implement overflow-safe bounds checking.
+ */
+ public static int addOverflowSafe(final int base, final int length) {
+ int result = base + length;
+ if (result < 0) {
+ return Integer.MAX_VALUE;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JacksonFeatureSet.java b/src/main/java/com/fasterxml/jackson/core/util/JacksonFeatureSet.java
index 970155d95e..42b8780885 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JacksonFeatureSet.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JacksonFeatureSet.java
@@ -52,11 +52,11 @@ public static JacksonFeatureSet fromDefaults(F[] a
flags |= f.getMask();
}
}
- return new JacksonFeatureSet(flags);
+ return new JacksonFeatureSet<>(flags);
}
public static JacksonFeatureSet fromBitmask(int bitmask) {
- return new JacksonFeatureSet(bitmask);
+ return new JacksonFeatureSet<>(bitmask);
}
/**
@@ -70,7 +70,7 @@ public static JacksonFeatureSet fromBitmask(int bi
*/
public JacksonFeatureSet with(F feature) {
int newMask = _enabled | feature.getMask();
- return (newMask == _enabled) ? this : new JacksonFeatureSet(newMask);
+ return (newMask == _enabled) ? this : new JacksonFeatureSet<>(newMask);
}
/**
@@ -84,7 +84,7 @@ public JacksonFeatureSet with(F feature) {
*/
public JacksonFeatureSet without(F feature) {
int newMask = _enabled & ~feature.getMask();
- return (newMask == _enabled) ? this : new JacksonFeatureSet(newMask);
+ return (newMask == _enabled) ? this : new JacksonFeatureSet<>(newMask);
}
/**
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 5879063d62..aec751e7ff 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
@@ -66,11 +66,11 @@ public JsonGeneratorDelegate(JsonGenerator d, boolean delegateCopyMethods) {
@Override public void assignCurrentValue(Object v) { delegate.assignCurrentValue(v); }
@Override public Object currentValue() { return delegate.currentValue(); }
- // TODO: deprecate in 2.14 or later
+ @Deprecated // since 2.17
@Override
public void setCurrentValue(Object v) { delegate.setCurrentValue(v); }
- // TODO: deprecate in 2.14 or later
+ @Deprecated // since 2.17
@Override
public Object getCurrentValue() { return delegate.getCurrentValue(); }
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 2ea888bb1d..950ccfa3d9 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserDelegate.java
@@ -7,6 +7,7 @@
import java.math.BigInteger;
import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.async.NonBlockingInputFeeder;
/**
* Helper class that implements
@@ -92,9 +93,25 @@ public StreamReadConstraints streamReadConstraints() {
/**********************************************************************
*/
- @Override public boolean requiresCustomCodec() { return delegate.requiresCustomCodec(); }
+ @Override
+ public boolean canParseAsync() {
+ return delegate.canParseAsync();
+ }
- @Override public JacksonFeatureSet getReadCapabilities() { return delegate.getReadCapabilities(); }
+ @Override
+ public NonBlockingInputFeeder getNonBlockingInputFeeder() {
+ return delegate.getNonBlockingInputFeeder();
+ }
+
+ @Override
+ public JacksonFeatureSet getReadCapabilities() {
+ return delegate.getReadCapabilities();
+ }
+
+ @Override
+ public boolean requiresCustomCodec() {
+ return delegate.requiresCustomCodec();
+ }
/*
/**********************************************************************
@@ -118,8 +135,8 @@ public StreamReadConstraints streamReadConstraints() {
@Override // since 2.13
public void assignCurrentValue(Object v) { delegate.assignCurrentValue(v); }
- // TODO: deprecate in 2.14 or later
@Override
+ @Deprecated
public void setCurrentValue(Object v) { delegate.setCurrentValue(v); }
/*
@@ -133,27 +150,37 @@ public StreamReadConstraints streamReadConstraints() {
@Override public JsonToken currentToken() { return delegate.currentToken(); }
@Override public int currentTokenId() { return delegate.currentTokenId(); }
@Override public String currentName() throws IOException { return delegate.currentName(); }
- @Override // since 2.13
- public Object currentValue() { return delegate.currentValue(); }
+ @Override public Object currentValue() { return delegate.currentValue(); }
- @Override // since 2.13
- public JsonLocation currentLocation() { return delegate.getCurrentLocation(); }
- @Override // since 2.13
- public JsonLocation currentTokenLocation() { return delegate.getTokenLocation(); }
+ @Override public JsonLocation currentLocation() { return delegate.currentLocation(); }
+ @Override public JsonLocation currentTokenLocation() { return delegate.currentTokenLocation(); }
+
+ @Override // since 2.18
+ public long currentTokenCount() { return delegate.currentTokenCount(); }
+
+ @Override
+ @Deprecated
+ public JsonToken getCurrentToken() { return delegate.getCurrentToken(); }
- // TODO: deprecate in 2.14 or later
- @Override public JsonToken getCurrentToken() { return delegate.getCurrentToken(); }
@Deprecated // since 2.12
- @Override public int getCurrentTokenId() { return delegate.getCurrentTokenId(); }
- // TODO: deprecate in 2.14 or later
- @Override public String getCurrentName() throws IOException { return delegate.getCurrentName(); }
- // TODO: deprecate in 2.14 or later
- @Override public Object getCurrentValue() { return delegate.getCurrentValue(); }
+ @Override
+ public int getCurrentTokenId() { return delegate.getCurrentTokenId(); }
- // TODO: deprecate in 2.14 or later
- @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
- // TODO: deprecate in 2.14 or later
- @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
+ @Override
+ @Deprecated // since 2.17
+ public String getCurrentName() throws IOException { return delegate.getCurrentName(); }
+
+ @Override
+ @Deprecated // since 2.17
+ public Object getCurrentValue() { return delegate.getCurrentValue(); }
+
+ @Override
+ @Deprecated // since 2.17
+ public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
+
+ @Override
+ @Deprecated // since 2.17
+ public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
/*
/**********************************************************************
@@ -220,6 +247,9 @@ public StreamReadConstraints streamReadConstraints() {
@Override
public NumberType getNumberType() throws IOException { return delegate.getNumberType(); }
+ @Override
+ public NumberTypeFP getNumberTypeFP() throws IOException { return delegate.getNumberTypeFP(); }
+
@Override
public Number getNumberValue() throws IOException { return delegate.getNumberValue(); }
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java b/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java
index 1c5889ff78..5ea25ca6a0 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java
@@ -93,7 +93,7 @@ public static JsonParserSequence createFlattened(boolean checkForExistingToken,
return new JsonParserSequence(checkForExistingToken,
new JsonParser[] { first, second });
}
- ArrayList p = new ArrayList();
+ ArrayList p = new ArrayList<>();
if (first instanceof JsonParserSequence) {
((JsonParserSequence) first).addFlattenedActiveParsers(p);
} else {
diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonRecyclerPools.java b/src/main/java/com/fasterxml/jackson/core/util/JsonRecyclerPools.java
index 5f38d3e23b..d3873a3082 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/JsonRecyclerPools.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/JsonRecyclerPools.java
@@ -6,7 +6,6 @@
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.util.RecyclerPool.BoundedPoolBase;
import com.fasterxml.jackson.core.util.RecyclerPool.ConcurrentDequePoolBase;
-import com.fasterxml.jackson.core.util.RecyclerPool.LockFreePoolBase;
/**
* Set of {@link RecyclerPool} implementations to be used by the default
@@ -18,9 +17,15 @@
public final class JsonRecyclerPools
{
/**
- * @return the default {@link RecyclerPool} implementation
- * which is the thread local based one:
- * basically alias to {@link #threadLocalPool()}).
+ * Method to call to get the default recycler pool instance:
+ * as of Jackson 2.18 this is same as calling
+ * {@link #threadLocalPool()}: Jackson 2.17.0 instead had this call
+ * {@link #newLockFreePool()} but this was reverted due to problems reported.
+ *
+ * Default pool will likely be changed in Jackson 3.0 to something else.
+ *
+ * @return the default {@link RecyclerPool} implementation to use
+ * if no specific implementation desired.
*/
public static RecyclerPool defaultPool() {
return threadLocalPool();
@@ -68,7 +73,11 @@ public static RecyclerPool newConcurrentDequePool() {
* Accessor for getting the shared/global {@link LockFreePool} instance.
*
* @return Globally shared instance of {@link LockFreePool}.
+ *
+ * @deprecated Since 2.18: use one of other implementations instead;
+ * see {@link LockFreePool} Javadocs for details
*/
+ @Deprecated // since 2.18
public static RecyclerPool sharedLockFreePool() {
return LockFreePool.GLOBAL;
}
@@ -77,7 +86,11 @@ public static RecyclerPool sharedLockFreePool() {
* Accessor for constructing a new, non-shared {@link LockFreePool} instance.
*
* @return Globally shared instance of {@link LockFreePool}.
+ *
+ * @deprecated Since 2.18: use one of other implementations instead;
+ * see {@link LockFreePool} Javadocs for details
*/
+ @Deprecated // since 2.18
public static RecyclerPool newLockFreePool() {
return LockFreePool.construct();
}
@@ -198,8 +211,18 @@ protected Object readResolve() {
*
* Pool is unbounded: see {@link RecyclerPool} for
* details on what this means.
+ *
+ * NOTE: serious issues found with 2.17.0 lead to deprecation
+ * of this implementation -- basically it is possible to have
+ * unbalanced acquire/release success rate lead to excessive
+ * growth of pooled instances.
+ * See
+ * jackson-core#1260 for details.
+ *
+ * @deprecated Since 2.18: use other implementations instead
*/
- public static class LockFreePool extends LockFreePoolBase
+ @Deprecated
+ public static class LockFreePool extends RecyclerPool.LockFreePoolBase
{
private static final long serialVersionUID = 1L;
diff --git a/src/main/java/com/fasterxml/jackson/core/util/RecyclerPool.java b/src/main/java/com/fasterxml/jackson/core/util/RecyclerPool.java
index 2a6c1e0f5f..0973e139bd 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/RecyclerPool.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/RecyclerPool.java
@@ -97,6 +97,39 @@ default P acquireAndLinkPooled() {
*/
void releasePooled(P pooled);
+ /**
+ * Optional method that may allow dropping of all pooled Objects; mostly
+ * useful for unbounded pool implementations that may retain significant
+ * memory and that may then be cleared regularly.
+ *
+ * @since 2.17
+ *
+ * @return {@code true} If pool supports operation and dropped all pooled
+ * Objects; {@code false} otherwise.
+ */
+ default boolean clear() {
+ return false;
+ }
+
+ /**
+ * Diagnostic method for obtaining an estimate of number of pooled items
+ * this pool contains, available for recycling.
+ * Note that in addition to this information possibly not being available
+ * (denoted by return value of {@code -1}) even when available this may be
+ * just an approximation.
+ *
+ * Default method implementation simply returns {@code -1} and is meant to be
+ * overridden by concrete sub-classes.
+ *
+ * @return Number of pooled entries available from this pool, if available;
+ * {@code -1} if not.
+ *
+ * @since 2.18
+ */
+ default int pooledCount() {
+ return -1;
+ }
+
/*
/**********************************************************************
/* Partial/base RecyclerPool implementations
@@ -133,7 +166,19 @@ public P acquireAndLinkPooled() {
@Override
public void releasePooled(P pooled) {
- ; // nothing to do, relies on ThreadLocal
+ // nothing to do, relies on ThreadLocal
+ }
+
+ // No way to actually even estimate...
+ @Override
+ public int pooledCount() {
+ return -1;
+ }
+
+ // Due to use of ThreadLocal no tracking available; cannot clear
+ @Override
+ public boolean clear() {
+ return false;
}
}
@@ -158,7 +203,23 @@ public P acquireAndLinkPooled() {
@Override
public void releasePooled(P pooled) {
- ; // nothing to do, there is no underlying pool
+ // nothing to do, there is no underlying pool
+ }
+
+ @Override
+ public int pooledCount() {
+ return 0;
+ }
+
+ /**
+ * Although no pooling occurs, we consider clearing to succeed,
+ * so returns always {@code true}.
+ *
+ * @return Always returns {@code true}
+ */
+ @Override
+ public boolean clear() {
+ return true;
}
}
@@ -226,11 +287,21 @@ public P acquirePooled() {
return pooled;
}
-
@Override
public void releasePooled(P pooled) {
pool.offerLast(pooled);
}
+
+ @Override
+ public int pooledCount() {
+ return pool.size();
+ }
+
+ @Override
+ public boolean clear() {
+ pool.clear();
+ return true;
+ }
}
/**
@@ -238,7 +309,17 @@ public void releasePooled(P pooled) {
* a lock free linked list for recycling instances.
* Pool is unbounded: see {@link RecyclerPool} for
* details on what this means.
+ *
+ * NOTE: serious issues found with 2.17.0 lead to deprecation
+ * of this implementation -- basically it is possible to have
+ * unbalanced acquire/release success rate lead to excessive
+ * growth of pooled instances.
+ * See
+ * jackson-core#1260 for details.
+ *
+ * @deprecated Since 2.18: use other implementations
*/
+ @Deprecated // since 2.18
abstract class LockFreePoolBase
>
extends StatefulImplBase
{
@@ -286,6 +367,22 @@ public void releasePooled(P pooled) {
}
}
+ @Override
+ public int pooledCount() {
+ int count = 0;
+ for (Node
curr = head.get(); curr != null; curr = curr.next) {
+ ++count;
+ }
+ return count;
+ }
+
+ // Yes, we can clear it
+ @Override
+ public boolean clear() {
+ head.set(null);
+ return true;
+ }
+
protected static class Node
{
final P value;
Node
next;
@@ -342,6 +439,17 @@ public void releasePooled(P pooled) {
pool.offer(pooled);
}
+ @Override
+ public int pooledCount() {
+ return pool.size();
+ }
+
+ @Override
+ public boolean clear() {
+ pool.clear();
+ return true;
+ }
+
// // // Other methods
public int capacity() {
diff --git a/src/main/java/com/fasterxml/jackson/core/util/Separators.java b/src/main/java/com/fasterxml/jackson/core/util/Separators.java
index 057c2bf881..1416d0d694 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/Separators.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/Separators.java
@@ -1,6 +1,7 @@
package com.fasterxml.jackson.core.util;
import java.io.Serializable;
+import java.util.Objects;
/**
* Value class used with some {@link com.fasterxml.jackson.core.PrettyPrinter}
@@ -23,6 +24,22 @@ public class Separators implements Serializable
*/
public final static String DEFAULT_ROOT_VALUE_SEPARATOR = " ";
+ /**
+ * String to use in empty Object to separate start and end markers.
+ * Default is single space, resulting in output of {@code { }}.
+ *
+ * @since 2.17
+ */
+ public final static String DEFAULT_OBJECT_EMPTY_SEPARATOR = " ";
+
+ /**
+ * String to use in empty Array to separate start and end markers.
+ * Default is single space, resulting in output of {@code [ ]}.
+ *
+ * @since 2.17
+ */
+ public final static String DEFAULT_ARRAY_EMPTY_SEPARATOR = " ";
+
/**
* Define the spacing around elements like commas and colons.
*
@@ -59,14 +76,20 @@ public String apply(char separator) {
private final Spacing objectFieldValueSpacing;
private final char objectEntrySeparator;
private final Spacing objectEntrySpacing;
+ private final String objectEmptySeparator;
private final char arrayValueSeparator;
private final Spacing arrayValueSpacing;
+ private final String arrayEmptySeparator;
private final String rootSeparator;
public static Separators createDefaultInstance() {
return new Separators();
}
+ /**
+ * Constructor for creating an instance with default settings for all
+ * separators.
+ */
public Separators() {
this(':', ',', ',');
}
@@ -82,15 +105,18 @@ public Separators(
) {
this(DEFAULT_ROOT_VALUE_SEPARATOR,
objectFieldValueSeparator, Spacing.BOTH,
- objectEntrySeparator, Spacing.NONE,
- arrayValueSeparator, Spacing.NONE);
+ objectEntrySeparator, Spacing.NONE, DEFAULT_OBJECT_EMPTY_SEPARATOR,
+ arrayValueSeparator, Spacing.NONE, DEFAULT_ARRAY_EMPTY_SEPARATOR);
}
/**
* Create an instance with the specified separator characters and spaces around those characters.
*
* @since 2.16
+ *
+ * @deprecated Since 2.17 use new canonical constructor
*/
+ @Deprecated // since 2.17
public Separators(
String rootSeparator,
char objectFieldValueSeparator,
@@ -99,24 +125,52 @@ public Separators(
Spacing objectEntrySpacing,
char arrayValueSeparator,
Spacing arrayValueSpacing
+ ) {
+ this(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, DEFAULT_OBJECT_EMPTY_SEPARATOR,
+ arrayValueSeparator, arrayValueSpacing, DEFAULT_ARRAY_EMPTY_SEPARATOR);
+ }
+
+ /**
+ * Canonical constructor for creating an instance with the specified separator
+ * characters and spaces around those characters.
+ *
+ * @since 2.17
+ */
+ public Separators(
+ String rootSeparator,
+ char objectFieldValueSeparator,
+ Spacing objectFieldValueSpacing,
+ char objectEntrySeparator,
+ Spacing objectEntrySpacing,
+ String objectEmptySeparator,
+ char arrayValueSeparator,
+ Spacing arrayValueSpacing,
+ String arrayEmptySeparator
) {
this.rootSeparator = rootSeparator;
this.objectFieldValueSeparator = objectFieldValueSeparator;
this.objectFieldValueSpacing = objectFieldValueSpacing;
this.objectEntrySeparator = objectEntrySeparator;
this.objectEntrySpacing = objectEntrySpacing;
+ this.objectEmptySeparator = objectEmptySeparator;
this.arrayValueSeparator = arrayValueSeparator;
this.arrayValueSpacing = arrayValueSpacing;
+ this.arrayEmptySeparator = arrayEmptySeparator;
}
public Separators withRootSeparator(String sep) {
- return (rootSeparator.equals(sep)) ? this
- : new Separators(sep, objectFieldValueSeparator, objectFieldValueSpacing, objectEntrySeparator, objectEntrySpacing, arrayValueSeparator, arrayValueSpacing);
+ return Objects.equals(rootSeparator, sep) ? this
+ : new Separators(sep, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, objectEmptySeparator,
+ arrayValueSeparator, arrayValueSpacing, arrayEmptySeparator);
}
-
+
public Separators withObjectFieldValueSeparator(char sep) {
return (objectFieldValueSeparator == sep) ? this
- : new Separators(rootSeparator, sep, objectFieldValueSpacing, objectEntrySeparator, objectEntrySpacing, arrayValueSeparator, arrayValueSpacing);
+ : new Separators(rootSeparator, sep, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, objectEmptySeparator,
+ arrayValueSeparator, arrayValueSpacing, arrayEmptySeparator);
}
/**
@@ -126,12 +180,16 @@ public Separators withObjectFieldValueSeparator(char sep) {
*/
public Separators withObjectFieldValueSpacing(Spacing spacing) {
return (objectFieldValueSpacing == spacing) ? this
- : new Separators(rootSeparator, objectFieldValueSeparator, spacing, objectEntrySeparator, objectEntrySpacing, arrayValueSeparator, arrayValueSpacing);
+ : new Separators(rootSeparator, objectFieldValueSeparator, spacing,
+ objectEntrySeparator, objectEntrySpacing, objectEmptySeparator,
+ arrayValueSeparator, arrayValueSpacing, arrayEmptySeparator);
}
public Separators withObjectEntrySeparator(char sep) {
return (objectEntrySeparator == sep) ? this
- : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing, sep, objectEntrySpacing, arrayValueSeparator, arrayValueSpacing);
+ : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ sep, objectEntrySpacing, objectEmptySeparator,
+ arrayValueSeparator, arrayValueSpacing, arrayEmptySeparator);
}
/**
@@ -141,12 +199,28 @@ public Separators withObjectEntrySeparator(char sep) {
*/
public Separators withObjectEntrySpacing(Spacing spacing) {
return (objectEntrySpacing == spacing) ? this
- : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing, objectEntrySeparator, spacing, arrayValueSeparator, arrayValueSpacing);
+ : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, spacing, objectEmptySeparator,
+ arrayValueSeparator, arrayValueSpacing, arrayEmptySeparator);
+ }
+
+ /**
+ * @return This instance (for call chaining)
+ *
+ * @since 2.17
+ */
+ public Separators withObjectEmptySeparator(String sep) {
+ return Objects.equals(objectEmptySeparator, sep) ? this
+ : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, sep,
+ arrayValueSeparator, arrayValueSpacing, arrayEmptySeparator);
}
public Separators withArrayValueSeparator(char sep) {
return (arrayValueSeparator == sep) ? this
- : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing, objectEntrySeparator, objectEntrySpacing, sep, arrayValueSpacing);
+ : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, objectEmptySeparator,
+ sep, arrayValueSpacing, arrayEmptySeparator);
}
/**
@@ -156,7 +230,21 @@ public Separators withArrayValueSeparator(char sep) {
*/
public Separators withArrayValueSpacing(Spacing spacing) {
return (arrayValueSpacing == spacing) ? this
- : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing, objectEntrySeparator, objectEntrySpacing, arrayValueSeparator, spacing);
+ : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, objectEmptySeparator,
+ arrayValueSeparator, spacing, arrayEmptySeparator);
+ }
+
+ /**
+ * @return This instance (for call chaining)
+ *
+ * @since 2.17
+ */
+ public Separators withArrayEmptySeparator(String sep) {
+ return Objects.equals(arrayEmptySeparator, sep) ? this
+ : new Separators(rootSeparator, objectFieldValueSeparator, objectFieldValueSpacing,
+ objectEntrySeparator, objectEntrySpacing, objectEmptySeparator,
+ arrayValueSeparator, arrayValueSpacing, sep);
}
/**
@@ -193,6 +281,15 @@ public char getObjectEntrySeparator() {
public Spacing getObjectEntrySpacing() {
return objectEntrySpacing;
}
+
+ /**
+ * @return String to use in empty Object
+ *
+ * @since 2.17
+ */
+ public String getObjectEmptySeparator() {
+ return objectEmptySeparator;
+ }
public char getArrayValueSeparator() {
return arrayValueSeparator;
@@ -206,4 +303,13 @@ public char getArrayValueSeparator() {
public Spacing getArrayValueSpacing() {
return arrayValueSpacing;
}
+
+ /**
+ * @return String to use in empty Array
+ *
+ * @since 2.17
+ */
+ public String getArrayEmptySeparator() {
+ return arrayEmptySeparator;
+ }
}
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 f7bc862779..06c96fe48b 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java
@@ -121,7 +121,7 @@ public class TextBuffer
/**********************************************************
*/
- public TextBuffer( BufferRecycler allocator) {
+ public TextBuffer(BufferRecycler allocator) {
_allocator = allocator;
}
@@ -327,7 +327,6 @@ public void resetWithString(String value) throws IOException
clearSegments();
}
_currentSize = 0;
-
}
/**
@@ -355,12 +354,11 @@ private char[] buf(int needed)
private void clearSegments()
{
_hasSegments = false;
- /* Let's start using _last_ segment from list; for one, it's
- * the biggest one, and it's also most likely to be cached
- */
- /* 28-Aug-2009, tatu: Actually, the current segment should
- * be the biggest one, already
- */
+ // Let's start using _last_ segment from list; for one, it's
+ // the biggest one, and it's also most likely to be cached
+
+ // 28-Aug-2009, tatu: Actually, the current segment should
+ // be the biggest one, already
//_currentSegment = _segments.get(_segments.size() - 1);
_segments.clear();
_currentSize = _segmentSize = 0;
@@ -372,6 +370,13 @@ private void clearSegments()
/**********************************************************
*/
+ /**
+ * @since 2.17
+ */
+ public BufferRecycler bufferRecycler() {
+ return _allocator;
+ }
+
/**
* @return Number of characters currently stored in this buffer
*/
@@ -519,15 +524,41 @@ public char[] contentsAsArray() throws IOException {
/**
* Convenience method for converting contents of the buffer
* into a Double value.
+ *
+ * NOTE! Caller MUST validate contents before calling this method,
+ * to ensure textual version is valid JSON floating-point token -- this
+ * method is not guaranteed to do any validation and behavior with invalid
+ * content is not defined (either throws an exception or returns arbitrary
+ * number).
*
* @param useFastParser whether to use {@code FastDoubleParser}
* @return Buffered text value parsed as a {@link Double}, if possible
*
- * @throws NumberFormatException if contents are not a valid Java number
+ * @throws NumberFormatException may (but is not guaranteed!) be thrown
+ * if contents are not a valid JSON floating-point number representation
*
* @since 2.14
*/
- public double contentsAsDouble(final boolean useFastParser) throws NumberFormatException {
+ public double contentsAsDouble(final boolean useFastParser) throws NumberFormatException
+ {
+ // Order in which check is somewhat arbitrary... try likeliest ones
+ // that do not require allocation first
+
+ // except _resultString first since it works best with JDK (non-fast parser)
+ if (_resultString != null) {
+ return NumberInput.parseDouble(_resultString, useFastParser);
+ }
+ if (_inputStart >= 0) { // shared?
+ return NumberInput.parseDouble(_inputBuffer, _inputStart, _inputLen, useFastParser);
+ }
+ if (!_hasSegments) { // all content in current segment!
+ return NumberInput.parseDouble(_currentSegment, 0, _currentSize, useFastParser);
+ }
+ if (_resultArray != null) {
+ return NumberInput.parseDouble(_resultArray, useFastParser);
+ }
+
+ // Otherwise, segmented so need to use slow path
try {
return NumberInput.parseDouble(contentsAsString(), useFastParser);
} catch (IOException e) {
@@ -568,14 +599,41 @@ public float contentsAsFloat() throws NumberFormatException {
/**
* Convenience method for converting contents of the buffer
* into a Float value.
+ *
+ * NOTE! Caller MUST validate contents before calling this method,
+ * to ensure textual version is valid JSON floating-point token -- this
+ * method is not guaranteed to do any validation and behavior with invalid
+ * content is not defined (either throws an exception or returns arbitrary
+ * number).
*
* @param useFastParser whether to use {@code FastDoubleParser}
* @return Buffered text value parsed as a {@link Float}, if possible
*
- * @throws NumberFormatException if contents are not a valid Java number
+ * @throws NumberFormatException may (but is not guaranteed!) be thrown
+ * if contents are not a valid JSON floating-point number representation
+ *
* @since 2.14
*/
- public float contentsAsFloat(final boolean useFastParser) throws NumberFormatException {
+ public float contentsAsFloat(final boolean useFastParser) throws NumberFormatException
+ {
+ // Order in which check is somewhat arbitrary... try likeliest ones
+ // that do not require allocation first
+
+ // except _resultString first since it works best with JDK (non-fast parser)
+ if (_resultString != null) {
+ return NumberInput.parseFloat(_resultString, useFastParser);
+ }
+ if (_inputStart >= 0) { // shared?
+ return NumberInput.parseFloat(_inputBuffer, _inputStart, _inputLen, useFastParser);
+ }
+ if (!_hasSegments) { // all content in current segment!
+ return NumberInput.parseFloat(_currentSegment, 0, _currentSize, useFastParser);
+ }
+ if (_resultArray != null) {
+ return NumberInput.parseFloat(_resultArray, useFastParser);
+ }
+
+ // Otherwise, segmented so need to use slow path
try {
return NumberInput.parseFloat(contentsAsString(), useFastParser);
} catch (IOException e) {
@@ -585,18 +643,38 @@ public float contentsAsFloat(final boolean useFastParser) throws NumberFormatExc
}
/**
- * @return Buffered text value parsed as a {@link BigDecimal}, if possible
- * @throws NumberFormatException if contents are not a valid Java number
- *
- * @deprecated Since 2.15 just access String contents if necessary, call
- * {@link NumberInput#parseBigDecimal(String, boolean)} (or other overloads)
- * directly instead
+ * @deprecated Since 2.15 use {@link #contentsAsDecimal(boolean)} instead.
*/
@Deprecated
public BigDecimal contentsAsDecimal() throws NumberFormatException {
- // Was more optimized earlier, removing special handling due to deprecation
+ return contentsAsDecimal(false);
+ }
+
+ /**
+ * @since 2.18
+ */
+ public BigDecimal contentsAsDecimal(final boolean useFastParser) throws NumberFormatException
+ {
+ // Order in which check is somewhat arbitrary... try likeliest ones
+ // that do not require allocation first
+
+ // except _resultString first since it works best with JDK (non-fast parser)
+ if (_resultString != null) {
+ return NumberInput.parseBigDecimal(_resultString, useFastParser);
+ }
+ if (_inputStart >= 0) { // shared?
+ return NumberInput.parseBigDecimal(_inputBuffer, _inputStart, _inputLen, useFastParser);
+ }
+ if (!_hasSegments) { // all content in current segment!
+ return NumberInput.parseBigDecimal(_currentSegment, 0, _currentSize, useFastParser);
+ }
+ if (_resultArray != null) {
+ return NumberInput.parseBigDecimal(_resultArray, useFastParser);
+ }
+
+ // Otherwise, segmented so need to use slow path
try {
- return NumberInput.parseBigDecimal(contentsAsArray());
+ return NumberInput.parseBigDecimal(contentsAsArray(), useFastParser);
} catch (IOException e) {
// JsonParseException is used to denote a string that is too long
throw new NumberFormatException(e.getMessage());
@@ -926,7 +1004,7 @@ public String setCurrentAndReturn(int len) throws IOException {
*/
public char[] finishCurrentSegment() throws IOException {
if (_segments == null) {
- _segments = new ArrayList();
+ _segments = new ArrayList<>();
}
_hasSegments = true;
_segments.add(_currentSegment);
@@ -1091,7 +1169,7 @@ private void expand()
{
// First, let's move current segment to segment list:
if (_segments == null) {
- _segments = new ArrayList();
+ _segments = new ArrayList<>();
}
char[] curr = _currentSegment;
_hasSegments = true;
diff --git a/src/main/java/com/fasterxml/jackson/core/util/ThreadLocalBufferManager.java b/src/main/java/com/fasterxml/jackson/core/util/ThreadLocalBufferManager.java
index aff68ee8e6..7688cb95e6 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/ThreadLocalBufferManager.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/ThreadLocalBufferManager.java
@@ -5,6 +5,7 @@
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
/**
* For issue [jackson-core#400] We keep a separate Set of all SoftReferences to BufferRecyclers
@@ -23,7 +24,7 @@ class ThreadLocalBufferManager
* A lock to make sure releaseBuffers is only executed by one thread at a time
* since it iterates over and modifies the allSoftBufRecyclers.
*/
- private final Object RELEASE_LOCK = new Object();
+ private final ReentrantLock RELEASE_LOCK = new ReentrantLock();
/**
* A set of all SoftReferences to all BufferRecyclers to be able to release them on shutdown.
@@ -36,13 +37,13 @@ class ThreadLocalBufferManager
* we do not need to use something like {@link IdentityHashMap}
*/
private final Map,Boolean> _trackedRecyclers
- = new ConcurrentHashMap, Boolean>();
+ = new ConcurrentHashMap<>();
/**
* Queue where gc will put just-cleared SoftReferences, previously referencing BufferRecyclers.
* We use it to remove the cleared softRefs from the above set.
*/
- private final ReferenceQueue _refQueue = new ReferenceQueue();
+ private final ReferenceQueue _refQueue = new ReferenceQueue<>();
/*
/**********************************************************
@@ -64,8 +65,9 @@ public static ThreadLocalBufferManager instance() {
* It will clear all bufRecyclers from the SoftRefs and release all SoftRefs itself from our set.
*/
public int releaseBuffers() {
- synchronized (RELEASE_LOCK) {
- int count = 0;
+ int count = 0;
+ RELEASE_LOCK.lock();
+ try {
// does this need to be in sync block too? Looping over Map definitely has to but...
removeSoftRefsClearedByGc(); // make sure the refQueue is empty
for (SoftReference ref : _trackedRecyclers.keySet()) {
@@ -73,13 +75,15 @@ public int releaseBuffers() {
++count;
}
_trackedRecyclers.clear(); //release cleared SoftRefs
- return count;
+ } finally {
+ RELEASE_LOCK.unlock();
}
+ return count;
}
public SoftReference wrapAndTrack(BufferRecycler br) {
SoftReference newRef;
- newRef = new SoftReference(br, _refQueue);
+ newRef = new SoftReference<>(br, _refQueue);
// also retain softRef to br in a set to be able to release it on shutdown
_trackedRecyclers.put(newRef, true);
// gc may have cleared one or more SoftRefs, clean them up to avoid a memleak
@@ -95,8 +99,7 @@ public SoftReference wrapAndTrack(BufferRecycler br) {
/**
* Remove cleared (inactive) SoftRefs from our set. Gc may have cleared one or more,
- * and made them inactive. We minimize contention by keeping synchronized sections short:
- * the poll/remove methods
+ * and made them inactive.
*/
private void removeSoftRefsClearedByGc() {
SoftReference> clearedSoftRef;
diff --git a/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java b/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java
index d8f830eba5..b38cd53cb6 100644
--- a/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java
+++ b/src/main/java/com/fasterxml/jackson/core/util/VersionUtil.java
@@ -69,7 +69,8 @@ public static Version versionFor(Class> cls)
} catch (Exception e) {
throw new IllegalArgumentException("Failed to get Versioned out of "+vClass);
}
- } catch (Exception e) { // ok to be missing (not good but acceptable)
+ } catch (Exception e) {
+ // ok to be missing (not good but acceptable)
;
}
return (v == null) ? Version.unknownVersion() : v;
diff --git a/src/moditect/module-info.java b/src/moditect/module-info.java
index 8d928d192b..566ec0c97f 100644
--- a/src/moditect/module-info.java
+++ b/src/moditect/module-info.java
@@ -20,4 +20,8 @@
// 03-Oct-2019, tatu: [core#567] Add self-use to avoid warnings
uses com.fasterxml.jackson.core.ObjectCodec;
+
+ // 25-Sep-2024: [core#1340] Need to explicitly add even in base
+ provides com.fasterxml.jackson.core.JsonFactory with
+ com.fasterxml.jackson.core.JsonFactory;
}
diff --git a/src/test/java/com/fasterxml/jackson/core/TestVersions.java b/src/test/java/com/fasterxml/jackson/core/ComponentVersionsTest.java
similarity index 58%
rename from src/test/java/com/fasterxml/jackson/core/TestVersions.java
rename to src/test/java/com/fasterxml/jackson/core/ComponentVersionsTest.java
index 053b66b8e4..5636153800 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestVersions.java
+++ b/src/test/java/com/fasterxml/jackson/core/ComponentVersionsTest.java
@@ -1,36 +1,56 @@
package com.fasterxml.jackson.core;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.json.*;
import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
+import com.fasterxml.jackson.core.testsupport.TestSupport;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests to verify functioning of {@link Version} class.
*/
-public class TestVersions extends com.fasterxml.jackson.core.BaseTest
+class ComponentVersionsTest
+ extends JUnit5TestBase
{
- public void testCoreVersions() throws Exception
+ @Test
+ void coreVersions() throws Exception
{
final JsonFactory f = new JsonFactory();
assertVersion(f.version());
- try (ReaderBasedJsonParser p = new ReaderBasedJsonParser(testIOContext(), 0, null, null,
+ try (ReaderBasedJsonParser p = new ReaderBasedJsonParser(TestSupport.testIOContext(), 0, null, null,
CharsToNameCanonicalizer.createRoot(f))) {
assertVersion(p.version());
}
- try (JsonGenerator g = new WriterBasedJsonGenerator(testIOContext(), 0, null, null, '"')) {
+ try (JsonGenerator g = new WriterBasedJsonGenerator(TestSupport.testIOContext(), 0, null, null, '"')) {
assertVersion(g.version());
}
}
- public void testMisc() {
+ @Test
+ void equality() {
Version unk = Version.unknownVersion();
assertEquals("0.0.0", unk.toString());
assertEquals("//0.0.0", unk.toFullString());
- assertTrue(unk.equals(unk));
+ assertEquals(unk, unk);
Version other = new Version(2, 8, 4, "",
"groupId", "artifactId");
assertEquals("2.8.4", other.toString());
assertEquals("groupId/artifactId/2.8.4", other.toFullString());
+
+ // [core#1141]: Avoid NPE for snapshot-info
+ Version unk2 = new Version(0, 0, 0, null, null, null);
+ assertEquals(unk, unk2);
+ }
+
+ @Test
+ void misc() {
+ Version unk = Version.unknownVersion();
+ int hash = unk.hashCode();
+ // Happens to be 0 at this point (Jackson 2.16)
+ assertEquals(0, hash);
}
/*
diff --git a/src/test/java/com/fasterxml/jackson/core/ErrorReportConfigurationTest.java b/src/test/java/com/fasterxml/jackson/core/ErrorReportConfigurationTest.java
index 956d07d070..ec60e1ee5b 100644
--- a/src/test/java/com/fasterxml/jackson/core/ErrorReportConfigurationTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/ErrorReportConfigurationTest.java
@@ -1,17 +1,22 @@
package com.fasterxml.jackson.core;
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.io.ContentReference;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
/**
* Unit tests for class {@link ErrorReportConfiguration}.
*
* @since 2.16
*/
-public class ErrorReportConfigurationTest
- extends BaseTest
+class ErrorReportConfigurationTest
+ extends JUnit5TestBase
{
-
/*
/**********************************************************
/* Unit Tests
@@ -24,7 +29,8 @@ public class ErrorReportConfigurationTest
private final ErrorReportConfiguration DEFAULTS = ErrorReportConfiguration.defaults();
- public void testNormalBuild()
+ @Test
+ void normalBuild()
{
ErrorReportConfiguration config = ErrorReportConfiguration.builder()
.maxErrorTokenLength(1004)
@@ -35,7 +41,8 @@ public void testNormalBuild()
assertEquals(2008, config.getMaxRawContentLength());
}
- public void testZeroLengths()
+ @Test
+ void zeroLengths()
{
// boundary tests, because we throw error on negative values
ErrorReportConfiguration config = ErrorReportConfiguration.builder()
@@ -47,7 +54,8 @@ public void testZeroLengths()
assertEquals(0, config.getMaxRawContentLength());
}
- public void testInvalidMaxErrorTokenLength()
+ @Test
+ void invalidMaxErrorTokenLength()
{
ErrorReportConfiguration.Builder builder = ErrorReportConfiguration.builder();
try {
@@ -66,7 +74,8 @@ public void testInvalidMaxErrorTokenLength()
}
}
- public void testDefaults()
+ @Test
+ void defaults()
{
// default value
assertEquals(DEFAULT_ERROR_LENGTH, DEFAULTS.getMaxErrorTokenLength());
@@ -76,7 +85,8 @@ public void testDefaults()
assertEquals(ErrorReportConfiguration.defaults(), ErrorReportConfiguration.defaults());
}
- public void testOverrideDefaultErrorReportConfiguration()
+ @Test
+ void overrideDefaultErrorReportConfiguration()
{
// (1) override with null, will be no change
ErrorReportConfiguration.overrideDefaultErrorReportConfiguration(null);
@@ -106,7 +116,8 @@ public void testOverrideDefaultErrorReportConfiguration()
}
}
- public void testRebuild()
+ @Test
+ void rebuild()
{
ErrorReportConfiguration config = ErrorReportConfiguration.builder().build();
ErrorReportConfiguration rebuiltConfig = config.rebuild().build();
@@ -115,7 +126,8 @@ public void testRebuild()
assertEquals(config.getMaxRawContentLength(), rebuiltConfig.getMaxRawContentLength());
}
- public void testBuilderConstructorWithErrorReportConfiguration()
+ @Test
+ void builderConstructorWithErrorReportConfiguration()
{
ErrorReportConfiguration configA = ErrorReportConfiguration.builder()
.maxErrorTokenLength(1234)
@@ -128,7 +140,8 @@ public void testBuilderConstructorWithErrorReportConfiguration()
assertEquals(configA.getMaxRawContentLength(), configB.getMaxRawContentLength());
}
- public void testWithJsonLocation() throws Exception
+ @Test
+ void withJsonLocation() throws Exception
{
// Truncated result
_verifyJsonLocationToString("abc", 2, "\"ab\"[truncated 1 chars]");
@@ -138,7 +151,8 @@ public void testWithJsonLocation() throws Exception
_verifyJsonLocationToString("abc", 4, "\"abc\"");
}
- public void testWithJsonFactory() throws Exception
+ @Test
+ void withJsonFactory() throws Exception
{
// default
_verifyJsonProcessingExceptionSourceLength(500,
@@ -160,7 +174,8 @@ public void testWithJsonFactory() throws Exception
.maxRawContentLength(0).build());
}
- public void testExpectedTokenLengthWithConfigurations()
+ @Test
+ void expectedTokenLengthWithConfigurations()
throws Exception
{
// default
@@ -201,7 +216,8 @@ public void testExpectedTokenLengthWithConfigurations()
}
}
- public void testNonPositiveErrorTokenConfig()
+ @Test
+ void nonPositiveErrorTokenConfig()
{
// Zero should be ok
ErrorReportConfiguration.builder().maxErrorTokenLength(0).build();
@@ -217,7 +233,8 @@ public void testNonPositiveErrorTokenConfig()
}
}
- public void testNullSetterThrowsException() {
+ @Test
+ void nullSetterThrowsException() {
try {
newStreamFactory().setErrorReportConfiguration(null);
fail();
diff --git a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java b/src/test/java/com/fasterxml/jackson/core/ExceptionsTest.java
similarity index 87%
rename from src/test/java/com/fasterxml/jackson/core/TestExceptions.java
rename to src/test/java/com/fasterxml/jackson/core/ExceptionsTest.java
index fa85a8dc51..5cd9d89d59 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestExceptions.java
+++ b/src/test/java/com/fasterxml/jackson/core/ExceptionsTest.java
@@ -2,15 +2,21 @@
import java.io.StringWriter;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.core.io.JsonEOFException;
-public class TestExceptions extends BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+class ExceptionsTest
+ extends JUnit5TestBase
{
private final JsonFactory JSON_F = newStreamFactory();
// For [core#10]
- public void testOriginalMesssage()
+ @Test
+ void originalMesssage()
{
JsonProcessingException exc = new JsonParseException(null, "Foobar", JsonLocation.NA);
String msg = exc.getMessage();
@@ -34,7 +40,8 @@ public void testOriginalMesssage()
}
// [core#198]
- public void testAccessToParser() throws Exception
+ @Test
+ void accessToParser() throws Exception
{
JsonParser p = JSON_F.createParser("{}");
assertToken(JsonToken.START_OBJECT, p.nextToken());
@@ -49,7 +56,8 @@ public void testAccessToParser() throws Exception
}
// [core#198]
- public void testAccessToGenerator() throws Exception
+ @Test
+ void accessToGenerator() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator g = JSON_F.createGenerator(w);
@@ -61,18 +69,20 @@ public void testAccessToGenerator() throws Exception
}
// [core#281]: new eof exception
- public void testEofExceptionsBytes() throws Exception {
+ @Test
+ void eofExceptionsBytes() throws Exception {
_testEofExceptions(MODE_INPUT_STREAM);
}
// [core#281]: new eof exception
- public void testEofExceptionsChars() throws Exception {
+ @Test
+ void eofExceptionsChars() throws Exception {
_testEofExceptions(MODE_READER);
}
private void _testEofExceptions(int mode) throws Exception
{
- JsonParser p = createParser(mode, "[ ");
+ JsonParser p = createParser(JSON_F, mode, "[ ");
assertToken(JsonToken.START_ARRAY, p.nextToken());
try {
p.nextToken();
@@ -82,7 +92,7 @@ private void _testEofExceptions(int mode) throws Exception
}
p.close();
- p = createParser(mode, "{ \"foo\" : [ ] ");
+ p = createParser(JSON_F, mode, "{ \"foo\" : [ ] ");
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
assertToken(JsonToken.START_ARRAY, p.nextToken());
@@ -95,7 +105,7 @@ private void _testEofExceptions(int mode) throws Exception
}
p.close();
- p = createParser(mode, "{ \"fo");
+ p = createParser(JSON_F, mode, "{ \"fo");
assertToken(JsonToken.START_OBJECT, p.nextToken());
try {
p.nextToken();
@@ -107,7 +117,7 @@ private void _testEofExceptions(int mode) throws Exception
}
p.close();
- p = createParser(mode, "{ \"field\" : ");
+ p = createParser(JSON_F, mode, "{ \"field\" : ");
assertToken(JsonToken.START_OBJECT, p.nextToken());
try {
p.nextToken();
@@ -121,9 +131,10 @@ private void _testEofExceptions(int mode) throws Exception
// any other cases we'd like to test?
}
- public void testContentSnippetWithOffset() throws Exception
+ @Test
+ void contentSnippetWithOffset() throws Exception
{
- final JsonFactory jsonF = this.streamFactoryBuilder()
+ final JsonFactory jsonF = streamFactoryBuilder()
.enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION)
.build();
diff --git a/src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java b/src/test/java/com/fasterxml/jackson/core/JDKSerializabilityTest.java
similarity index 84%
rename from src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java
rename to src/test/java/com/fasterxml/jackson/core/JDKSerializabilityTest.java
index dacd8f19f3..d160ed49ef 100644
--- a/src/test/java/com/fasterxml/jackson/core/TestJDKSerializability.java
+++ b/src/test/java/com/fasterxml/jackson/core/JDKSerializabilityTest.java
@@ -2,15 +2,20 @@
import java.io.*;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.io.ContentReference;
import com.fasterxml.jackson.core.util.RecyclerPool;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.JsonRecyclerPools;
+import static org.junit.jupiter.api.Assertions.*;
+
/**
* Unit tests for [core#31] (https://github.com/FasterXML/jackson-core/issues/31)
*/
-public class TestJDKSerializability extends BaseTest
+class JDKSerializabilityTest
+ extends JUnit5TestBase
{
/*
/**********************************************************************
@@ -18,7 +23,8 @@ public class TestJDKSerializability extends BaseTest
/**********************************************************************
*/
- public void testJsonFactorySerializable() throws Exception
+ @Test
+ void jsonFactorySerializable() throws Exception
{
JsonFactory f = new JsonFactory();
String origJson = "{\"simple\":[1,true,{}]}";
@@ -40,7 +46,8 @@ public void testJsonFactorySerializable() throws Exception
/**********************************************************************
*/
- public void testBase64Variant() throws Exception
+ @Test
+ void base64Variant() throws Exception
{
{
Base64Variant orig = Base64Variants.PEM;
@@ -58,8 +65,8 @@ public void testBase64Variant() throws Exception
Base64Variant mod = orig.withWritePadding(true);
assertTrue(mod.usesPadding());
assertNotSame(orig, mod);
- assertFalse(orig.equals(mod));
- assertFalse(mod.equals(orig));
+ assertNotEquals(orig, mod);
+ assertNotEquals(mod, orig);
final String exp = _encodeBase64(mod);
byte[] stuff = jdkSerialize(mod);
@@ -71,7 +78,8 @@ public void testBase64Variant() throws Exception
}
}
- public void testPrettyPrinter() throws Exception
+ @Test
+ void prettyPrinter() throws Exception
{
PrettyPrinter p = new DefaultPrettyPrinter();
byte[] stuff = jdkSerialize(p);
@@ -80,12 +88,13 @@ public void testPrettyPrinter() throws Exception
assertNotNull(back);
}
- public void testLocation() throws Exception
+ @Test
+ void location() throws Exception
{
JsonFactory jf = new JsonFactory();
JsonParser jp = jf.createParser(" { }");
assertToken(JsonToken.START_OBJECT, jp.nextToken());
- JsonLocation loc = jp.getCurrentLocation();
+ JsonLocation loc = jp.currentLocation();
byte[] stuff = jdkSerialize(loc);
JsonLocation loc2 = jdkDeserialize(stuff);
@@ -96,7 +105,8 @@ public void testLocation() throws Exception
jp.close();
}
- public void testSourceReference() throws Exception
+ @Test
+ void sourceReference() throws Exception
{
ContentReference ref = ContentReference.construct(true, "text",
ErrorReportConfiguration.defaults());
@@ -113,7 +123,9 @@ public void testSourceReference() throws Exception
/**********************************************************************
*/
- public void testRecyclerPools() throws Exception
+ @Test
+ @Deprecated
+ void recyclerPools() throws Exception
{
// First: shared/global pools that will always remain/become globally
// shared instances
@@ -149,14 +161,15 @@ private > T _testRecyclerPoolNonShared(T pool) throws
assertNotSame(pool, result);
return result;
}
-
+
/*
/**********************************************************************
/* Exception types
/**********************************************************************
*/
- public void testParseException() throws Exception
+ @Test
+ void parseException() throws Exception
{
JsonFactory jf = new JsonFactory();
JsonParser p = jf.createParser(" { garbage! }");
@@ -174,7 +187,8 @@ public void testParseException() throws Exception
assertNotNull(result);
}
- public void testGenerationException() throws Exception
+ @Test
+ void generationException() throws Exception
{
JsonFactory jf = new JsonFactory();
JsonGenerator g = jf.createGenerator(new ByteArrayOutputStream());
@@ -198,7 +212,8 @@ public void testGenerationException() throws Exception
/**********************************************************************
*/
- public void testPointerSerializationNonEmpty() throws Exception
+ @Test
+ void pointerSerializationNonEmpty() throws Exception
{
// First, see that we can write and read a general JsonPointer
final String INPUT = "/Image/15/name";
@@ -228,14 +243,15 @@ public void testPointerSerializationNonEmpty() throws Exception
assertEquals(leaf.hashCode(), copy.hashCode());
}
- public void testPointerSerializationEmpty() throws Exception
+ @Test
+ void pointerSerializationEmpty() throws Exception
{
// and then verify that "empty" instance gets canonicalized
final JsonPointer emptyP = JsonPointer.empty();
byte[] ser = jdkSerialize(emptyP);
JsonPointer result = jdkDeserialize(ser);
- assertSame("Should get same 'empty' instance when JDK serialize+deserialize",
- emptyP, result);
+ assertSame(emptyP, result,
+ "Should get same 'empty' instance when JDK serialize+deserialize");
}
/*
@@ -244,29 +260,6 @@ public void testPointerSerializationEmpty() throws Exception
/**********************************************************
*/
- protected byte[] jdkSerialize(Object o) throws IOException
- {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000);
- ObjectOutputStream obOut = new ObjectOutputStream(bytes);
- obOut.writeObject(o);
- obOut.close();
- return bytes.toByteArray();
- }
-
- @SuppressWarnings("unchecked")
- protected T jdkDeserialize(byte[] raw) throws IOException
- {
- ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(raw));
- try {
- return (T) objIn.readObject();
- } catch (ClassNotFoundException e) {
- fail("Missing class: "+e.getMessage());
- return null;
- } finally {
- objIn.close();
- }
- }
-
@SuppressWarnings("resource")
protected String _copyJson(JsonFactory f, String json, boolean useBytes) throws IOException
{
diff --git a/src/test/java/com/fasterxml/jackson/core/BaseTest.java b/src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java
similarity index 55%
rename from src/test/java/com/fasterxml/jackson/core/BaseTest.java
rename to src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java
index ad5eeab8ae..788136d42b 100644
--- a/src/test/java/com/fasterxml/jackson/core/BaseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/JUnit5TestBase.java
@@ -10,11 +10,13 @@
import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
import com.fasterxml.jackson.core.testsupport.ThrottledReader;
-import junit.framework.TestCase;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
-@SuppressWarnings("resource")
-public abstract class BaseTest
- extends TestCase
+/**
+ * Replacement of JUnit4-based {@code BaseTest}
+ */
+public class JUnit5TestBase
{
protected final static String FIELD_BASENAME = "f";
@@ -90,226 +92,28 @@ public abstract class BaseTest
/**********************************************************
*/
- /**
- * Sample class from Jackson tutorial ("JacksonInFiveMinutes")
- */
- protected static class FiveMinuteUser {
- public enum Gender { MALE, FEMALE };
-
- public static class Name
- {
- private String _first, _last;
-
- public Name() { }
- public Name(String f, String l) {
- _first = f;
- _last = l;
- }
-
- public String getFirst() { return _first; }
- public String getLast() { return _last; }
-
- public void setFirst(String s) { _first = s; }
- public void setLast(String s) { _last = s; }
-
- @Override
- public boolean equals(Object o)
- {
- if (o == this) return true;
- if (o == null || o.getClass() != getClass()) return false;
- Name other = (Name) o;
- return _first.equals(other._first) && _last.equals(other._last);
- }
- }
-
- private Gender _gender;
- private Name _name;
- private boolean _isVerified;
- private byte[] _userImage;
+ protected final static JsonFactory JSON_FACTORY = new JsonFactory();
- public FiveMinuteUser() { }
- public FiveMinuteUser(String first, String last, boolean verified, Gender g, byte[] data)
- {
- _name = new Name(first, last);
- _isVerified = verified;
- _gender = g;
- _userImage = data;
- }
-
- public Name getName() { return _name; }
- public boolean isVerified() { return _isVerified; }
- public Gender getGender() { return _gender; }
- public byte[] getUserImage() { return _userImage; }
-
- public void setName(Name n) { _name = n; }
- public void setVerified(boolean b) { _isVerified = b; }
- public void setGender(Gender g) { _gender = g; }
- public void setUserImage(byte[] b) { _userImage = b; }
-
- @Override
- public boolean equals(Object o)
- {
- if (o == this) return true;
- if (o == null || o.getClass() != getClass()) return false;
- FiveMinuteUser other = (FiveMinuteUser) o;
- if (_isVerified != other._isVerified) return false;
- if (_gender != other._gender) return false;
- if (!_name.equals(other._name)) return false;
- byte[] otherImage = other._userImage;
- if (otherImage.length != _userImage.length) return false;
- for (int i = 0, len = _userImage.length; i < len; ++i) {
- if (_userImage[i] != otherImage[i]) {
- return false;
- }
- }
- return true;
- }
- }
- protected final JsonFactory JSON_FACTORY = new JsonFactory();
/*
- /**********************************************************
- /* High-level helpers
- /**********************************************************
+ /**********************************************************************
+ /* Factory methods
+ /**********************************************************************
*/
- protected void verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents)
- throws IOException
- {
- verifyJsonSpecSampleDoc(p, verifyContents, true);
- }
-
- protected void verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents,
- boolean requireNumbers)
- throws IOException
- {
- if (!p.hasCurrentToken()) {
- p.nextToken();
- }
- // first basic check, mostly for test coverage
- assertNull(p.getTypeId());
- assertNull(p.getObjectId());
-
- assertToken(JsonToken.START_OBJECT, p.currentToken()); // main object
-
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Image'
- if (verifyContents) {
- verifyFieldName(p, "Image");
- }
-
- assertToken(JsonToken.START_OBJECT, p.nextToken()); // 'image' object
-
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Width'
- if (verifyContents) {
- verifyFieldName(p, "Width");
- }
-
- verifyIntToken(p.nextToken(), requireNumbers);
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_WIDTH);
- }
-
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Height'
- if (verifyContents) {
- verifyFieldName(p, "Height");
- }
- verifyIntToken(p.nextToken(), requireNumbers);
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_HEIGHT);
- }
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Title'
- if (verifyContents) {
- verifyFieldName(p, "Title");
- }
- assertToken(JsonToken.VALUE_STRING, p.nextToken());
- assertEquals(SAMPLE_SPEC_VALUE_TITLE, getAndVerifyText(p));
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Thumbnail'
- if (verifyContents) {
- verifyFieldName(p, "Thumbnail");
- }
-
- assertToken(JsonToken.START_OBJECT, p.nextToken()); // 'thumbnail' object
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Url'
- if (verifyContents) {
- verifyFieldName(p, "Url");
- }
- assertToken(JsonToken.VALUE_STRING, p.nextToken());
- if (verifyContents) {
- assertEquals(SAMPLE_SPEC_VALUE_TN_URL, getAndVerifyText(p));
- }
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Height'
- if (verifyContents) {
- verifyFieldName(p, "Height");
- }
- verifyIntToken(p.nextToken(), requireNumbers);
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_HEIGHT);
- }
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Width'
- if (verifyContents) {
- verifyFieldName(p, "Width");
- }
- // Width value is actually a String in the example
- assertToken(JsonToken.VALUE_STRING, p.nextToken());
- if (verifyContents) {
- assertEquals(SAMPLE_SPEC_VALUE_TN_WIDTH, getAndVerifyText(p));
- }
-
- assertToken(JsonToken.END_OBJECT, p.nextToken()); // 'thumbnail' object
- assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'IDs'
- assertToken(JsonToken.START_ARRAY, p.nextToken()); // 'ids' array
- verifyIntToken(p.nextToken(), requireNumbers); // ids[0]
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID1);
- }
- verifyIntToken(p.nextToken(), requireNumbers); // ids[1]
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID2);
- }
- verifyIntToken(p.nextToken(), requireNumbers); // ids[2]
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID3);
- }
- verifyIntToken(p.nextToken(), requireNumbers); // ids[3]
- if (verifyContents) {
- verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID4);
- }
- assertToken(JsonToken.END_ARRAY, p.nextToken()); // 'ids' array
-
- assertToken(JsonToken.END_OBJECT, p.nextToken()); // 'image' object
-
- assertToken(JsonToken.END_OBJECT, p.nextToken()); // main object
- }
-
- private void verifyIntToken(JsonToken t, boolean requireNumbers)
- {
- if (t == JsonToken.VALUE_NUMBER_INT) {
- return;
- }
- if (requireNumbers) { // to get error
- assertToken(JsonToken.VALUE_NUMBER_INT, t);
- }
- // if not number, must be String
- if (t != JsonToken.VALUE_STRING) {
- fail("Expected INT or STRING value, got "+t);
- }
+ public static JsonFactory sharedStreamFactory() {
+ return JSON_FACTORY;
}
- protected void verifyFieldName(JsonParser p, String expName)
- throws IOException
- {
- assertEquals(expName, p.getText());
- assertEquals(expName, p.getCurrentName());
+ protected JsonFactory newStreamFactory() {
+ return new JsonFactory();
}
- protected void verifyIntValue(JsonParser p, long expValue)
- throws IOException
- {
- // First, via textual
- assertEquals(String.valueOf(expValue), p.getText());
+ protected JsonFactoryBuilder streamFactoryBuilder() {
+ return (JsonFactoryBuilder) JsonFactory.builder();
}
/*
@@ -412,19 +216,19 @@ protected JsonParser createParserForDataInput(TokenStreamFactory f,
/**********************************************************
*/
- protected JsonGenerator createGenerator(OutputStream out) throws IOException {
+ public static JsonGenerator createGenerator(OutputStream out) throws IOException {
return createGenerator(JSON_FACTORY, out);
}
- protected JsonGenerator createGenerator(TokenStreamFactory f, OutputStream out) throws IOException {
+ public static JsonGenerator createGenerator(TokenStreamFactory f, OutputStream out) throws IOException {
return f.createGenerator(out);
}
- protected JsonGenerator createGenerator(Writer w) throws IOException {
+ public static JsonGenerator createGenerator(Writer w) throws IOException {
return createGenerator(JSON_FACTORY, w);
}
- protected JsonGenerator createGenerator(TokenStreamFactory f, Writer w) throws IOException {
+ public static JsonGenerator createGenerator(TokenStreamFactory f, Writer w) throws IOException {
return f.createGenerator(w);
}
@@ -434,21 +238,10 @@ protected JsonGenerator createGenerator(TokenStreamFactory f, Writer w) throws I
/**********************************************************************
*/
- protected static IOContext testIOContext() {
+ public static IOContext testIOContext() {
return TestSupport.testIOContext();
}
- /*
- /**********************************************************
- /* Helper read/write methods
- /**********************************************************
- */
-
- protected void writeJsonDoc(JsonFactory f, String doc, Writer w) throws IOException
- {
- writeJsonDoc(f, doc, f.createGenerator(w));
- }
-
protected void writeJsonDoc(JsonFactory f, String doc, JsonGenerator g) throws IOException
{
JsonParser p = f.createParser(a2q(doc));
@@ -482,9 +275,9 @@ protected String readAndWrite(JsonFactory f, JsonParser p) throws IOException
}
/*
- /**********************************************************
- /* Additional assertion methods
- /**********************************************************
+ /**********************************************************************
+ /* Assertions
+ /**********************************************************************
*/
protected void assertToken(JsonToken expToken, JsonToken actToken)
@@ -499,23 +292,12 @@ protected void assertToken(JsonToken expToken, JsonParser p)
assertToken(expToken, p.currentToken());
}
- protected void assertType(Object ob, Class> expType)
- {
- if (ob == null) {
- fail("Expected an object of type "+expType.getName()+", got null");
- }
- Class> cls = ob.getClass();
- if (!expType.isAssignableFrom(cls)) {
- fail("Expected type "+expType.getName()+", got "+cls.getName());
- }
- }
-
/**
* @param e Exception to check
* @param anyMatches Array of Strings of which AT LEAST ONE ("any") has to be included
* in {@code e.getMessage()} -- using case-INSENSITIVE comparison
*/
- protected void verifyException(Throwable e, String... anyMatches)
+ public static void verifyException(Throwable e, String... anyMatches)
{
String msg = e.getMessage();
String lmsg = (msg == null) ? "" : msg.toLowerCase();
@@ -533,7 +315,7 @@ protected void verifyException(Throwable e, String... anyMatches)
* available methods, and ensures results are consistent, before
* returning them
*/
- protected String getAndVerifyText(JsonParser p) throws IOException
+ public static String getAndVerifyText(JsonParser p) throws IOException
{
// Ok, let's verify other accessors
int actLen = p.getTextLength();
@@ -544,36 +326,26 @@ protected String getAndVerifyText(JsonParser p) throws IOException
if (str.length() != actLen) {
fail("Internal problem (p.token == "+p.currentToken()+"): p.getText().length() ['"+str+"'] == "+str.length()+"; p.getTextLength() == "+actLen);
}
- assertEquals("String access via getText(), getTextXxx() must be the same", str, str2);
+ assertEquals(str, str2, "String access via getText(), getTextXxx() must be the same");
return str;
}
/*
- /**********************************************************
- /* And other helpers
- /**********************************************************
+ /**********************************************************************
+ /* Escaping/quoting
+ /**********************************************************************
*/
- @Deprecated // use q instead
- protected static String quote(String str) {
- return q(str);
- }
-
- protected static String q(String str) {
+ protected String q(String str) {
return '"'+str+'"';
}
- @Deprecated // use a2q instead
- protected static String aposToQuotes(String json) {
- return a2q(json);
+ public static String a2q(String json) {
+ return json.replace('\'', '"');
}
- protected static String a2q(String json) {
- return json.replace("'", "\"");
- }
-
- protected byte[] encodeInUTF32BE(String input)
+ public static byte[] encodeInUTF32BE(String input)
{
int len = input.length();
byte[] result = new byte[len * 4];
@@ -587,16 +359,22 @@ protected byte[] encodeInUTF32BE(String input)
return result;
}
- // @since 2.9.7
protected static byte[] utf8Bytes(String str) {
return str.getBytes(StandardCharsets.UTF_8);
}
- protected static String utf8String(ByteArrayOutputStream bytes) {
+ protected String utf8String(ByteArrayOutputStream bytes) {
return new String(bytes.toByteArray(), StandardCharsets.UTF_8);
}
- protected void fieldNameFor(StringBuilder sb, int index)
+ public static String fieldNameFor(int index)
+ {
+ StringBuilder sb = new StringBuilder(16);
+ fieldNameFor(sb, index);
+ return sb.toString();
+ }
+
+ private static void fieldNameFor(StringBuilder sb, int index)
{
/* let's do something like "f1.1" to exercise different
* field names (important for byte-based codec)
@@ -617,28 +395,6 @@ protected void fieldNameFor(StringBuilder sb, int index)
}
}
- // @since 2.9.7
- protected JsonFactory sharedStreamFactory() {
- return JSON_FACTORY;
- }
-
- // @since 2.9.7
- protected JsonFactory newStreamFactory() {
- return new JsonFactory();
- }
-
- // @since 2.9.8
- protected JsonFactoryBuilder streamFactoryBuilder() {
- return (JsonFactoryBuilder) JsonFactory.builder();
- }
-
- protected String fieldNameFor(int index)
- {
- StringBuilder sb = new StringBuilder(16);
- fieldNameFor(sb, index);
- return sb.toString();
- }
-
protected int[] calcQuads(String word) {
return calcQuads(utf8Bytes(word));
}
@@ -663,12 +419,18 @@ protected int[] calcQuads(byte[] wordBytes) {
return result;
}
- protected byte[] readResource(String ref)
+ /*
+ /**********************************************************************
+ /* Content reading, serialization
+ /**********************************************************************
+ */
+
+ public static byte[] readResource(String ref)
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
final byte[] buf = new byte[4000];
- InputStream in = getClass().getResourceAsStream(ref);
+ InputStream in = JUnit5TestBase.class.getResourceAsStream(ref);
if (in != null) {
try {
int len;
@@ -685,4 +447,28 @@ protected byte[] readResource(String ref)
}
return bytes.toByteArray();
}
+
+ public static byte[] jdkSerialize(Object o) throws IOException
+ {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000);
+ ObjectOutputStream obOut = new ObjectOutputStream(bytes);
+ obOut.writeObject(o);
+ obOut.close();
+ return bytes.toByteArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T jdkDeserialize(byte[] raw) throws IOException
+ {
+ ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(raw));
+ try {
+ return (T) objIn.readObject();
+ } catch (ClassNotFoundException e) {
+ fail("Missing class: "+e.getMessage());
+ return null;
+ } finally {
+ objIn.close();
+ }
+ }
+
}
diff --git a/src/test/java/com/fasterxml/jackson/core/JsonLocationTest.java b/src/test/java/com/fasterxml/jackson/core/JsonLocationTest.java
index 769d406df8..2844e889fe 100644
--- a/src/test/java/com/fasterxml/jackson/core/JsonLocationTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/JsonLocationTest.java
@@ -4,30 +4,41 @@
import java.io.File;
import java.io.InputStream;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.io.ContentReference;
import static org.assertj.core.api.Assertions.assertThat;
-public class JsonLocationTest extends BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Tests for verifying internal working of {@link JsonLocation} class itself,
+ * as opposed to accuracy of reported location information by parsers.
+ */
+class JsonLocationTest
+ extends JUnit5TestBase
{
static class Foobar { }
- public void testBasics()
+ @Test
+ void basics()
{
JsonLocation loc1 = new JsonLocation(_sourceRef("src"),
10L, 10L, 1, 2);
JsonLocation loc2 = new JsonLocation(null, 10L, 10L, 3, 2);
assertEquals(loc1, loc1);
- assertFalse(loc1.equals(null));
- assertFalse(loc1.equals(loc2));
- assertFalse(loc2.equals(loc1));
+ assertNotEquals(null, loc1);
+ assertNotEquals(loc1, loc2);
+ assertNotEquals(loc2, loc1);
// don't care about what it is; should not compute to 0 with data above
assertTrue(loc1.hashCode() != 0);
assertTrue(loc2.hashCode() != 0);
}
- public void testBasicToString() throws Exception
+ @Test
+ void basicToString() throws Exception
{
// no location; presumed to be Binary due to defaulting
assertEquals("[Source: UNKNOWN; line: 3, column: 2]",
@@ -61,7 +72,8 @@ public void testBasicToString() throws Exception
new JsonLocation(_rawSourceRef(true, srcRef), 10L, 10L, 1, 2).toString());
}
- public void testTruncatedSource() throws Exception
+ @Test
+ void truncatedSource() throws Exception
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ErrorReportConfiguration.DEFAULT_MAX_RAW_CONTENT_LENGTH; ++i) {
@@ -80,7 +92,8 @@ public void testTruncatedSource() throws Exception
}
// for [jackson-core#658]
- public void testEscapeNonPrintable() throws Exception
+ @Test
+ void escapeNonPrintable() throws Exception
{
final String DOC = "[ \"tab:[\t]/null:[\0]\" ]";
JsonLocation loc = new JsonLocation(_sourceRef(DOC), 0L, 0L, -1, -1);
@@ -90,7 +103,8 @@ public void testEscapeNonPrintable() throws Exception
}
// for [jackson-core#356]
- public void testDisableSourceInclusion() throws Exception
+ @Test
+ void disableSourceInclusion() throws Exception
{
JsonFactory f = JsonFactory.builder()
.disable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION)
@@ -124,9 +138,10 @@ private void _verifyContentDisabled(JsonParseException e) {
assertNull(loc.contentReference().getRawContent());
assertThat(loc.sourceDescription()).startsWith("REDACTED");
}
-
+
// for [jackson-core#739]: try to support equality
- public void testLocationEquality() throws Exception
+ @Test
+ void locationEquality() throws Exception
{
// important: create separate but equal instances
File src1 = new File("/tmp/foo");
@@ -151,8 +166,8 @@ public void testLocationEquality() throws Exception
5L, 0L, 1, 2);
loc2 = new JsonLocation(_sourceRef(bogus, 1, 4),
5L, 0L, 1, 2);
- assertFalse(loc1.equals(loc2));
- assertFalse(loc2.equals(loc1));
+ assertNotEquals(loc1, loc2);
+ assertNotEquals(loc2, loc1);
}
private ContentReference _sourceRef(String rawSrc) {
diff --git a/src/test/java/com/fasterxml/jackson/core/JsonpCharacterEscapesTest.java b/src/test/java/com/fasterxml/jackson/core/JsonpCharacterEscapesTest.java
index 1e70fe41e5..cb5e095a31 100644
--- a/src/test/java/com/fasterxml/jackson/core/JsonpCharacterEscapesTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/JsonpCharacterEscapesTest.java
@@ -1,28 +1,29 @@
package com.fasterxml.jackson.core;
import com.fasterxml.jackson.core.io.SerializedString;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Unit tests for class {@link JsonpCharacterEscapes}.
*
- * @date 2017-07-20
* @see JsonpCharacterEscapes
*
**/
-public class JsonpCharacterEscapesTest{
-
+class JsonpCharacterEscapesTest
+ extends JUnit5TestBase
+{
@Test
- public void testGetEscapeSequenceOne() {
+ void getEscapeSequenceOne() {
JsonpCharacterEscapes jsonpCharacterEscapes = JsonpCharacterEscapes.instance();
assertEquals(new SerializedString("\\u2028"),jsonpCharacterEscapes.getEscapeSequence(0x2028));
}
@Test
- public void testGetEscapeSequenceTwo() {
+ void getEscapeSequenceTwo() {
JsonpCharacterEscapes jsonpCharacterEscapes = JsonpCharacterEscapes.instance();
assertEquals(new SerializedString("\\u2029"),jsonpCharacterEscapes.getEscapeSequence(0x2029));
diff --git a/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java b/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java
index 92c57aab93..fb07650031 100644
--- a/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java
@@ -3,12 +3,17 @@
import java.math.BigDecimal;
import java.math.BigInteger;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.base.ParserMinimalBase;
-public class ParserFeatureDefaultsTest extends BaseTest
-{
- static class TestParser extends ParserMinimalBase {
+import static org.junit.jupiter.api.Assertions.assertEquals;
+class ParserFeatureDefaultsTest
+ extends JUnit5TestBase
+{
+ static class TestParser extends ParserMinimalBase
+ {
@Override
public JsonToken nextToken() {
return null;
@@ -18,6 +23,7 @@ public JsonToken nextToken() {
protected void _handleEOF() {
}
+ @Deprecated
@Override
public String getCurrentName() {
return null;
@@ -85,11 +91,13 @@ public Version version() {
return null;
}
+ @Deprecated
@Override
public JsonLocation getCurrentLocation() {
return null;
}
+ @Deprecated
@Override
public JsonLocation getTokenLocation() {
return null;
@@ -136,11 +144,13 @@ public BigDecimal getDecimalValue() {
}
}
- public void testParserFlagDefaults() throws Exception
+ @Test
+ void parserFlagDefaults() throws Exception
{
try (JsonParser p = new TestParser()) {
for (JsonParser.Feature feat : JsonParser.Feature.values()) {
- assertEquals("Feature "+feat, feat.enabledByDefault(), p.isEnabled(feat));
+ assertEquals(feat.enabledByDefault(), p.isEnabled(feat),
+ "Feature "+feat);
}
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/VersionTest.java b/src/test/java/com/fasterxml/jackson/core/VersionClassTest.java
similarity index 76%
rename from src/test/java/com/fasterxml/jackson/core/VersionTest.java
rename to src/test/java/com/fasterxml/jackson/core/VersionClassTest.java
index 69123265b8..d0c72348e9 100644
--- a/src/test/java/com/fasterxml/jackson/core/VersionTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/VersionClassTest.java
@@ -1,16 +1,18 @@
package com.fasterxml.jackson.core;
-import org.junit.Test;
-import static org.junit.Assert.*;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Unit tests for class {@link Version}.
- *
- **/
-public class VersionTest
+ */
+class VersionClassTest
+ extends JUnit5TestBase
{
@Test
- public void testEqualsAndHashCode() {
+ void equalsAndHashCode() {
Version version1 = new Version(1, 2, 3, "", "", "");
Version version2 = new Version(1, 2, 3, "", "", "");
@@ -20,8 +22,8 @@ public void testEqualsAndHashCode() {
assertEquals(version1.hashCode(), version2.hashCode());
}
- @Test
- public void testCompareToOne() {
+ @Test
+ void compareToOne() {
Version version = Version.unknownVersion();
Version versionTwo = new Version(0, (-263), (-1820), "",
"", "");
@@ -29,8 +31,8 @@ public void testCompareToOne() {
assertEquals(263, version.compareTo(versionTwo));
}
- @Test
- public void testCompareToReturningZero() {
+ @Test
+ void compareToReturningZero() {
Version version = Version.unknownVersion();
Version versionTwo = new Version(0, 0, 0, "",
"", "");
@@ -38,16 +40,16 @@ public void testCompareToReturningZero() {
assertEquals(0, version.compareTo(versionTwo));
}
- @Test
- public void testCreatesVersionTaking6ArgumentsAndCallsCompareTo() {
+ @Test
+ void createsVersionTaking6ArgumentsAndCallsCompareTo() {
Version version = new Version(0, 0, 0, null, null, "");
Version versionTwo = new Version(0, 0, 0, "", "", "//0.0.0");
assertTrue(version.compareTo(versionTwo) < 0);
}
- @Test
- public void testCompareToTwo() {
+ @Test
+ void compareToTwo() {
Version version = Version.unknownVersion();
Version versionTwo = new Version((-1), 0, 0, "0.0.0",
"", "");
@@ -55,24 +57,24 @@ public void testCompareToTwo() {
assertTrue(version.compareTo(versionTwo) > 0);
}
- @Test
- public void testCompareToAndCreatesVersionTaking6ArgumentsAndUnknownVersion() {
+ @Test
+ void compareToAndCreatesVersionTaking6ArgumentsAndUnknownVersion() {
Version version = Version.unknownVersion();
Version versionTwo = new Version(0, 0, 0, "//0.0.0", "//0.0.0", "");
assertTrue(version.compareTo(versionTwo) < 0);
}
- @Test
- public void testCompareToSnapshotSame() {
+ @Test
+ void compareToSnapshotSame() {
Version version = new Version(0, 0, 0, "alpha", "com.fasterxml", "bogus");
Version versionTwo = new Version(0, 0, 0, "alpha", "com.fasterxml", "bogus");
assertEquals(0, version.compareTo(versionTwo));
}
- @Test
- public void testCompareToSnapshotDifferent() {
+ @Test
+ void compareToSnapshotDifferent() {
Version version = new Version(0, 0, 0, "alpha", "com.fasterxml", "bogus");
Version versionTwo = new Version(0, 0, 0, "beta", "com.fasterxml", "bogus");
@@ -80,8 +82,8 @@ public void testCompareToSnapshotDifferent() {
assertTrue(versionTwo.compareTo(version) > 0);
}
- @Test
- public void testCompareWhenOnlyFirstHasSnapshot() {
+ @Test
+ void compareWhenOnlyFirstHasSnapshot() {
Version version = new Version(0, 0, 0, "beta", "com.fasterxml", "bogus");
Version versionTwo = new Version(0, 0, 0, null, "com.fasterxml", "bogus");
@@ -89,8 +91,8 @@ public void testCompareWhenOnlyFirstHasSnapshot() {
assertTrue(versionTwo.compareTo(version) > 0);
}
- @Test
- public void testCompareWhenOnlySecondHasSnapshot() {
+ @Test
+ void compareWhenOnlySecondHasSnapshot() {
Version version = new Version(0, 0, 0, "", "com.fasterxml", "bogus");
Version versionTwo = new Version(0, 0, 0, "beta", "com.fasterxml", "bogus");
diff --git a/src/test/java/com/fasterxml/jackson/core/async/AsyncTestBase.java b/src/test/java/com/fasterxml/jackson/core/async/AsyncTestBase.java
index 207b7a3d52..40624bf351 100644
--- a/src/test/java/com/fasterxml/jackson/core/async/AsyncTestBase.java
+++ b/src/test/java/com/fasterxml/jackson/core/async/AsyncTestBase.java
@@ -7,7 +7,7 @@
import com.fasterxml.jackson.core.testsupport.AsyncReaderWrapperForByteArray;
import com.fasterxml.jackson.core.testsupport.AsyncReaderWrapperForByteBuffer;
-public abstract class AsyncTestBase extends BaseTest
+public abstract class AsyncTestBase extends JUnit5TestBase
{
final static String SPACES = " ";
@@ -25,8 +25,8 @@ public static AsyncReaderWrapper asyncForBytes(JsonFactory f,
}
public static AsyncReaderWrapper asyncForByteBuffer(JsonFactory f,
- int bytesPerRead,
- byte[] bytes, int padding) throws IOException
+ int bytesPerRead,
+ byte[] bytes, int padding) throws IOException
{
return new AsyncReaderWrapperForByteBuffer(f.createNonBlockingByteBufferParser(),
bytesPerRead, bytes, padding);
@@ -44,6 +44,6 @@ protected final JsonToken verifyStart(AsyncReaderWrapper reader) throws Exceptio
}
protected final byte[] _jsonDoc(String doc) throws IOException {
- return doc.getBytes("UTF-8");
+ return utf8Bytes(doc);
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java b/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java
index 8b5ba2efd8..fae04c8a56 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/base64/Base64BinaryParsingTest.java
@@ -1,29 +1,34 @@
package com.fasterxml.jackson.core.base64;
-import static org.junit.Assert.assertArrayEquals;
-
import java.io.*;
-import org.junit.Assert;
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.*;
-public class Base64BinaryParsingTest
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+class Base64BinaryParsingTest
+ extends JUnit5TestBase
{
- public void testBase64UsingInputStream() throws Exception
+ private final JsonFactory JSON_F = newStreamFactory();
+
+ @Test
+ void base64UsingInputStream() throws Exception
{
_testBase64Text(MODE_INPUT_STREAM);
_testBase64Text(MODE_INPUT_STREAM_THROTTLED);
_testBase64Text(MODE_DATA_INPUT);
}
- public void testBase64UsingReader() throws Exception
+ @Test
+ void base64UsingReader() throws Exception
{
_testBase64Text(MODE_READER);
}
- public void testStreaming() throws IOException
+ @Test
+ void streaming() throws IOException
{
_testStreaming(MODE_INPUT_STREAM);
_testStreaming(MODE_INPUT_STREAM_THROTTLED);
@@ -31,7 +36,8 @@ public void testStreaming() throws IOException
_testStreaming(MODE_READER);
}
- public void testSimple() throws IOException
+ @Test
+ void simple() throws IOException
{
for (int mode : ALL_MODES) {
// [core#414]: Allow leading/trailign white-space, ensure it is accepted
@@ -42,31 +48,35 @@ public void testSimple() throws IOException
}
}
- public void testInArray() throws IOException
+ @Test
+ void inArray() throws IOException
{
for (int mode : ALL_MODES) {
_testInArray(mode);
}
}
- public void testWithEscaped() throws IOException {
+ @Test
+ void withEscaped() throws IOException {
for (int mode : ALL_MODES) {
_testEscaped(mode);
}
}
- public void testWithEscapedPadding() throws IOException {
+ @Test
+ void withEscapedPadding() throws IOException {
for (int mode : ALL_MODES) {
_testEscapedPadding(mode);
}
}
- public void testInvalidTokenForBase64() throws IOException
+ @Test
+ void invalidTokenForBase64() throws IOException
{
for (int mode : ALL_MODES) {
// First: illegal padding
- JsonParser p = createParser(mode, "[ ]");
+ JsonParser p = createParser(JSON_F, mode, "[ ]");
assertToken(JsonToken.START_ARRAY, p.nextToken());
try {
p.getBinaryValue();
@@ -79,12 +89,13 @@ public void testInvalidTokenForBase64() throws IOException
}
}
- public void testInvalidChar() throws IOException
+ @Test
+ void invalidChar() throws IOException
{
for (int mode : ALL_MODES) {
// First: illegal padding
- JsonParser p = createParser(mode, q("a==="));
+ JsonParser p = createParser(JSON_F, mode, q("a==="));
assertToken(JsonToken.VALUE_STRING, p.nextToken());
try {
p.getBinaryValue(Base64Variants.MIME);
@@ -95,7 +106,7 @@ public void testInvalidChar() throws IOException
p.close();
// second: invalid space within
- p = createParser(mode, q("ab de"));
+ p = createParser(JSON_F, mode, q("ab de"));
assertToken(JsonToken.VALUE_STRING, p.nextToken());
try {
p.getBinaryValue(Base64Variants.MIME);
@@ -106,7 +117,7 @@ public void testInvalidChar() throws IOException
p.close();
// third: something else
- p = createParser(mode, q("ab#?"));
+ p = createParser(JSON_F, mode, q("ab#?"));
assertToken(JsonToken.VALUE_STRING, p.nextToken());
try {
p.getBinaryValue(Base64Variants.MIME);
@@ -118,7 +129,8 @@ public void testInvalidChar() throws IOException
}
}
- public void testOkMissingPadding() throws IOException {
+ @Test
+ void okMissingPadding() throws IOException {
final byte[] DOC1 = new byte[] { (byte) 0xAD };
_testOkMissingPadding(DOC1, MODE_INPUT_STREAM);
_testOkMissingPadding(DOC1, MODE_INPUT_STREAM_THROTTLED);
@@ -136,16 +148,17 @@ private void _testOkMissingPadding(byte[] input, int mode) throws IOException
{
final Base64Variant b64 = Base64Variants.MODIFIED_FOR_URL;
final String encoded = b64.encode(input, false);
- JsonParser p = createParser(mode, q(encoded));
+ JsonParser p = createParser(JSON_F, mode, q(encoded));
// 1 byte -> 2 encoded chars; 2 bytes -> 3 encoded chars
assertEquals(input.length+1, encoded.length());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
byte[] actual = p.getBinaryValue(b64);
- Assert.assertArrayEquals(input, actual);
+ assertArrayEquals(input, actual);
p.close();
}
- public void testFailDueToMissingPadding() throws IOException {
+ @Test
+ void failDueToMissingPadding() throws IOException {
final String DOC1 = q("fQ"); // 1 bytes, no padding
_testFailDueToMissingPadding(DOC1, MODE_INPUT_STREAM);
_testFailDueToMissingPadding(DOC1, MODE_INPUT_STREAM_THROTTLED);
@@ -163,7 +176,7 @@ private void _testFailDueToMissingPadding(String doc, int mode) throws IOExcepti
final String EXP_EXCEPTION_MATCH = "Unexpected end of base64-encoded String: base64 variant 'MIME' expects padding";
// First, without getting text value first:
- JsonParser p = createParser(mode, doc);
+ JsonParser p = createParser(JSON_F, mode, doc);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
try {
/*byte[] b =*/ p.getBinaryValue(Base64Variants.MIME);
@@ -174,7 +187,7 @@ private void _testFailDueToMissingPadding(String doc, int mode) throws IOExcepti
p.close();
// second, access String first
- p = createParser(mode, doc);
+ p = createParser(JSON_F, mode, doc);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
/*String str =*/ p.getText();
try {
@@ -193,7 +206,7 @@ private void _testFailDueToMissingPadding(String doc, int mode) throws IOExcepti
*/
@SuppressWarnings("resource")
- public void _testBase64Text(int mode) throws Exception
+ void _testBase64Text(int mode) throws Exception
{
// let's actually iterate over sets of encoding modes, lengths
@@ -205,7 +218,6 @@ public void _testBase64Text(int mode) throws Exception
Base64Variants.PEM
};
- JsonFactory jsonFactory = sharedStreamFactory();
final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
StringWriter chars = null;
for (int len : LENS) {
@@ -218,18 +230,18 @@ public void _testBase64Text(int mode) throws Exception
if (mode == MODE_READER) {
chars = new StringWriter();
- g = jsonFactory.createGenerator(chars);
+ g = JSON_F.createGenerator(chars);
} else {
bytes.reset();
- g = jsonFactory.createGenerator(bytes, JsonEncoding.UTF8);
+ g = JSON_F.createGenerator(bytes, JsonEncoding.UTF8);
}
g.writeBinary(variant, input, 0, input.length);
g.close();
JsonParser p;
if (mode == MODE_READER) {
- p = jsonFactory.createParser(chars.toString());
+ p = JSON_F.createParser(chars.toString());
} else {
- p = createParser(jsonFactory, mode, bytes.toByteArray());
+ p = createParser(JSON_F, mode, bytes.toByteArray());
}
assertToken(JsonToken.VALUE_STRING, p.nextToken());
@@ -274,7 +286,6 @@ private void _testStreaming(int mode) throws IOException
139000
};
- JsonFactory jsonFactory = sharedStreamFactory();
final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
StringWriter chars = null;
@@ -283,10 +294,10 @@ private void _testStreaming(int mode) throws IOException
JsonGenerator g;
if (mode == MODE_READER) {
chars = new StringWriter();
- g = jsonFactory.createGenerator(chars);
+ g = JSON_F.createGenerator(chars);
} else {
bytes.reset();
- g = jsonFactory.createGenerator(bytes, JsonEncoding.UTF8);
+ g = JSON_F.createGenerator(bytes, JsonEncoding.UTF8);
}
g.writeStartObject();
@@ -298,14 +309,14 @@ private void _testStreaming(int mode) throws IOException
// and verify
JsonParser p;
if (mode == MODE_READER) {
- p = jsonFactory.createParser(chars.toString());
+ p = JSON_F.createParser(chars.toString());
} else {
- p = createParser(jsonFactory, mode, bytes.toByteArray());
+ p = createParser(JSON_F, mode, bytes.toByteArray());
}
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
- assertEquals("b", p.getCurrentName());
+ assertEquals("b", p.currentName());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
ByteArrayOutputStream result = new ByteArrayOutputStream(size);
int gotten = p.readBinaryValue(result);
@@ -342,7 +353,7 @@ private void _testSimple(int mode, boolean leadingWS, boolean trailingWS) throws
}
final String DOC = "\""+INPUT_STR+"\"";
- JsonParser p = createParser(mode, DOC);
+ JsonParser p = createParser(JSON_F, mode, DOC);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
byte[] data = p.getBinaryValue();
@@ -353,12 +364,10 @@ private void _testSimple(int mode, boolean leadingWS, boolean trailingWS) throws
private void _testInArray(int mode) throws IOException
{
- JsonFactory f = sharedStreamFactory();
-
final int entryCount = 7;
StringWriter sw = new StringWriter();
- JsonGenerator jg = f.createGenerator(sw);
+ JsonGenerator jg = JSON_F.createGenerator(sw);
jg.writeStartArray();
byte[][] entries = new byte[entryCount][];
@@ -374,7 +383,7 @@ private void _testInArray(int mode) throws IOException
jg.writeEndArray();
jg.close();
- JsonParser p = createParser(f, mode, sw.toString());
+ JsonParser p = createParser(JSON_F, mode, sw.toString());
assertToken(JsonToken.START_ARRAY, p.nextToken());
@@ -394,7 +403,7 @@ private void _testEscaped(int mode) throws IOException
// First, try with embedded linefeed half-way through:
String DOC = q("VGVz\\ndCE="); // note: must double-quote to get linefeed
- JsonParser p = createParser(mode, DOC);
+ JsonParser p = createParser(JSON_F, mode, DOC);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
byte[] b = p.getBinaryValue();
assertEquals("Test!", new String(b, "US-ASCII"));
@@ -406,7 +415,7 @@ private void _testEscaped(int mode) throws IOException
// and then with escaped chars
// DOC = quote("V\\u0047V\\u007AdCE="); // note: must escape backslash...
DOC = q("V\\u0047V\\u007AdCE="); // note: must escape backslash...
- p = createParser(mode, DOC);
+ p = createParser(JSON_F, mode, DOC);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
b = p.getBinaryValue();
assertEquals("Test!", new String(b, "US-ASCII"));
@@ -422,7 +431,7 @@ private void _testEscapedPadding(int mode) throws IOException
final String DOC = q("VGVzdCE\\u003d");
// 06-Sep-2018, tatu: actually one more, test escaping of padding
- JsonParser p = createParser(mode, DOC);
+ JsonParser p = createParser(JSON_F, mode, DOC);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("Test!", new String(p.getBinaryValue(), "US-ASCII"));
if (mode != MODE_DATA_INPUT) {
@@ -431,7 +440,7 @@ private void _testEscapedPadding(int mode) throws IOException
p.close();
// also, try out alternate access method
- p = createParser(mode, DOC);
+ p = createParser(JSON_F, mode, DOC);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("Test!", new String(_readBinary(p), "US-ASCII"));
if (mode != MODE_DATA_INPUT) {
@@ -441,7 +450,7 @@ private void _testEscapedPadding(int mode) throws IOException
// and then different padding; "X" -> "WA=="
final String DOC2 = q("WA\\u003D\\u003D");
- p = createParser(mode, DOC2);
+ p = createParser(JSON_F, mode, DOC2);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("X", new String(p.getBinaryValue(), "US-ASCII"));
if (mode != MODE_DATA_INPUT) {
@@ -449,7 +458,7 @@ private void _testEscapedPadding(int mode) throws IOException
}
p.close();
- p = createParser(mode, DOC2);
+ p = createParser(JSON_F, mode, DOC2);
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals("X", new String(_readBinary(p), "US-ASCII"));
if (mode != MODE_DATA_INPUT) {
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java b/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java
index 7d7386b551..fba48aa987 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/base64/Base64CodecTest.java
@@ -2,14 +2,17 @@
import java.util.Arrays;
-import org.junit.Assert;
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.*;
-public class Base64CodecTest
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+class Base64CodecTest
+ extends JUnit5TestBase
{
- public void testVariantAccess()
+ @Test
+ void variantAccess()
{
for (Base64Variant var : new Base64Variant[] {
Base64Variants.MIME,
@@ -28,7 +31,8 @@ public void testVariantAccess()
}
}
- public void testProps()
+ @Test
+ void props()
{
Base64Variant std = Base64Variants.MIME;
// let's verify basic props of std cocec
@@ -42,7 +46,8 @@ public void testProps()
assertEquals(76, std.getMaxLineLength());
}
- public void testCharEncoding() throws Exception
+ @Test
+ void charEncoding() throws Exception
{
Base64Variant std = Base64Variants.MIME;
assertEquals(Base64Variant.BASE64_VALUE_INVALID, std.decodeBase64Char('?'));
@@ -73,32 +78,34 @@ public void testCharEncoding() throws Exception
byte[] exp = EXP_STR.getBytes("UTF-8");
byte[] act = new byte[exp.length];
std.encodeBase64Chunk(TRIPLET, act, 0);
- Assert.assertArrayEquals(exp, act);
+ assertArrayEquals(exp, act);
}
- public void testConvenienceMethods() throws Exception
+ @Test
+ void convenienceMethods() throws Exception
{
final Base64Variant std = Base64Variants.MIME;
byte[] input = new byte[] { 1, 2, 34, 127, -1 };
String encoded = std.encode(input, false);
byte[] decoded = std.decode(encoded);
- Assert.assertArrayEquals(input, decoded);
+ assertArrayEquals(input, decoded);
assertEquals(q(encoded), std.encode(input, true));
// [core#414]: check white-space allow too
decoded = std.decode("\n"+encoded);
- Assert.assertArrayEquals(input, decoded);
+ assertArrayEquals(input, decoded);
decoded = std.decode(" "+encoded);
- Assert.assertArrayEquals(input, decoded);
+ assertArrayEquals(input, decoded);
decoded = std.decode(encoded + " ");
- Assert.assertArrayEquals(input, decoded);
+ assertArrayEquals(input, decoded);
decoded = std.decode(encoded + "\n");
- Assert.assertArrayEquals(input, decoded);
+ assertArrayEquals(input, decoded);
}
- public void testConvenienceMethodWithLFs() throws Exception
+ @Test
+ void convenienceMethodWithLFs() throws Exception
{
final Base64Variant std = Base64Variants.MIME;
@@ -125,7 +132,8 @@ public void testConvenienceMethodWithLFs() throws Exception
}
@SuppressWarnings("unused")
- public void testErrors() throws Exception
+ @Test
+ void errors() throws Exception
{
try {
Base64Variant b = new Base64Variant("foobar", "xyz", false, '!', 24);
@@ -149,7 +157,8 @@ public void testErrors() throws Exception
}
}
- public void testPaddingReadBehaviour() throws Exception {
+ @Test
+ void paddingReadBehaviour() throws Exception {
for (Base64Variant variant: Arrays.asList(Base64Variants.MIME, Base64Variants.MIME_NO_LINEFEEDS, Base64Variants.PEM)) {
@@ -209,6 +218,5 @@ public void testPaddingReadBehaviour() throws Exception {
Base64Variants.MODIFIED_FOR_URL.withPaddingAllowed().decode(BASE64_HELLO_WITHOUT_PADDING);
Base64Variants.MODIFIED_FOR_URL.withPaddingForbidden().decode(BASE64_HELLO_WITHOUT_PADDING);
-
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/Base64GenerationTest.java b/src/test/java/com/fasterxml/jackson/core/base64/Base64GenerationTest.java
index 1a48d24e6f..fd295c1903 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/Base64GenerationTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/base64/Base64GenerationTest.java
@@ -2,11 +2,15 @@
import java.io.*;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
-public class Base64GenerationTest
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class Base64GenerationTest
+ extends JUnit5TestBase
{
/* The usual sample input string, from Thomas Hobbes's "Leviathan"
* (via Wikipedia)
@@ -45,14 +49,16 @@ public class Base64GenerationTest
private final JsonFactory JSON_F = new JsonFactory();
- public void testStreamingBinaryWrites() throws Exception
+ @Test
+ void streamingBinaryWrites() throws Exception
{
_testStreamingWrites(JSON_F, true);
_testStreamingWrites(JSON_F, false);
}
// For [core#55]
- public void testIssue55() throws Exception
+ @Test
+ void issue55() throws Exception
{
final JsonFactory f = new JsonFactory();
@@ -84,14 +90,16 @@ public void testIssue55() throws Exception
* as some kind of sanity check. Reader-side should more thoroughly
* test things, as it does need writers to construct the data first.
*/
- public void testSimpleBinaryWrite() throws Exception
+ @Test
+ void simpleBinaryWrite() throws Exception
{
_testSimpleBinaryWrite(false);
_testSimpleBinaryWrite(true);
}
// for [core#318]
- public void testBinaryAsEmbeddedObject() throws Exception
+ @Test
+ void binaryAsEmbeddedObject() throws Exception
{
JsonGenerator g;
diff --git a/src/test/java/com/fasterxml/jackson/core/base64/Base64Padding912Test.java b/src/test/java/com/fasterxml/jackson/core/base64/Base64Padding912Test.java
index 3f29dd21ea..0e40c699fa 100644
--- a/src/test/java/com/fasterxml/jackson/core/base64/Base64Padding912Test.java
+++ b/src/test/java/com/fasterxml/jackson/core/base64/Base64Padding912Test.java
@@ -1,24 +1,32 @@
package com.fasterxml.jackson.core.base64;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.*;
-public class Base64Padding912Test
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class Base64Padding912Test
+ extends JUnit5TestBase
{
private final JsonFactory JSON_F = newStreamFactory();
-
- public void testPaddingUsingInputStream() throws Exception
+
+ @Test
+ void paddingUsingInputStream() throws Exception
{
_testPadding(MODE_INPUT_STREAM);
_testPadding(MODE_INPUT_STREAM_THROTTLED);
}
- public void testPaddingUsingReader() throws Exception
+ @Test
+ void paddingUsingReader() throws Exception
{
_testPadding(MODE_READER);
}
- public void testPaddingUsingDataInput() throws Exception
+ @Test
+ void paddingUsingDataInput() throws Exception
{
_testPadding(MODE_DATA_INPUT);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/DeeplyNestedContentReadTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/DeeplyNestedContentReadTest.java
index 95f73663d4..d03f6fc5d0 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/DeeplyNestedContentReadTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/DeeplyNestedContentReadTest.java
@@ -1,22 +1,28 @@
package com.fasterxml.jackson.core.constraints;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
/**
* Unit test(s) for verifying handling of new (in 2.15) StreamReadConstraints
* wrt maximum nesting depth.
*/
-public class DeeplyNestedContentReadTest
- extends com.fasterxml.jackson.core.BaseTest
+class DeeplyNestedContentReadTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory JSON_F = newStreamFactory();
private final int MAX_NESTING = StreamReadConstraints.DEFAULT_MAX_DEPTH;
private final int TESTED_NESTING = MAX_NESTING + 50;
-
- public void testDeepNestingStreaming() throws Exception
+
+ @Test
+ void deepNestingStreaming() throws Exception
{
final String DOC = createDeepNestedDoc(TESTED_NESTING);
for (int mode : ALL_STREAMING_MODES) {
@@ -37,7 +43,8 @@ private void _testDeepNesting(JsonParser p) throws Exception
}
}
- public void testLegacyConstraintSettingTest() throws Exception
+ @Test
+ void legacyConstraintSettingTest() throws Exception
{
final int LOWER_MAX = 40;
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/LargeDocReadTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/LargeDocReadTest.java
index 0208e19578..14c4a84a9d 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/LargeDocReadTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/LargeDocReadTest.java
@@ -3,12 +3,17 @@
import java.io.IOException;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.async.AsyncTestBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.testsupport.AsyncReaderWrapper;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
// [core#1047]: Add max-name-length constraints
-public class LargeDocReadTest extends AsyncTestBase
+class LargeDocReadTest extends AsyncTestBase
{
private final JsonFactory JSON_F_DEFAULT = newStreamFactory();
@@ -16,22 +21,29 @@ public class LargeDocReadTest extends AsyncTestBase
.streamReadConstraints(StreamReadConstraints.builder().maxDocumentLength(10_000L).build())
.build();
+ private final JsonFactory JSON_F_MAX_TOKENS_1K = JsonFactory.builder()
+ .streamReadConstraints(StreamReadConstraints.builder().maxTokenCount(1_000L).build())
+ .build();
+
// Test name that is below default max name
- public void testLargeNameBytes() throws Exception {
+ @Test
+ void largeNameBytes() throws Exception {
final String doc = generateJSON(StreamReadConstraints.defaults().getMaxNameLength() - 100);
try (JsonParser p = createParserUsingStream(JSON_F_DEFAULT, doc, "UTF-8")) {
consumeTokens(p);
}
}
- public void testLargeNameChars() throws Exception {
+ @Test
+ void largeNameChars() throws Exception {
final String doc = generateJSON(StreamReadConstraints.defaults().getMaxNameLength() - 100);
try (JsonParser p = createParserUsingReader(JSON_F_DEFAULT, doc)) {
consumeTokens(p);
}
}
- public void testLargeNameWithSmallLimitBytes() throws Exception
+ @Test
+ void largeNameWithSmallLimitBytes() throws Exception
{
final String doc = generateJSON(12_000);
try (JsonParser p = createParserUsingStream(JSON_F_DOC_10K, doc, "UTF-8")) {
@@ -42,7 +54,8 @@ public void testLargeNameWithSmallLimitBytes() throws Exception
}
}
- public void testLargeNameWithSmallLimitChars() throws Exception
+ @Test
+ void largeNameWithSmallLimitChars() throws Exception
{
final String doc = generateJSON(12_000);
try (JsonParser p = createParserUsingReader(JSON_F_DOC_10K, doc)) {
@@ -53,7 +66,8 @@ public void testLargeNameWithSmallLimitChars() throws Exception
}
}
- public void testLargeNameWithSmallLimitAsync() throws Exception
+ @Test
+ void largeNameWithSmallLimitAsync() throws Exception
{
final byte[] doc = utf8Bytes(generateJSON(12_000));
@@ -74,6 +88,18 @@ public void testLargeNameWithSmallLimitAsync() throws Exception
}
}
+ @Test
+ void tokenLimitBytes() throws Exception {
+ final String doc = generateJSON(StreamReadConstraints.defaults().getMaxNameLength() - 100);
+ try (JsonParser p = createParserUsingStream(JSON_F_MAX_TOKENS_1K, doc, "UTF-8")) {
+ consumeTokens(p);
+ fail("expected StreamConstraintsException");
+ } catch (StreamConstraintsException e) {
+ assertEquals("Token count (1001) exceeds the maximum allowed (1000, from `StreamReadConstraints.getMaxTokenCount()`)",
+ e.getMessage());
+ }
+ }
+
private void consumeTokens(JsonParser p) throws IOException {
while (p.nextToken() != null) {
;
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/LargeNameReadTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/LargeNameReadTest.java
index 4c5665cfcb..a2ac0d4610 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/LargeNameReadTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/LargeNameReadTest.java
@@ -3,12 +3,16 @@
import java.io.IOException;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.json.async.NonBlockingJsonParser;
+import static org.junit.jupiter.api.Assertions.fail;
+
// [core#1047]: Add max-name-length constraints
-public class LargeNameReadTest extends BaseTest
+class LargeNameReadTest extends JUnit5TestBase
{
private final JsonFactory JSON_F_DEFAULT = newStreamFactory();
@@ -16,25 +20,39 @@ public class LargeNameReadTest extends BaseTest
.streamReadConstraints(StreamReadConstraints.builder().maxNameLength(100).build())
.build();
+ private final JsonFactory JSON_F_NAME_100_B = new JsonFactory();
+ {
+ JSON_F_NAME_100_B.setStreamReadConstraints(StreamReadConstraints.builder()
+ .maxNameLength(100).build());
+ }
+
// Test name that is below default max name
- public void testLargeNameBytes() throws Exception {
+ @Test
+ void largeNameBytes() throws Exception {
final String doc = generateJSON(StreamReadConstraints.defaults().getMaxNameLength() - 100);
try (JsonParser p = createParserUsingStream(JSON_F_DEFAULT, doc, "UTF-8")) {
consumeTokens(p);
}
}
- public void testLargeNameChars() throws Exception {
+ @Test
+ void largeNameChars() throws Exception {
final String doc = generateJSON(StreamReadConstraints.defaults().getMaxNameLength() - 100);
try (JsonParser p = createParserUsingReader(JSON_F_DEFAULT, doc)) {
consumeTokens(p);
}
}
- public void testLargeNameWithSmallLimitBytes() throws Exception
+ @Test
+ void largeNameWithSmallLimitBytes() throws Exception {
+ _testLargeNameWithSmallLimitBytes(JSON_F_NAME_100);
+ _testLargeNameWithSmallLimitBytes(JSON_F_NAME_100_B);
+ }
+
+ private void _testLargeNameWithSmallLimitBytes(JsonFactory jf) throws Exception
{
final String doc = generateJSON(1000);
- try (JsonParser p = createParserUsingStream(JSON_F_NAME_100, doc, "UTF-8")) {
+ try (JsonParser p = createParserUsingStream(jf, doc, "UTF-8")) {
consumeTokens(p);
fail("expected StreamConstraintsException");
} catch (StreamConstraintsException e) {
@@ -42,10 +60,16 @@ public void testLargeNameWithSmallLimitBytes() throws Exception
}
}
- public void testLargeNameWithSmallLimitChars() throws Exception
+ @Test
+ void largeNameWithSmallLimitChars() throws Exception {
+ _testLargeNameWithSmallLimitChars(JSON_F_NAME_100);
+ _testLargeNameWithSmallLimitChars(JSON_F_NAME_100_B);
+ }
+
+ private void _testLargeNameWithSmallLimitChars(JsonFactory jf) throws Exception
{
final String doc = generateJSON(1000);
- try (JsonParser p = createParserUsingReader(JSON_F_NAME_100, doc)) {
+ try (JsonParser p = createParserUsingReader(jf, doc)) {
consumeTokens(p);
fail("expected StreamConstraintsException");
} catch (StreamConstraintsException e) {
@@ -53,7 +77,8 @@ public void testLargeNameWithSmallLimitChars() throws Exception
}
}
- public void testLargeNameWithSmallLimitAsync() throws Exception
+ @Test
+ void largeNameWithSmallLimitAsync() throws Exception
{
final byte[] doc = utf8Bytes(generateJSON(1000));
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberReadTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberReadTest.java
index 24eb8ba8e4..458f8ab3b6 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberReadTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberReadTest.java
@@ -3,16 +3,21 @@
import java.math.BigDecimal;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
/**
* Set of basic unit tests for verifying that "too big" number constraints
* are caught by various JSON parser backends.
*/
@SuppressWarnings("resource")
-public class LargeNumberReadTest
- extends com.fasterxml.jackson.core.BaseTest
+class LargeNumberReadTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory JSON_F = newStreamFactory();
@@ -22,13 +27,15 @@ public class LargeNumberReadTest
/**********************************************************************
*/
- public void testBigBigDecimalsBytesFailByDefault() throws Exception
+ @Test
+ void bigBigDecimalsBytesFailByDefault() throws Exception
{
_testBigBigDecimals(MODE_INPUT_STREAM, true);
_testBigBigDecimals(MODE_INPUT_STREAM_THROTTLED, true);
}
- public void testBigBigDecimalsBytes() throws Exception
+ @Test
+ void bigBigDecimalsBytes() throws Exception
{
try {
_testBigBigDecimals(MODE_INPUT_STREAM, false);
@@ -44,7 +51,8 @@ public void testBigBigDecimalsBytes() throws Exception
}
}
- public void testBigBigDecimalsCharsFailByDefault() throws Exception
+ @Test
+ void bigBigDecimalsCharsFailByDefault() throws Exception
{
try {
_testBigBigDecimals(MODE_READER, false);
@@ -54,12 +62,14 @@ public void testBigBigDecimalsCharsFailByDefault() throws Exception
}
}
- public void testBigBigDecimalsChars() throws Exception
+ @Test
+ void bigBigDecimalsChars() throws Exception
{
_testBigBigDecimals(MODE_READER, true);
}
- public void testBigBigDecimalsDataInputFailByDefault() throws Exception
+ @Test
+ void bigBigDecimalsDataInputFailByDefault() throws Exception
{
try {
_testBigBigDecimals(MODE_DATA_INPUT, false);
@@ -69,7 +79,8 @@ public void testBigBigDecimalsDataInputFailByDefault() throws Exception
}
}
- public void testBigBigDecimalsDataInput() throws Exception
+ @Test
+ void bigBigDecimalsDataInput() throws Exception
{
_testBigBigDecimals(MODE_DATA_INPUT, true);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberWriteTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberWriteTest.java
index 1ebd6c538b..fa4414bea8 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberWriteTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/LargeNumberWriteTest.java
@@ -10,12 +10,12 @@
import java.math.BigDecimal;
import java.math.BigInteger;
-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;
-import com.fasterxml.jackson.core.StreamReadConstraints;
+import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
/**
* Tests verifying that there are no limits for writing very long numbers
@@ -24,7 +24,7 @@
*
* @since 2.15
*/
-public class LargeNumberWriteTest extends BaseTest
+class LargeNumberWriteTest extends JUnit5TestBase
{
private final JsonFactory VANILLA_JSON_F = new JsonFactory();
@@ -50,7 +50,8 @@ public class LargeNumberWriteTest extends BaseTest
BIG_INT = new BigInteger(sb.toString());
}
- public void testWriteLargeIntegerByteArray() throws Exception
+ @Test
+ void writeLargeIntegerByteArray() throws Exception
{
try(
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -63,7 +64,8 @@ public void testWriteLargeIntegerByteArray() throws Exception
}
}
- public void testWriteLargeIntegerStringWriter() throws Exception
+ @Test
+ void writeLargeIntegerStringWriter() throws Exception
{
try(
StringWriter out = new StringWriter();
@@ -76,7 +78,8 @@ public void testWriteLargeIntegerStringWriter() throws Exception
}
}
- public void testWriteLargeIntegerDataOutput() throws Exception
+ @Test
+ void writeLargeIntegerDataOutput() throws Exception
{
try(
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -95,7 +98,8 @@ public void testWriteLargeIntegerDataOutput() throws Exception
}
}
- public void testWriteLargeDecimalByteArray() throws Exception
+ @Test
+ void writeLargeDecimalByteArray() throws Exception
{
try(
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -108,7 +112,8 @@ public void testWriteLargeDecimalByteArray() throws Exception
}
}
- public void testWriteLargeDecimalStringWriter() throws Exception
+ @Test
+ void writeLargeDecimalStringWriter() throws Exception
{
try(
StringWriter out = new StringWriter();
@@ -121,7 +126,8 @@ public void testWriteLargeDecimalStringWriter() throws Exception
}
}
- public void testWriteLargeDecimalDataOutput() throws Exception
+ @Test
+ void writeLargeDecimalDataOutput() throws Exception
{
try(
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -161,7 +167,7 @@ private void _verifyLargeNumberDoc(JsonParser p, BigInteger bigValue) throws Exc
{
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
- assertEquals("field", p.getCurrentName());
+ assertEquals("field", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(bigValue, p.getBigIntegerValue());
assertToken(JsonToken.END_OBJECT, p.nextToken());
@@ -172,7 +178,7 @@ private void _verifyLargeNumberDoc(JsonParser p, BigDecimal bigValue) throws Exc
{
assertToken(JsonToken.START_OBJECT, p.nextToken());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
- assertEquals("field", p.getCurrentName());
+ assertEquals("field", p.currentName());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
assertEquals(bigValue, p.getDecimalValue());
assertToken(JsonToken.END_OBJECT, p.nextToken());
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/StreamReadConstraintsDefaultsTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/StreamReadConstraintsDefaultsTest.java
index 0859701c73..83650bc7d6 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/StreamReadConstraintsDefaultsTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/StreamReadConstraintsDefaultsTest.java
@@ -1,15 +1,15 @@
package com.fasterxml.jackson.core.constraints;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.StreamReadConstraints;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
-public class StreamReadConstraintsDefaultsTest
+class StreamReadConstraintsDefaultsTest
{
@Test
- public void testOverride() {
+ void override() {
final long maxDocLen = 10_000_000L;
final int numLen = 1234;
final int strLen = 12345;
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/StreamWriteConstraintsDefaultsTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/StreamWriteConstraintsDefaultsTest.java
index 374631be46..fcedb2b55e 100644
--- a/src/test/java/com/fasterxml/jackson/core/constraints/StreamWriteConstraintsDefaultsTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/StreamWriteConstraintsDefaultsTest.java
@@ -1,13 +1,14 @@
package com.fasterxml.jackson.core.constraints;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.StreamWriteConstraints;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
-public class StreamWriteConstraintsDefaultsTest {
+class StreamWriteConstraintsDefaultsTest {
@Test
- public void testOverride() {
+ void override() {
final int depth = 123;
StreamWriteConstraints constraints = StreamWriteConstraints.builder()
.maxNestingDepth(depth)
diff --git a/src/test/java/com/fasterxml/jackson/core/constraints/TokenCountTest.java b/src/test/java/com/fasterxml/jackson/core/constraints/TokenCountTest.java
new file mode 100644
index 0000000000..787a33e37b
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/constraints/TokenCountTest.java
@@ -0,0 +1,165 @@
+package com.fasterxml.jackson.core.constraints;
+
+import java.nio.ByteBuffer;
+
+import com.fasterxml.jackson.core.JUnit5TestBase;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.StreamReadConstraints;
+import com.fasterxml.jackson.core.json.async.NonBlockingByteBufferJsonParser;
+import com.fasterxml.jackson.core.json.async.NonBlockingJsonParser;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Set of basic unit tests for verifying that the token count
+ * functionality works as expected.
+ */
+public class TokenCountTest extends JUnit5TestBase {
+ private final static JsonFactory JSON_FACTORY = JsonFactory.builder()
+ .streamReadConstraints(StreamReadConstraints.builder().maxTokenCount(Long.MAX_VALUE).build())
+ .build();
+ private final static String ARRAY_DOC = a2q("{ 'nums': [1,2,3,4,5,6,7,8,9,10] }");
+ private final static String SHORT_ARRAY_DOC = a2q("{ 'nums': [1,2,3] }");
+
+ @Test
+ void arrayDoc() throws Exception
+ {
+ for (int mode : ALL_MODES) {
+ _testArrayDoc(mode);
+ }
+ }
+
+ @Test
+ void arrayDocNonBlockingArray() throws Exception
+ {
+ final byte[] input = ARRAY_DOC.getBytes("UTF-8");
+ try (NonBlockingJsonParser p = (NonBlockingJsonParser) JSON_FACTORY.createNonBlockingByteArrayParser()) {
+ p.feedInput(input, 0, input.length);
+ p.endOfInput();
+ _testArrayDoc(p);
+ }
+ }
+
+ @Test
+ void arrayDocNonBlockingBuffer() throws Exception
+ {
+ final byte[] input = ARRAY_DOC.getBytes("UTF-8");
+ try (NonBlockingByteBufferJsonParser p = (NonBlockingByteBufferJsonParser) JSON_FACTORY.createNonBlockingByteBufferParser()) {
+ p.feedInput(ByteBuffer.wrap(input, 0, input.length));
+ p.endOfInput();
+ _testArrayDoc(p);
+ }
+ }
+
+ @Test
+ void shortArrayDoc() throws Exception
+ {
+ for (int mode : ALL_MODES) {
+ _testShortArrayDoc(mode);
+ }
+ }
+
+ @Test
+ void shortArrayDocNonBlockingArray() throws Exception
+ {
+ final byte[] input = SHORT_ARRAY_DOC.getBytes("UTF-8");
+ try (NonBlockingJsonParser p = (NonBlockingJsonParser) JSON_FACTORY.createNonBlockingByteArrayParser()) {
+ p.feedInput(input, 0, input.length);
+ p.endOfInput();
+ _testShortArrayDoc(p);
+ }
+ }
+
+ @Test
+ void shortArrayDocNonBlockingBuffer() throws Exception
+ {
+ final byte[] input = SHORT_ARRAY_DOC.getBytes("UTF-8");
+ try (NonBlockingByteBufferJsonParser p = (NonBlockingByteBufferJsonParser)
+ JSON_FACTORY.createNonBlockingByteBufferParser()) {
+ p.feedInput(ByteBuffer.wrap(input, 0, input.length));
+ p.endOfInput();
+ _testShortArrayDoc(p);
+ }
+ }
+
+ @Test
+ void sampleDoc() throws Exception
+ {
+ for (int mode : ALL_MODES) {
+ _testSampleDoc(mode);
+ }
+ }
+
+ @Test
+ void sampleDocNonBlockingArray() throws Exception
+ {
+ final byte[] input = SAMPLE_DOC_JSON_SPEC.getBytes("UTF-8");
+ try (NonBlockingJsonParser p = (NonBlockingJsonParser) JSON_FACTORY.createNonBlockingByteArrayParser()) {
+ p.feedInput(input, 0, input.length);
+ p.endOfInput();
+ _testSampleDoc(p);
+ }
+ }
+
+ @Test
+ void sampleDocNonBlockingBuffer() throws Exception
+ {
+ final byte[] input = SAMPLE_DOC_JSON_SPEC.getBytes("UTF-8");
+ try (NonBlockingByteBufferJsonParser p = (NonBlockingByteBufferJsonParser)
+ JSON_FACTORY.createNonBlockingByteBufferParser()) {
+ p.feedInput(ByteBuffer.wrap(input, 0, input.length));
+ p.endOfInput();
+ _testSampleDoc(p);
+ }
+ }
+
+ private void _testArrayDoc(int mode) throws Exception
+ {
+ try (JsonParser p = createParser(JSON_FACTORY, mode, ARRAY_DOC)) {
+ _testArrayDoc(p);
+ }
+ }
+
+ private void _testArrayDoc(JsonParser p) throws Exception
+ {
+ assertEquals(0, p.currentTokenCount());
+ consumeTokens(p);
+ assertEquals(15, p.currentTokenCount());
+ }
+
+ private void _testShortArrayDoc(int mode) throws Exception
+ {
+ try (JsonParser p = createParser(JSON_FACTORY, mode, SHORT_ARRAY_DOC)) {
+ _testShortArrayDoc(p);
+ }
+ }
+
+ private void _testShortArrayDoc(JsonParser p) throws Exception
+ {
+ assertEquals(0, p.currentTokenCount());
+ consumeTokens(p);
+ assertEquals(8, p.currentTokenCount());
+ }
+
+ private void _testSampleDoc(int mode) throws Exception
+ {
+ try (JsonParser p = createParser(JSON_FACTORY, mode, SAMPLE_DOC_JSON_SPEC)) {
+ _testSampleDoc(p);
+ }
+ }
+
+ private void _testSampleDoc(JsonParser p) throws Exception
+ {
+ assertEquals(0, p.currentTokenCount());
+ consumeTokens(p);
+ assertEquals(27, p.currentTokenCount());
+ }
+
+ private void consumeTokens(JsonParser p) throws Exception {
+ while (p.nextToken() != null) {
+ ;
+ }
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalParser967Test.java b/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalParser967Test.java
index b6948ca25d..bdff6b5718 100644
--- a/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalParser967Test.java
+++ b/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalParser967Test.java
@@ -1,18 +1,24 @@
package com.fasterxml.jackson.core.dos;
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
import com.fasterxml.jackson.core.*;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
// For [core#967]
-public class PerfBigDecimalParser967Test
+class PerfBigDecimalParser967Test
{
private final JsonFactory JSON_F = new JsonFactory();
// For [core#967]: shouldn't take multiple seconds
- @Test(timeout = 3000)
- public void bigDecimalFromString() throws Exception {
+ @Test
+ @Timeout(value = 3000, unit = TimeUnit.MILLISECONDS)
+ void bigDecimalFromString() throws Exception {
// Jackson's BigDecimalParser seems to be slower than JDK's;
// won't fail if using latter.
StringBuilder sb = new StringBuilder(900);
@@ -24,14 +30,14 @@ public void bigDecimalFromString() throws Exception {
try (JsonParser p = JSON_F.createParser(DOC)) {
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
- Assert.assertNotNull(p.getDecimalValue());
+ assertNotNull(p.getDecimalValue());
}
}
protected void assertToken(JsonToken expToken, JsonToken actToken)
{
if (actToken != expToken) {
- Assert.fail("Expected token "+expToken+", current token "+actToken);
+ fail("Expected token "+expToken+", current token "+actToken);
}
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalToInteger968Test.java b/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalToInteger968Test.java
index de94afae6c..079960716a 100644
--- a/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalToInteger968Test.java
+++ b/src/test/java/com/fasterxml/jackson/core/dos/PerfBigDecimalToInteger968Test.java
@@ -1,43 +1,50 @@
package com.fasterxml.jackson.core.dos;
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
import com.fasterxml.jackson.core.*;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
// For [core#968]]
-public class PerfBigDecimalToInteger968Test
+class PerfBigDecimalToInteger968Test
{
private final JsonFactory JSON_F = new JsonFactory();
-
+
// For [core#968]: shouldn't take multiple seconds
- @Test(timeout = 2000)
- public void bigIntegerViaBigDecimal() throws Exception {
+ @Test
+ @Timeout(value = 2000, unit = TimeUnit.MILLISECONDS)
+ void bigIntegerViaBigDecimal() throws Exception {
final String DOC = "1e25000000";
try (JsonParser p = JSON_F.createParser(DOC)) {
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
try {
p.getBigIntegerValue();
- Assert.fail("Should not pass");
+ fail("Should not pass");
} catch (StreamConstraintsException e) {
- Assert.assertEquals("BigDecimal scale (-25000000) magnitude exceeds the maximum allowed (100000)", e.getMessage());
+ assertEquals("BigDecimal scale (-25000000) magnitude exceeds the maximum allowed (100000)", e.getMessage());
}
}
}
- @Test(timeout = 2000)
- public void tinyIntegerViaBigDecimal() throws Exception {
+ @Test
+ @Timeout(value = 2000, unit = TimeUnit.MILLISECONDS)
+ void tinyIntegerViaBigDecimal() throws Exception {
final String DOC = "1e-25000000";
try (JsonParser p = JSON_F.createParser(DOC)) {
assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
try {
p.getBigIntegerValue();
- Assert.fail("Should not pass");
+ fail("Should not pass");
} catch (StreamConstraintsException e) {
- Assert.assertEquals("BigDecimal scale (25000000) magnitude exceeds the maximum allowed (100000)", e.getMessage());
+ assertEquals("BigDecimal scale (25000000) magnitude exceeds the maximum allowed (100000)", e.getMessage());
}
}
}
@@ -45,7 +52,7 @@ public void tinyIntegerViaBigDecimal() throws Exception {
protected void assertToken(JsonToken expToken, JsonToken actToken)
{
if (actToken != expToken) {
- Assert.fail("Expected token "+expToken+", current token "+actToken);
+ fail("Expected token "+expToken+", current token "+actToken);
}
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/BasicGeneratorFilteringTest.java b/src/test/java/com/fasterxml/jackson/core/filter/BasicGeneratorFilteringTest.java
index 10d3844e7b..6549c80159 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/BasicGeneratorFilteringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/BasicGeneratorFilteringTest.java
@@ -6,15 +6,19 @@
import java.util.*;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
import com.fasterxml.jackson.core.io.SerializedString;
+import static org.junit.jupiter.api.Assertions.*;
+
/**
* Low-level tests for explicit, hand-written tests for generator-side
* filtering.
*/
@SuppressWarnings("resource")
-public class BasicGeneratorFilteringTest extends BaseTest
+class BasicGeneratorFilteringTest extends JUnit5TestBase
{
static final TokenFilter INCLUDE_ALL_SCALARS = new TokenFilter();
@@ -23,7 +27,7 @@ static class NameMatchFilter extends TokenFilter
private final Set _names;
public NameMatchFilter(String... names) {
- _names = new HashSet(Arrays.asList(names));
+ _names = new HashSet<>(Arrays.asList(names));
}
@Override
@@ -49,7 +53,7 @@ static class NameExcludeFilter extends TokenFilter
private final boolean _inclArrays;
public NameExcludeFilter(boolean inclArrays, String... names) {
- _names = new HashSet(Arrays.asList(names));
+ _names = new HashSet<>(Arrays.asList(names));
_inclArrays = inclArrays;
}
@@ -73,7 +77,7 @@ static class StrictNameMatchFilter extends TokenFilter
private final Set _names;
public StrictNameMatchFilter(String... names) {
- _names = new HashSet(Arrays.asList(names));
+ _names = new HashSet<>(Arrays.asList(names));
}
@Override
@@ -171,7 +175,8 @@ public boolean _includeScalar() {
private final JsonFactory JSON_F = new JsonFactory();
- public void testNonFiltering() throws Exception
+ @Test
+ void nonFiltering() throws Exception
{
// First, verify non-filtering
StringWriter w = new StringWriter();
@@ -183,7 +188,8 @@ public void testNonFiltering() throws Exception
w.toString());
}
- public void testSingleMatchFilteringWithoutPath() throws Exception
+ @Test
+ void singleMatchFilteringWithoutPath() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -202,7 +208,8 @@ public void testSingleMatchFilteringWithoutPath() throws Exception
assertEquals("3", w.toString());
}
- public void testSingleMatchFilteringWithPath() throws Exception
+ @Test
+ void singleMatchFilteringWithPath() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator origGen = _createGenerator(w);
@@ -224,7 +231,8 @@ public void testSingleMatchFilteringWithPath() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testSingleMatchFilteringWithPathSkippedArray() throws Exception
+ @Test
+ void singleMatchFilteringWithPathSkippedArray() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator origGen = _createGenerator(w);
@@ -247,7 +255,8 @@ public void testSingleMatchFilteringWithPathSkippedArray() throws Exception
}
// Alternative take, using slightly different calls for FIELD_NAME, START_ARRAY
- public void testSingleMatchFilteringWithPathAlternate1() throws Exception {
+ @Test
+ void singleMatchFilteringWithPathAlternate1() throws Exception {
_testSingleMatchFilteringWithPathAlternate1(false);
_testSingleMatchFilteringWithPathAlternate1(true);
}
@@ -302,7 +311,8 @@ private void _testSingleMatchFilteringWithPathAlternate1(boolean exclude) throws
}
}
- public void testSingleMatchFilteringWithPathRawBinary() throws Exception
+ @Test
+ void singleMatchFilteringWithPathRawBinary() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -326,7 +336,7 @@ public void testSingleMatchFilteringWithPathRawBinary() throws Exception
gen.writeStartArray();
gen.writeBinary(new byte[] { 1 });
gen.writeNumber((short) 1);
- gen.writeNumber((int) 2);
+ gen.writeNumber(2);
gen.writeNumber((long) 3);
gen.writeNumber(BigInteger.valueOf(4));
gen.writeRaw(" ");
@@ -338,7 +348,7 @@ public void testSingleMatchFilteringWithPathRawBinary() throws Exception
gen.writeArrayFieldStart("extra");
gen.writeNumber((short) 1);
- gen.writeNumber((int) 2);
+ gen.writeNumber(2);
gen.writeNumber((long) 3);
gen.writeNumber(BigInteger.valueOf(4));
gen.writeNumber(new BigDecimal("5.0"));
@@ -353,7 +363,8 @@ public void testSingleMatchFilteringWithPathRawBinary() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testMultipleMatchFilteringWithPath1() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath1() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -380,7 +391,8 @@ public void testMultipleMatchFilteringWithPath1() throws Exception
assertEquals(a2q("{'a':123,'b':true}"), w.toString());
}
- public void testMultipleMatchFilteringWithPath2() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath2() throws Exception
{
StringWriter w = new StringWriter();
@@ -393,7 +405,8 @@ public void testMultipleMatchFilteringWithPath2() throws Exception
assertEquals(3, gen.getMatchCount());
}
- public void testMultipleMatchFilteringWithPath3() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath3() throws Exception
{
StringWriter w = new StringWriter();
@@ -406,7 +419,8 @@ public void testMultipleMatchFilteringWithPath3() throws Exception
assertEquals(2, gen.getMatchCount());
}
- public void testNoMatchFiltering1() throws Exception
+ @Test
+ void noMatchFiltering1() throws Exception
{
StringWriter w = new StringWriter();
@@ -419,7 +433,8 @@ public void testNoMatchFiltering1() throws Exception
assertEquals(0, gen.getMatchCount());
}
- public void testNoMatchFiltering2() throws Exception
+ @Test
+ void noMatchFiltering2() throws Exception
{
StringWriter w = new StringWriter();
@@ -433,7 +448,8 @@ public void testNoMatchFiltering2() throws Exception
assertEquals(0, gen.getMatchCount());
}
- public void testNoMatchFiltering3() throws Exception
+ @Test
+ void noMatchFiltering3() throws Exception
{
StringWriter w = new StringWriter();
@@ -447,7 +463,8 @@ public void testNoMatchFiltering3() throws Exception
assertEquals(0, gen.getMatchCount());
}
- public void testNoMatchFiltering4() throws Exception
+ @Test
+ void noMatchFiltering4() throws Exception
{
StringWriter w = new StringWriter();
@@ -460,7 +477,8 @@ public void testNoMatchFiltering4() throws Exception
assertEquals(0, gen.getMatchCount());
}
- public void testNoMatchFiltering5() throws Exception
+ @Test
+ void noMatchFiltering5() throws Exception
{
StringWriter w = new StringWriter();
@@ -474,7 +492,8 @@ public void testNoMatchFiltering5() throws Exception
assertEquals(0, gen.getMatchCount());
}
- public void testNoMatchFiltering6() throws Exception
+ @Test
+ void noMatchFiltering6() throws Exception
{
StringWriter w = new StringWriter();
@@ -488,7 +507,8 @@ public void testNoMatchFiltering6() throws Exception
assertEquals(0, gen.getMatchCount());
}
- public void testValueOmitsFieldName1() throws Exception
+ @Test
+ void valueOmitsFieldName1() throws Exception
{
StringWriter w = new StringWriter();
@@ -501,7 +521,8 @@ public void testValueOmitsFieldName1() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testMultipleMatchFilteringWithPath4() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath4() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -513,7 +534,8 @@ public void testMultipleMatchFilteringWithPath4() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testValueOmitsFieldName2() throws Exception
+ @Test
+ void valueOmitsFieldName2() throws Exception
{
StringWriter w = new StringWriter();
@@ -526,7 +548,8 @@ public void testValueOmitsFieldName2() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testIndexMatchWithPath1() throws Exception
+ @Test
+ void indexMatchWithPath1() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -545,7 +568,8 @@ public void testIndexMatchWithPath1() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testIndexMatchWithPath2() throws Exception
+ @Test
+ void indexMatchWithPath2() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -585,7 +609,8 @@ public void testIndexMatchWithPath2() throws Exception
assertEquals(1, gen.getMatchCount());
}
- public void testWriteStartObjectWithObject() throws Exception
+ @Test
+ void writeStartObjectWithObject() throws Exception
{
StringWriter w = new StringWriter();
@@ -611,7 +636,8 @@ public void testWriteStartObjectWithObject() throws Exception
}
// [core#580]
- public void testRawValueDelegationWithArray() throws Exception
+ @Test
+ void rawValueDelegationWithArray() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -631,7 +657,8 @@ public void testRawValueDelegationWithArray() throws Exception
}
// [core#588]
- public void testRawValueDelegationWithObject() throws Exception
+ @Test
+ void rawValueDelegationWithObject() throws Exception
{
StringWriter w = new StringWriter();
FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(_createGenerator(w),
@@ -648,7 +675,8 @@ public void testRawValueDelegationWithObject() throws Exception
assertEquals(a2q("{'f1':1,'f2':12.3,'f3':3}"), w.toString());
}
- public void testIncludeEmptyArrayIfNotFiltered() throws Exception
+ @Test
+ void includeEmptyArrayIfNotFiltered() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -669,7 +697,8 @@ public void testIncludeEmptyArrayIfNotFiltered() throws Exception
assertEquals(a2q("{'empty_array':[]}"), w.toString());
}
- public void testIncludeEmptyArray() throws Exception
+ @Test
+ void includeEmptyArray() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -690,7 +719,8 @@ public void testIncludeEmptyArray() throws Exception
assertEquals(a2q("{'empty_array':[],'filtered_array':[]}"), w.toString());
}
- public void testIncludeEmptyObjectIfNotFiltered() throws Exception
+ @Test
+ void includeEmptyObjectIfNotFiltered() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -713,7 +743,8 @@ public void testIncludeEmptyObjectIfNotFiltered() throws Exception
assertEquals(a2q("{'empty_object':{}}"), w.toString());
}
- public void testIncludeEmptyObject() throws Exception
+ @Test
+ void includeEmptyObject() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -734,7 +765,8 @@ public void testIncludeEmptyObject() throws Exception
assertEquals(a2q("{'empty_object':{},'filtered_object':{}}"), w.toString());
}
- public void testIncludeEmptyArrayInObjectIfNotFiltered() throws Exception
+ @Test
+ void includeEmptyArrayInObjectIfNotFiltered() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -759,7 +791,8 @@ public void testIncludeEmptyArrayInObjectIfNotFiltered() throws Exception
assertEquals(a2q("{'object_with_empty_array':{'foo':[]}}"), w.toString());
}
- public void testIncludeEmptyArrayInObject() throws Exception
+ @Test
+ void includeEmptyArrayInObject() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -785,7 +818,8 @@ public void testIncludeEmptyArrayInObject() throws Exception
}
- public void testIncludeEmptyObjectInArrayIfNotFiltered() throws Exception
+ @Test
+ void includeEmptyObjectInArrayIfNotFiltered() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -810,7 +844,8 @@ public void testIncludeEmptyObjectInArrayIfNotFiltered() throws Exception
assertEquals(a2q("{'array_with_empty_object':[{}]}"), w.toString());
}
- public void testIncludeEmptyObjectInArray() throws Exception
+ @Test
+ void includeEmptyObjectInArray() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -838,7 +873,8 @@ public void testIncludeEmptyObjectInArray() throws Exception
}
- public void testIncludeEmptyTopLevelObject() throws Exception
+ @Test
+ void includeEmptyTopLevelObject() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
@@ -854,7 +890,8 @@ public void testIncludeEmptyTopLevelObject() throws Exception
assertEquals(a2q("{}"), w.toString());
}
- public void testIncludeEmptyTopLevelArray() throws Exception
+ @Test
+ void includeEmptyTopLevelArray() throws Exception
{
StringWriter w = new StringWriter();
JsonGenerator gen = new FilteringGeneratorDelegate(
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java b/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java
index a006a4b46f..32c20c9c36 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java
@@ -4,17 +4,21 @@
import java.util.*;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
+import static org.junit.jupiter.api.Assertions.*;
+
@SuppressWarnings("resource")
-public class BasicParserFilteringTest extends BaseTest
+class BasicParserFilteringTest extends JUnit5TestBase
{
static class NameMatchFilter extends TokenFilter
{
private final Set _names;
public NameMatchFilter(String... names) {
- _names = new HashSet(Arrays.asList(names));
+ _names = new HashSet<>(Arrays.asList(names));
}
@Override
@@ -39,7 +43,7 @@ static class StrictNameMatchFilter extends TokenFilter
private final Set _names;
public StrictNameMatchFilter(String... names) {
- _names = new HashSet(Arrays.asList(names));
+ _names = new HashSet<>(Arrays.asList(names));
}
@Override
@@ -207,14 +211,16 @@ public boolean _includeScalar() {
private final String SIMPLE = a2q(
"{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':0.25},'b':true}");
- public void testNonFiltering() throws Exception
+ @Test
+ void nonFiltering() throws Exception
{
JsonParser p = JSON_F.createParser(SIMPLE);
String result = readAndWrite(JSON_F, p);
assertEquals(SIMPLE, result);
}
- public void testSingleMatchFilteringWithoutPath() throws Exception
+ @Test
+ void singleMatchFilteringWithoutPath() throws Exception
{
JsonParser p0 = JSON_F.createParser(SIMPLE);
FilteringParserDelegate p = new FilteringParserDelegate(p0,
@@ -227,7 +233,8 @@ public void testSingleMatchFilteringWithoutPath() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testSingleMatchFilteringWithPath1() throws Exception
+ @Test
+ void singleMatchFilteringWithPath1() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -241,7 +248,8 @@ public void testSingleMatchFilteringWithPath1() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testSingleMatchFilteringWithPath2() throws Exception
+ @Test
+ void singleMatchFilteringWithPath2() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -255,7 +263,8 @@ public void testSingleMatchFilteringWithPath2() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testSingleMatchFilteringWithPath3() throws Exception
+ @Test
+ void singleMatchFilteringWithPath3() throws Exception
{
String jsonString = a2q("{'a':123,'ob':{'value0':2,'value':3,'value2':4},'array':[1,2],'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -269,7 +278,8 @@ public void testSingleMatchFilteringWithPath3() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testNotAllowMultipleMatchesWithoutPath1() throws Exception
+ @Test
+ void notAllowMultipleMatchesWithoutPath1() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4,'value':{'value0':2}},'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -283,7 +293,8 @@ public void testNotAllowMultipleMatchesWithoutPath1() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testNotAllowMultipleMatchesWithoutPath2() throws Exception
+ @Test
+ void notAllowMultipleMatchesWithoutPath2() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'array':[3,4],'ob':{'value0':2,'value':3,'value2':4,'value':{'value0':2}},'value':\"val\",'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -297,7 +308,8 @@ public void testNotAllowMultipleMatchesWithoutPath2() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testNotAllowMultipleMatchesWithPath1() throws Exception
+ @Test
+ void notAllowMultipleMatchesWithPath1() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'array':[3,4],'ob':{'value':3,'array':[5,6],'value':{'value0':2}},'value':\"val\",'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -312,7 +324,8 @@ public void testNotAllowMultipleMatchesWithPath1() throws Exception
}
- public void testNotAllowMultipleMatchesWithPath2() throws Exception
+ @Test
+ void notAllowMultipleMatchesWithPath2() throws Exception
{
String jsonString = a2q("{'a':123,'ob':{'value':3,'array':[1,2],'value':{'value0':2}},'array':[3,4]}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -326,7 +339,8 @@ public void testNotAllowMultipleMatchesWithPath2() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testNotAllowMultipleMatchesWithPath3() throws Exception
+ @Test
+ void notAllowMultipleMatchesWithPath3() throws Exception
{
String jsonString = a2q("{'ob':{'value':3,'ob':{'value':2}},'value':\"val\"}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -340,7 +354,8 @@ public void testNotAllowMultipleMatchesWithPath3() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testNotAllowMultipleMatchesWithPath4() throws Exception
+ @Test
+ void notAllowMultipleMatchesWithPath4() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value1':1},'ob2':{'ob':{'value2':2}},'value':\"val\",'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -354,7 +369,8 @@ public void testNotAllowMultipleMatchesWithPath4() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testAllowMultipleMatchesWithoutPath() throws Exception
+ @Test
+ void allowMultipleMatchesWithoutPath() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4,'value':{'value0':2}},'value':\"val\",'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -368,7 +384,8 @@ public void testAllowMultipleMatchesWithoutPath() throws Exception
assertEquals(3, p.getMatchCount());
}
- public void testAllowMultipleMatchesWithPath1() throws Exception
+ @Test
+ void allowMultipleMatchesWithPath1() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4,'value':{'value0':2}},'value':\"val\",'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -382,7 +399,8 @@ public void testAllowMultipleMatchesWithPath1() throws Exception
assertEquals(3, p.getMatchCount());
}
- public void testAllowMultipleMatchesWithPath2() throws Exception
+ @Test
+ void allowMultipleMatchesWithPath2() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'array':[3,4],'value':{'value0':2}},'value':\"val\",'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -396,7 +414,8 @@ public void testAllowMultipleMatchesWithPath2() throws Exception
assertEquals(2, p.getMatchCount());
}
- public void testMultipleMatchFilteringWithPath1() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath1() throws Exception
{
JsonParser p0 = JSON_F.createParser(SIMPLE);
FilteringParserDelegate p = new FilteringParserDelegate(p0,
@@ -408,7 +427,8 @@ public void testMultipleMatchFilteringWithPath1() throws Exception
}
- public void testMultipleMatchFilteringWithPath2() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath2() throws Exception
{
String INPUT = a2q("{'a':123,'ob':{'value0':2,'value':3,'value2':4},'b':true}");
JsonParser p0 = JSON_F.createParser(INPUT);
@@ -421,7 +441,8 @@ public void testMultipleMatchFilteringWithPath2() throws Exception
assertEquals(2, p.getMatchCount());
}
- public void testMultipleMatchFilteringWithPath3() throws Exception
+ @Test
+ void multipleMatchFilteringWithPath3() throws Exception
{
final String JSON = a2q("{'root':{'a0':true,'a':{'value':3},'b':{'value':\"foo\"}},'b0':false}");
JsonParser p0 = JSON_F.createParser(JSON);
@@ -433,7 +454,8 @@ public void testMultipleMatchFilteringWithPath3() throws Exception
assertEquals(2, p.getMatchCount());
}
- public void testNoMatchFiltering1() throws Exception
+ @Test
+ void noMatchFiltering1() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -447,7 +469,8 @@ public void testNoMatchFiltering1() throws Exception
assertEquals(0, p.getMatchCount());
}
- public void testNoMatchFiltering2() throws Exception
+ @Test
+ void noMatchFiltering2() throws Exception
{
String object = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
String jsonString = String.format("[%s,%s,%s]", object, object, object);
@@ -462,7 +485,8 @@ public void testNoMatchFiltering2() throws Exception
assertEquals(0, p.getMatchCount());
}
- public void testNoMatchFiltering3() throws Exception
+ @Test
+ void noMatchFiltering3() throws Exception
{
String object = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
String jsonString = String.format("[[%s],[%s],[%s]]", object, object, object);
@@ -477,7 +501,8 @@ public void testNoMatchFiltering3() throws Exception
assertEquals(0, p.getMatchCount());
}
- public void testNoMatchFiltering4() throws Exception
+ @Test
+ void noMatchFiltering4() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -491,7 +516,8 @@ public void testNoMatchFiltering4() throws Exception
assertEquals(0, p.getMatchCount());
}
- public void testNoMatchFiltering5() throws Exception
+ @Test
+ void noMatchFiltering5() throws Exception
{
String object = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
String jsonString = String.format("[%s,%s,%s]", object, object, object);
@@ -506,7 +532,8 @@ public void testNoMatchFiltering5() throws Exception
assertEquals(0, p.getMatchCount());
}
- public void testNoMatchFiltering6() throws Exception
+ @Test
+ void noMatchFiltering6() throws Exception
{
String object = a2q("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}");
String jsonString = String.format("[[%s],[%s],[%s]]", object, object, object);
@@ -521,7 +548,8 @@ public void testNoMatchFiltering6() throws Exception
assertEquals(0, p.getMatchCount());
}
- public void testValueOmitsFieldName1() throws Exception
+ @Test
+ void valueOmitsFieldName1() throws Exception
{
String jsonString = a2q("{'a':123,'array':[1,2]}");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -535,7 +563,8 @@ public void testValueOmitsFieldName1() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testValueOmitsFieldName2() throws Exception
+ @Test
+ void valueOmitsFieldName2() throws Exception
{
String jsonString = a2q("['a',{'value0':3,'b':{'value':4}},123]");
JsonParser p0 = JSON_F.createParser(jsonString);
@@ -549,7 +578,8 @@ public void testValueOmitsFieldName2() throws Exception
assertEquals(2, p.getMatchCount());
}
- public void testIndexMatchWithPath1() throws Exception
+ @Test
+ void indexMatchWithPath1() throws Exception
{
FilteringParserDelegate p = new FilteringParserDelegate(JSON_F.createParser(SIMPLE),
new IndexMatchFilter(1), Inclusion.INCLUDE_ALL_AND_PATH, true);
@@ -564,7 +594,8 @@ public void testIndexMatchWithPath1() throws Exception
assertEquals(1, p.getMatchCount());
}
- public void testIndexMatchWithPath2() throws Exception
+ @Test
+ void indexMatchWithPath2() throws Exception
{
FilteringParserDelegate p = new FilteringParserDelegate(JSON_F.createParser(SIMPLE),
new IndexMatchFilter(0, 1), Inclusion.INCLUDE_ALL_AND_PATH, true);
@@ -578,7 +609,8 @@ public void testIndexMatchWithPath2() throws Exception
assertEquals(3, p.getMatchCount());
}
- public void testBasicSingleMatchFilteringWithPath() throws Exception
+ @Test
+ void basicSingleMatchFilteringWithPath() throws Exception
{
JsonParser p0 = JSON_F.createParser(SIMPLE);
JsonParser p = new FilteringParserDelegate(p0,
@@ -592,7 +624,8 @@ public void testBasicSingleMatchFilteringWithPath() throws Exception
assertEquals(a2q("{'ob':{'value':3}}"), result);
}
- public void testTokensSingleMatchWithPath() throws Exception
+ @Test
+ void tokensSingleMatchWithPath() throws Exception
{
JsonParser p0 = JSON_F.createParser(SIMPLE);
JsonParser p = new FilteringParserDelegate(p0,
@@ -623,16 +656,16 @@ public void testTokensSingleMatchWithPath() throws Exception
assertEquals(JsonToken.FIELD_NAME, p.getCurrentToken());
assertTrue(p.hasToken(JsonToken.FIELD_NAME));
assertTrue(p.hasTokenId(JsonTokenId.ID_FIELD_NAME));
- assertEquals("ob", p.getCurrentName());
+ assertEquals("ob", p.currentName());
// assertEquals("ob", p.getText());
assertToken(JsonToken.START_OBJECT, p.nextToken());
- assertEquals("ob", p.getCurrentName());
+ assertEquals("ob", p.currentName());
- assertEquals(p0.getCurrentLocation(), p.getCurrentLocation());
+ assertEquals(p0.currentLocation(), p.currentLocation());
assertToken(JsonToken.FIELD_NAME, p.nextToken());
- assertEquals("value", p.getCurrentName());
+ assertEquals("value", p.currentName());
assertEquals("value", p.getText());
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
@@ -669,7 +702,8 @@ public void testTokensSingleMatchWithPath() throws Exception
p.close();
}
- public void testSkippingForSingleWithPath() throws Exception
+ @Test
+ void skippingForSingleWithPath() throws Exception
{
JsonParser p0 = JSON_F.createParser(SIMPLE);
JsonParser p = new FilteringParserDelegate(p0,
@@ -684,7 +718,8 @@ public void testSkippingForSingleWithPath() throws Exception
assertNull(p.nextToken());
}
- public void testIncludeEmptyArrayIfNotFiltered() throws Exception {
+ @Test
+ void includeEmptyArrayIfNotFiltered() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'empty_array':[],'filtered_array':[5]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -695,7 +730,8 @@ public void testIncludeEmptyArrayIfNotFiltered() throws Exception {
assertEquals(a2q("{'empty_array':[]}"), readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyArray() throws Exception {
+ @Test
+ void includeEmptyArray() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'empty_array':[],'filtered_array':[5]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -706,7 +742,8 @@ public void testIncludeEmptyArray() throws Exception {
assertEquals(a2q("{'empty_array':[],'filtered_array':[]}"), readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyObjectIfNotFiltered() throws Exception {
+ @Test
+ void includeEmptyObjectIfNotFiltered() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'empty_object':{},'filtered_object':{'foo':5}}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -717,7 +754,8 @@ public void testIncludeEmptyObjectIfNotFiltered() throws Exception {
assertEquals(a2q("{'empty_object':{}}"), readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyObject() throws Exception {
+ @Test
+ void includeEmptyObject() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'empty_object':{},'filtered_object':{'foo':5}}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -728,7 +766,8 @@ public void testIncludeEmptyObject() throws Exception {
assertEquals(a2q("{'empty_object':{},'filtered_object':{}}"), readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyArrayInObjectIfNotFiltered() throws Exception {
+ @Test
+ void includeEmptyArrayInObjectIfNotFiltered() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'object_with_empty_array':{'foo':[]},'object_with_filtered_array':{'foo':[5]}}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -739,7 +778,8 @@ public void testIncludeEmptyArrayInObjectIfNotFiltered() throws Exception {
assertEquals(a2q("{'object_with_empty_array':{'foo':[]}}"), readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyArrayInObject() throws Exception {
+ @Test
+ void includeEmptyArrayInObject() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'object_with_empty_array':{'foo':[]},'object_with_filtered_array':{'foo':[5]}}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -752,7 +792,8 @@ public void testIncludeEmptyArrayInObject() throws Exception {
readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyObjectInArrayIfNotFiltered() throws Exception {
+ @Test
+ void includeEmptyObjectInArrayIfNotFiltered() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'array_with_empty_object':[{}],'array_with_filtered_object':[{'foo':5}]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -763,7 +804,8 @@ public void testIncludeEmptyObjectInArrayIfNotFiltered() throws Exception {
assertEquals(a2q("{'array_with_empty_object':[{}]}"), readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyObjectInArray() throws Exception {
+ @Test
+ void includeEmptyObjectInArray() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'array_with_empty_object':[{}],'array_with_filtered_object':[{'foo':5}]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -776,7 +818,8 @@ public void testIncludeEmptyObjectInArray() throws Exception {
readAndWrite(JSON_F, p));
}
- public void testIncludeEmptyArrayIfNotFilteredAfterFiltered() throws Exception {
+ @Test
+ void includeEmptyArrayIfNotFilteredAfterFiltered() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"[5, {'empty_array':[],'filtered_array':[5]}]"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -787,7 +830,8 @@ public void testIncludeEmptyArrayIfNotFilteredAfterFiltered() throws Exception {
assertEquals(a2q("[{'empty_array':[]}]"), readAndWrite(JSON_F, p));
}
- public void testExcludeObjectAtTheBeginningOfArray() throws Exception {
+ @Test
+ void excludeObjectAtTheBeginningOfArray() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'parent':[{'exclude':false},{'include':true}]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -798,7 +842,8 @@ public void testExcludeObjectAtTheBeginningOfArray() throws Exception {
assertEquals(a2q("{'parent':[{'include':true}]}"), readAndWrite(JSON_F, p));
}
- public void testExcludeObjectAtTheEndOfArray() throws Exception {
+ @Test
+ void excludeObjectAtTheEndOfArray() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'parent':[{'include':true},{'exclude':false}]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -809,7 +854,8 @@ public void testExcludeObjectAtTheEndOfArray() throws Exception {
assertEquals(a2q("{'parent':[{'include':true}]}"), readAndWrite(JSON_F, p));
}
- public void testExcludeObjectInMiddleOfArray() throws Exception {
+ @Test
+ void excludeObjectInMiddleOfArray() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"{'parent':[{'include-1':1},{'skip':0},{'include-2':2}]}"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -820,7 +866,8 @@ public void testExcludeObjectInMiddleOfArray() throws Exception {
assertEquals(a2q("{'parent':[{'include-1':1},{'include-2':2}]}"), readAndWrite(JSON_F, p));
}
- public void testExcludeLastArrayInsideArray() throws Exception {
+ @Test
+ void excludeLastArrayInsideArray() throws Exception {
JsonParser p0 = JSON_F.createParser(a2q(
"['skipped', [], ['skipped']]"));
JsonParser p = new FilteringParserDelegate(p0,
@@ -831,7 +878,8 @@ public void testExcludeLastArrayInsideArray() throws Exception {
assertEquals(a2q("[[]]"), readAndWrite(JSON_F, p));
}
- public void testCallbacksFromFilteringParserDelegate1() throws Exception {
+ @Test
+ void callbacksFromFilteringParserDelegate1() throws Exception {
LoggingFilter loggingFilter = new LoggingFilter(new JsonPointerBasedFilter("/parent"));
JsonParser p0 = JSON_F.createParser(a2q(
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering609Test.java b/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering609Test.java
index 52373253a4..2b60fd04ca 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering609Test.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering609Test.java
@@ -3,12 +3,16 @@
import java.io.*;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
// for [core#609]
-public class GeneratorFiltering609Test
- extends com.fasterxml.jackson.core.BaseTest
+class GeneratorFiltering609Test
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
static class NullExcludingTokenFilter extends TokenFilter {
static final NullExcludingTokenFilter INSTANCE =
@@ -58,7 +62,8 @@ public void writeFieldName(String name) throws IOException {
}
// for [core#609]: will pass in 2.10 for some cases
- public void testIssue609() throws Exception
+ @Test
+ void issue609() throws Exception
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
JsonGenerator g = createGenerator(outputStream);
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering890Test.java b/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering890Test.java
index 579bdabfd2..a9bd5c6773 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering890Test.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/GeneratorFiltering890Test.java
@@ -1,9 +1,10 @@
package com.fasterxml.jackson.core.filter;
-import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JUnit5TestBase;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
+import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -14,9 +15,11 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
// for [core#890]
-public class GeneratorFiltering890Test
- extends BaseTest
+class GeneratorFiltering890Test
+ extends JUnit5TestBase
{
private static final class OrTokenFilter extends TokenFilter {
@@ -70,7 +73,8 @@ private TokenFilter executeDelegates(final UnaryOperator operator)
}
}
- public void testIssue890_singleProperty() throws Exception
+ @Test
+ void issue890SingleProperty() throws Exception
{
// GIVEN
final Set jsonPointers = Stream.of("/0/id").collect(Collectors.toSet());
@@ -92,7 +96,8 @@ public void testIssue890_singleProperty() throws Exception
assertEquals("[{\"id\":1}]", json);
}
- public void testIssue890_twoProperties() throws Exception
+ @Test
+ void issue890TwoProperties() throws Exception
{
// GIVEN
final Set jsonPointers = Stream.of("/0/id", "/0/stuff/0/name").collect(Collectors.toSet());
@@ -114,7 +119,8 @@ public void testIssue890_twoProperties() throws Exception
assertEquals("[{\"id\":1,\"stuff\":[{\"name\":\"first\"}]}]", json);
}
- public void testIssue890_fullArray() throws Exception
+ @Test
+ void issue890FullArray() throws Exception
{
// GIVEN
final Set jsonPointers = Stream.of("//id", "//stuff//name").collect(Collectors.toSet());
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerGeneratorFilteringTest.java b/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerGeneratorFilteringTest.java
index e52ee35969..896f0e3b8f 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerGeneratorFilteringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerGeneratorFilteringTest.java
@@ -3,16 +3,21 @@
import java.io.*;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
@SuppressWarnings("resource")
-public class JsonPointerGeneratorFilteringTest extends com.fasterxml.jackson.core.BaseTest
+class JsonPointerGeneratorFilteringTest extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory JSON_F = new JsonFactory();
final String SIMPLE_INPUT = a2q("{'a':1,'b':[1,2,3],'c':{'d':{'a':true}},'d':null}");
- public void testSimplePropertyWithPath() throws Exception
+ @Test
+ void simplePropertyWithPath() throws Exception
{
_assert(SIMPLE_INPUT, "/c", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':{'d':{'a':true}}}", false);
_assert(SIMPLE_INPUT, "/c/d", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':{'d':{'a':true}}}", false);
@@ -27,7 +32,8 @@ public void testSimplePropertyWithPath() throws Exception
_assert(SIMPLE_INPUT, "/x", Inclusion.INCLUDE_ALL_AND_PATH, "", false);
}
- public void testSimplePropertyWithoutPath() throws Exception
+ @Test
+ void simplePropertyWithoutPath() throws Exception
{
_assert(SIMPLE_INPUT, "/c", Inclusion.ONLY_INCLUDE_ALL, "{'d':{'a':true}}", false);
_assert(SIMPLE_INPUT, "/c/d", Inclusion.ONLY_INCLUDE_ALL, "{'a':true}", false);
@@ -40,7 +46,8 @@ public void testSimplePropertyWithoutPath() throws Exception
_assert(SIMPLE_INPUT, "/x", Inclusion.ONLY_INCLUDE_ALL, "", false);
}
- public void testArrayElementWithPath() throws Exception
+ @Test
+ void arrayElementWithPath() throws Exception
{
_assert(SIMPLE_INPUT, "/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[1,2,3]}", false);
_assert(SIMPLE_INPUT, "/b/1", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[2]}", false);
@@ -50,7 +57,8 @@ public void testArrayElementWithPath() throws Exception
_assert(SIMPLE_INPUT, "/b/8", Inclusion.INCLUDE_ALL_AND_PATH, "", false);
}
- public void testArrayNestedWithPath() throws Exception
+ @Test
+ void arrayNestedWithPath() throws Exception
{
_assert("{'a':[true,{'b':3,'d':2},false]}", "/a/1/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'a':[{'b':3}]}", false);
_assert("[true,[1]]", "/0", Inclusion.INCLUDE_ALL_AND_PATH, "[true]", false);
@@ -63,7 +71,8 @@ public void testArrayNestedWithPath() throws Exception
_assert("[true,[1,2,[true],3],0]", "/1/3/0", Inclusion.INCLUDE_ALL_AND_PATH, "", false);
}
- public void testArrayNestedWithoutPath() throws Exception
+ @Test
+ void arrayNestedWithoutPath() throws Exception
{
_assert("{'a':[true,{'b':3,'d':2},false]}", "/a/1/b", Inclusion.ONLY_INCLUDE_ALL, "3", false);
_assert("[true,[1,2,[true],3],0]", "/0", Inclusion.ONLY_INCLUDE_ALL, "true", false);
@@ -77,7 +86,8 @@ public void testArrayNestedWithoutPath() throws Exception
// final String SIMPLE_INPUT = aposToQuotes("{'a':1,'b':[1,2,3],'c':{'d':{'a':true}},'d':null}");
- public void testArrayElementWithoutPath() throws Exception
+ @Test
+ void arrayElementWithoutPath() throws Exception
{
_assert(SIMPLE_INPUT, "/b", Inclusion.ONLY_INCLUDE_ALL, "[1,2,3]", false);
_assert(SIMPLE_INPUT, "/b/1", Inclusion.ONLY_INCLUDE_ALL, "2", false);
@@ -89,7 +99,8 @@ public void testArrayElementWithoutPath() throws Exception
_assert(SIMPLE_INPUT, "/x", Inclusion.ONLY_INCLUDE_ALL, "", false);
}
- public void testAllowMultipleMatchesWithPath() throws Exception
+ @Test
+ void allowMultipleMatchesWithPath() throws Exception
{
_assert("[1,2,3]", "/0", Inclusion.INCLUDE_ALL_AND_PATH, "[1]", true);
_assert("[1,2,3]", "/1", Inclusion.INCLUDE_ALL_AND_PATH, "[2]", true);
@@ -132,15 +143,18 @@ private void _assert(String input, String pathExpr, Inclusion tokenFilterInclusi
// for [core#582]: regression wrt array filtering
- public void testArrayFiltering582WithoutObject() throws IOException {
+ @Test
+ void arrayFiltering582WithoutObject() throws IOException {
_testArrayFiltering582(0);
}
- public void testArrayFiltering582WithoutSize() throws IOException {
+ @Test
+ void arrayFiltering582WithoutSize() throws IOException {
_testArrayFiltering582(1);
}
- public void testArrayFiltering582WithSize() throws IOException {
+ @Test
+ void arrayFiltering582WithSize() throws IOException {
_testArrayFiltering582(2);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerParserFilteringTest.java b/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerParserFilteringTest.java
index 7c1097f65f..b843505f87 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerParserFilteringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerParserFilteringTest.java
@@ -3,9 +3,13 @@
import java.io.StringWriter;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
-public class JsonPointerParserFilteringTest extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class JsonPointerParserFilteringTest extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory JSON_F = new JsonFactory();
@@ -13,7 +17,8 @@ public class JsonPointerParserFilteringTest extends com.fasterxml.jackson.core.B
final String SIMPLE_INPUT = a2q("{'a':1,'b':[1,2,3],'c':{'d':{'a':true}},'d':null}");
- public void testSimplestWithPath() throws Exception
+ @Test
+ void simplestWithPath() throws Exception
{
_assert(SIMPLEST_INPUT, "/a", Inclusion.INCLUDE_ALL_AND_PATH, "{'a':1}");
_assert(SIMPLEST_INPUT, "/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':2}");
@@ -22,7 +27,8 @@ public void testSimplestWithPath() throws Exception
_assert(SIMPLEST_INPUT, "/d", Inclusion.INCLUDE_ALL_AND_PATH, "");
}
- public void testSimplestNoPath() throws Exception
+ @Test
+ void simplestNoPath() throws Exception
{
_assert(SIMPLEST_INPUT, "/a", Inclusion.ONLY_INCLUDE_ALL, "1");
_assert(SIMPLEST_INPUT, "/b", Inclusion.ONLY_INCLUDE_ALL, "2");
@@ -31,7 +37,8 @@ public void testSimplestNoPath() throws Exception
_assert(SIMPLEST_INPUT, "/d", Inclusion.ONLY_INCLUDE_ALL, "");
}
- public void testSimpleWithPath() throws Exception
+ @Test
+ void simpleWithPath() throws Exception
{
_assert(SIMPLE_INPUT, "/c", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':{'d':{'a':true}}}");
_assert(SIMPLE_INPUT, "/c/d", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':{'d':{'a':true}}}");
@@ -43,7 +50,8 @@ public void testSimpleWithPath() throws Exception
_assert(SIMPLE_INPUT, "/b/3", Inclusion.INCLUDE_ALL_AND_PATH, "");
}
- public void testSimpleNoPath() throws Exception
+ @Test
+ void simpleNoPath() throws Exception
{
_assert(SIMPLE_INPUT, "/c", Inclusion.ONLY_INCLUDE_ALL, "{'d':{'a':true}}");
diff --git a/src/test/java/com/fasterxml/jackson/core/filter/ParserFiltering700Test.java b/src/test/java/com/fasterxml/jackson/core/filter/ParserFiltering700Test.java
index 16d31d0062..99198677ce 100644
--- a/src/test/java/com/fasterxml/jackson/core/filter/ParserFiltering700Test.java
+++ b/src/test/java/com/fasterxml/jackson/core/filter/ParserFiltering700Test.java
@@ -1,10 +1,14 @@
package com.fasterxml.jackson.core.filter;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
+import static org.junit.jupiter.api.Assertions.*;
+
@SuppressWarnings("resource")
-public class ParserFiltering700Test extends BaseTest
+class ParserFiltering700Test extends JUnit5TestBase
{
static class NoTypeFilter extends TokenFilter {
@Override
@@ -25,7 +29,8 @@ public TokenFilter includeProperty(String name) {
private final JsonFactory JSON_F = newStreamFactory();
// [core#700], simplified
- public void testSkippingRootLevel() throws Exception
+ @Test
+ void skippingRootLevel() throws Exception
{
final String json = a2q("{'@type':'yyy','value':12}");
// should become: {"value":12}
@@ -54,7 +59,8 @@ public void testSkippingRootLevel() throws Exception
}
// [core#700], medium test
- public void testSkippingOneNested() throws Exception
+ @Test
+ void skippingOneNested() throws Exception
{
final String json = a2q("{'value':{'@type':'yyy','a':12}}");
// should become: {"value":{"a":12}}
@@ -87,7 +93,8 @@ public void testSkippingOneNested() throws Exception
}
// [core#700], full test
- public void testSkippingForSingleWithPath() throws Exception
+ @Test
+ void skippingForSingleWithPath() throws Exception
{
_testSkippingForSingleWithPath(false);
_testSkippingForSingleWithPath(true);
diff --git a/src/test/java/com/fasterxml/jackson/core/format/DataFormatMatcherTest.java b/src/test/java/com/fasterxml/jackson/core/format/DataFormatMatcherTest.java
index c4d4377e4f..00664d93f6 100644
--- a/src/test/java/com/fasterxml/jackson/core/format/DataFormatMatcherTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/format/DataFormatMatcherTest.java
@@ -5,14 +5,19 @@
import com.fasterxml.jackson.core.JsonFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
/**
* Unit tests for class {@link DataFormatMatcher}.
*/
-public class DataFormatMatcherTest extends com.fasterxml.jackson.core.BaseTest
+class DataFormatMatcherTest extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory JSON_F = new JsonFactory();
- public void testGetDataStream() throws IOException {
+ @Test
+ void getDataStream() throws IOException {
byte[] byteArray = new byte[2];
MatchStrength matchStrength = MatchStrength.WEAK_MATCH;
DataFormatMatcher dataFormatMatcher = new DataFormatMatcher(null,
@@ -26,7 +31,8 @@ public void testGetDataStream() throws IOException {
inputStream.close();
}
- public void testCreatesDataFormatMatcherTwo() throws IOException {
+ @Test
+ void createsDataFormatMatcherTwo() throws IOException {
try {
@SuppressWarnings("unused")
DataFormatMatcher dataFormatMatcher = new DataFormatMatcher(null,
@@ -37,7 +43,8 @@ public void testCreatesDataFormatMatcherTwo() throws IOException {
}
}
- public void testGetMatchedFormatNameReturnsNameWhenMatches() {
+ @Test
+ void getMatchedFormatNameReturnsNameWhenMatches() {
DataFormatMatcher dataFormatMatcher = new DataFormatMatcher(null,
new byte[2],
1,
@@ -47,7 +54,8 @@ public void testGetMatchedFormatNameReturnsNameWhenMatches() {
assertEquals(JsonFactory.FORMAT_NAME_JSON, dataFormatMatcher.getMatchedFormatName());
}
- public void testDetectorConfiguration() {
+ @Test
+ void detectorConfiguration() {
DataFormatDetector df0 = new DataFormatDetector(JSON_F);
// Defaults are: SOLID for optimal, WEAK for minimum, so:
diff --git a/src/test/java/com/fasterxml/jackson/core/format/TestJsonFormatDetection.java b/src/test/java/com/fasterxml/jackson/core/format/TestJsonFormatDetection.java
index a22e81ef0b..63242a9410 100644
--- a/src/test/java/com/fasterxml/jackson/core/format/TestJsonFormatDetection.java
+++ b/src/test/java/com/fasterxml/jackson/core/format/TestJsonFormatDetection.java
@@ -4,9 +4,14 @@
import com.fasterxml.jackson.core.*;
-public class TestJsonFormatDetection extends com.fasterxml.jackson.core.BaseTest
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class TestJsonFormatDetection extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testSimpleValidArray() throws Exception
+ @Test
+ void simpleValidArray() throws Exception
{
JsonFactory jsonF = new JsonFactory();
DataFormatDetector detector = new DataFormatDetector(jsonF);
@@ -28,7 +33,8 @@ public void testSimpleValidArray() throws Exception
jp.close();
}
- public void testSimpleValidObject() throws Exception
+ @Test
+ void simpleValidObject() throws Exception
{
JsonFactory jsonF = new JsonFactory();
DataFormatDetector detector = new DataFormatDetector(jsonF);
@@ -41,21 +47,22 @@ public void testSimpleValidObject() throws Exception
// no "certain" match with JSON, but solid:
assertEquals(MatchStrength.SOLID_MATCH, matcher.getMatchStrength());
// and thus:
- JsonParser jp = matcher.createParserWithMatch();
- assertToken(JsonToken.START_OBJECT, jp.nextToken());
- assertToken(JsonToken.FIELD_NAME, jp.nextToken());
- assertEquals("field", jp.getCurrentName());
- assertToken(JsonToken.VALUE_TRUE, jp.nextToken());
- assertToken(JsonToken.END_OBJECT, jp.nextToken());
- assertNull(jp.nextToken());
- jp.close();
+ JsonParser p = matcher.createParserWithMatch();
+ assertToken(JsonToken.START_OBJECT, p.nextToken());
+ assertToken(JsonToken.FIELD_NAME, p.nextToken());
+ assertEquals("field", p.currentName());
+ assertToken(JsonToken.VALUE_TRUE, p.nextToken());
+ assertToken(JsonToken.END_OBJECT, p.nextToken());
+ assertNull(p.nextToken());
+ p.close();
}
/**
* While JSON String is not a strong match alone, it should
* be detected unless some better match is available
*/
- public void testSimpleValidString() throws Exception
+ @Test
+ void simpleValidString() throws Exception
{
JsonFactory jsonF = new JsonFactory();
DataFormatDetector detector = new DataFormatDetector(jsonF);
@@ -80,7 +87,8 @@ private void _testSimpleValidString(JsonFactory jsonF, DataFormatMatcher matcher
jp.close();
}
- public void testSimpleInvalid() throws Exception
+ @Test
+ void simpleInvalid() throws Exception
{
DataFormatDetector detector = new DataFormatDetector(new JsonFactory());
final String NON_JSON = "";
diff --git a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz32208UTF32ParseTest.java b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz32208UTF32ParseTest.java
index 8e16d388c3..9cab10dab7 100644
--- a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz32208UTF32ParseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz32208UTF32ParseTest.java
@@ -5,16 +5,21 @@
import java.io.InputStream;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.io.UTF32Reader;
import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
+import static org.junit.jupiter.api.Assertions.fail;
+
// Trying to repro: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=32216
// but so far without success (fails on seemingly legit validation problem)
-public class Fuzz32208UTF32ParseTest extends BaseTest
+class Fuzz32208UTF32ParseTest extends JUnit5TestBase
{
private final byte[] DOC = readResource("/data/fuzz-json-utf32-32208.json");
- public void testFuzz32208ViaParser() throws Exception
+ @Test
+ void fuzz32208ViaParser() throws Exception
{
final JsonFactory f = new JsonFactory();
@@ -30,7 +35,8 @@ public void testFuzz32208ViaParser() throws Exception
}
// How about through UTF32Reader itself?
- public void testFuzz32208Direct() throws Exception
+ @Test
+ void fuzz32208Direct() throws Exception
{
_testFuzz32208Direct(1);
_testFuzz32208Direct(2);
@@ -43,7 +49,8 @@ public void testFuzz32208Direct() throws Exception
_testFuzz32208Direct(991);
}
- public void testFuzz32208DirectSingleByte() throws Exception
+ @Test
+ void fuzz32208DirectSingleByte() throws Exception
{
UTF32Reader r = new UTF32Reader(null, new ByteArrayInputStream(DOC),
new byte[500], 0, 0, false);
diff --git a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz34435ParseTest.java b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz34435ParseTest.java
index d3689a525e..201419fb5a 100644
--- a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz34435ParseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz34435ParseTest.java
@@ -1,15 +1,20 @@
package com.fasterxml.jackson.core.fuzz;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
+import static org.junit.jupiter.api.Assertions.fail;
+
// Trying to repro: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34435
-public class Fuzz34435ParseTest extends BaseTest
+class Fuzz34435ParseTest extends JUnit5TestBase
{
private final byte[] DOC = readResource("/data/fuzz-json-34435.json");
- public void testFuzz34435ViaParser() throws Exception
+ @Test
+ void fuzz34435ViaParser() throws Exception
{
final JsonFactory f = JsonFactory.builder()
// NOTE: test set up enables a few non-standard features
diff --git a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz52688ParseTest.java b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz52688ParseTest.java
index fb1f2bab25..a6b51c3042 100644
--- a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz52688ParseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz52688ParseTest.java
@@ -4,12 +4,17 @@
import java.math.BigInteger;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
// Reproducing: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=52688
// (reported as [core#834]
-public class Fuzz52688ParseTest extends BaseTest
+class Fuzz52688ParseTest extends JUnit5TestBase
{
private final JsonFactory JSON_F = new JsonFactory();
@@ -19,7 +24,8 @@ public class Fuzz52688ParseTest extends BaseTest
+"2222"
+"222");
- public void testBigNumberUTF16Parse() throws Exception
+ @Test
+ void bigNumberUTF16Parse() throws Exception
{
// 41 bytes as UTF16-LE; becomes 21 characters (last broken)
final byte[] DOC = {
@@ -49,7 +55,8 @@ public void testBigNumberUTF16Parse() throws Exception
}
}
- public void testBigNumberUTF8Parse() throws Exception
+ @Test
+ void bigNumberUTF8Parse() throws Exception
{
// Similar to UTF-16 case
final byte[] DOC = {
diff --git a/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz61198_1169_NumberParseTest.java b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz61198_1169_NumberParseTest.java
new file mode 100644
index 0000000000..b5acdac54d
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/fuzz/Fuzz61198_1169_NumberParseTest.java
@@ -0,0 +1,57 @@
+package com.fasterxml.jackson.core.fuzz;
+
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.json.JsonReadFeature;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+// For
+//
+// * [core#1169],
+// * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=61198
+class Fuzz61198_1169_NumberParseTest extends JUnit5TestBase
+{
+ // NOTE! Not enough to enable just first, but both it seem
+ private final JsonFactory JSON_F = JsonFactory.builder()
+ .enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS)
+ .enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS)
+ .build();
+
+ @Test
+ void leadingPlusSignMalformedBytes() throws Exception {
+ _testLeadingPlusMalformed(JSON_F, MODE_INPUT_STREAM);
+ _testLeadingPlusMalformed(JSON_F, MODE_INPUT_STREAM_THROTTLED);
+ }
+
+ @Test
+ void leadingPlusSignMalformedReader() throws Exception {
+ _testLeadingPlusMalformed(JSON_F, MODE_READER);
+ _testLeadingPlusMalformed(JSON_F, MODE_READER_THROTTLED);
+ }
+
+ @Test
+ void leadingPlusSignMalformedOther() throws Exception {
+ _testLeadingPlusMalformed(JSON_F, MODE_DATA_INPUT);
+ }
+
+ private void _testLeadingPlusMalformed(JsonFactory f, int mode) throws Exception
+ {
+ // But also, invalid case:
+ try (JsonParser p = createParser(f, mode, "[ +X 1 ")) {
+ assertToken(JsonToken.START_ARRAY, p.nextToken());
+ try {
+ JsonToken t = p.nextToken();
+ assertToken(JsonToken.VALUE_NUMBER_INT, t);
+ // Either one works:
+// p.getNumberType();
+ p.getIntValue();
+ fail("Should not pass, got: "+t);
+ } catch (JsonParseException e) {
+ verifyException(e, "Unexpected character ('X' (code 88");
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/BigDecimalParserTest.java b/src/test/java/com/fasterxml/jackson/core/io/BigDecimalParserTest.java
index a4e41cd3d8..9ec4cc6cda 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/BigDecimalParserTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/BigDecimalParserTest.java
@@ -1,27 +1,85 @@
package com.fasterxml.jackson.core.io;
-public class BigDecimalParserTest extends com.fasterxml.jackson.core.BaseTest {
- public void testLongStringParse() {
+import java.math.BigDecimal;
+
+import ch.randelshofer.fastdoubleparser.JavaBigDecimalParser;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class BigDecimalParserTest extends com.fasterxml.jackson.core.JUnit5TestBase
+{
+ @Test
+ void longInvalidStringParse() {
try {
- BigDecimalParser.parse(genLongString());
+ BigDecimalParser.parse(genLongInvalidString());
fail("expected NumberFormatException");
} catch (NumberFormatException nfe) {
- assertTrue("exception message starts as expected?", nfe.getMessage().startsWith("Value \"AAAAA"));
- assertTrue("exception message value contains truncated", nfe.getMessage().contains("truncated"));
+ assertTrue(nfe.getMessage().startsWith("Value \"AAAAA"), "exception message starts as expected?");
+ assertTrue(nfe.getMessage().contains("truncated"), "exception message value contains truncated");
}
}
- public void testLongStringFastParse() {
+ @Test
+ void longInvalidStringFastParse() {
try {
- BigDecimalParser.parseWithFastParser(genLongString());
+ BigDecimalParser.parseWithFastParser(genLongInvalidString());
fail("expected NumberFormatException");
} catch (NumberFormatException nfe) {
- assertTrue("exception message starts as expected?", nfe.getMessage().startsWith("Value \"AAAAA"));
- assertTrue("exception message value contains truncated", nfe.getMessage().contains("truncated"));
+ assertTrue(nfe.getMessage().startsWith("Value \"AAAAA"), "exception message starts as expected?");
+ assertTrue(nfe.getMessage().contains("truncated"), "exception message value contains truncated");
+ }
+ }
+
+ @Test
+ void longValidStringParse() {
+ String num = genLongValidString(500);
+ final BigDecimal EXP = new BigDecimal(num);
+
+ // Parse from String first, then char[]
+
+ assertEquals(EXP, BigDecimalParser.parse(num));
+ assertEquals(EXP, BigDecimalParser.parse(num.toCharArray(), 0, num.length()));
+ }
+
+ @Test
+ void longValidStringFastParse() {
+ String num = genLongValidString(500);
+ final BigDecimal EXP = new BigDecimal(num);
+
+ // Parse from String first, then char[]
+ assertEquals(EXP, BigDecimalParser.parseWithFastParser(num));
+ assertEquals(EXP, BigDecimalParser.parseWithFastParser(num.toCharArray(), 0, num.length()));
+ }
+
+ @Test
+ void issueDatabind4694() {
+ final String str = "-11000.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
+ final BigDecimal expected = new BigDecimal(str);
+ assertEquals(expected, JavaBigDecimalParser.parseBigDecimal(str));
+ assertEquals(expected, BigDecimalParser.parse(str));
+ assertEquals(expected, BigDecimalParser.parseWithFastParser(str));
+ final char[] arr = str.toCharArray();
+ assertEquals(expected, BigDecimalParser.parse(arr, 0, arr.length));
+ assertEquals(expected, BigDecimalParser.parseWithFastParser(arr, 0, arr.length));
+ }
+
+ static String genLongInvalidString() {
+ final int len = 1500;
+ final StringBuilder sb = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ sb.append("A");
}
+ return sb.toString();
}
- private String genLongString() {
- return BigIntegerParserTest.genLongString();
+ static String genLongValidString(int len) {
+ final StringBuilder sb = new StringBuilder(len+5);
+ sb.append("0.");
+ for (int i = 0; i < len; i++) {
+ sb.append('0');
+ }
+ sb.append('1');
+ return sb.toString();
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/BigIntegerParserTest.java b/src/test/java/com/fasterxml/jackson/core/io/BigIntegerParserTest.java
index 7b8265d79a..a515f65638 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/BigIntegerParserTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/BigIntegerParserTest.java
@@ -1,8 +1,14 @@
package com.fasterxml.jackson.core.io;
-public class BigIntegerParserTest extends com.fasterxml.jackson.core.BaseTest {
+import org.junit.jupiter.api.Test;
- public void testFastParseBigIntegerFailsWithENotation() {
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class BigIntegerParserTest extends com.fasterxml.jackson.core.JUnit5TestBase {
+
+ @Test
+ void fastParseBigIntegerFailsWithENotation() {
String num = "2e308";
try {
BigIntegerParser.parseWithFastParser(num);
@@ -12,26 +18,28 @@ public void testFastParseBigIntegerFailsWithENotation() {
}
}
- public void testLongStringFastParseBigInteger() {
+ @Test
+ void longStringFastParseBigInteger() {
try {
BigIntegerParser.parseWithFastParser(genLongString());
fail("expected NumberFormatException");
} catch (NumberFormatException nfe) {
- assertTrue("exception message starts as expected?", nfe.getMessage().startsWith("Value \"AAAAA"));
- assertTrue("exception message value contains: truncated", nfe.getMessage().contains("truncated"));
- assertTrue("exception message value contains: BigInteger", nfe.getMessage().contains("BigInteger"));
+ assertTrue(nfe.getMessage().startsWith("Value \"AAAAA"), "exception message starts as expected?");
+ assertTrue(nfe.getMessage().contains("truncated"), "exception message value contains: truncated");
+ assertTrue(nfe.getMessage().contains("BigInteger"), "exception message value contains: BigInteger");
}
}
- public void testLongStringFastParseBigIntegerRadix() {
+ @Test
+ void longStringFastParseBigIntegerRadix() {
try {
BigIntegerParser.parseWithFastParser(genLongString(), 8);
fail("expected NumberFormatException");
} catch (NumberFormatException nfe) {
- assertTrue("exception message starts as expected?", nfe.getMessage().startsWith("Value \"AAAAA"));
- assertTrue("exception message value contains: truncated", nfe.getMessage().contains("truncated"));
- assertTrue("exception message value contains: radix 8", nfe.getMessage().contains("radix 8"));
- assertTrue("exception message value contains: BigInteger", nfe.getMessage().contains("BigInteger"));
+ assertTrue(nfe.getMessage().startsWith("Value \"AAAAA"), "exception message starts as expected?");
+ assertTrue(nfe.getMessage().contains("truncated"), "exception message value contains: truncated");
+ assertTrue(nfe.getMessage().contains("radix 8"), "exception message value contains: radix 8");
+ assertTrue(nfe.getMessage().contains("BigInteger"), "exception message value contains: BigInteger");
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/BufferRecyclerPoolTest.java b/src/test/java/com/fasterxml/jackson/core/io/BufferRecyclerPoolTest.java
index cc4c29f0f2..f7f5b86328 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/BufferRecyclerPoolTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/BufferRecyclerPoolTest.java
@@ -1,45 +1,59 @@
package com.fasterxml.jackson.core.io;
-import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JUnit5TestBase;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.json.JsonGeneratorImpl;
+import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.util.BufferRecycler;
-import com.fasterxml.jackson.core.util.RecyclerPool;
import com.fasterxml.jackson.core.util.JsonRecyclerPools;
+import com.fasterxml.jackson.core.util.RecyclerPool;
+import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.OutputStream;
-public class BufferRecyclerPoolTest extends BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+// Tests for [core#1064] wrt custom `BufferRecycler`
+class BufferRecyclerPoolTest extends JUnit5TestBase
{
- public void testNoOp() throws Exception {
+ @Test
+ void noOp() throws Exception {
// no-op pool doesn't actually pool anything, so avoid checking it
- checkBufferRecyclerPoolImpl(JsonRecyclerPools.nonRecyclingPool(), false);
+ checkBufferRecyclerPoolImpl(JsonRecyclerPools.nonRecyclingPool(), false, true);
}
- public void testThreadLocal() throws Exception {
- checkBufferRecyclerPoolImpl(JsonRecyclerPools.threadLocalPool(), true);
+ @Test
+ void threadLocal() throws Exception {
+ checkBufferRecyclerPoolImpl(JsonRecyclerPools.threadLocalPool(), true, false);
}
- public void testLockFree() throws Exception {
- checkBufferRecyclerPoolImpl(JsonRecyclerPools.newLockFreePool(), true);
+ @Test
+ @Deprecated
+ void lockFree() throws Exception {
+ checkBufferRecyclerPoolImpl(JsonRecyclerPools.newLockFreePool(), true, true);
}
- public void testConcurrentDequeue() throws Exception {
- checkBufferRecyclerPoolImpl(JsonRecyclerPools.newConcurrentDequePool(), true);
+ @Test
+ void concurrentDequeue() throws Exception {
+ checkBufferRecyclerPoolImpl(JsonRecyclerPools.newConcurrentDequePool(), true, true);
}
- public void testBounded() throws Exception {
- checkBufferRecyclerPoolImpl(JsonRecyclerPools.newBoundedPool(1), true);
+ @Test
+ void bounded() throws Exception {
+ checkBufferRecyclerPoolImpl(JsonRecyclerPools.newBoundedPool(1), true, true);
}
- public void testPluggingPool() throws Exception {
- checkBufferRecyclerPoolImpl(new TestPool(), true);
+ @Test
+ void pluggingPool() throws Exception {
+ checkBufferRecyclerPoolImpl(new TestPool(), true, true);
}
private void checkBufferRecyclerPoolImpl(RecyclerPool pool,
- boolean checkPooledResource) throws Exception {
+ boolean checkPooledResource,
+ boolean implementsClear)
+ throws Exception
+ {
JsonFactory jsonFactory = JsonFactory.builder()
.recyclerPool(pool)
.build();
@@ -48,11 +62,22 @@ private void checkBufferRecyclerPoolImpl(RecyclerPool pool,
if (checkPooledResource) {
// acquire the pooled BufferRecycler again and check if it is the same instance used before
BufferRecycler pooledBufferRecycler = pool.acquireAndLinkPooled();
- try {
- assertSame(usedBufferRecycler, pooledBufferRecycler);
- } finally {
- pooledBufferRecycler.releaseToPool();
- }
+ assertSame(usedBufferRecycler, pooledBufferRecycler);
+ // might as well return it back
+ pooledBufferRecycler.releaseToPool();
+ }
+
+ // Also: check `clear()` method -- optional, but supported by all impls
+ // except for ThreadLocal-based one
+ if (implementsClear) {
+ assertTrue(pool.clear());
+
+ // cannot easily verify anything else except that we do NOT get the same recycled instance
+ BufferRecycler br2 = pool.acquireAndLinkPooled();
+ assertNotNull(br2);
+ assertNotSame(usedBufferRecycler, br2);
+ } else {
+ assertFalse(pool.clear());
}
}
@@ -60,7 +85,7 @@ private BufferRecycler write(Object value, JsonFactory jsonFactory, int expected
BufferRecycler bufferRecycler;
NopOutputStream out = new NopOutputStream();
try (JsonGenerator gen = jsonFactory.createGenerator(out)) {
- bufferRecycler = ((JsonGeneratorImpl) gen).ioContext()._bufferRecycler;
+ bufferRecycler = ((GeneratorBase) gen).ioContext().bufferRecycler();
gen.writeObject(value);
}
assertEquals(expectedSize, out.size);
@@ -99,8 +124,22 @@ public BufferRecycler acquirePooled() {
}
@Override
- public void releasePooled(BufferRecycler recycler) {
- this.bufferRecycler = recycler;
+ public void releasePooled(BufferRecycler r) {
+ if (bufferRecycler == r) { // just sanity check for this test
+ throw new IllegalStateException("BufferRecyler released more than once");
+ }
+ bufferRecycler = r;
+ }
+
+ @Override
+ public int pooledCount() {
+ return (bufferRecycler == null) ? 0 : 1;
+ }
+
+ @Override
+ public boolean clear() {
+ bufferRecycler = null;
+ return true;
}
}
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestMergedStream.java b/src/test/java/com/fasterxml/jackson/core/io/MergedStreamTest.java
similarity index 88%
rename from src/test/java/com/fasterxml/jackson/core/io/TestMergedStream.java
rename to src/test/java/com/fasterxml/jackson/core/io/MergedStreamTest.java
index 81a75ba1e7..249337788f 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/TestMergedStream.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/MergedStreamTest.java
@@ -4,10 +4,15 @@
import com.fasterxml.jackson.core.JsonEncoding;
-public class TestMergedStream
- extends com.fasterxml.jackson.core.BaseTest
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MergedStreamTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testSimple() throws Exception
+ @Test
+ void simple() throws Exception
{
IOContext ctxt = testIOContext();
// bit complicated; must use recyclable buffer...
diff --git a/src/test/java/com/fasterxml/jackson/core/io/NumberInputTest.java b/src/test/java/com/fasterxml/jackson/core/io/NumberInputTest.java
new file mode 100644
index 0000000000..7c792e541e
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/io/NumberInputTest.java
@@ -0,0 +1,143 @@
+package com.fasterxml.jackson.core.io;
+
+import java.math.BigInteger;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class NumberInputTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
+{
+ @Test
+ void nastySmallDouble()
+ {
+ //relates to https://github.com/FasterXML/jackson-core/issues/750
+ //prior to jackson v2.14, this value used to be returned as Double.MIN_VALUE
+ final String nastySmallDouble = "2.2250738585072012e-308";
+ assertEquals(Double.parseDouble(nastySmallDouble), NumberInput.parseDouble(nastySmallDouble, false));
+ assertEquals(Double.parseDouble(nastySmallDouble), NumberInput.parseDouble(nastySmallDouble, true));
+ }
+
+ @Test
+ void parseFloat()
+ {
+ final String exampleFloat = "1.199999988079071";
+ assertEquals(1.1999999f, NumberInput.parseFloat(exampleFloat, false));
+ assertEquals(1.1999999f, NumberInput.parseFloat(exampleFloat, true));
+ assertEquals(1.2f, (float)NumberInput.parseDouble(exampleFloat, false));
+ assertEquals(1.2f, (float)NumberInput.parseDouble(exampleFloat, true));
+
+ final String exampleFloat2 = "7.006492321624086e-46";
+ assertEquals("1.4E-45", Float.toString(NumberInput.parseFloat(exampleFloat2, false)));
+ assertEquals("1.4E-45", Float.toString(NumberInput.parseFloat(exampleFloat2, true)));
+ }
+
+ @Test
+ void parseLongBigInteger()
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ stringBuilder.append(7);
+ }
+ String test1000 = stringBuilder.toString();
+ assertEquals(new BigInteger(test1000), NumberInput.parseBigInteger(test1000, false));
+ assertEquals(new BigInteger(test1000), NumberInput.parseBigInteger(test1000, true));
+ for (int i = 0; i < 1000; i++) {
+ stringBuilder.append(7);
+ }
+ String test2000 = stringBuilder.toString();
+ assertEquals(new BigInteger(test2000), NumberInput.parseBigInteger(test2000, false));
+ assertEquals(new BigInteger(test2000), NumberInput.parseBigInteger(test2000, true));
+ }
+
+ @Test
+ void bigIntegerWithRadix()
+ {
+ final String val = "1ABCDEF";
+ final int radix = 16;
+ BigInteger expected = new BigInteger(val, radix);
+ assertEquals(expected, NumberInput.parseBigIntegerWithRadix(val, radix, true));
+ assertEquals(expected, NumberInput.parseBigIntegerWithRadix(val, radix, false));
+ }
+
+ @Test
+ void parseBigIntegerFailsWithENotation()
+ {
+ try {
+ NumberInput.parseBigInteger("1e10", false);
+ fail("expected NumberFormatException");
+ } catch (NumberFormatException e) {
+ verifyException(e, "1e10");
+ }
+ }
+
+ @Test
+ void looksLikeValidNumberTrue()
+ {
+ assertTrue(NumberInput.looksLikeValidNumber("0"));
+ assertTrue(NumberInput.looksLikeValidNumber("1"));
+ assertTrue(NumberInput.looksLikeValidNumber("-1"));
+ assertTrue(NumberInput.looksLikeValidNumber("+1")); // non-JSON
+ assertTrue(NumberInput.looksLikeValidNumber("0001")); // non-JSON
+
+ // https://github.com/FasterXML/jackson-databind/issues/4435
+ assertTrue(NumberInput.looksLikeValidNumber(".0"));
+ assertTrue(NumberInput.looksLikeValidNumber("-.0"));
+ assertTrue(NumberInput.looksLikeValidNumber("+.0"));
+ assertTrue(NumberInput.looksLikeValidNumber(".01"));
+ assertTrue(NumberInput.looksLikeValidNumber("-.01"));
+ assertTrue(NumberInput.looksLikeValidNumber("+.01"));
+
+ assertTrue(NumberInput.looksLikeValidNumber("0.01"));
+ assertTrue(NumberInput.looksLikeValidNumber("-0.10"));
+ assertTrue(NumberInput.looksLikeValidNumber("+0.25")); // non-JSON
+
+ assertTrue(NumberInput.looksLikeValidNumber("10.33"));
+ assertTrue(NumberInput.looksLikeValidNumber("-1.39"));
+ assertTrue(NumberInput.looksLikeValidNumber("+125.0")); // non-JSON
+
+ assertTrue(NumberInput.looksLikeValidNumber("1E10"));
+ assertTrue(NumberInput.looksLikeValidNumber("-1E10"));
+ assertTrue(NumberInput.looksLikeValidNumber("1e-10"));
+ assertTrue(NumberInput.looksLikeValidNumber("1e+10"));
+ assertTrue(NumberInput.looksLikeValidNumber("+1e+10"));
+ assertTrue(NumberInput.looksLikeValidNumber("1.4E-45"));
+ assertTrue(NumberInput.looksLikeValidNumber("1.4e+45"));
+
+ // https://github.com/FasterXML/jackson-core/issues/1308
+ assertTrue(NumberInput.looksLikeValidNumber("0."));
+ assertTrue(NumberInput.looksLikeValidNumber("6."));
+ assertTrue(NumberInput.looksLikeValidNumber("65."));
+ assertTrue(NumberInput.looksLikeValidNumber("654."));
+ assertTrue(NumberInput.looksLikeValidNumber("65432."));
+ assertTrue(NumberInput.looksLikeValidNumber("-0."));
+ assertTrue(NumberInput.looksLikeValidNumber("-6."));
+ assertTrue(NumberInput.looksLikeValidNumber("-65."));
+ assertTrue(NumberInput.looksLikeValidNumber("-654."));
+ assertTrue(NumberInput.looksLikeValidNumber("-65432."));
+ assertTrue(NumberInput.looksLikeValidNumber("+0."));
+ assertTrue(NumberInput.looksLikeValidNumber("+6."));
+ assertTrue(NumberInput.looksLikeValidNumber("+65."));
+ assertTrue(NumberInput.looksLikeValidNumber("+654."));
+ assertTrue(NumberInput.looksLikeValidNumber("+65432."));
+ }
+
+ @Test
+ void looksLikeValidNumberFalse()
+ {
+ // https://github.com/FasterXML/jackson-databind/issues/4435 and
+ // https://github.com/FasterXML/jackson-core/issues/1308
+ assertFalse(NumberInput.looksLikeValidNumber(""));
+ assertFalse(NumberInput.looksLikeValidNumber(" "));
+ assertFalse(NumberInput.looksLikeValidNumber(" "));
+ assertFalse(NumberInput.looksLikeValidNumber("."));
+ assertFalse(NumberInput.looksLikeValidNumber("10_000"));
+ assertFalse(NumberInput.looksLikeValidNumber("-"));
+ assertFalse(NumberInput.looksLikeValidNumber("+"));
+ assertFalse(NumberInput.looksLikeValidNumber("-."));
+ assertFalse(NumberInput.looksLikeValidNumber("+."));
+ assertFalse(NumberInput.looksLikeValidNumber("-E"));
+ assertFalse(NumberInput.looksLikeValidNumber("+E"));
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java b/src/test/java/com/fasterxml/jackson/core/io/NumberOutputTest.java
similarity index 50%
rename from src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
rename to src/test/java/com/fasterxml/jackson/core/io/NumberOutputTest.java
index bad5bdbc03..272a7799e8 100644
--- a/src/test/java/com/fasterxml/jackson/core/util/TestNumberPrinting.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/NumberOutputTest.java
@@ -1,17 +1,17 @@
-package com.fasterxml.jackson.core.util;
+package com.fasterxml.jackson.core.io;
import java.util.Random;
-import com.fasterxml.jackson.core.io.NumberOutput;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
-/**
- * Set of basic unit tests for verifying that the low-level number
- * printing methods work as expected.
- */
-public class TestNumberPrinting
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class NumberOutputTest
{
- public void testIntPrinting() throws Exception
+ @Test
+ void intPrinting() throws Exception
{
assertIntPrint(0);
assertIntPrint(-3);
@@ -38,7 +38,8 @@ public void testIntPrinting() throws Exception
}
}
- public void testLongPrinting() throws Exception
+ @Test
+ void longPrinting() throws Exception
{
// First, let's just cover couple of edge cases
assertLongPrint(0L, 0);
@@ -52,11 +53,53 @@ public void testLongPrinting() throws Exception
Random rnd = new Random(12345L);
// Bigger value space, need more iterations for long
for (int i = 0; i < 678000; ++i) {
- long l = ((long) rnd.nextInt() << 32) | (long) rnd.nextInt();
+ long l = ((long) rnd.nextInt() << 32) | rnd.nextInt();
assertLongPrint(l, i);
}
}
+ // // // Tests for divBy1000
+
+ @Test
+ void divBy1000Small()
+ {
+ for (int number = 0; number <= 999_999; ++number) {
+ int expected = number / 1000;
+ int actual = NumberOutput.divBy1000(number);
+ if (expected != actual) { // only construct String if fail
+ fail("With "+number+" should get "+expected+", got: "+actual);
+ }
+ }
+ }
+
+ @Test
+ void divBy1000Sampled()
+ {
+ for (int number = 1_000_000; number > 0; number += 7) {
+ int expected = number / 1000;
+ int actual = NumberOutput.divBy1000(number);
+ if (expected != actual) { // only construct String if fail
+ fail("With "+number+" should get "+expected+", got: "+actual);
+ }
+ }
+ }
+
+ // And then full range, not included in CI since code shouldn't change;
+ // but has been run to verify full range manually
+ @Test
+ // Comment out for manual testing:
+ @Disabled
+ void divBy1000FullRange() {
+ // To get to Integer.MAX_VALUE, need to check for overflow
+ for (int number = 0; number >= 0; ++number) {
+ int expected = number / 1000;
+ int actual = NumberOutput.divBy1000(number);
+ if (expected != actual) { // only construct String if fail
+ fail("With "+number+" should get "+expected+", got: "+actual);
+ }
+ }
+ }
+
/*
/**********************************************************
/* Internal methods
@@ -69,11 +112,11 @@ private void assertIntPrint(int value)
String act = printToString(value);
if (!exp.equals(act)) {
- assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+")", exp, act);
+ assertEquals(exp, act, "Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+")");
}
String alt = NumberOutput.toString(value);
if (!exp.equals(alt)) {
- assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+")", exp, act);
+ assertEquals(exp, act, "Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+")");
}
}
@@ -83,11 +126,11 @@ private void assertLongPrint(long value, int index)
String act = printToString(value);
if (!exp.equals(act)) {
- assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+"; number index "+index+")", exp, act);
+ assertEquals(exp, act, "Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+"; number index "+index+")");
}
String alt = NumberOutput.toString(value);
if (!exp.equals(alt)) {
- assertEquals("Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+"; number index "+index+")", exp, act);
+ assertEquals(exp, act, "Expected conversion (exp '"+exp+"', len "+exp.length()+"; act len "+act.length()+"; number index "+index+")");
}
}
@@ -104,4 +147,4 @@ private String printToString(long value)
int offset = NumberOutput.outputLong(value, buffer, 0);
return new String(buffer, 0, offset);
}
-}
+}
\ No newline at end of file
diff --git a/src/test/java/com/fasterxml/jackson/core/io/SegmentedStringWriterTest.java b/src/test/java/com/fasterxml/jackson/core/io/SegmentedStringWriterTest.java
index 761f009752..329d8de5ba 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/SegmentedStringWriterTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/SegmentedStringWriterTest.java
@@ -1,11 +1,19 @@
package com.fasterxml.jackson.core.io;
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.util.BufferRecycler;
+import com.fasterxml.jackson.core.util.JsonRecyclerPools;
+
+import static org.junit.jupiter.api.Assertions.*;
-public class SegmentedStringWriterTest
- extends com.fasterxml.jackson.core.BaseTest
+class SegmentedStringWriterTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testSimple() throws Exception
+ @Test
+ void simple() throws Exception
{
BufferRecycler br = new BufferRecycler();
SegmentedStringWriter w = new SegmentedStringWriter(br);
@@ -44,4 +52,37 @@ public void testSimple() throws Exception
String act = w.getAndClear();
assertEquals(exp.toString(), act);
}
+
+ // [core#1195]: Try to verify that BufferRecycler instance is indeed reused
+ @Test
+ void bufferRecyclerReuse() throws Exception
+ {
+ JsonFactory f = new JsonFactory();
+ BufferRecycler br = new BufferRecycler()
+ // need to link with some pool
+ .withPool(JsonRecyclerPools.newBoundedPool(3));
+
+ SegmentedStringWriter ssw = new SegmentedStringWriter(br);
+ assertSame(br, ssw.bufferRecycler());
+
+ JsonGenerator g = f.createGenerator(ssw);
+ IOContext ioCtxt = ((GeneratorBase) g).ioContext();
+ assertSame(br, ioCtxt.bufferRecycler());
+ assertTrue(ioCtxt.bufferRecycler().isLinkedWithPool());
+
+ g.writeStartArray();
+ g.writeEndArray();
+ g.close();
+
+ // Generator.close() should NOT release buffer recycler
+ assertTrue(br.isLinkedWithPool());
+
+ // Nor accessing contents
+ assertEquals("[]", ssw.getAndClear());
+ assertTrue(br.isLinkedWithPool());
+
+ // only explicit release does
+ br.releaseToPool();
+ assertFalse(br.isLinkedWithPool());
+ }
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestCharTypes.java b/src/test/java/com/fasterxml/jackson/core/io/TestCharTypes.java
index fc1704f97a..35e2d6cbcb 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/TestCharTypes.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/TestCharTypes.java
@@ -1,9 +1,14 @@
package com.fasterxml.jackson.core.io;
-public class TestCharTypes
- extends com.fasterxml.jackson.core.BaseTest
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class TestCharTypes
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testAppendQuoted0_31 ()
+ @Test
+ void appendQuoted031()
{
final String[] inputs = { "\u0000", "\u001F", "abcd", "\u0001ABCD\u0002", "WX\u000F\u0010YZ" };
final String[] expecteds = { "\\u0000", "\\u001F", "abcd", "\\u0001ABCD\\u0002", "WX\\u000F\\u0010YZ" };
@@ -21,7 +26,8 @@ public void testAppendQuoted0_31 ()
}
}
- public void testHexOutOfRange()
+ @Test
+ void hexOutOfRange()
{
final int[] inputs = {0, -1, 1, 129, -129};
for (int input : inputs) {
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java b/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java
index ebd0b1d272..bd77be584f 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/TestIOContext.java
@@ -1,14 +1,19 @@
package com.fasterxml.jackson.core.io;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.ErrorReportConfiguration;
import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.core.StreamWriteConstraints;
import com.fasterxml.jackson.core.util.BufferRecycler;
-public class TestIOContext
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class TestIOContext
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testAllocations() throws Exception
+ @Test
+ void allocations() throws Exception
{
IOContext ctxt = new IOContext(StreamReadConstraints.defaults(),
StreamWriteConstraints.defaults(),
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java b/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java
index c916dfb1e9..4dfba90b9a 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/TestJsonStringEncoder.java
@@ -3,14 +3,18 @@
import java.io.StringWriter;
import java.util.Random;
-import static org.junit.Assert.*;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import com.fasterxml.jackson.core.*;
-public class TestJsonStringEncoder
- extends com.fasterxml.jackson.core.BaseTest
+class TestJsonStringEncoder
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testQuoteAsString() throws Exception
+ @Test
+ void quoteAsString() throws Exception
{
JsonStringEncoder encoder = new JsonStringEncoder();
char[] result = encoder.quoteAsString("foobar");
@@ -25,7 +29,8 @@ public void testQuoteAsString() throws Exception
assertArrayEquals("\\\"x\\\"".toCharArray(), result);
}
- public void testQuoteCharSequenceAsString() throws Exception
+ @Test
+ void quoteCharSequenceAsString() throws Exception
{
StringBuilder output = new StringBuilder();
StringBuilder builder = new StringBuilder();
@@ -40,7 +45,8 @@ public void testQuoteCharSequenceAsString() throws Exception
}
// For [JACKSON-853]
- public void testQuoteLongAsString() throws Exception
+ @Test
+ void quoteLongAsString() throws Exception
{
JsonStringEncoder encoder = new JsonStringEncoder();
StringBuilder sb = new StringBuilder();
@@ -56,7 +62,8 @@ public void testQuoteLongAsString() throws Exception
assertEquals(exp, new String(result));
}
- public void testQuoteLongCharSequenceAsString() throws Exception
+ @Test
+ void quoteLongCharSequenceAsString() throws Exception
{
StringBuilder output = new StringBuilder();
StringBuilder input = new StringBuilder();
@@ -72,7 +79,8 @@ public void testQuoteLongCharSequenceAsString() throws Exception
}
- public void testQuoteAsUTF8() throws Exception
+ @Test
+ void quoteAsUTF8() throws Exception
{
// In this case, let's actually use existing JsonGenerator to produce expected values
JsonFactory f = new JsonFactory();
@@ -95,7 +103,8 @@ public void testQuoteAsUTF8() throws Exception
}
}
- public void testEncodeAsUTF8() throws Exception
+ @Test
+ void encodeAsUTF8() throws Exception
{
JsonStringEncoder encoder = new JsonStringEncoder();
String[] strings = new String[] {
@@ -112,7 +121,8 @@ public void testEncodeAsUTF8() throws Exception
}
}
- public void testCtrlChars() throws Exception
+ @Test
+ void ctrlChars() throws Exception
{
char[] input = new char[] { 0, 1, 2, 3, 4 };
char[] quoted = JsonStringEncoder.getInstance().quoteAsString(new String(input));
@@ -120,7 +130,8 @@ public void testCtrlChars() throws Exception
}
// [JACKSON-884]
- public void testCharSequenceWithCtrlChars() throws Exception
+ @Test
+ void charSequenceWithCtrlChars() throws Exception
{
char[] input = new char[] { 0, 1, 2, 3, 4 };
StringBuilder builder = new StringBuilder();
@@ -131,7 +142,8 @@ public void testCharSequenceWithCtrlChars() throws Exception
}
// [core#712]: simple sanity checks for calculation logic
- public void testByteBufferDefaultSize()
+ @Test
+ void byteBufferDefaultSize()
{
// byte size is simple, x2 except below buffer size 24
assertEquals(JsonStringEncoder.MIN_BYTE_BUFFER_SIZE,
@@ -152,7 +164,8 @@ public void testByteBufferDefaultSize()
}
// [core#712]: simple sanity checks for calculation logic
- public void testCharBufferDefaultSize()
+ @Test
+ void charBufferDefaultSize()
{
// char[] bit more complex, starts with minimum size of 16
assertEquals(JsonStringEncoder.MIN_CHAR_BUFFER_SIZE,
diff --git a/src/test/java/com/fasterxml/jackson/core/io/TestNumberInput.java b/src/test/java/com/fasterxml/jackson/core/io/TestNumberInput.java
deleted file mode 100644
index 9c8c42d8d7..0000000000
--- a/src/test/java/com/fasterxml/jackson/core/io/TestNumberInput.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.fasterxml.jackson.core.io;
-
-import java.math.BigInteger;
-
-public class TestNumberInput
- extends com.fasterxml.jackson.core.BaseTest
-{
- public void testNastySmallDouble()
- {
- //relates to https://github.com/FasterXML/jackson-core/issues/750
- //prior to jackson v2.14, this value used to be returned as Double.MIN_VALUE
- final String nastySmallDouble = "2.2250738585072012e-308";
- assertEquals(Double.parseDouble(nastySmallDouble), NumberInput.parseDouble(nastySmallDouble));
- assertEquals(Double.parseDouble(nastySmallDouble), NumberInput.parseDouble(nastySmallDouble, true));
- }
-
- public void testParseFloat()
- {
- final String exampleFloat = "1.199999988079071";
- assertEquals(1.1999999f, NumberInput.parseFloat(exampleFloat));
- assertEquals(1.1999999f, NumberInput.parseFloat(exampleFloat, true));
- assertEquals(1.2f, (float)NumberInput.parseDouble(exampleFloat));
- assertEquals(1.2f, (float)NumberInput.parseDouble(exampleFloat, true));
-
- final String exampleFloat2 = "7.006492321624086e-46";
- assertEquals("1.4E-45", Float.toString(NumberInput.parseFloat(exampleFloat2)));
- assertEquals("1.4E-45", Float.toString(NumberInput.parseFloat(exampleFloat2, true)));
- }
-
- public void testParseLongBigInteger()
- {
- StringBuilder stringBuilder = new StringBuilder();
- for (int i = 0; i < 1000; i++) {
- stringBuilder.append(7);
- }
- String test1000 = stringBuilder.toString();
- assertEquals(new BigInteger(test1000), NumberInput.parseBigInteger(test1000));
- assertEquals(new BigInteger(test1000), NumberInput.parseBigInteger(test1000, true));
- for (int i = 0; i < 1000; i++) {
- stringBuilder.append(7);
- }
- String test2000 = stringBuilder.toString();
- assertEquals(new BigInteger(test2000), NumberInput.parseBigInteger(test2000));
- assertEquals(new BigInteger(test2000), NumberInput.parseBigInteger(test2000, true));
- }
-
- public void testBigIntegerWithRadix()
- {
- final String val = "1ABCDEF";
- final int radix = 16;
- BigInteger expected = new BigInteger(val, radix);
- assertEquals(expected, NumberInput.parseBigIntegerWithRadix(val, radix, true));
- assertEquals(expected, NumberInput.parseBigIntegerWithRadix(val, radix, false));
- }
-
- public void testParseBigIntegerFailsWithENotation()
- {
- try {
- NumberInput.parseBigInteger("1e10");
- fail("expected NumberFormatException");
- } catch (NumberFormatException nfe) {
- // expected
- }
- }
-}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java b/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java
index 1907b9bf82..3344ae3708 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/UTF8WriterTest.java
@@ -2,12 +2,15 @@
import java.io.*;
-import org.junit.Assert;
+import org.junit.jupiter.api.Test;
-public class UTF8WriterTest
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+class UTF8WriterTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
- public void testSimple() throws Exception
+ @Test
+ void simple() throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
UTF8Writer w = new UTF8Writer(_ioContext(), out);
@@ -36,7 +39,8 @@ public void testSimple() throws Exception
assertEquals(str+str+str, act);
}
- public void testSimpleAscii() throws Exception
+ @Test
+ void simpleAscii() throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
UTF8Writer w = new UTF8Writer(_ioContext(), out);
@@ -55,7 +59,8 @@ public void testSimpleAscii() throws Exception
assertEquals(str, act);
}
- public void testFlushAfterClose() throws Exception
+ @Test
+ void flushAfterClose() throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
UTF8Writer w = new UTF8Writer(_ioContext(), out);
@@ -74,7 +79,8 @@ public void testFlushAfterClose() throws Exception
w.flush();
}
- public void testSurrogatesOk() throws Exception
+ @Test
+ void surrogatesOk() throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
UTF8Writer w = new UTF8Writer(_ioContext(), out);
@@ -86,7 +92,7 @@ public void testSurrogatesOk() throws Exception
assertEquals(4, out.size());
final byte[] EXP_SURROGATES = new byte[] { (byte) 0xF0, (byte) 0x9F,
(byte) 0x98, (byte) 0x83 };
- Assert.assertArrayEquals(EXP_SURROGATES, out.toByteArray());
+ assertArrayEquals(EXP_SURROGATES, out.toByteArray());
// and then as String
out = new ByteArrayOutputStream();
@@ -94,11 +100,12 @@ public void testSurrogatesOk() throws Exception
w.write("\uD83D\uDE03");
w.close();
assertEquals(4, out.size());
- Assert.assertArrayEquals(EXP_SURROGATES, out.toByteArray());
+ assertArrayEquals(EXP_SURROGATES, out.toByteArray());
}
@SuppressWarnings("resource")
- public void testSurrogatesFail() throws Exception
+ @Test
+ void surrogatesFail() throws Exception
{
ByteArrayOutputStream out;
@@ -136,6 +143,23 @@ public void testSurrogatesFail() throws Exception
}
}
+ // For [core#1218]
+ // @since 2.17
+ @Test
+ void surrogateConversion()
+ {
+ for (int first = UTF8Writer.SURR1_FIRST; first <= UTF8Writer.SURR1_LAST; first++) {
+ for (int second = UTF8Writer.SURR2_FIRST; second <= UTF8Writer.SURR2_LAST; second++) {
+ int expected = 0x10000 + ((first - UTF8Writer.SURR1_FIRST) << 10) + (second - UTF8Writer.SURR2_FIRST);
+ int actual = (first << 10) + second + UTF8Writer.SURROGATE_BASE;
+ if (expected != actual) {
+ fail("Mismatch on: "+Integer.toHexString(first) + " " + Integer.toHexString(second)
+ +"; expected: "+expected+", actual: "+actual);
+ }
+ }
+ }
+ }
+
private IOContext _ioContext() {
return testIOContext();
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToDecimalTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToDecimalTest.java
index 9752fd9909..94cff48ec7 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToDecimalTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToDecimalTest.java
@@ -8,11 +8,10 @@
import static java.lang.Double.longBitsToDouble;
import static java.lang.StrictMath.scalb;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-public class DoubleToDecimalTest {
+class DoubleToDecimalTest {
@Test
- void testExtremeValues() {
+ void extremeValues() {
toDec(Double.NEGATIVE_INFINITY);
toDec(-Double.MAX_VALUE);
toDec(-Double.MIN_NORMAL);
@@ -49,7 +48,7 @@ void testExtremeValues() {
The rendering is either too long or it is not the closest decimal.
*/
@Test
- void testPowersOf10() {
+ void powersOf10() {
for (int e = E_MIN; e <= E_MAX; ++e) {
toDec(Double.parseDouble("1e" + e));
}
@@ -60,21 +59,21 @@ void testPowersOf10() {
The rendering is either too long or it is not the closest decimal.
*/
@Test
- void testPowersOf2() {
+ void powersOf2() {
for (double v = Double.MIN_VALUE; v <= Double.MAX_VALUE; v *= 2) {
toDec(v);
}
}
@Test
- void testSomeAnomalies() {
+ void someAnomalies() {
for (String dec : Anomalies) {
toDec(Double.parseDouble(dec));
}
}
@Test
- void testPaxson() {
+ void paxson() {
for (int i = 0; i < PaxsonSignificands.length; ++i) {
toDec(scalb(PaxsonSignificands[i], PaxsonExponents[i]));
}
@@ -85,7 +84,7 @@ void testPaxson() {
These are all exact doubles.
*/
@Test
- void testLongs() {
+ void longs() {
for (int i = 10_000; i < 100_000; ++i) {
toDec(i * 1e15);
}
@@ -96,17 +95,17 @@ void testLongs() {
These are all exact doubles and exercise a fast path.
*/
@Test
- void testInts() {
+ void ints() {
for (int i = 0; i <= 1_000_000; ++i) {
toDec(i);
}
}
@Test
- void testConstants() {
+ void constants() {
assertEquals(DoubleToDecimal.P, P, "P");
- assertTrue((long) (double) C_MIN == C_MIN, "C_MIN");
- assertTrue((long) (double) C_MAX == C_MAX, "C_MAX");
+ assertEquals(C_MIN, (long) (double) C_MIN, "C_MIN");
+ assertEquals(C_MAX, (long) (double) C_MAX, "C_MAX");
assertEquals(Double.MIN_VALUE, MIN_VALUE, "MIN_VALUE");
assertEquals(Double.MIN_NORMAL, MIN_NORMAL, "MIN_NORMAL");
assertEquals(Double.MAX_VALUE, MAX_VALUE, "MAX_VALUE");
@@ -124,7 +123,7 @@ void testConstants() {
}
@Test
- void testHardValues() {
+ void hardValues() {
for (double v : hard0()) {
toDec(v);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToStringTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToStringTest.java
index ac920d971d..00693e74f7 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToStringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/DoubleToStringTest.java
@@ -1,8 +1,8 @@
package com.fasterxml.jackson.core.io.schubfach;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public abstract class DoubleToStringTest {
abstract String f(double f);
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalChecker.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalChecker.java
index 92107efcd2..3f3620a1af 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalChecker.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalChecker.java
@@ -45,8 +45,8 @@ public class FloatToDecimalChecker extends ToDecimalChecker {
static final int H = flog10pow2(P) + 2;
static final float MIN_VALUE = scalb(1.0f, Q_MIN);
- static final float MIN_NORMAL = scalb((float) C_MIN, Q_MIN);
- static final float MAX_VALUE = scalb((float) C_MAX, Q_MAX);
+ static final float MIN_NORMAL = scalb(C_MIN, Q_MIN);
+ static final float MAX_VALUE = scalb(C_MAX, Q_MAX);
static final int E_MIN = e(MIN_VALUE);
static final int E_MAX = e(MAX_VALUE);
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalTest.java
index f6893940dd..6c539faf49 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToDecimalTest.java
@@ -8,14 +8,13 @@
import static java.lang.Float.intBitsToFloat;
import static java.lang.StrictMath.scalb;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-public class FloatToDecimalTest {
+class FloatToDecimalTest {
/*
MIN_NORMAL is incorrectly rendered by the JDK.
*/
@Test
- void testExtremeValues() {
+ void extremeValues() {
toDec(Float.NEGATIVE_INFINITY);
toDec(-Float.MAX_VALUE);
toDec(-Float.MIN_NORMAL);
@@ -52,7 +51,7 @@ void testExtremeValues() {
The rendering is either too long or it is not the closest decimal.
*/
@Test
- void testPowersOf10() {
+ void powersOf10() {
for (int e = E_MIN; e <= E_MAX; ++e) {
toDec(Float.parseFloat("1e" + e));
}
@@ -63,17 +62,17 @@ void testPowersOf10() {
The rendering is either too long or it is not the closest decimal.
*/
@Test
- void testPowersOf2() {
+ void powersOf2() {
for (float v = Float.MIN_VALUE; v <= Float.MAX_VALUE; v *= 2) {
toDec(v);
}
}
@Test
- void testConstants() {
+ void constants() {
assertEquals(FloatToDecimal.P, P, "P");
- assertTrue((long) (float) C_MIN == C_MIN, "C_MIN");
- assertTrue((long) (float) C_MAX == C_MAX, "C_MAX");
+ assertEquals(C_MIN, (long) (float) C_MIN, "C_MIN");
+ assertEquals(C_MAX, (long) (float) C_MAX, "C_MAX");
assertEquals(Float.MIN_VALUE, MIN_VALUE, "MIN_VALUE");
assertEquals(Float.MIN_NORMAL, MIN_NORMAL, "MIN_NORMAL");
assertEquals(Float.MAX_VALUE, MAX_VALUE, "MAX_VALUE");
@@ -91,14 +90,14 @@ void testConstants() {
}
@Test
- void testSomeAnomalies() {
+ void someAnomalies() {
for (String dec : Anomalies) {
toDec(Float.parseFloat(dec));
}
}
@Test
- void testPaxson() {
+ void paxson() {
for (int i = 0; i < PaxsonSignificands.length; ++i) {
toDec(scalb(PaxsonSignificands[i], PaxsonExponents[i]));
}
@@ -109,7 +108,7 @@ void testPaxson() {
These are all exact floats and exercise the fast path.
*/
@Test
- void testInts() {
+ void ints() {
// 29-Nov-2022, tatu: Reduce from original due to slowness
// for (int i = 1; i < 1 << P - 1; ++i) {
for (int i = 1; i < 1 << P - 1; i += 3) {
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToStringTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToStringTest.java
index 6f70811320..03ab4cb538 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToStringTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/FloatToStringTest.java
@@ -1,8 +1,8 @@
package com.fasterxml.jackson.core.io.schubfach;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
public abstract class FloatToStringTest {
abstract String f(float f);
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/MathUtilsTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/MathUtilsTest.java
index 95de7c8fc7..1477ca0d6b 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/MathUtilsTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/MathUtilsTest.java
@@ -35,7 +35,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
-public class MathUtilsTest {
+class MathUtilsTest {
private static final BigInteger THREE = valueOf(3);
@@ -146,7 +146,7 @@ private static void testG(int k, long g1, long g0) {
Verifies the soundness of the values returned by g1() and g0().
*/
@Test
- void testG() {
+ void g() {
for (int k = MathUtils.K_MIN; k <= MathUtils.K_MAX; ++k) {
testG(k, g1(k), g0(k));
}
@@ -443,16 +443,16 @@ void testFlog2pow10() {
}
@Test
- void testBinaryConstants() {
- assertTrue((long) (double) C_MIN == C_MIN, "C_MIN");
- assertTrue((long) (double) C_MAX == C_MAX, "C_MAX");
+ void binaryConstants() {
+ assertEquals(C_MIN, (long) (double) C_MIN, "C_MIN");
+ assertEquals(C_MAX, (long) (double) C_MAX, "C_MAX");
assertEquals(MIN_VALUE, scalb(1.0, Q_MIN), "MIN_VALUE");
assertEquals(MIN_NORMAL, scalb((double) C_MIN, Q_MIN), "MIN_NORMAL");
assertEquals(MAX_VALUE, scalb((double) C_MAX, Q_MAX), "MAX_VALUE");
}
@Test
- void testDecimalConstants() {
+ void decimalConstants() {
assertEquals(MathUtils.K_MIN, K_MIN, "K_MIN");
assertEquals(MathUtils.K_MAX, K_MAX, "K_MAX");
assertEquals(MathUtils.H, H, "H");
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachDoubleTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachDoubleTest.java
index 13258cac1a..7079a63fc2 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachDoubleTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachDoubleTest.java
@@ -1,9 +1,5 @@
package com.fasterxml.jackson.core.io.schubfach;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
public class SchubfachDoubleTest extends DoubleToStringTest {
@Override
String f(double f) {
diff --git a/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachFloatTest.java b/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachFloatTest.java
index 6f1a0c04ca..b0c6d55c62 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachFloatTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/schubfach/SchubfachFloatTest.java
@@ -1,9 +1,5 @@
package com.fasterxml.jackson.core.io.schubfach;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
public class SchubfachFloatTest extends FloatToStringTest {
@Override
String f(float f) {
diff --git a/src/test/java/com/fasterxml/jackson/core/json/BoundsChecksWithJsonFactoryTest.java b/src/test/java/com/fasterxml/jackson/core/json/BoundsChecksWithJsonFactoryTest.java
index 2731a6cab8..a834d45172 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/BoundsChecksWithJsonFactoryTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/BoundsChecksWithJsonFactoryTest.java
@@ -1,10 +1,14 @@
package com.fasterxml.jackson.core.json;
-import com.fasterxml.jackson.core.BaseTest;
+import com.fasterxml.jackson.core.JUnit5TestBase;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.TokenStreamFactory;
-public class BoundsChecksWithJsonFactoryTest
- extends BaseTest
+import static org.junit.jupiter.api.Assertions.fail;
+
+class BoundsChecksWithJsonFactoryTest
+ extends JUnit5TestBase
{
interface ByteBackedCreation {
void call(byte[] data, int offset, int len) throws Exception;
@@ -20,7 +24,8 @@ interface CharBackedCreation {
/**********************************************************************
*/
- public void testBoundsWithByteArrayInput() throws Exception {
+ @Test
+ void boundsWithByteArrayInput() throws Exception {
final TokenStreamFactory PARSER_F = newStreamFactory();
_testBoundsWithByteArrayInput(
@@ -64,28 +69,31 @@ private void _testBoundsWithByteArrayInput(ByteBackedCreation creator,
/**********************************************************************
*/
- public void testBoundsWithCharArrayInput() throws Exception {
+ @Test
+ void boundsWithCharArrayInput() throws Exception {
final TokenStreamFactory PARSER_F = newStreamFactory();
- testBoundsWithCharArrayInput(
+ boundsWithCharArrayInput(
(data,offset,len)->PARSER_F.createParser(data, offset, len));
}
- private void testBoundsWithCharArrayInput(CharBackedCreation creator) throws Exception
+ @Test
+ private void boundsWithCharArrayInput(CharBackedCreation creator) throws Exception
{
final char[] DATA = new char[10];
- testBoundsWithCharArrayInput(creator, DATA, -1, 1);
- testBoundsWithCharArrayInput(creator, DATA, 4, -1);
- testBoundsWithCharArrayInput(creator, DATA, 4, -6);
- testBoundsWithCharArrayInput(creator, DATA, 9, 5);
+ boundsWithCharArrayInput(creator, DATA, -1, 1);
+ boundsWithCharArrayInput(creator, DATA, 4, -1);
+ boundsWithCharArrayInput(creator, DATA, 4, -6);
+ boundsWithCharArrayInput(creator, DATA, 9, 5);
// and the integer overflow, too
- testBoundsWithCharArrayInput(creator, DATA, Integer.MAX_VALUE, 4);
- testBoundsWithCharArrayInput(creator, DATA, Integer.MAX_VALUE, Integer.MAX_VALUE);
+ boundsWithCharArrayInput(creator, DATA, Integer.MAX_VALUE, 4);
+ boundsWithCharArrayInput(creator, DATA, Integer.MAX_VALUE, Integer.MAX_VALUE);
// and null checks too
- testBoundsWithCharArrayInput(creator, null, 0, 3);
+ boundsWithCharArrayInput(creator, null, 0, 3);
}
- private void testBoundsWithCharArrayInput(CharBackedCreation creator,
+ @Test
+ private void boundsWithCharArrayInput(CharBackedCreation creator,
char[] data, int offset, int len) throws Exception
{
try {
diff --git a/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java b/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java
index 5228e0f89e..9cd8b2ce5b 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java
@@ -4,16 +4,22 @@
import com.fasterxml.jackson.core.*;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
// For [core#549], ability to use alternate quote characters
-public class CustomQuoteCharTest
- extends com.fasterxml.jackson.core.BaseTest
+class CustomQuoteCharTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
final JsonFactory JSON_F = streamFactoryBuilder()
.quoteChar('\'')
.build();
// Only ASCII range supported as of 2.10
- public void testInvalidQuote() throws Exception
+ @Test
+ void invalidQuote() throws Exception
{
try {
streamFactoryBuilder()
@@ -24,7 +30,8 @@ public void testInvalidQuote() throws Exception
}
}
- public void testBasicAposWithCharBased() throws Exception
+ @Test
+ void basicAposWithCharBased() throws Exception
{
StringWriter w;
JsonGenerator g;
@@ -44,7 +51,8 @@ public void testBasicAposWithCharBased() throws Exception
assertEquals("['hello world']", w.toString());
}
- public void testBasicAposWithByteBased() throws Exception
+ @Test
+ void basicAposWithByteBased() throws Exception
{
ByteArrayOutputStream out;
JsonGenerator g;
@@ -64,7 +72,8 @@ public void testBasicAposWithByteBased() throws Exception
assertEquals("['hello world']", out.toString("UTF-8"));
}
- public void testAposQuotingWithCharBased() throws Exception
+ @Test
+ void aposQuotingWithCharBased() throws Exception
{
StringWriter w;
JsonGenerator g;
@@ -85,7 +94,8 @@ public void testAposQuotingWithCharBased() throws Exception
assertEquals("['It\\u0027s a sin']", w.toString());
}
- public void testAposQuotingWithByteBased() throws Exception
+ @Test
+ void aposQuotingWithByteBased() throws Exception
{
ByteArrayOutputStream out;
JsonGenerator g;
diff --git a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailFromReaderTest.java b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailFromReaderTest.java
index d13df0c836..dae9063103 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailFromReaderTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailFromReaderTest.java
@@ -6,32 +6,40 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import java.io.ByteArrayOutputStream;
+
+import static org.junit.jupiter.api.Assertions.fail;
import java.io.OutputStreamWriter;
import java.io.StringReader;
-public class GeneratorFailFromReaderTest
- extends com.fasterxml.jackson.core.BaseTest
+import org.junit.jupiter.api.Test;
+
+class GeneratorFailFromReaderTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory F = new JsonFactory();
// [core#177]
// Also: should not try writing JSON String if field name expected
// (in future maybe take one as alias... but not yet)
- public void testFailOnWritingStringNotFieldNameBytes() throws Exception {
+ @Test
+ void failOnWritingStringNotFieldNameBytes() throws Exception {
_testFailOnWritingStringNotFieldName(F, false);
}
// [core#177]
- public void testFailOnWritingStringNotFieldNameChars() throws Exception {
+ @Test
+ void failOnWritingStringNotFieldNameChars() throws Exception {
_testFailOnWritingStringNotFieldName(F, true);
}
- public void testFailOnWritingStringFromReaderWithTooFewCharacters() throws Exception {
+ @Test
+ void failOnWritingStringFromReaderWithTooFewCharacters() throws Exception {
_testFailOnWritingStringFromReaderWithTooFewCharacters(F, true);
_testFailOnWritingStringFromReaderWithTooFewCharacters(F, false);
}
- public void testFailOnWritingStringFromNullReader() throws Exception {
+ @Test
+ void failOnWritingStringFromNullReader() throws Exception {
_testFailOnWritingStringFromNullReader(F, true);
_testFailOnWritingStringFromNullReader(F, false);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java
index 59664c8881..c3f895b870 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFailTest.java
@@ -4,17 +4,22 @@
import java.io.OutputStreamWriter;
import com.fasterxml.jackson.core.JsonEncoding;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
-public class GeneratorFailTest
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.fail;
+
+class GeneratorFailTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory F = new JsonFactory();
// [core#167]: no error for writing field name twice
- public void testDupFieldNameWrites() throws Exception
+ @Test
+ void dupFieldNameWrites() throws Exception
{
_testDupFieldNameWrites(F, false);
_testDupFieldNameWrites(F, true);
@@ -23,17 +28,20 @@ public void testDupFieldNameWrites() throws Exception
// [core#177]
// Also: should not try writing JSON String if field name expected
// (in future maybe take one as alias... but not yet)
- public void testFailOnWritingStringNotFieldNameBytes() throws Exception {
+ @Test
+ void failOnWritingStringNotFieldNameBytes() throws Exception {
_testFailOnWritingStringNotFieldName(F, false);
}
// [core#177]
- public void testFailOnWritingStringNotFieldNameChars() throws Exception {
+ @Test
+ void failOnWritingStringNotFieldNameChars() throws Exception {
_testFailOnWritingStringNotFieldName(F, true);
}
// for [core#282]
- public void testFailOnWritingFieldNameInRoot() throws Exception {
+ @Test
+ void failOnWritingFieldNameInRoot() throws Exception {
_testFailOnWritingFieldNameInRoot(F, false);
_testFailOnWritingFieldNameInRoot(F, true);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java
index cc5927b9f4..2a54323073 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/GeneratorFeaturesTest.java
@@ -6,17 +6,22 @@
import com.fasterxml.jackson.core.*;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
/**
* Set of basic unit tests for verifying that the basic generator
* functionality works as expected.
*/
-public class GeneratorFeaturesTest
- extends com.fasterxml.jackson.core.BaseTest
+class GeneratorFeaturesTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
private final JsonFactory JSON_F = new JsonFactory();
@SuppressWarnings("deprecation")
- public void testConfigDefaults() throws IOException
+ @Test
+ void configDefaults() throws IOException
{
JsonGenerator g = JSON_F.createGenerator(new StringWriter());
assertFalse(g.isEnabled(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS));
@@ -34,7 +39,8 @@ public void testConfigDefaults() throws IOException
}
@SuppressWarnings("deprecation")
- public void testConfigOverrides() throws IOException
+ @Test
+ void configOverrides() throws IOException
{
// but also allow overide
JsonGenerator g = JSON_F.createGenerator(new StringWriter());
@@ -53,7 +59,8 @@ public void testConfigOverrides() throws IOException
g.close();
}
- public void testFieldNameQuoting() throws IOException
+ @Test
+ void fieldNameQuoting() throws IOException
{
JsonFactory f = new JsonFactory();
// by default, quoting should be enabled
@@ -70,7 +77,8 @@ public void testFieldNameQuoting() throws IOException
_testFieldNameQuoting(f, true);
}
- public void testNonNumericQuoting() throws IOException
+ @Test
+ void nonNumericQuoting() throws IOException
{
JsonFactory f = new JsonFactory();
// by default, quoting should be enabled
@@ -91,7 +99,8 @@ public void testNonNumericQuoting() throws IOException
* Testing for [JACKSON-176], ability to force serializing numbers
* as JSON Strings.
*/
- public void testNumbersAsJSONStrings() throws IOException
+ @Test
+ void numbersAsJSONStrings() throws IOException
{
JsonFactory f = new JsonFactory();
// by default should output numbers as-is:
@@ -110,7 +119,8 @@ public void testNumbersAsJSONStrings() throws IOException
}
- public void testBigDecimalAsPlain() throws IOException
+ @Test
+ void bigDecimalAsPlain() throws IOException
{
JsonFactory f = new JsonFactory();
BigDecimal ENG = new BigDecimal("1E+2");
@@ -129,7 +139,8 @@ public void testBigDecimalAsPlain() throws IOException
assertEquals("100", sw.toString());
}
- public void testBigDecimalAsPlainString() throws Exception
+ @Test
+ void bigDecimalAsPlainString() throws Exception
{
BigDecimal ENG = new BigDecimal("1E+2");
JsonFactory f = JsonFactory.builder()
@@ -153,7 +164,8 @@ public void testBigDecimalAsPlainString() throws Exception
// [core#315]
@SuppressWarnings("deprecation")
- public void testTooBigBigDecimal() throws Exception
+ @Test
+ void tooBigBigDecimal() throws Exception
{
JsonFactory f = new JsonFactory();
f.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
@@ -238,7 +250,8 @@ private String _writeNumbers(JsonFactory f, boolean useBytes) throws IOException
}
// for [core#246]
- public void testFieldNameQuotingEnabled() throws IOException
+ @Test
+ void fieldNameQuotingEnabled() throws IOException
{
// // First, test with default factory, with quoting enabled by default
@@ -288,7 +301,8 @@ private void _testFieldNameQuotingEnabled(JsonFactory f, boolean useBytes,
}
@SuppressWarnings("deprecation")
- public void testChangeOnGenerator() throws IOException
+ @Test
+ void changeOnGenerator() throws IOException
{
StringWriter w = new StringWriter();
@@ -296,7 +310,7 @@ public void testChangeOnGenerator() throws IOException
g.enable(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
g.writeNumber(123);
g.close();
- assertEquals(quote("123"), w.toString());
+ assertEquals(q("123"), w.toString());
// but also the opposite
w = new StringWriter();
@@ -356,7 +370,8 @@ private void _testNonNumericQuoting(JsonFactory f, boolean quoted)
}
// [core#717]: configurable hex digits; lower-case
- public void testHexLowercase() throws Exception {
+ @Test
+ void hexLowercase() throws Exception {
JsonFactory f = JsonFactory.builder()
.disable(JsonWriteFeature.WRITE_HEX_UPPER_CASE)
.build();
@@ -365,7 +380,8 @@ public void testHexLowercase() throws Exception {
}
// [core#717]: configurable hex digits; upper-case (default)
- public void testHexUppercase() throws Exception
+ @Test
+ void hexUppercase() throws Exception
{
JsonFactory f = JsonFactory.builder()
.enable(JsonWriteFeature.WRITE_HEX_UPPER_CASE)
diff --git a/src/test/java/com/fasterxml/jackson/core/json/InputStreamInitTest.java b/src/test/java/com/fasterxml/jackson/core/json/InputStreamInitTest.java
index ede1a98d35..7249000482 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/InputStreamInitTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/InputStreamInitTest.java
@@ -7,9 +7,13 @@
import com.fasterxml.jackson.core.*;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
// [core#763] (and [databind#3455]
-public class InputStreamInitTest
- extends com.fasterxml.jackson.core.BaseTest
+class InputStreamInitTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
static class FailingInputStream extends InputStream {
public boolean closed = false;
@@ -41,7 +45,8 @@ protected InputStream _optimizedStreamFromURL(URL url) {
}
}
- public void testForFile() throws Exception
+ @Test
+ void forFile() throws Exception
{
final FailingJsonFactory jsonF = new FailingJsonFactory();
try {
@@ -54,7 +59,8 @@ public void testForFile() throws Exception
assertTrue(jsonF.lastStream.closed);
}
- public void testForURL() throws Exception
+ @Test
+ void forURL() throws Exception
{
final FailingJsonFactory jsonF = new FailingJsonFactory();
try {
diff --git a/src/test/java/com/fasterxml/jackson/core/json/JsonFactoryTest.java b/src/test/java/com/fasterxml/jackson/core/json/JsonFactoryTest.java
index e08126f652..65d2cb0b26 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/JsonFactoryTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/JsonFactoryTest.java
@@ -5,12 +5,16 @@
import java.util.Iterator;
import com.fasterxml.jackson.core.*;
+
+import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.core.json.async.NonBlockingJsonParser;
import com.fasterxml.jackson.core.type.ResolvedType;
import com.fasterxml.jackson.core.type.TypeReference;
-public class JsonFactoryTest
- extends com.fasterxml.jackson.core.BaseTest
+import static org.junit.jupiter.api.Assertions.*;
+
+class JsonFactoryTest
+ extends com.fasterxml.jackson.core.JUnit5TestBase
{
static class BogusCodec extends ObjectCodec {
@Override
@@ -115,7 +119,8 @@ public String getSchemaType() {
final JsonFactory JSON_F = sharedStreamFactory();
@SuppressWarnings("deprecation")
- public void testGeneratorFeatures() throws Exception
+ @Test
+ void generatorFeatures() throws Exception
{
assertNull(JSON_F.getCodec());
@@ -130,7 +135,8 @@ public void testGeneratorFeatures() throws Exception
assertFalse(f.isEnabled(JsonGenerator.Feature.QUOTE_FIELD_NAMES));
}
- public void testFactoryFeatures() throws Exception
+ @Test
+ void factoryFeatures() throws Exception
{
JsonFactory f = JsonFactory.builder()
.configure(JsonFactory.Feature.INTERN_FIELD_NAMES, false)
@@ -144,7 +150,8 @@ public void testFactoryFeatures() throws Exception
assertFalse(JSON_F.canHandleBinaryNatively());
}
- public void testFactoryMisc() throws Exception
+ @Test
+ void factoryMisc() throws Exception
{
assertNull(JSON_F.getInputDecorator());
assertNull(JSON_F.getOutputDecorator());
@@ -163,7 +170,8 @@ public void testFactoryMisc() throws Exception
// Basically simply exercises basic functionality, to ensure
// there are no obvious problems; needed since testing never
// disables this handling otherwise
- public void testDisablingBufferRecycling() throws Exception
+ @Test
+ void disablingBufferRecycling() throws Exception
{
JsonFactory f = JsonFactory.builder()
.disable(JsonFactory.Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING)
@@ -205,7 +213,8 @@ public void testDisablingBufferRecycling() throws Exception
}
}
- public void testJsonWithFiles() throws Exception
+ @Test
+ void jsonWithFiles() throws Exception
{
File file = File.createTempFile("jackson-test", null);
file.deleteOnExit();
@@ -239,7 +248,8 @@ public void testJsonWithFiles() throws Exception
// #72
@SuppressWarnings("deprecation")
- public void testCopy() throws Exception
+ @Test
+ void copy() throws Exception
{
JsonFactory jf = new JsonFactory();
// first, verify defaults
@@ -274,7 +284,8 @@ public void testCopy() throws Exception
assertSame(codec, jf3.getCodec());
}
- public void testRootValues() throws Exception
+ @Test
+ void rootValues() throws Exception
{
JsonFactory f = new JsonFactory();
assertEquals(" ", f.getRootValueSeparator());
@@ -291,11 +302,13 @@ public void testRootValues() throws Exception
assertEquals("1/2/3", w.toString());
}
- public void testCanonicalizationEnabled() throws Exception {
+ @Test
+ void canonicalizationEnabled() throws Exception {
doCanonicalizationTest(false);
}
- public void testCanonicalizationDisabled() throws Exception {
+ @Test
+ void canonicalizationDisabled() throws Exception {
doCanonicalizationTest(false);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/json/JsonParserClosedCaseTest.java b/src/test/java/com/fasterxml/jackson/core/json/JsonParserClosedCaseTest.java
index 06483ba4be..cee87c07d4 100644
--- a/src/test/java/com/fasterxml/jackson/core/json/JsonParserClosedCaseTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/json/JsonParserClosedCaseTest.java
@@ -10,21 +10,20 @@
import com.fasterxml.jackson.core.io.SerializedString;
import com.fasterxml.jackson.core.testsupport.MockDataInput;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
/**
* Tests asserts that using closed `JsonParser` doesn't cause ArrayIndexOutOfBoundsException
* with `nextXxx()` methods but returns `null` as expected.
*/
-@RunWith(Parameterized.class)
public class JsonParserClosedCaseTest {
private static final JsonFactory JSON_F = new JsonFactory();
- private JsonParser parser;
+ JsonParser parser;
/**
* Creates a list of parsers to tests.
@@ -32,7 +31,6 @@ public class JsonParserClosedCaseTest {
* @return List of Object[2]. Object[0] is is the name of the class, Object[1] is instance itself.
* @throws IOException when closing stream fails.
*/
- @Parameters(name = "{0}")
public static Collection