Skip to content

Commit

Permalink
Add JsonParser feature to ignore a trailing comma (fixes FasterXML#118,
Browse files Browse the repository at this point in the history
  • Loading branch information
bdhess committed Oct 28, 2016
1 parent 5e59e9c commit d7a6f6c
Show file tree
Hide file tree
Showing 5 changed files with 455 additions and 92 deletions.
25 changes: 24 additions & 1 deletion src/main/java/com/fasterxml/jackson/core/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,30 @@ public enum Feature {
*
* @since 2.8
*/
ALLOW_MISSING_VALUES(false)
ALLOW_MISSING_VALUES(false),

/**
* Feature that determines whether {@link JsonParser} will allow for a single trailing
* comma following the final value (in an Array) or member (in an Object). These commas
* will simply be ignored.
* <p>
* For example, when this feature is enabled, <code>[true,true,]</code> is equivalent to
* <code>[true, true]</code> and <code>{"a": true,}</code> is equivalent to
* <code>{"a": true}</code>.
* <p>
* When combined with <code>ALLOW_MISSING_VALUES</code>, this feature takes priority, and
* the final trailing comma in an array declaration does not imply a missing
* (<code>null</code>) value. For example, when both <code>ALLOW_MISSING_VALUES</code>
* and <code>ALLOW_TRAILING_COMMA</code> are enabled, <code>[true,true,]</code> is
* equivalent to <code>[true, true]</code>, and <code>[true,true,,]</code> is equivalent to
* <code>[true, true, null]</code>.
* <p>
* Since the JSON specification does not permit trailing commas, this is a non-standard
* feature, and as such disabled by default.
*
* @since 2.9
*/
ALLOW_TRAILING_COMMA(false)
;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,26 +652,20 @@ public final JsonToken nextToken() throws IOException
_binaryValue = null;

// Closing scope?
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_OBJECT);
if (i == INT_RBRACKET || i == INT_RCURLY) {
_closeScope(i);
return _currToken;
}

// Nope: do we then expect a comma?
if (_parsingContext.expectComma()) {
i = _skipComma(i);

// Was that a trailing comma?
if (isEnabled(Feature.ALLOW_TRAILING_COMMA) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return _currToken;
}
}

/* And should we now have a name? Always true for Object contexts, since
Expand Down Expand Up @@ -811,26 +805,20 @@ public boolean nextFieldName(SerializableString sstr) throws IOException
}
_binaryValue = null;

if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
return false;
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
// Closing scope?
if (i == INT_RBRACKET || i == INT_RCURLY) {
_closeScope(i);
return false;
}

if (_parsingContext.expectComma()) {
i = _skipComma(i);

// Was that a trailing comma?
if (isEnabled(Feature.ALLOW_TRAILING_COMMA) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return false;
}
}

if (!_parsingContext.inObject()) {
Expand Down Expand Up @@ -2834,4 +2822,29 @@ protected void _reportInvalidToken(String matchedPart, String msg) throws IOExce
}
_reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
}

/*
/**********************************************************
/* Internal methods, other
/**********************************************************
*/

private void _closeScope(int i) throws JsonParseException {
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -575,19 +575,9 @@ public JsonToken nextToken() throws IOException
_tokenInputRow = _currInputRow;

// Closing scope?
if (i == INT_RBRACKET) {
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_OBJECT);
if (i == INT_RBRACKET || i == INT_RCURLY) {
_closeScope(i);
return _currToken;
}

// Nope: do we then expect a comma?
Expand All @@ -596,6 +586,12 @@ public JsonToken nextToken() throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
}
i = _skipWS();

// Was that a trailing comma?
if (isEnabled(Feature.ALLOW_TRAILING_COMMA) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return _currToken;
}
}

/* And should we now have a name? Always true for
Expand Down Expand Up @@ -2788,6 +2784,23 @@ public JsonLocation getCurrentLocation() {
/**********************************************************
*/

private void _closeScope(int i) throws JsonParseException {
if (i == INT_RBRACKET) {
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
}
if (i == INT_RCURLY) {
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
}
}

/**
* Helper method needed to fix [Issue#148], masking of 0x00 character
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -738,21 +738,9 @@ public JsonToken nextToken() throws IOException
_binaryValue = null;

// Closing scope?
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_ARRAY);
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
return (_currToken = JsonToken.END_OBJECT);
if (i == INT_RBRACKET || i == INT_RCURLY) {
_closeScope(i);
return _currToken;
}

// Nope: do we then expect a comma?
Expand All @@ -761,6 +749,12 @@ public JsonToken nextToken() throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
}
i = _skipWS();

// Was that a trailing comma?
if (isEnabled(Feature.ALLOW_TRAILING_COMMA) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return _currToken;
}
}

/* And should we now have a name? Always true for
Expand Down Expand Up @@ -930,22 +924,8 @@ public boolean nextFieldName(SerializableString str) throws IOException
_binaryValue = null;

// Closing scope?
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
return false;
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
if (i == INT_RBRACKET || i == INT_RCURLY) {
_closeScope(i);
return false;
}

Expand All @@ -955,6 +935,12 @@ public boolean nextFieldName(SerializableString str) throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
}
i = _skipWS();

// Was that a trailing comma?
if (isEnabled(Feature.ALLOW_TRAILING_COMMA) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return false;
}
}

if (!_parsingContext.inObject()) {
Expand Down Expand Up @@ -1017,22 +1003,8 @@ public String nextFieldName() throws IOException
}
_binaryValue = null;

if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
return null;
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
if (i == INT_RBRACKET || i == INT_RCURLY) {
_closeScope(i);
return null;
}

Expand All @@ -1042,7 +1014,14 @@ public String nextFieldName() throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.typeDesc()+" entries");
}
i = _skipWS();

// Was that a trailing comma?
if (isEnabled(Feature.ALLOW_TRAILING_COMMA) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return null;
}
}

if (!_parsingContext.inObject()) {
_updateLocation();
_nextTokenNotInObject(i);
Expand Down Expand Up @@ -3733,6 +3712,25 @@ private final void _updateNameLocation()
/**********************************************************
*/

private void _closeScope(int i) throws JsonParseException {
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
}
if (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
}
}

/**
* Helper method needed to fix [Issue#148], masking of 0x00 character
*/
Expand Down
Loading

0 comments on commit d7a6f6c

Please sign in to comment.