Skip to content

Commit 8a009d1

Browse files
committed
Merge pull request #267 from LokeshN/Issue117-branch
Fix for issue #117 - Supports the missing values in an array
2 parents 4709c6a + 531b450 commit 8a009d1

File tree

4 files changed

+155
-2
lines changed

4 files changed

+155
-2
lines changed

src/main/java/com/fasterxml/jackson/core/JsonParser.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,20 @@ public enum Feature {
208208
*
209209
* @since 2.6
210210
*/
211-
IGNORE_UNDEFINED(false)
211+
IGNORE_UNDEFINED(false),
212+
213+
214+
/**
215+
* Feature allows the support for missing values in a JSON array. Enabling this feature
216+
* will replace any missing value by null in the JSON array.
217+
* <p>
218+
* For example, enabling this feature will represent a JSON array <code>["value1",,"value3",]</code>
219+
* as <code>["value1", null, "value3", null]</code>
220+
* <p>
221+
* Since the JSON specification does not allow missing values, this is a non-compliant JSON
222+
* feature, and is disabled by default
223+
*/
224+
ALLOW_MISSING_VALUES(false)
212225
;
213226

214227
/**

src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.*;
44

55
import com.fasterxml.jackson.core.*;
6+
import com.fasterxml.jackson.core.JsonParser.Feature;
67
import com.fasterxml.jackson.core.base.ParserBase;
78
import com.fasterxml.jackson.core.io.CharTypes;
89
import com.fasterxml.jackson.core.io.IOContext;
@@ -666,9 +667,22 @@ public final JsonToken nextToken() throws IOException
666667
}
667668
t = JsonToken.START_OBJECT;
668669
break;
670+
/*
671+
* This check proceeds only if the Feature.ALLOW_MISSING_VALUES is enabled
672+
* The Check is for missing values. Incase of missing values in an array, the next token will be either ',' or ']'.
673+
* This case, decrements the already incremented _inputPtr in the buffer in case of comma(,)
674+
* so that the existing flow goes back to checking the next token which will be comma again and
675+
* it continues the parsing.
676+
* Also the case returns NULL as current token in case of ',' or ']'.
677+
*/
678+
case ',':
669679
case ']':
680+
if(isEnabled(Feature.ALLOW_MISSING_VALUES)) {
681+
_inputPtr--;
682+
return (_currToken = JsonToken.VALUE_NULL);
683+
}
670684
case '}':
671-
// Error: neither is valid at this point; valid closers have
685+
// Error: } is not valid at this point; valid closers have
672686
// been handled earlier
673687
_reportUnexpectedChar(i, "expected a value");
674688
case 't':
@@ -1077,6 +1091,20 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
10771091
case '8':
10781092
case '9':
10791093
return (_currToken = _parsePosNumber(i));
1094+
/*
1095+
* This check proceeds only if the Feature.ALLOW_MISSING_VALUES is enabled
1096+
* The Check is for missing values. Incase of missing values in an array, the next token will be either ',' or ']'.
1097+
* This case, decrements the already incremented _inputPtr in the buffer in case of comma(,)
1098+
* so that the existing flow goes back to checking the next token which will be comma again and
1099+
* it continues the parsing.
1100+
* Also the case returns NULL as current token in case of ',' or ']'.
1101+
*/
1102+
case ',':
1103+
case ']':
1104+
if(isEnabled(Feature.ALLOW_MISSING_VALUES)) {
1105+
_inputPtr--;
1106+
return (_currToken = JsonToken.VALUE_NULL);
1107+
}
10801108
}
10811109
return (_currToken = _handleOddValue(i));
10821110
}

src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,20 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException
848848
case '8':
849849
case '9':
850850
return (_currToken = _parsePosNumber(i));
851+
/*
852+
* This check proceeds only if the Feature.ALLOW_MISSING_VALUES is enabled
853+
* The Check is for missing values. Incase of missing values in an array, the next token will be either ',' or ']'.
854+
* This case, decrements the already incremented _inputPtr in the buffer in case of comma(,)
855+
* so that the existing flow goes back to checking the next token which will be comma again and
856+
* it continues the parsing.
857+
* Also the case returns NULL as current token in case of ',' or ']'.
858+
*/
859+
case ',':
860+
case ']':
861+
if(isEnabled(Feature.ALLOW_MISSING_VALUES)) {
862+
_inputPtr--;
863+
return (_currToken = JsonToken.VALUE_NULL);
864+
}
851865
}
852866
return (_currToken = _handleUnexpectedValue(i));
853867
}

src/test/java/com/fasterxml/jackson/core/main/TestArrayParsing.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,102 @@ public void testInvalidExtraComma() throws Exception
6969
}
7070
jp.close();
7171
}
72+
73+
/**
74+
* Tests the missing value as 'null' in an array
75+
* This needs enabling of the Feature.ALLOW_MISSING_VALUES in JsonParser
76+
* This tests both Stream based parsing and the Reader based parsing
77+
* @throws Exception
78+
*/
79+
public void testMissingValueAsNullByEnablingFeature() throws Exception
80+
{
81+
_testMissingValueByEnablingFeature(true);
82+
_testMissingValueByEnablingFeature(false);
83+
}
84+
85+
/**
86+
* Tests the missing value in an array by not enabling
87+
* the Feature.ALLOW_MISSING_VALUES
88+
* @throws Exception
89+
*/
90+
public void testMissingValueAsNullByNotEnablingFeature() throws Exception
91+
{
92+
_testMissingValueNotEnablingFeature(true);
93+
_testMissingValueNotEnablingFeature(false);
94+
}
95+
96+
/**
97+
* Tests the not missing any value in an array by enabling the
98+
* Feature.ALLOW_MISSING_VALUES in JsonParser
99+
* This tests both Stream based parsing and the Reader based parsing for not missing any value
100+
* @throws Exception
101+
*/
102+
public void testNotMissingValueByEnablingFeature() throws Exception
103+
{
104+
_testNotMissingValueByEnablingFeature(true);
105+
_testNotMissingValueByEnablingFeature(false);
106+
}
107+
108+
private void _testMissingValueByEnablingFeature(boolean useStream) throws Exception {
109+
final String DOC = "[ \"a\",,,,\"abc\", ] ";
110+
111+
JsonFactory f = new JsonFactory();
112+
f.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
113+
114+
JsonParser jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
115+
: createParserUsingReader(f, DOC);
116+
117+
assertToken(JsonToken.START_ARRAY, jp.nextToken());
118+
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
119+
assertEquals("a", jp.getValueAsString());
120+
121+
assertToken(JsonToken.VALUE_NULL, jp.nextToken());
122+
assertToken(JsonToken.VALUE_NULL, jp.nextToken());
123+
assertToken(JsonToken.VALUE_NULL, jp.nextToken());
124+
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
125+
assertToken(JsonToken.VALUE_NULL, jp.nextToken());
126+
assertToken(JsonToken.END_ARRAY, jp.nextToken());
127+
128+
jp.close();
129+
}
130+
131+
private void _testMissingValueNotEnablingFeature(boolean useStream) throws Exception {
132+
final String DOC = "[ \"a\",,\"abc\"] ";
133+
134+
JsonFactory f = new JsonFactory();
135+
136+
JsonParser jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
137+
: createParserUsingReader(f, DOC);
138+
139+
assertToken(JsonToken.START_ARRAY, jp.nextToken());
140+
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
141+
assertEquals("a", jp.getValueAsString());
142+
try {
143+
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
144+
fail("Expecting exception here");
145+
}
146+
catch(JsonParseException ex){
147+
verifyException(ex, "expected a valid value", "expected a value");
148+
}
149+
jp.close();
150+
}
151+
152+
private void _testNotMissingValueByEnablingFeature(boolean useStream) throws Exception {
153+
final String DOC = "[ \"a\",\"abc\"] ";
154+
155+
JsonFactory f = new JsonFactory();
156+
f.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
157+
158+
JsonParser jp = useStream ? createParserUsingStream(f, DOC, "UTF-8")
159+
: createParserUsingReader(f, DOC);
160+
161+
assertToken(JsonToken.START_ARRAY, jp.nextToken());
162+
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
163+
assertEquals("a", jp.getValueAsString());
164+
165+
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
166+
assertToken(JsonToken.END_ARRAY, jp.nextToken());
167+
168+
jp.close();
169+
}
72170
}

0 commit comments

Comments
 (0)