diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java index 2c9dbfc090..e87640f708 100644 --- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java +++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java @@ -6,6 +6,7 @@ import java.math.BigInteger; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; import com.fasterxml.jackson.core.util.JsonGeneratorDelegate; /** @@ -17,6 +18,7 @@ */ public class FilteringGeneratorDelegate extends JsonGeneratorDelegate { + /* /********************************************************** /* Configuration @@ -44,18 +46,7 @@ public class FilteringGeneratorDelegate extends JsonGeneratorDelegate * done and only explicitly included entries are output; if `true` then * path from main level down to match is also included as necessary. */ - protected boolean _includePath; - - /* NOTE: this feature is included in the first version (2.6), but - * there is no public API to enable it, yet, since there isn't an - * actual use case. But it seemed possible need could arise, which - * is feature has not yet been removed. If no use is found within - * first version or two, just remove. - * - * Marked as deprecated since its status is uncertain. - */ - @Deprecated - protected boolean _includeImmediateParent; + protected TokenFilter.Inclusion _inclusion; /* /********************************************************** @@ -89,8 +80,15 @@ public class FilteringGeneratorDelegate extends JsonGeneratorDelegate /********************************************************** */ + @Deprecated public FilteringGeneratorDelegate(JsonGenerator d, TokenFilter f, boolean includePath, boolean allowMultipleMatches) + { + this(d, f, includePath ? Inclusion.INCLUDE_ALL_AND_PATH : Inclusion.ONLY_INCLUDE_ALL, allowMultipleMatches); + } + + public FilteringGeneratorDelegate(JsonGenerator d, TokenFilter f, + TokenFilter.Inclusion inclusion, boolean allowMultipleMatches) { // By default, do NOT delegate copy methods super(d, false); @@ -98,7 +96,7 @@ public FilteringGeneratorDelegate(JsonGenerator d, TokenFilter f, // and this is the currently active filter for root values _itemFilter = f; _filterContext = TokenFilterContext.createRootContext(f); - _includePath = includePath; + _inclusion = inclusion; _allowMultipleMatches = allowMultipleMatches; } @@ -169,6 +167,10 @@ public void writeStartArray() throws IOException _checkParentPath(); _filterContext = _filterContext.createChildArrayContext(_itemFilter, true); delegate.writeStartArray(); + } else if (_itemFilter != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + _checkParentPath(false /* isMatch */); + _filterContext = _filterContext.createChildArrayContext(_itemFilter, true); + delegate.writeStartArray(); } else { _filterContext = _filterContext.createChildArrayContext(_itemFilter, false); } @@ -198,6 +200,10 @@ public void writeStartArray(int size) throws IOException _checkParentPath(); _filterContext = _filterContext.createChildArrayContext(_itemFilter, true); delegate.writeStartArray(size); + } else if (_itemFilter != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + _checkParentPath(false /* isMatch */); + _filterContext = _filterContext.createChildArrayContext(_itemFilter, true); + delegate.writeStartArray(size); } else { _filterContext = _filterContext.createChildArrayContext(_itemFilter, false); } @@ -296,6 +302,10 @@ public void writeStartObject() throws IOException _checkParentPath(); _filterContext = _filterContext.createChildObjectContext(f, true); delegate.writeStartObject(); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + _checkParentPath(false /* isMatch */); + _filterContext = _filterContext.createChildObjectContext(f, true); + delegate.writeStartObject(); } else { // filter out _filterContext = _filterContext.createChildObjectContext(f, false); } @@ -326,6 +336,10 @@ public void writeStartObject(Object forValue) throws IOException _checkParentPath(); _filterContext = _filterContext.createChildObjectContext(f, true); delegate.writeStartObject(forValue); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + _checkParentPath(false /* isMatch */); + _filterContext = _filterContext.createChildObjectContext(f, true); + delegate.writeStartObject(forValue); } else { // filter out _filterContext = _filterContext.createChildObjectContext(f, false); } @@ -439,7 +453,7 @@ public void writeString(String value) throws IOException } } _checkParentPath(); - } + } delegate.writeString(value); } @@ -461,7 +475,7 @@ public void writeString(char[] text, int offset, int len) throws IOException } } _checkParentPath(); - } + } delegate.writeString(text, offset, len); } @@ -482,7 +496,7 @@ public void writeString(SerializableString value) throws IOException } } _checkParentPath(); - } + } delegate.writeString(value); } @@ -613,7 +627,7 @@ public void writeNumber(short v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -634,7 +648,7 @@ public void writeNumber(int v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -655,7 +669,7 @@ public void writeNumber(long v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -676,7 +690,7 @@ public void writeNumber(BigInteger v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -697,7 +711,7 @@ public void writeNumber(double v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -718,7 +732,7 @@ public void writeNumber(float v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -739,7 +753,7 @@ public void writeNumber(BigDecimal v) throws IOException } } _checkParentPath(); - } + } delegate.writeNumber(v); } @@ -781,7 +795,7 @@ public void writeBoolean(boolean v) throws IOException } } _checkParentPath(); - } + } delegate.writeBoolean(v); } @@ -802,7 +816,7 @@ public void writeNull() throws IOException } } _checkParentPath(); - } + } delegate.writeNull(); } @@ -925,13 +939,23 @@ public void copyCurrentStructure(JsonParser jp) throws IOException { protected void _checkParentPath() throws IOException { - ++_matchCount; + _checkParentPath(true); + } + + protected void _checkParentPath(boolean isMatch) throws IOException + { + if (isMatch) { + ++_matchCount; + } // only need to construct path if parent wasn't written - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { _filterContext.writePath(delegate); + } else if (_inclusion == Inclusion.INCLUDE_NON_NULL) { + // path has already been written, except for maybe field name + _filterContext.ensureFieldNameWritten(delegate); } // also: if no multiple matches desired, short-cut checks - if (!_allowMultipleMatches) { + if (isMatch && !_allowMultipleMatches) { // Mark parents as "skip" so that further check calls are not made _filterContext.skipParentChecks(); } @@ -945,12 +969,11 @@ protected void _checkParentPath() throws IOException protected void _checkPropertyParentPath() throws IOException { ++_matchCount; - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { _filterContext.writePath(delegate); - } else if (_includeImmediateParent) { - // 21-Apr-2015, tatu: Note that there is no API to enable this currently... - // retained for speculative future use - _filterContext.writeImmediatePath(delegate); + } else if (_inclusion == Inclusion.INCLUDE_NON_NULL) { + // path has already been written, except for maybe field name + _filterContext.ensureFieldNameWritten(delegate); } // also: if no multiple matches desired, short-cut checks 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 80c17e022c..8c8ebb7680 100644 --- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java +++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java @@ -6,6 +6,7 @@ import java.math.BigInteger; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; import com.fasterxml.jackson.core.util.JsonParserDelegate; import static com.fasterxml.jackson.core.JsonTokenId.*; @@ -46,19 +47,8 @@ public class FilteringParserDelegate extends JsonParserDelegate * done and only explicitly included entries are output; if `true` then * path from main level down to match is also included as necessary. */ - protected boolean _includePath; - - /* NOTE: this feature is included in the first version (2.6), but - * there is no public API to enable it, yet, since there isn't an - * actual use case. But it seemed possible need could arise, which - * is feature has not yet been removed. If no use is found within - * first version or two, just remove. - * - * Marked as deprecated since its status is uncertain. - */ - @Deprecated - protected boolean _includeImmediateParent; - + protected TokenFilter.Inclusion _inclusion; + /* /********************************************************** /* State @@ -111,15 +101,22 @@ public class FilteringParserDelegate extends JsonParserDelegate /********************************************************** */ + @Deprecated public FilteringParserDelegate(JsonParser p, TokenFilter f, boolean includePath, boolean allowMultipleMatches) + { + this(p, f, includePath ? Inclusion.INCLUDE_ALL_AND_PATH : Inclusion.ONLY_INCLUDE_ALL, allowMultipleMatches); + } + + public FilteringParserDelegate(JsonParser p, TokenFilter f, + TokenFilter.Inclusion inclusion, boolean allowMultipleMatches) { super(p); rootFilter = f; // and this is the currently active filter for root values _itemFilter = f; _headContext = TokenFilterContext.createRootContext(f); - _includePath = includePath; + _inclusion = inclusion; _allowMultipleMatches = allowMultipleMatches; } @@ -235,9 +232,10 @@ public JsonToken nextToken() throws IOException // If all the conditions matches then check for scalar / non-scalar property if (!_allowMultipleMatches && (_currToken != null) && (_exposedContext == null)) { - // if scalar, and scalar not present in obj/array and !includePath and INCLUDE_ALL - // matched once, return null - if (_currToken.isScalarValue() && !_headContext.isStartHandled() && !_includePath + // if scalar, and scalar not present in obj/array and _inclusion == ONLY_INCLUDE_ALL + // and INCLUDE_ALL matched once, return null + if (_currToken.isScalarValue() && !_headContext.isStartHandled() + && _inclusion == Inclusion.ONLY_INCLUDE_ALL && (_itemFilter == TokenFilter.INCLUDE_ALL)) { return (_currToken = null); } @@ -318,11 +316,15 @@ public JsonToken nextToken() throws IOException if (f == TokenFilter.INCLUDE_ALL) { _headContext = _headContext.createChildArrayContext(f, true); return (_currToken = t); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + // TODO don't count as match? + _headContext = _headContext.createChildArrayContext(f, true); + return (_currToken = t); } _headContext = _headContext.createChildArrayContext(f, false); - + // Also: only need buffering if parent path to be included - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { t = _nextTokenWithBuffering(_headContext); if (t != null) { _currToken = t; @@ -354,10 +356,14 @@ public JsonToken nextToken() throws IOException if (f == TokenFilter.INCLUDE_ALL) { _headContext = _headContext.createChildObjectContext(f, true); return (_currToken = t); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + // TODO don't count as match? + _headContext = _headContext.createChildObjectContext(f, true); + return (_currToken = t); } _headContext = _headContext.createChildObjectContext(f, false); // Also: only need buffering if parent path to be included - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { t = _nextTokenWithBuffering(_headContext); if (t != null) { _currToken = t; @@ -391,14 +397,6 @@ public JsonToken nextToken() throws IOException f = _headContext.setFieldName(name); if (f == TokenFilter.INCLUDE_ALL) { _itemFilter = f; - if (!_includePath) { - // Minor twist here: if parent NOT included, may need to induce output of - // surrounding START_OBJECT/END_OBJECT - if (_includeImmediateParent && !_headContext.isStartHandled()) { - t = _headContext.nextTokenToRead(); // returns START_OBJECT but also marks it handled - _exposedContext = _headContext; - } - } return (_currToken = t); } if (f == null) { @@ -415,7 +413,7 @@ public JsonToken nextToken() throws IOException _itemFilter = f; if (f == TokenFilter.INCLUDE_ALL) { if (_verifyAllowedMatches()) { - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { return (_currToken = t); } } else { @@ -423,7 +421,7 @@ public JsonToken nextToken() throws IOException delegate.skipChildren(); } } - if (_includePath) { + if (_inclusion != Inclusion.ONLY_INCLUDE_ALL) { t = _nextTokenWithBuffering(_headContext); if (t != null) { _currToken = t; @@ -496,10 +494,13 @@ protected final JsonToken _nextToken2() throws IOException if (f == TokenFilter.INCLUDE_ALL) { _headContext = _headContext.createChildArrayContext(f, true); return (_currToken = t); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + _headContext = _headContext.createChildArrayContext(f, true); + return (_currToken = t); } _headContext = _headContext.createChildArrayContext(f, false); // but if we didn't figure it out yet, need to buffer possible events - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { t = _nextTokenWithBuffering(_headContext); if (t != null) { _currToken = t; @@ -531,9 +532,12 @@ protected final JsonToken _nextToken2() throws IOException if (f == TokenFilter.INCLUDE_ALL) { _headContext = _headContext.createChildObjectContext(f, true); return (_currToken = t); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + _headContext = _headContext.createChildObjectContext(f, true); + return (_currToken = t); } _headContext = _headContext.createChildObjectContext(f, false); - if (_includePath) { + if (_inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { t = _nextTokenWithBuffering(_headContext); if (t != null) { _currToken = t; @@ -579,13 +583,12 @@ protected final JsonToken _nextToken2() throws IOException } _itemFilter = f; if (f == TokenFilter.INCLUDE_ALL) { - if (_verifyAllowedMatches() && _includePath) { + if (_verifyAllowedMatches() && _inclusion == Inclusion.INCLUDE_ALL_AND_PATH) { return (_currToken = t); } -// if (_includeImmediateParent) { ... continue main_loop; } - if (_includePath) { + if (_inclusion != Inclusion.ONLY_INCLUDE_ALL) { t = _nextTokenWithBuffering(_headContext); if (t != null) { _currToken = t; @@ -647,6 +650,10 @@ protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffR if (f == TokenFilter.INCLUDE_ALL) { _headContext = _headContext.createChildArrayContext(f, true); return _nextBuffered(buffRoot); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + // TODO don't count as match? + _headContext = _headContext.createChildArrayContext(f, true); + return _nextBuffered(buffRoot); } _headContext = _headContext.createChildArrayContext(f, false); continue main_loop; @@ -674,6 +681,10 @@ protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffR if (f == TokenFilter.INCLUDE_ALL) { _headContext = _headContext.createChildObjectContext(f, true); return _nextBuffered(buffRoot); + } else if (f != null && _inclusion == Inclusion.INCLUDE_NON_NULL) { + // TODO don't count as match? + _headContext = _headContext.createChildArrayContext(f, true); + return _nextBuffered(buffRoot); } _headContext = _headContext.createChildObjectContext(f, false); continue main_loop; diff --git a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilter.java b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilter.java index 4546fbfd32..0595ede879 100644 --- a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilter.java +++ b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilter.java @@ -16,6 +16,30 @@ public class TokenFilter { + /** + * Enumeration that controls how TokenFilter return values are interpreted + * + * @since 2.11 + */ + public enum Inclusion { + /** + * Tokens will only be included if the filter returns TokenFilter.INCLUDE_ALL + */ + ONLY_INCLUDE_ALL, + /** + * When TokenFilter.INCLUDE_ALL is returned, the corresponding token will + * be included as well as enclosing tokens up to the root + */ + INCLUDE_ALL_AND_PATH, + /** + * Tokens will be included if any non-null filter is returned. + * The exception is if a field name returns a non-null filter, + * but the field value returns a null filter. In this case the + * field name and value will both be omitted. + */ + INCLUDE_NON_NULL + } + // // Marker values /** diff --git a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java index c414633ee6..70c8a61b5c 100644 --- a/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java +++ b/src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java @@ -147,6 +147,17 @@ public TokenFilter checkValue(TokenFilter filter) { return filter.includeRootValue(ix); } + /** + * Method called to ensure that field name, if present, has been written + */ + public void ensureFieldNameWritten(JsonGenerator gen) throws IOException + { + if (_needToHandleName) { + _needToHandleName = false; + gen.writeFieldName(_currentName); + } + } + /** * Method called to ensure that parent path from root is written up to * and including this node. @@ -175,35 +186,6 @@ public void writePath(JsonGenerator gen) throws IOException } } - /** - * Variant of {@link #writePath(JsonGenerator)} called when all we - * need is immediately surrounding Object. Method typically called - * when including a single property but not including full path - * to root. - */ - public void writeImmediatePath(JsonGenerator gen) throws IOException - { - if ((_filter == null) || (_filter == TokenFilter.INCLUDE_ALL)) { - return; - } - if (_startHandled) { - // even if Object started, need to start leaf-level name - if (_needToHandleName) { - gen.writeFieldName(_currentName); - } - } else { - _startHandled = true; - if (_type == TYPE_OBJECT) { - gen.writeStartObject(); - if (_needToHandleName) { - gen.writeFieldName(_currentName); - } - } else if (_type == TYPE_ARRAY) { - gen.writeStartArray(); - } - } - } - private void _writePath(JsonGenerator gen) throws IOException { if ((_filter == null) || (_filter == TokenFilter.INCLUDE_ALL)) { 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 8419541a4e..e50f3a741a 100644 --- a/src/test/java/com/fasterxml/jackson/core/filter/BasicGeneratorFilteringTest.java +++ b/src/test/java/com/fasterxml/jackson/core/filter/BasicGeneratorFilteringTest.java @@ -6,6 +6,7 @@ import java.util.*; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; import com.fasterxml.jackson.core.io.SerializedString; /** @@ -67,6 +68,23 @@ public TokenFilter includeProperty(String name) { } } + static class StrictNameMatchFilter extends TokenFilter + { + private final Set _names; + + public StrictNameMatchFilter(String... names) { + _names = new HashSet(Arrays.asList(names)); + } + + @Override + public TokenFilter includeProperty(String name) { + if (_names.contains(name)) { + return TokenFilter.INCLUDE_ALL; + } + return null; + } + } + static class IndexMatchFilter extends TokenFilter { private final BitSet _indices; @@ -95,6 +113,22 @@ public TokenFilter includeElement(int index) { protected boolean _includeScalar() { return false; } } + static class NoArraysFilter extends TokenFilter + { + @Override + public TokenFilter filterStartArray() { + return null; + } + } + + static class NoObjectsFilter extends TokenFilter + { + @Override + public TokenFilter filterStartObject() { + return null; + } + } + /* /********************************************************** /* Test methods @@ -120,7 +154,7 @@ public void testSingleMatchFilteringWithoutPath() throws Exception StringWriter w = new StringWriter(); JsonGenerator gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new NameMatchFilter("value"), - false, // includePath + Inclusion.ONLY_INCLUDE_ALL, false // multipleMatches ); final String JSON = "{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"; @@ -141,7 +175,7 @@ public void testSingleMatchFilteringWithPath() throws Exception NameMatchFilter filter = new NameMatchFilter("value"); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(origGen, filter, - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); @@ -163,7 +197,7 @@ public void testSingleMatchFilteringWithPathSkippedArray() throws Exception NameMatchFilter filter = new NameMatchFilter("value"); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(origGen, filter, - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); @@ -192,8 +226,8 @@ private void _testSingleMatchFilteringWithPathAlternate1(boolean exclude) throws : new NameMatchFilter("value"); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), tf, - true, // includePath - true // multipleMatches + Inclusion.INCLUDE_ALL_AND_PATH, + false // multipleMatches ); //final String JSON = "{'a':123,'array':[1,2],'ob':{'value0':2,'value':[3],'value2':'foo'},'b':true}"; @@ -239,7 +273,7 @@ public void testSingleMatchFilteringWithPathRawBinary() throws Exception StringWriter w = new StringWriter(); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new NameMatchFilter("array"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); //final String JSON = "{'header':['ENCODED',raw],'array':['base64stuff',1,2,3,4,5,6.25,7.5],'extra':[1,2,3,4,5,6.25,7.5]}"; @@ -290,7 +324,7 @@ public void testMultipleMatchFilteringWithPath1() throws Exception StringWriter w = new StringWriter(); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new NameMatchFilter("value0", "value2"), - true, /* includePath */ true /* multipleMatches */ ); + Inclusion.INCLUDE_ALL_AND_PATH, true /* multipleMatches */ ); final String JSON = "{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"; writeJsonDoc(JSON_F, JSON, gen); assertEquals(aposToQuotes("{'ob':{'value0':2,'value2':4}}"), w.toString()); @@ -318,7 +352,7 @@ public void testMultipleMatchFilteringWithPath2() throws Exception FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new NameMatchFilter("array", "b", "value"), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); final String JSON = "{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"; writeJsonDoc(JSON_F, JSON, gen); assertEquals(aposToQuotes("{'array':[1,2],'ob':{'value':3},'b':true}"), w.toString()); @@ -331,13 +365,108 @@ public void testMultipleMatchFilteringWithPath3() throws Exception FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new NameMatchFilter("value"), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); final String JSON = "{'root':{'a0':true,'a':{'value':3},'b':{'value':'abc'}},'b0':false}"; writeJsonDoc(JSON_F, JSON, gen); assertEquals(aposToQuotes("{'root':{'a':{'value':3},'b':{'value':'abc'}}}"), w.toString()); assertEquals(2, gen.getMatchCount()); } + public void testNoMatchFiltering1() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new NameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, true); + final String JSON = "{'root':{'a0':true,'b':{'value':4}},'b0':false}"; + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("{'root':{'b':{}}}"), w.toString()); + assertEquals(0, gen.getMatchCount()); + } + + public void testNoMatchFiltering2() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new NameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, true); + final String object = "{'root':{'a0':true,'b':{'value':4}},'b0':false}"; + final String JSON = String.format("[%s,%s,%s]", object, object, object); + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("[{'root':{'b':{}}},{'root':{'b':{}}},{'root':{'b':{}}}]"), w.toString()); + assertEquals(0, gen.getMatchCount()); + } + + public void testNoMatchFiltering3() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new NameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, true); + final String object = "{'root':{'a0':true,'b':{'value':4}},'b0':false}"; + final String JSON = String.format("[[%s],[%s],[%s]]", object, object, object); + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("[[{'root':{'b':{}}}],[{'root':{'b':{}}}],[{'root':{'b':{}}}]]"), w.toString()); + assertEquals(0, gen.getMatchCount()); + } + + public void testNoMatchFiltering4() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new StrictNameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, true); + final String JSON = "{'root':{'a0':true,'a':{'value':3},'b':{'value':4}},'b0':false}"; + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("{}"), w.toString()); + assertEquals(0, gen.getMatchCount()); + } + + public void testNoMatchFiltering5() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new StrictNameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, true); + final String object = "{'root':{'a0':true,'b':{'value':4}},'b0':false}"; + final String JSON = String.format("[%s,%s,%s]", object, object, object); + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("[{},{},{}]"), w.toString()); + assertEquals(0, gen.getMatchCount()); + } + + public void testNoMatchFiltering6() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new StrictNameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, true); + final String object = "{'root':{'a0':true,'b':{'value':4}},'b0':false}"; + final String JSON = String.format("[[%s],[%s],[%s]]", object, object, object); + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("[[{}],[{}],[{}]]"), w.toString()); + assertEquals(0, gen.getMatchCount()); + } + + public void testValueOmitsFieldName1() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new NoArraysFilter(), + Inclusion.INCLUDE_NON_NULL, true); + final String JSON = "{'root':['a'],'b0':false}"; + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("{'b0':false}"), w.toString()); + assertEquals(1, gen.getMatchCount()); + } + public void testMultipleMatchFilteringWithPath4() throws Exception { StringWriter w = new StringWriter(); @@ -350,12 +479,25 @@ public void testMultipleMatchFilteringWithPath4() throws Exception assertEquals(1, gen.getMatchCount()); } + public void testValueOmitsFieldName2() throws Exception + { + StringWriter w = new StringWriter(); + + FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), + new NoObjectsFilter(), + Inclusion.INCLUDE_NON_NULL, true); + final String JSON = "['a',{'root':{'b':{'value':4}},'b0':false}]"; + writeJsonDoc(JSON_F, JSON, gen); + assertEquals(aposToQuotes("['a']"), w.toString()); + assertEquals(1, gen.getMatchCount()); + } + public void testIndexMatchWithPath1() throws Exception { StringWriter w = new StringWriter(); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new IndexMatchFilter(1), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); final String JSON = "{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':'abc'},'b':true}"; writeJsonDoc(JSON_F, JSON, gen); assertEquals(aposToQuotes("{'array':[2]}"), w.toString()); @@ -363,7 +505,7 @@ public void testIndexMatchWithPath1() throws Exception w = new StringWriter(); gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new IndexMatchFilter(0), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); writeJsonDoc(JSON_F, JSON, gen); assertEquals(aposToQuotes("{'array':[1]}"), w.toString()); assertEquals(1, gen.getMatchCount()); @@ -374,7 +516,7 @@ public void testIndexMatchWithPath2() throws Exception StringWriter w = new StringWriter(); FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), new IndexMatchFilter(0,1), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); String JSON = "{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"; writeJsonDoc(JSON_F, JSON, gen); assertEquals(aposToQuotes("{'array':[1,2]}"), w.toString()); @@ -415,7 +557,7 @@ public void testWriteStartObjectWithObject() throws Exception FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(JSON_F.createGenerator(w), TokenFilter.INCLUDE_ALL, - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); String value = "val"; 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 b75fc0ee21..ce190f8d40 100644 --- a/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java +++ b/src/test/java/com/fasterxml/jackson/core/filter/BasicParserFilteringTest.java @@ -1,9 +1,11 @@ package com.fasterxml.jackson.core.filter; +import java.io.StringWriter; import java.math.BigInteger; import java.util.*; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; @SuppressWarnings("resource") public class BasicParserFilteringTest extends BaseTest @@ -33,6 +35,23 @@ public TokenFilter includeProperty(String name) { protected boolean _includeScalar() { return false; } } + static class StrictNameMatchFilter extends TokenFilter + { + private final Set _names; + + public StrictNameMatchFilter(String... names) { + _names = new HashSet(Arrays.asList(names)); + } + + @Override + public TokenFilter includeProperty(String name) { + if (_names.contains(name)) { + return TokenFilter.INCLUDE_ALL; + } + return null; + } + } + static class IndexMatchFilter extends TokenFilter { private final BitSet _indices; @@ -61,6 +80,22 @@ public TokenFilter includeElement(int index) { protected boolean _includeScalar() { return false; } } + static class NoArraysFilter extends TokenFilter + { + @Override + public TokenFilter filterStartArray() { + return null; + } + } + + static class NoObjectsFilter extends TokenFilter + { + @Override + public TokenFilter filterStartObject() { + return null; + } + } + /* /********************************************************** /* Test methods @@ -84,7 +119,7 @@ public void testSingleMatchFilteringWithoutPath() throws Exception JsonParser p0 = JSON_F.createParser(SIMPLE); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - false, // includePath + Inclusion.ONLY_INCLUDE_ALL, false // multipleMatches ); String result = readAndWrite(JSON_F, p); @@ -98,7 +133,7 @@ public void testSingleMatchFilteringWithPath1() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("a"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); String result = readAndWrite(JSON_F, p); @@ -112,7 +147,7 @@ public void testSingleMatchFilteringWithPath2() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); String result = readAndWrite(JSON_F, p); @@ -126,7 +161,7 @@ public void testSingleMatchFilteringWithPath3() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("ob"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); String result = readAndWrite(JSON_F, p); @@ -140,7 +175,7 @@ public void testNotAllowMultipleMatchesWithoutPath1() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - false, // includePath + Inclusion.ONLY_INCLUDE_ALL, false // multipleMatches -false ); String result = readAndWrite(JSON_F, p); @@ -154,7 +189,7 @@ public void testNotAllowMultipleMatchesWithoutPath2() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new IndexMatchFilter(1), - false, // includePath + Inclusion.ONLY_INCLUDE_ALL, false // multipleMatches -false ); String result = readAndWrite(JSON_F, p); @@ -168,7 +203,7 @@ public void testNotAllowMultipleMatchesWithPath1() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new IndexMatchFilter(1), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches -false ); String result = readAndWrite(JSON_F, p); @@ -183,7 +218,7 @@ public void testNotAllowMultipleMatchesWithPath2() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new IndexMatchFilter(1), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches -false ); String result = readAndWrite(JSON_F, p); @@ -197,7 +232,7 @@ public void testNotAllowMultipleMatchesWithPath3() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches -false ); String result = readAndWrite(JSON_F, p); @@ -211,7 +246,7 @@ public void testNotAllowMultipleMatchesWithPath4() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("ob"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches -false ); String result = readAndWrite(JSON_F, p); @@ -225,7 +260,7 @@ public void testAllowMultipleMatchesWithoutPath() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - false, // includePath + Inclusion.ONLY_INCLUDE_ALL, true // multipleMatches - true ); String result = readAndWrite(JSON_F, p); @@ -239,7 +274,7 @@ public void testAllowMultipleMatchesWithPath1() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, true // multipleMatches - true ); String result = readAndWrite(JSON_F, p); @@ -253,7 +288,7 @@ public void testAllowMultipleMatchesWithPath2() throws Exception JsonParser p0 = JSON_F.createParser(jsonString); FilteringParserDelegate p = new FilteringParserDelegate(p0, new IndexMatchFilter(1), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, true // multipleMatches - true ); String result = readAndWrite(JSON_F, p); @@ -266,7 +301,7 @@ public void testMultipleMatchFilteringWithPath1() throws Exception JsonParser p0 = JSON_F.createParser(SIMPLE); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value0", "value2"), - true, /* includePath */ true /* multipleMatches */ ); + Inclusion.INCLUDE_ALL_AND_PATH, true /* multipleMatches */ ); String result = readAndWrite(JSON_F, p); assertEquals(aposToQuotes("{'ob':{'value0':2,'value2':0.25}}"), result); assertEquals(2, p.getMatchCount()); @@ -279,7 +314,7 @@ public void testMultipleMatchFilteringWithPath2() throws Exception JsonParser p0 = JSON_F.createParser(INPUT); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("b", "value"), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); String result = readAndWrite(JSON_F, p); assertEquals(aposToQuotes("{'ob':{'value':3},'b':true}"), result); @@ -292,22 +327,140 @@ public void testMultipleMatchFilteringWithPath3() throws Exception JsonParser p0 = JSON_F.createParser(JSON); FilteringParserDelegate p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, true); + Inclusion.INCLUDE_ALL_AND_PATH, true); String result = readAndWrite(JSON_F, p); assertEquals(aposToQuotes("{'root':{'a':{'value':3},'b':{'value':\"foo\"}}}"), result); assertEquals(2, p.getMatchCount()); } + public void testNoMatchFiltering1() throws Exception + { + String jsonString = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new NameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("{'array':[],'ob':{}}"), result); + assertEquals(0, p.getMatchCount()); + } + + public void testNoMatchFiltering2() throws Exception + { + String object = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"); + String jsonString = String.format("[%s,%s,%s]", object, object, object); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new NameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("[{'array':[],'ob':{}},{'array':[],'ob':{}},{'array':[],'ob':{}}]"), result); + assertEquals(0, p.getMatchCount()); + } + + public void testNoMatchFiltering3() throws Exception + { + String object = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"); + String jsonString = String.format("[[%s],[%s],[%s]]", object, object, object); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new NameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("[[{'array':[],'ob':{}}],[{'array':[],'ob':{}}],[{'array':[],'ob':{}}]]"), result); + assertEquals(0, p.getMatchCount()); + + StringWriter w = new StringWriter(); + } + + public void testNoMatchFiltering4() throws Exception + { + String jsonString = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new StrictNameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("{}"), result); + assertEquals(0, p.getMatchCount()); + } + + public void testNoMatchFiltering5() throws Exception + { + String object = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"); + String jsonString = String.format("[%s,%s,%s]", object, object, object); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new StrictNameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("[{},{},{}]"), result); + assertEquals(0, p.getMatchCount()); + } + + public void testNoMatchFiltering6() throws Exception + { + String object = aposToQuotes("{'a':123,'array':[1,2],'ob':{'value0':2,'value':3,'value2':4},'b':true}"); + String jsonString = String.format("[[%s],[%s],[%s]]", object, object, object); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new StrictNameMatchFilter("invalid"), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("[[{}],[{}],[{}]]"), result); + assertEquals(0, p.getMatchCount()); + } + + public void testValueOmitsFieldName1() throws Exception + { + String jsonString = aposToQuotes("{'a':123,'array':[1,2]}"); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new NoArraysFilter(), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("{'a':123}"), result); + assertEquals(0, p.getMatchCount()); + } + + public void testValueOmitsFieldName2() throws Exception + { + String jsonString = aposToQuotes("['a',{'value0':3,'b':{'value':4}}]"); + JsonParser p0 = JSON_F.createParser(jsonString); + FilteringParserDelegate p = new FilteringParserDelegate(p0, + new NoObjectsFilter(), + Inclusion.INCLUDE_NON_NULL, + true // multipleMatches + ); + String result = readAndWrite(JSON_F, p); + assertEquals(aposToQuotes("['a']"), result); + assertEquals(1, p.getMatchCount()); + } + public void testIndexMatchWithPath1() throws Exception { FilteringParserDelegate p = new FilteringParserDelegate(JSON_F.createParser(SIMPLE), - new IndexMatchFilter(1), true, true); + new IndexMatchFilter(1), Inclusion.INCLUDE_ALL_AND_PATH, true); String result = readAndWrite(JSON_F, p); assertEquals(aposToQuotes("{'array':[2]}"), result); assertEquals(1, p.getMatchCount()); p = new FilteringParserDelegate(JSON_F.createParser(SIMPLE), - new IndexMatchFilter(0), true, true); + new IndexMatchFilter(0), Inclusion.INCLUDE_ALL_AND_PATH, true); result = readAndWrite(JSON_F, p); assertEquals(aposToQuotes("{'array':[1]}"), result); assertEquals(1, p.getMatchCount()); @@ -316,13 +469,13 @@ public void testIndexMatchWithPath1() throws Exception public void testIndexMatchWithPath2() throws Exception { FilteringParserDelegate p = new FilteringParserDelegate(JSON_F.createParser(SIMPLE), - new IndexMatchFilter(0, 1), true, true); + new IndexMatchFilter(0, 1), Inclusion.INCLUDE_ALL_AND_PATH, true); assertEquals(aposToQuotes("{'array':[1,2]}"), readAndWrite(JSON_F, p)); assertEquals(2, p.getMatchCount()); String JSON = aposToQuotes("{'a':123,'array':[1,2,3,4,5],'b':[1,2,3]}"); p = new FilteringParserDelegate(JSON_F.createParser(JSON), - new IndexMatchFilter(1, 3), true, true); + new IndexMatchFilter(1, 3), Inclusion.INCLUDE_ALL_AND_PATH, true); assertEquals(aposToQuotes("{'array':[2,4],'b':[2]}"), readAndWrite(JSON_F, p)); assertEquals(3, p.getMatchCount()); } @@ -332,7 +485,7 @@ public void testBasicSingleMatchFilteringWithPath() throws Exception JsonParser p0 = JSON_F.createParser(SIMPLE); JsonParser p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); @@ -346,7 +499,7 @@ public void testTokensSingleMatchWithPath() throws Exception JsonParser p0 = JSON_F.createParser(SIMPLE); JsonParser p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); @@ -423,7 +576,7 @@ public void testSkippingForSingleWithPath() throws Exception JsonParser p0 = JSON_F.createParser(SIMPLE); JsonParser p = new FilteringParserDelegate(p0, new NameMatchFilter("value"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches ); 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 245a9806e0..9fcac6c597 100644 --- a/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerGeneratorFilteringTest.java +++ b/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerGeneratorFilteringTest.java @@ -3,6 +3,7 @@ import java.io.*; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; @SuppressWarnings("resource") public class JsonPointerGeneratorFilteringTest extends com.fasterxml.jackson.core.BaseTest @@ -13,82 +14,82 @@ public class JsonPointerGeneratorFilteringTest extends com.fasterxml.jackson.cor public void testSimplePropertyWithPath() throws Exception { - _assert(SIMPLE_INPUT, "/c", true, "{'c':{'d':{'a':true}}}"); - _assert(SIMPLE_INPUT, "/c/d", true, "{'c':{'d':{'a':true}}}"); - _assert(SIMPLE_INPUT, "/c/d/a", true, "{'c':{'d':{'a':true}}}"); + _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}}}"); + _assert(SIMPLE_INPUT, "/c/d/a", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':{'d':{'a':true}}}"); - _assert(SIMPLE_INPUT, "/c/d/a", true, "{'c':{'d':{'a':true}}}"); + _assert(SIMPLE_INPUT, "/c/d/a", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':{'d':{'a':true}}}"); - _assert(SIMPLE_INPUT, "/a", true, "{'a':1}"); - _assert(SIMPLE_INPUT, "/d", true, "{'d':null}"); + _assert(SIMPLE_INPUT, "/a", Inclusion.INCLUDE_ALL_AND_PATH, "{'a':1}"); + _assert(SIMPLE_INPUT, "/d", Inclusion.INCLUDE_ALL_AND_PATH, "{'d':null}"); // and then non-match - _assert(SIMPLE_INPUT, "/x", true, ""); + _assert(SIMPLE_INPUT, "/x", Inclusion.INCLUDE_ALL_AND_PATH, ""); } public void testSimplePropertyWithoutPath() throws Exception { - _assert(SIMPLE_INPUT, "/c", false, "{'d':{'a':true}}"); - _assert(SIMPLE_INPUT, "/c/d", false, "{'a':true}"); - _assert(SIMPLE_INPUT, "/c/d/a", false, "true"); + _assert(SIMPLE_INPUT, "/c", Inclusion.ONLY_INCLUDE_ALL, "{'d':{'a':true}}"); + _assert(SIMPLE_INPUT, "/c/d", Inclusion.ONLY_INCLUDE_ALL, "{'a':true}"); + _assert(SIMPLE_INPUT, "/c/d/a", Inclusion.ONLY_INCLUDE_ALL, "true"); - _assert(SIMPLE_INPUT, "/a", false, "1"); - _assert(SIMPLE_INPUT, "/d", false, "null"); + _assert(SIMPLE_INPUT, "/a", Inclusion.ONLY_INCLUDE_ALL, "1"); + _assert(SIMPLE_INPUT, "/d", Inclusion.ONLY_INCLUDE_ALL, "null"); // and then non-match - _assert(SIMPLE_INPUT, "/x", false, ""); + _assert(SIMPLE_INPUT, "/x", Inclusion.ONLY_INCLUDE_ALL, ""); } public void testArrayElementWithPath() throws Exception { - _assert(SIMPLE_INPUT, "/b", true, "{'b':[1,2,3]}"); - _assert(SIMPLE_INPUT, "/b/1", true, "{'b':[2]}"); - _assert(SIMPLE_INPUT, "/b/2", true, "{'b':[3]}"); + _assert(SIMPLE_INPUT, "/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[1,2,3]}"); + _assert(SIMPLE_INPUT, "/b/1", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[2]}"); + _assert(SIMPLE_INPUT, "/b/2", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[3]}"); // and then non-match - _assert(SIMPLE_INPUT, "/b/8", true, ""); + _assert(SIMPLE_INPUT, "/b/8", Inclusion.INCLUDE_ALL_AND_PATH, ""); } public void testArrayNestedWithPath() throws Exception { - _assert("{'a':[true,{'b':3,'d':2},false]}", "/a/1/b", true, "{'a':[{'b':3}]}"); - _assert("[true,[1]]", "/0", true, "[true]"); - _assert("[true,[1]]", "/1", true, "[[1]]"); - _assert("[true,[1,2,[true],3],0]", "/0", true, "[true]"); - _assert("[true,[1,2,[true],3],0]", "/1", true, "[[1,2,[true],3]]"); - - _assert("[true,[1,2,[true],3],0]", "/1/2", true, "[[[true]]]"); - _assert("[true,[1,2,[true],3],0]", "/1/2/0", true, "[[[true]]]"); - _assert("[true,[1,2,[true],3],0]", "/1/3/0", true, ""); + _assert("{'a':[true,{'b':3,'d':2},false]}", "/a/1/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'a':[{'b':3}]}"); + _assert("[true,[1]]", "/0", Inclusion.INCLUDE_ALL_AND_PATH, "[true]"); + _assert("[true,[1]]", "/1", Inclusion.INCLUDE_ALL_AND_PATH, "[[1]]"); + _assert("[true,[1,2,[true],3],0]", "/0", Inclusion.INCLUDE_ALL_AND_PATH, "[true]"); + _assert("[true,[1,2,[true],3],0]", "/1", Inclusion.INCLUDE_ALL_AND_PATH, "[[1,2,[true],3]]"); + + _assert("[true,[1,2,[true],3],0]", "/1/2", Inclusion.INCLUDE_ALL_AND_PATH, "[[[true]]]"); + _assert("[true,[1,2,[true],3],0]", "/1/2/0", Inclusion.INCLUDE_ALL_AND_PATH, "[[[true]]]"); + _assert("[true,[1,2,[true],3],0]", "/1/3/0", Inclusion.INCLUDE_ALL_AND_PATH, ""); } public void testArrayNestedWithoutPath() throws Exception { - _assert("{'a':[true,{'b':3,'d':2},false]}", "/a/1/b", false, "3"); - _assert("[true,[1,2,[true],3],0]", "/0", false, "true"); - _assert("[true,[1,2,[true],3],0]", "/1", false, + _assert("{'a':[true,{'b':3,'d':2},false]}", "/a/1/b", Inclusion.ONLY_INCLUDE_ALL, "3"); + _assert("[true,[1,2,[true],3],0]", "/0", Inclusion.ONLY_INCLUDE_ALL, "true"); + _assert("[true,[1,2,[true],3],0]", "/1", Inclusion.ONLY_INCLUDE_ALL, "[1,2,[true],3]"); - _assert("[true,[1,2,[true],3],0]", "/1/2", false, "[true]"); - _assert("[true,[1,2,[true],3],0]", "/1/2/0", false, "true"); - _assert("[true,[1,2,[true],3],0]", "/1/3/0", false, ""); + _assert("[true,[1,2,[true],3],0]", "/1/2", Inclusion.ONLY_INCLUDE_ALL, "[true]"); + _assert("[true,[1,2,[true],3],0]", "/1/2/0", Inclusion.ONLY_INCLUDE_ALL, "true"); + _assert("[true,[1,2,[true],3],0]", "/1/3/0", Inclusion.ONLY_INCLUDE_ALL, ""); } // final String SIMPLE_INPUT = aposToQuotes("{'a':1,'b':[1,2,3],'c':{'d':{'a':true}},'d':null}"); public void testArrayElementWithoutPath() throws Exception { - _assert(SIMPLE_INPUT, "/b", false, "[1,2,3]"); - _assert(SIMPLE_INPUT, "/b/1", false, "2"); - _assert(SIMPLE_INPUT, "/b/2", false, "3"); + _assert(SIMPLE_INPUT, "/b", Inclusion.ONLY_INCLUDE_ALL, "[1,2,3]"); + _assert(SIMPLE_INPUT, "/b/1", Inclusion.ONLY_INCLUDE_ALL, "2"); + _assert(SIMPLE_INPUT, "/b/2", Inclusion.ONLY_INCLUDE_ALL, "3"); - _assert(SIMPLE_INPUT, "/b/8", false, ""); + _assert(SIMPLE_INPUT, "/b/8", Inclusion.ONLY_INCLUDE_ALL, ""); // and then non-match - _assert(SIMPLE_INPUT, "/x", false, ""); + _assert(SIMPLE_INPUT, "/x", Inclusion.ONLY_INCLUDE_ALL, ""); } - private void _assert(String input, String pathExpr, boolean includeParent, String exp) + private void _assert(String input, String pathExpr, Inclusion tokenFilterInclusion, String exp) throws Exception { StringWriter w = new StringWriter(); @@ -96,7 +97,7 @@ private void _assert(String input, String pathExpr, boolean includeParent, Strin JsonGenerator g0 = JSON_F.createGenerator(w); FilteringGeneratorDelegate g = new FilteringGeneratorDelegate(g0, new JsonPointerBasedFilter(pathExpr), - includeParent, false); + tokenFilterInclusion, false); try { writeJsonDoc(JSON_F, input, g); 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 58ecca795d..86fa975902 100644 --- a/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerParserFilteringTest.java +++ b/src/test/java/com/fasterxml/jackson/core/filter/JsonPointerParserFilteringTest.java @@ -3,6 +3,7 @@ import java.io.StringWriter; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; public class JsonPointerParserFilteringTest extends com.fasterxml.jackson.core.BaseTest { @@ -14,55 +15,55 @@ public class JsonPointerParserFilteringTest extends com.fasterxml.jackson.core.B public void testSimplestWithPath() throws Exception { - _assert(SIMPLEST_INPUT, "/a", true, "{'a':1}"); - _assert(SIMPLEST_INPUT, "/b", true, "{'b':2}"); - _assert(SIMPLEST_INPUT, "/c", true, "{'c':3}"); - _assert(SIMPLEST_INPUT, "/c/0", true, ""); - _assert(SIMPLEST_INPUT, "/d", true, ""); + _assert(SIMPLEST_INPUT, "/a", Inclusion.INCLUDE_ALL_AND_PATH, "{'a':1}"); + _assert(SIMPLEST_INPUT, "/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':2}"); + _assert(SIMPLEST_INPUT, "/c", Inclusion.INCLUDE_ALL_AND_PATH, "{'c':3}"); + _assert(SIMPLEST_INPUT, "/c/0", Inclusion.INCLUDE_ALL_AND_PATH, ""); + _assert(SIMPLEST_INPUT, "/d", Inclusion.INCLUDE_ALL_AND_PATH, ""); } public void testSimplestNoPath() throws Exception { - _assert(SIMPLEST_INPUT, "/a", false, "1"); - _assert(SIMPLEST_INPUT, "/b", false, "2"); - _assert(SIMPLEST_INPUT, "/b/2", false, ""); - _assert(SIMPLEST_INPUT, "/c", false, "3"); - _assert(SIMPLEST_INPUT, "/d", false, ""); + _assert(SIMPLEST_INPUT, "/a", Inclusion.ONLY_INCLUDE_ALL, "1"); + _assert(SIMPLEST_INPUT, "/b", Inclusion.ONLY_INCLUDE_ALL, "2"); + _assert(SIMPLEST_INPUT, "/b/2", Inclusion.ONLY_INCLUDE_ALL, ""); + _assert(SIMPLEST_INPUT, "/c", Inclusion.ONLY_INCLUDE_ALL, "3"); + _assert(SIMPLEST_INPUT, "/d", Inclusion.ONLY_INCLUDE_ALL, ""); } public void testSimpleWithPath() throws Exception { - _assert(SIMPLE_INPUT, "/c", true, "{'c':{'d':{'a':true}}}"); - _assert(SIMPLE_INPUT, "/c/d", true, "{'c':{'d':{'a':true}}}"); - _assert(SIMPLE_INPUT, "/a", true, "{'a':1}"); - _assert(SIMPLE_INPUT, "/b", true, "{'b':[1,2,3]}"); - _assert(SIMPLE_INPUT, "/b/0", true, "{'b':[1]}"); - _assert(SIMPLE_INPUT, "/b/1", true, "{'b':[2]}"); - _assert(SIMPLE_INPUT, "/b/2", true, "{'b':[3]}"); - _assert(SIMPLE_INPUT, "/b/3", true, ""); + _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}}}"); + _assert(SIMPLE_INPUT, "/a", Inclusion.INCLUDE_ALL_AND_PATH, "{'a':1}"); + _assert(SIMPLE_INPUT, "/b", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[1,2,3]}"); + _assert(SIMPLE_INPUT, "/b/0", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[1]}"); + _assert(SIMPLE_INPUT, "/b/1", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[2]}"); + _assert(SIMPLE_INPUT, "/b/2", Inclusion.INCLUDE_ALL_AND_PATH, "{'b':[3]}"); + _assert(SIMPLE_INPUT, "/b/3", Inclusion.INCLUDE_ALL_AND_PATH, ""); } public void testSimpleNoPath() throws Exception { - _assert(SIMPLE_INPUT, "/c", false, "{'d':{'a':true}}"); + _assert(SIMPLE_INPUT, "/c", Inclusion.ONLY_INCLUDE_ALL, "{'d':{'a':true}}"); - _assert(SIMPLE_INPUT, "/c/d", false, "{'a':true}"); - _assert(SIMPLE_INPUT, "/a", false, "1"); - _assert(SIMPLE_INPUT, "/b", false, "[1,2,3]"); - _assert(SIMPLE_INPUT, "/b/0", false, "1"); - _assert(SIMPLE_INPUT, "/b/1", false, "2"); - _assert(SIMPLE_INPUT, "/b/2", false, "3"); - _assert(SIMPLE_INPUT, "/b/3", false, ""); + _assert(SIMPLE_INPUT, "/c/d", Inclusion.ONLY_INCLUDE_ALL, "{'a':true}"); + _assert(SIMPLE_INPUT, "/a", Inclusion.ONLY_INCLUDE_ALL, "1"); + _assert(SIMPLE_INPUT, "/b", Inclusion.ONLY_INCLUDE_ALL, "[1,2,3]"); + _assert(SIMPLE_INPUT, "/b/0", Inclusion.ONLY_INCLUDE_ALL, "1"); + _assert(SIMPLE_INPUT, "/b/1", Inclusion.ONLY_INCLUDE_ALL, "2"); + _assert(SIMPLE_INPUT, "/b/2", Inclusion.ONLY_INCLUDE_ALL, "3"); + _assert(SIMPLE_INPUT, "/b/3", Inclusion.ONLY_INCLUDE_ALL, ""); } @SuppressWarnings("resource") - void _assert(String input, String pathExpr, boolean includeParent, String exp) + void _assert(String input, String pathExpr, TokenFilter.Inclusion inclusion, String exp) throws Exception { JsonParser p0 = JSON_F.createParser(input); FilteringParserDelegate p = new FilteringParserDelegate(p0, new JsonPointerBasedFilter(pathExpr), - includeParent, false); + inclusion, false); StringWriter w = new StringWriter(); JsonGenerator g = JSON_F.createGenerator(w); diff --git a/src/test/java/com/fasterxml/jackson/core/json/async/AsyncTokenFilterTest.java b/src/test/java/com/fasterxml/jackson/core/json/async/AsyncTokenFilterTest.java index ded3a27cc6..33e77a194d 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/async/AsyncTokenFilterTest.java +++ b/src/test/java/com/fasterxml/jackson/core/json/async/AsyncTokenFilterTest.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.core.async.AsyncTestBase; import com.fasterxml.jackson.core.filter.FilteringParserDelegate; import com.fasterxml.jackson.core.filter.TokenFilter; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; // [core#462], [core#463] public class AsyncTokenFilterTest extends AsyncTestBase @@ -33,7 +34,7 @@ public void testFilteredNonBlockingParserAllContent() throws IOException { NonBlockingJsonParser nonBlockingParser = (NonBlockingJsonParser) JSON_F.createNonBlockingByteArrayParser(); FilteringParserDelegate filteredParser = new FilteringParserDelegate(nonBlockingParser, - TOKEN_FILTER, true, true); + TOKEN_FILTER, Inclusion.INCLUDE_ALL_AND_PATH, true); nonBlockingParser.feedInput(INPUT_BYTES, 0, INPUT_BYTES.length); int expectedIdx = 0; while (expectedIdx < EXPECTED_TOKENS.length) { @@ -54,7 +55,7 @@ public void testSkipChildrenFailOnSplit() throws IOException NonBlockingJsonParser nbParser = (NonBlockingJsonParser) JSON_F.createNonBlockingByteArrayParser(); @SuppressWarnings("resource") FilteringParserDelegate filteredParser = new FilteringParserDelegate(nbParser, - TOKEN_FILTER, true, true); + TOKEN_FILTER, Inclusion.INCLUDE_ALL_AND_PATH, true); nbParser.feedInput(INPUT_BYTES, 0, 5); assertToken(JsonToken.START_OBJECT, nbParser.nextToken()); diff --git a/src/test/java/com/fasterxml/jackson/core/write/UTF8GeneratorTest.java b/src/test/java/com/fasterxml/jackson/core/write/UTF8GeneratorTest.java index 7cd399af4b..f8f20f4d5e 100644 --- a/src/test/java/com/fasterxml/jackson/core/write/UTF8GeneratorTest.java +++ b/src/test/java/com/fasterxml/jackson/core/write/UTF8GeneratorTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.filter.FilteringGeneratorDelegate; import com.fasterxml.jackson.core.filter.JsonPointerBasedFilter; +import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.json.UTF8JsonGenerator; import com.fasterxml.jackson.core.util.BufferRecycler; @@ -74,7 +75,7 @@ public void testFilteringWithEscapedChars() throws Exception FilteringGeneratorDelegate gen = new FilteringGeneratorDelegate(g, new JsonPointerBasedFilter("/escapes"), - true, // includePath + Inclusion.INCLUDE_ALL_AND_PATH, false // multipleMatches );