Skip to content

Commit

Permalink
Add JsonParser feature to ignore trailing commas (fixes #118)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdhess committed Mar 31, 2016
1 parent a562a86 commit 46d5e6d
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 79 deletions.
18 changes: 17 additions & 1 deletion src/main/java/com/fasterxml/jackson/core/JsonParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,23 @@ 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, under this regime <code>[true,true,]</code> is equivalent to
* <code>[true, true]</code> and <code>{"a": true,}</code> is equivalent to
* <code>{"a": true}</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.8
*/
ALLOW_TRAILING_COMMAS(false)
;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,26 +609,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_COMMAS) && (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 @@ -768,26 +762,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_COMMAS) && (i == INT_RBRACKET || i == INT_RCURLY)) {
_closeScope(i);
return false;
}
}

if (!_parsingContext.inObject()) {
Expand Down Expand Up @@ -2786,4 +2774,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 @@ -712,21 +712,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 @@ -735,6 +723,12 @@ public JsonToken nextToken() throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
}
i = _skipWS();

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

/* And should we now have a name? Always true for
Expand Down Expand Up @@ -904,22 +898,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 @@ -929,6 +909,12 @@ public boolean nextFieldName(SerializableString str) throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
}
i = _skipWS();

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

if (!_parsingContext.inObject()) {
Expand Down Expand Up @@ -991,22 +977,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 @@ -1016,7 +988,14 @@ public String nextFieldName() throws IOException
_reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
}
i = _skipWS();

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

if (!_parsingContext.inObject()) {
_updateLocation();
_nextTokenNotInObject(i);
Expand Down Expand Up @@ -3703,6 +3682,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 46d5e6d

Please sign in to comment.