Skip to content

Commit b3f47ea

Browse files
committed
Merge branch '3.0' into 3.x
2 parents d7edd35 + 3a0f89c commit b3f47ea

File tree

4 files changed

+243
-121
lines changed

4 files changed

+243
-121
lines changed

release-notes/VERSION-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ a pure JSON library.
2323
(fix by @cowtowncoder, w/ Claude code)
2424
#1180: `JsonLocation` off for unrecognized tokens
2525
(fix by @cowtowncoder, w/ Claude code)
26+
#1418: `TokenFilter#includeEmptyArray()` causes an error in some cases where an object element is filtered
27+
(reported by @21Joakim)
28+
(fix by @cowtowncoder, w/ Claude code)
2629
#1470: Add method `copyCurrentStructureExact()` to `JsonGenerator`
2730
(contributed by Lars H)
2831
#1477: Add `JsonGenerator.has(StreamWriteCapability)` convenience method

src/main/java/tools/jackson/core/filter/FilteringParserDelegate.java

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -601,10 +601,13 @@ protected final JsonToken _nextToken2() throws JacksonException
601601
boolean returnEnd = _headContext.isStartHandled();
602602
f = _headContext.getFilter();
603603
if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
604-
boolean includeEmpty = f.includeEmptyArray(_headContext.hasCurrentIndex());
605604
f.filterFinishArray();
606-
if (includeEmpty) {
607-
return _nextBuffered(_headContext);
605+
if (!returnEnd) {
606+
boolean includeEmpty = f.includeEmptyArray(_headContext.hasCurrentIndex());
607+
if (includeEmpty) {
608+
_headContext._needToHandleName = false;
609+
return _nextBuffered(_headContext);
610+
}
608611
}
609612
}
610613
_headContext = _headContext.getParent();
@@ -619,11 +622,15 @@ protected final JsonToken _nextToken2() throws JacksonException
619622
boolean returnEnd = _headContext.isStartHandled();
620623
f = _headContext.getFilter();
621624
if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
622-
boolean includeEmpty = f.includeEmptyObject(_headContext.hasCurrentName());
623625
f.filterFinishObject();
624-
if (includeEmpty) {
625-
return _nextBuffered(_headContext);
626-
} }
626+
if (!returnEnd) {
627+
boolean includeEmpty = f.includeEmptyObject(_headContext.hasCurrentName());
628+
if (includeEmpty) {
629+
_headContext._needToHandleName = false;
630+
return _nextBuffered(_headContext);
631+
}
632+
}
633+
}
627634
_headContext = _headContext.getParent();
628635
_itemFilter = _headContext.getFilter();
629636
if (returnEnd) {
@@ -767,15 +774,19 @@ protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffR
767774
// Unlike with other loops, here we know that content was NOT
768775
// included (won't get this far otherwise)
769776
f = _headContext.getFilter();
777+
boolean gotEnd = (_headContext == buffRoot);
778+
boolean returnEnd = gotEnd && _headContext.isStartHandled();
779+
770780
if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
771-
boolean includeEmpty = f.includeEmptyArray(_headContext.hasCurrentIndex());
772781
f.filterFinishArray();
773-
if (includeEmpty) {
774-
return _nextBuffered(buffRoot);
782+
if (!returnEnd) {
783+
boolean includeEmpty = f.includeEmptyArray(_headContext.hasCurrentIndex());
784+
if (includeEmpty) {
785+
_headContext._needToHandleName = false;
786+
return _nextBuffered(buffRoot);
787+
}
775788
}
776789
}
777-
boolean gotEnd = (_headContext == buffRoot);
778-
boolean returnEnd = gotEnd && _headContext.isStartHandled();
779790

780791
_headContext = _headContext.getParent();
781792
_itemFilter = _headContext.getFilter();
@@ -793,19 +804,19 @@ protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffR
793804
// Unlike with other loops, here we know that content was NOT
794805
// included (won't get this far otherwise)
795806
f = _headContext.getFilter();
807+
boolean gotEnd = (_headContext == buffRoot);
808+
boolean returnEnd = gotEnd && _headContext.isStartHandled();
809+
796810
if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
797-
boolean includeEmpty = f.includeEmptyObject(_headContext.hasCurrentName());
798811
f.filterFinishObject();
799-
if (includeEmpty) {
800-
_headContext._currentName = _headContext._parent == null
801-
? null
802-
: _headContext._parent._currentName;
803-
_headContext._needToHandleName = false;
804-
return _nextBuffered(buffRoot);
812+
if (!returnEnd) {
813+
boolean includeEmpty = f.includeEmptyObject(_headContext.hasCurrentName());
814+
if (includeEmpty) {
815+
_headContext._needToHandleName = false;
816+
return _nextBuffered(buffRoot);
817+
}
805818
}
806819
}
807-
boolean gotEnd = (_headContext == buffRoot);
808-
boolean returnEnd = gotEnd && _headContext.isStartHandled();
809820

810821
_headContext = _headContext.getParent();
811822
_itemFilter = _headContext.getFilter();

src/main/java/tools/jackson/core/filter/TokenFilter.java

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected TokenFilter() { }
5656

5757
/*
5858
/**********************************************************************
59-
/* API, structured values
59+
/* API, structured values: parser and generator
6060
/**********************************************************************
6161
*/
6262

@@ -220,6 +220,42 @@ public TokenFilter includeRootValue(int index) {
220220
return this;
221221
}
222222

223+
/**
224+
* Call made to verify whether leaf-level empty Array value
225+
* should be included in filtered input or output or not.
226+
*<p>
227+
* The default implementation returns {@code false} to exclude
228+
* empty Arrays from input/output.
229+
*
230+
* @param contentsFiltered True if Array had contents but they were
231+
* filtered out (NOT included); false if we had actual empty Array.
232+
*
233+
* @return True if value is to be included; false if not
234+
*
235+
* @since 2.14
236+
*/
237+
public boolean includeEmptyArray(boolean contentsFiltered) {
238+
return false;
239+
}
240+
241+
/**
242+
* Call made to verify whether leaf-level empty Object value
243+
* should be included in filtered input or output or not.
244+
*<p>
245+
* The default implementation returns {@code false} to exclude
246+
* empty Arrays from input/output.
247+
*
248+
* @param contentsFiltered True if Object had contents but they were
249+
* filtered out (NOT included); false if we had actual empty Object.
250+
*
251+
* @return True if value is to be included; false if not
252+
*
253+
* @since 2.14
254+
*/
255+
public boolean includeEmptyObject(boolean contentsFiltered) {
256+
return false;
257+
}
258+
223259
/*
224260
/**********************************************************************
225261
/* API, scalar values (being read)
@@ -254,7 +290,7 @@ public boolean includeValue(JsonParser p) throws JacksonException {
254290
/**
255291
* Call made to verify whether leaf-level
256292
* boolean value
257-
* should be included in output or not.
293+
* should be included in output (written) or not.
258294
*
259295
* @param value Value to check
260296
*
@@ -267,7 +303,7 @@ public boolean includeBoolean(boolean value) {
267303
/**
268304
* Call made to verify whether leaf-level
269305
* null value
270-
* should be included in output or not.
306+
* should be included in output (written) or not.
271307
*
272308
* @return True if ({@code null}) value is to be included; false if not
273309
*/
@@ -278,7 +314,7 @@ public boolean includeNull() {
278314
/**
279315
* Call made to verify whether leaf-level
280316
* String value
281-
* should be included in output or not.
317+
* should be included in output (written) or not.
282318
*
283319
* @param value Value to check
284320
*
@@ -291,7 +327,7 @@ public boolean includeString(String value) {
291327
/**
292328
* Call made to verify whether leaf-level
293329
* "streaming" String value
294-
* should be included in output or not.
330+
* should be included in output (written) or not.
295331
*<p>
296332
* NOTE: note that any reads from passed in {@code Reader} may lead
297333
* to actual loss of content to write; typically method should NOT
@@ -311,7 +347,7 @@ public boolean includeString(java.io.Reader r, int maxLen) {
311347
/**
312348
* Call made to verify whether leaf-level
313349
* <code>int</code> value
314-
* should be included in output or not.
350+
* should be included in output (written) or not.
315351
*
316352
* NOTE: also called for `short`, `byte`
317353
*
@@ -326,7 +362,7 @@ public boolean includeNumber(int value) {
326362
/**
327363
* Call made to verify whether leaf-level
328364
* <code>long</code> value
329-
* should be included in output or not.
365+
* should be included in output (written) or not.
330366
*
331367
* @param value Value to check
332368
*
@@ -339,7 +375,7 @@ public boolean includeNumber(long value) {
339375
/**
340376
* Call made to verify whether leaf-level
341377
* <code>float</code> value
342-
* should be included in output or not.
378+
* should be included in output (written) or not.
343379
*
344380
* @param value Value to check
345381
*
@@ -352,7 +388,7 @@ public boolean includeNumber(float value) {
352388
/**
353389
* Call made to verify whether leaf-level
354390
* <code>double</code> value
355-
* should be included in output or not.
391+
* should be included in output (written) or not.
356392
*
357393
* @param value Value to check
358394
*
@@ -365,7 +401,7 @@ public boolean includeNumber(double value) {
365401
/**
366402
* Call made to verify whether leaf-level
367403
* {@link BigDecimal} value
368-
* should be included in output or not.
404+
* should be included in output (written) or not.
369405
*
370406
* @param value Value to check
371407
*
@@ -378,7 +414,7 @@ public boolean includeNumber(BigDecimal value) {
378414
/**
379415
* Call made to verify whether leaf-level
380416
* {@link BigInteger} value
381-
* should be included in output or not.
417+
* should be included in output (written) or not.
382418
*
383419
* @param value Value to check
384420
*
@@ -391,7 +427,7 @@ public boolean includeNumber(BigInteger value) {
391427
/**
392428
* Call made to verify whether leaf-level
393429
* Binary value
394-
* should be included in output or not.
430+
* should be included in output (written) or not.
395431
*<p>
396432
* NOTE: no binary payload passed; assumption is this won't be of much use.
397433
*
@@ -404,7 +440,7 @@ public boolean includeBinary() {
404440
/**
405441
* Call made to verify whether leaf-level
406442
* raw (pre-encoded, not quoted by generator) value
407-
* should be included in output or not.
443+
* should be included in output (written) or not.
408444
*<p>
409445
* NOTE: value itself not passed since it may come on multiple forms
410446
* and is unlikely to be of much use in determining inclusion
@@ -419,7 +455,7 @@ public boolean includeRawValue() {
419455
/**
420456
* Call made to verify whether leaf-level
421457
* embedded (Opaque) value
422-
* should be included in output or not.
458+
* should be included in output (written) or not.
423459
*
424460
* @param value Value to check
425461
*
@@ -429,36 +465,6 @@ public boolean includeEmbeddedValue(Object value) {
429465
return _includeScalar();
430466
}
431467

432-
/**
433-
* Call made to verify whether leaf-level empty Array value
434-
* should be included in output or not.
435-
*
436-
* @param contentsFiltered True if Array had contents but they were
437-
* filtered out (NOT included); false if we had actual empty Array.
438-
*
439-
* @return True if value is to be included; false if not
440-
*
441-
* @since 2.14
442-
*/
443-
public boolean includeEmptyArray(boolean contentsFiltered) {
444-
return false;
445-
}
446-
447-
/**
448-
* Call made to verify whether leaf-level empty Object value
449-
* should be included in output or not.
450-
*
451-
* @param contentsFiltered True if Object had contents but they were
452-
* filtered out (NOT included); false if we had actual empty Object.
453-
*
454-
* @return True if value is to be included; false if not
455-
*
456-
* @since 2.14
457-
*/
458-
public boolean includeEmptyObject(boolean contentsFiltered) {
459-
return false;
460-
}
461-
462468
/*
463469
/**********************************************************************
464470
/* Overrides

0 commit comments

Comments
 (0)