Merge pull request #16017 from beiske/xcontent_exclude

Add option to exclude based on paths in XContent
This commit is contained in:
Konrad Beiske 2016-02-03 13:51:49 +01:00
commit 2c247e9d56
14 changed files with 994 additions and 177 deletions

View File

@ -41,13 +41,28 @@ public interface XContent {
/**
* Creates a new generator using the provided output stream.
*/
XContentGenerator createGenerator(OutputStream os) throws IOException;
default XContentGenerator createGenerator(OutputStream os) throws IOException {
return createGenerator(os, null, true);
}
/**
* Creates a new generator using the provided output stream and some filters.
* Creates a new generator using the provided output stream and some
* inclusive filters. Same as createGenerator(os, filters, true).
*/
XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException;
default XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException {
return createGenerator(os, filters, true);
}
/**
* Creates a new generator using the provided output stream and some
* filters.
*
* @param inclusive
* If true only paths matching a filter will be included in
* output. If false no path matching a filter will be included in
* output
*/
XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException;
/**
* Creates a parser over the provided string content.
*/
@ -77,4 +92,5 @@ public interface XContent {
* Creates a parser over the provided reader.
*/
XContentParser createParser(Reader reader) throws IOException;
}

View File

@ -83,6 +83,10 @@ public final class XContentBuilder implements BytesStream, Releasable {
return new XContentBuilder(xContent, new BytesStreamOutput(), filters);
}
public static XContentBuilder builder(XContent xContent, String[] filters, boolean inclusive) throws IOException {
return new XContentBuilder(xContent, new BytesStreamOutput(), filters, inclusive);
}
private XContentGenerator generator;
private final OutputStream bos;
@ -102,13 +106,25 @@ public final class XContentBuilder implements BytesStream, Releasable {
}
/**
* Constructs a new builder using the provided xcontent, an OutputStream and some filters. The
* filters are used to filter fields that won't be written to the OutputStream. Make sure
* to call {@link #close()} when the builder is done with.
* Constructs a new builder using the provided xcontent, an OutputStream and
* some filters. If filters are specified, only those values matching a
* filter will be written to the output stream. Make sure to call
* {@link #close()} when the builder is done with.
*/
public XContentBuilder(XContent xContent, OutputStream bos, String[] filters) throws IOException {
this(xContent, bos, filters, true);
}
/**
* Constructs a new builder using the provided xcontent, an OutputStream and
* some filters. If {@code filters} are specified and {@code inclusive} is
* true, only those values matching a filter will be written to the output
* stream. If {@code inclusive} is false, those matching will be excluded.
* Make sure to call {@link #close()} when the builder is done with.
*/
public XContentBuilder(XContent xContent, OutputStream bos, String[] filters, boolean inclusive) throws IOException {
this.bos = bos;
this.generator = xContent.createGenerator(bos, filters);
this.generator = xContent.createGenerator(bos, filters, inclusive);
}
public XContentBuilder fieldCaseConversion(FieldCaseConversion fieldCaseConversion) {

View File

@ -121,5 +121,6 @@ public interface XContentGenerator extends Closeable {
void flush() throws IOException;
@Override
void close() throws IOException;
}

View File

@ -67,13 +67,8 @@ public class CborXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os) throws IOException {
return new CborXContentGenerator(cborFactory.createGenerator(os, JsonEncoding.UTF8), os);
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException {
return new CborXContentGenerator(cborFactory.createGenerator(os, JsonEncoding.UTF8), os, filters);
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new CborXContentGenerator(cborFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
}
@Override
@ -108,4 +103,5 @@ public class CborXContent implements XContent {
public XContentParser createParser(Reader reader) throws IOException {
return new CborXContentParser(cborFactory.createParser(reader));
}
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.xcontent.cbor;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContentGenerator;
@ -31,7 +32,11 @@ import java.io.OutputStream;
public class CborXContentGenerator extends JsonXContentGenerator {
public CborXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
super(jsonGenerator, os, filters);
this(jsonGenerator, os, filters, true);
}
public CborXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
super(jsonGenerator, os, filters, inclusive);
}
@Override

View File

@ -71,13 +71,8 @@ public class JsonXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os) throws IOException {
return new JsonXContentGenerator(jsonFactory.createGenerator(os, JsonEncoding.UTF8), os);
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException {
return new JsonXContentGenerator(jsonFactory.createGenerator(os, JsonEncoding.UTF8), os, filters);
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new JsonXContentGenerator(jsonFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
}
@Override

View File

@ -72,6 +72,10 @@ public class JsonXContentGenerator implements XContentGenerator {
private boolean prettyPrint = false;
public JsonXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
this(jsonGenerator, os, filters, true);
}
public JsonXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
if (jsonGenerator instanceof GeneratorBase) {
this.base = (GeneratorBase) jsonGenerator;
} else {
@ -82,7 +86,8 @@ public class JsonXContentGenerator implements XContentGenerator {
this.generator = jsonGenerator;
this.filter = null;
} else {
this.filter = new FilteringGeneratorDelegate(jsonGenerator, new FilterPathBasedFilter(filters), true, true);
this.filter = new FilteringGeneratorDelegate(jsonGenerator,
new FilterPathBasedFilter(filters, inclusive), true, true);
this.generator = this.filter;
}
@ -375,6 +380,7 @@ public class JsonXContentGenerator implements XContentGenerator {
}
}
@Override
public final void writeRawValue(BytesReference content) throws IOException {
XContentType contentType = XContentFactory.xContentType(content);
if (contentType == null) {
@ -450,4 +456,5 @@ public class JsonXContentGenerator implements XContentGenerator {
}
generator.close();
}
}

View File

@ -68,13 +68,8 @@ public class SmileXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os) throws IOException {
return new SmileXContentGenerator(smileFactory.createGenerator(os, JsonEncoding.UTF8), os);
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException {
return new SmileXContentGenerator(smileFactory.createGenerator(os, JsonEncoding.UTF8), os, filters);
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new SmileXContentGenerator(smileFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
}
@Override

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.xcontent.smile;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContentGenerator;
@ -31,7 +32,11 @@ import java.io.OutputStream;
public class SmileXContentGenerator extends JsonXContentGenerator {
public SmileXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
super(jsonGenerator, os, filters);
this(jsonGenerator, os, filters, true);
}
public SmileXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
super(jsonGenerator, os, filters, inclusive);
}
@Override

View File

@ -31,25 +31,30 @@ public class FilterPathBasedFilter extends TokenFilter {
* Marker value that should be used to indicate that a property name
* or value matches one of the filter paths.
*/
private static final TokenFilter MATCHING = new TokenFilter(){};
private static final TokenFilter MATCHING = new TokenFilter() {
};
/**
* Marker value that should be used to indicate that none of the
* property names/values matches one of the filter paths.
*/
private static final TokenFilter NO_MATCHING = new TokenFilter(){};
private static final TokenFilter NO_MATCHING = new TokenFilter() {
};
private final FilterPath[] filters;
public FilterPathBasedFilter(FilterPath[] filters) {
private final boolean inclusive;
public FilterPathBasedFilter(FilterPath[] filters, boolean inclusive) {
if (CollectionUtils.isEmpty(filters)) {
throw new IllegalArgumentException("filters cannot be null or empty");
}
this.inclusive = inclusive;
this.filters = filters;
}
public FilterPathBasedFilter(String[] filters) {
this(FilterPath.compile(filters));
public FilterPathBasedFilter(String[] filters, boolean inclusive) {
this(FilterPath.compile(filters), inclusive);
}
/**
@ -77,31 +82,32 @@ public class FilterPathBasedFilter extends TokenFilter {
}
if ((nextFilters != null) && (nextFilters.isEmpty() == false)) {
return new FilterPathBasedFilter(nextFilters.toArray(new FilterPath[nextFilters.size()]));
return new FilterPathBasedFilter(nextFilters.toArray(new FilterPath[nextFilters.size()]), inclusive);
}
}
return NO_MATCHING;
}
@Override
public TokenFilter includeProperty(String name) {
TokenFilter include = evaluate(name, filters);
if (include == MATCHING) {
return TokenFilter.INCLUDE_ALL;
TokenFilter filter = evaluate(name, filters);
if (filter == MATCHING) {
return inclusive ? TokenFilter.INCLUDE_ALL : null;
}
if (include == NO_MATCHING) {
return null;
if (filter == NO_MATCHING) {
return inclusive ? null : TokenFilter.INCLUDE_ALL;
}
return include;
return filter;
}
@Override
protected boolean _includeScalar() {
for (FilterPath filter : filters) {
if (filter.matches()) {
return true;
return inclusive;
}
}
return false;
return !inclusive;
}
}

View File

@ -66,13 +66,8 @@ public class YamlXContent implements XContent {
}
@Override
public XContentGenerator createGenerator(OutputStream os) throws IOException {
return new YamlXContentGenerator(yamlFactory.createGenerator(os, JsonEncoding.UTF8), os);
}
@Override
public XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException {
return new YamlXContentGenerator(yamlFactory.createGenerator(os, JsonEncoding.UTF8), os, filters);
public XContentGenerator createGenerator(OutputStream os, String[] filters, boolean inclusive) throws IOException {
return new YamlXContentGenerator(yamlFactory.createGenerator(os, JsonEncoding.UTF8), os, filters, inclusive);
}
@Override

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.xcontent.yaml;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContentGenerator;
@ -31,7 +32,11 @@ import java.io.OutputStream;
public class YamlXContentGenerator extends JsonXContentGenerator {
public YamlXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String... filters) {
super(jsonGenerator, os, filters);
this(jsonGenerator, os, filters, true);
}
public YamlXContentGenerator(JsonGenerator jsonGenerator, OutputStream os, String[] filters, boolean inclusive) {
super(jsonGenerator, os, filters, inclusive);
}
@Override

View File

@ -31,59 +31,111 @@ public class FilterPathGeneratorFilteringTests extends ESTestCase {
private final JsonFactory JSON_FACTORY = new JsonFactory();
public void testFilters() throws Exception {
public void testInclusiveFilters() throws Exception {
final String SAMPLE = "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}";
assertResult(SAMPLE, "a", "{'a':0}");
assertResult(SAMPLE, "b", "{'b':true}");
assertResult(SAMPLE, "c", "{'c':'c_value'}");
assertResult(SAMPLE, "d", "{'d':[0,1,2]}");
assertResult(SAMPLE, "e", "{'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "z", "");
assertResult(SAMPLE, "a", true, "{'a':0}");
assertResult(SAMPLE, "b", true, "{'b':true}");
assertResult(SAMPLE, "c", true, "{'c':'c_value'}");
assertResult(SAMPLE, "d", true, "{'d':[0,1,2]}");
assertResult(SAMPLE, "e", true, "{'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "z", true, "");
assertResult(SAMPLE, "e.f1", "{'e':[{'f1':'f1_value'}]}");
assertResult(SAMPLE, "e.f2", "{'e':[{'f2':'f2_value'}]}");
assertResult(SAMPLE, "e.f*", "{'e':[{'f1':'f1_value','f2':'f2_value'}]}");
assertResult(SAMPLE, "e.*2", "{'e':[{'f2':'f2_value'},{'g2':'g2_value'}]}");
assertResult(SAMPLE, "e.f1", true, "{'e':[{'f1':'f1_value'}]}");
assertResult(SAMPLE, "e.f2", true, "{'e':[{'f2':'f2_value'}]}");
assertResult(SAMPLE, "e.f*", true, "{'e':[{'f1':'f1_value','f2':'f2_value'}]}");
assertResult(SAMPLE, "e.*2", true, "{'e':[{'f2':'f2_value'},{'g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.k", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.k.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.k", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.k.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i.j", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.*", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i.j", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.*", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i.j.k", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j.k", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.*.k", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.*", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i.j.k", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j.k", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.*.k", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.*", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i.j.k.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j.k.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.*.k.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.*.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.k.*", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "*.i.j.k.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j.k.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.*.k.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.*.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i.j.k.*", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j.*.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "**.l", "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.*.j.*.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "**.l", true, "{'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "**.*2", "{'e':[{'f2':'f2_value'},{'g2':'g2_value'}]}");
assertResult(SAMPLE, "**.*2", true, "{'e':[{'f2':'f2_value'},{'g2':'g2_value'}]}");
}
public void testFiltersWithDots() throws Exception {
assertResult("{'a':0,'b.c':'value','b':{'c':'c_value'}}", "b.c", "{'b':{'c':'c_value'}}");
assertResult("{'a':0,'b.c':'value','b':{'c':'c_value'}}", "b\\.c", "{'b.c':'value'}");
public void testExclusiveFilters() throws Exception {
final String SAMPLE = "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}";
assertResult(SAMPLE, "a", false, "{'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "b", false, "{'a':0,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "c", false, "{'a':0,'b':true,'d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "d", false, "{'a':0,'b':true,'c':'c_value','e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "e", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "z", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "e.f1", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "e.f2", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value'},{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "e.f*", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'g1':'g1_value','g2':'g2_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "e.*2", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value'},{'g1':'g1_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
assertResult(SAMPLE, "h.i", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.j", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.j.k", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.j.k.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.*", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "*.i", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "*.i.j", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.*.j", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.*", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "*.i.j.k", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.*.j.k", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.*.k", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.j.*", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "*.i.j.k.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.*.j.k.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.*.k.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.j.*.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.i.j.k.*", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "h.*.j.*.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "**.l", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value','f2':'f2_value'},{'g1':'g1_value','g2':'g2_value'}]}");
assertResult(SAMPLE, "**.*2", false, "{'a':0,'b':true,'c':'c_value','d':[0,1,2],'e':[{'f1':'f1_value'},{'g1':'g1_value'}],'h':{'i':{'j':{'k':{'l':'l_value'}}}}}");
}
private void assertResult(String input, String filter, String expected) throws Exception {
public void testInclusiveFiltersWithDots() throws Exception {
assertResult("{'a':0,'b.c':'value','b':{'c':'c_value'}}", "b.c", true, "{'b':{'c':'c_value'}}");
assertResult("{'a':0,'b.c':'value','b':{'c':'c_value'}}", "b\\.c", true, "{'b.c':'value'}");
}
public void testExclusiveFiltersWithDots() throws Exception {
assertResult("{'a':0,'b.c':'value','b':{'c':'c_value'}}", "b.c", false, "{'a':0,'b.c':'value'}");
assertResult("{'a':0,'b.c':'value','b':{'c':'c_value'}}", "b\\.c", false, "{'a':0,'b':{'c':'c_value'}}");
}
private void assertResult(String input, String filter, boolean inclusive, String expected) throws Exception {
try (BytesStreamOutput os = new BytesStreamOutput()) {
try (FilteringGeneratorDelegate generator = new FilteringGeneratorDelegate(JSON_FACTORY.createGenerator(os), new FilterPathBasedFilter(new String[]{filter}), true, true)) {
try (FilteringGeneratorDelegate generator = new FilteringGeneratorDelegate(JSON_FACTORY.createGenerator(os),
new FilterPathBasedFilter(new String[] { filter }, inclusive), true, true)) {
try (JsonParser parser = JSON_FACTORY.createParser(replaceQuotes(input))) {
while (parser.nextToken() != null) {
generator.copyCurrentStructure(parser);