From 3bb1e00e90a5297fcfd05e7a168f6a36557a62bf Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Tue, 6 Mar 2012 22:10:37 +0100 Subject: [PATCH] Added generic type in Filter. --- .../java/com/jayway/jsonpath/Criteria.java | 86 +++++- .../main/java/com/jayway/jsonpath/Filter.java | 83 +++-- .../jsonpath/IndefinitePathException.java | 19 +- .../jsonpath/InvalidCriteriaException.java | 19 +- .../jsonpath/InvalidModelPathException.java | 19 +- .../java/com/jayway/jsonpath/JsonModel.java | 60 ++-- .../java/com/jayway/jsonpath/JsonPath.java | 7 - .../internal/filter/ArrayQueryFilter.java | 22 +- .../jsonpath/spi/JsonProviderFactory.java | 19 +- .../jayway/jsonpath/spi/MappingProvider.java | 19 +- .../jsonpath/spi/MappingProviderFactory.java | 19 +- .../java/com/jayway/jsonpath/FilterTest.java | 292 +++++++++++++++--- .../com/jayway/jsonpath/JsonModelTest.java | 2 +- .../jayway/jsonpath/JsonPathFilterTest.java | 35 ++- 14 files changed, 533 insertions(+), 168 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java index fba61101..fa9871ab 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java @@ -1,16 +1,28 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath; -import javax.lang.model.type.NullType; import java.util.*; import java.util.regex.Pattern; import static java.util.Arrays.asList; +import static org.apache.commons.lang.Validate.notEmpty; +import static org.apache.commons.lang.Validate.notNull; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/5/12 - * Time: 12:08 PM + * @author Kalle Stenflo */ public class Criteria { @@ -30,12 +42,14 @@ public class Criteria { public Criteria(String key) { + notEmpty(key, "key can not be null or empty"); this.criteriaChain = new ArrayList(); this.criteriaChain.add(this); this.key = key; } protected Criteria(List criteriaChain, String key) { + notEmpty(key, "key can not be null or empty"); this.criteriaChain = criteriaChain; this.criteriaChain.add(this); this.key = key; @@ -77,6 +91,10 @@ public class Criteria { expectedVal = this.criteria.get(key); if ("$gt".equals(key)) { + if (expectedVal == null || actualVal == null) { + return false; + } + Number expectedNumber = (Number) expectedVal; Number actualNumber = (Number) actualVal; @@ -84,6 +102,10 @@ public class Criteria { } else if ("$gte".equals(key)) { + if (expectedVal == null || actualVal == null) { + return false; + } + Number expectedNumber = (Number) expectedVal; Number actualNumber = (Number) actualVal; @@ -91,6 +113,10 @@ public class Criteria { } else if ("$lt".equals(key)) { + if (expectedVal == null || actualVal == null) { + return false; + } + Number expectedNumber = (Number) expectedVal; Number actualNumber = (Number) actualVal; @@ -98,12 +124,22 @@ public class Criteria { } else if ("$lte".equals(key)) { + if (expectedVal == null || actualVal == null) { + return false; + } + Number expectedNumber = (Number) expectedVal; Number actualNumber = (Number) actualVal; return (actualNumber.doubleValue() <= expectedNumber.doubleValue()); } else if ("$ne".equals(key)) { + if (expectedVal == null && actualVal == null) { + return false; + } + if (expectedVal == null) { + return !(actualVal == null); + } return !expectedVal.equals(actualVal); @@ -142,22 +178,33 @@ public class Criteria { } else if ("$type".equals(key)) { Class exp = (Class) expectedVal; - Class act = map.containsKey(this.key) ? map.get(this.key).getClass() : NullType.class; - - return act.equals(exp); + Class act = null; + if (map.containsKey(this.key)) { + Object actVal = map.get(this.key); + if (actVal != null) { + act = actVal.getClass(); + } + } + if (act == null) { + return false; + } else { + return act.equals(exp); + } } else if ("$regex".equals(key)) { Pattern exp = (Pattern) expectedVal; String act = (String) actualVal; - + if(act == null){ + return false; + } return exp.matcher(act).matches(); } else if ("$or".equals(key)) { - System.out.println("auch"); + throw new UnsupportedOperationException("Or not supported yet"); } @@ -167,7 +214,12 @@ public class Criteria { } } if (isValue != NOT_SET) { - return isValue.equals(map.get(key)); + + if (isValue == null) { + return (map.get(key) == null); + } else { + return isValue.equals(map.get(key)); + } } else { } @@ -212,6 +264,15 @@ public class Criteria { this.isValue = o; return this; } + /** + * Creates a criterion using equality + * + * @param o + * @return + */ + public Criteria eq(Object o) { + return is(o); + } /** * Creates a criterion using the $ne operator @@ -304,12 +365,12 @@ public class Criteria { } public Criteria nin(Collection o) { + notNull(o, "collection can not be null"); criteria.put("$nin", o); return this; } - /** * Creates a criterion using the $all operator * @@ -430,5 +491,4 @@ public class Criteria { } - } diff --git a/json-path/src/main/java/com/jayway/jsonpath/Filter.java b/json-path/src/main/java/com/jayway/jsonpath/Filter.java index bbc883ee..35f5b42a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Filter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Filter.java @@ -1,23 +1,46 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath; import java.util.*; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/5/12 - * Time: 5:31 PM + * A filter is used to filter the content of a JSON array in a JSONPath. + * + * Sample + * + * + * String doc = {"items": [{"name" : "john"}, {"name": "bob"}]} + * + * List names = JsonPath.read(doc, "$items[?].name", Filter.filter(Criteria.where("name").is("john")); + * + * + * @See Criteria + * + * @author Kalle Stenflo */ -public abstract class Filter { - - public abstract boolean apply(Map map); - - public List doFilter(List> filterItems) { - List result = new ArrayList(); - - for (Map filterItem : filterItems) { +public abstract class Filter { - if(apply(filterItem)){ + public static Filter filter(Criteria criteria) { + return new MapFilter(criteria); + } + + public List doFilter(List filterItems) { + List result = new ArrayList(); + for (T filterItem : filterItems) { + if (accept(filterItem)) { result.add(filterItem); } } @@ -25,9 +48,9 @@ public abstract class Filter { } - public static Filter filter(Criteria criteria) { - return new MapFilter(criteria); - } + public abstract boolean accept(T obj); + + public abstract Filter addCriteria(Criteria criteria); // -------------------------------------------------------- @@ -35,7 +58,21 @@ public abstract class Filter { // Default filter implementation // // -------------------------------------------------------- - private static class MapFilter extends Filter { + public static abstract class FilterAdapter extends Filter { + + @Override + public boolean accept(T obj){ + return false; + } + + @Override + public Filter addCriteria(Criteria criteria) { + throw new UnsupportedOperationException("can not add criteria to a FilterAdapter."); + } + } + + + private static class MapFilter extends FilterAdapter> { private HashMap criteria = new LinkedHashMap(); @@ -54,23 +91,17 @@ public abstract class Filter { return this; } - protected List getCriteria() { - return new ArrayList(this.criteria.values()); - } - @Override - public boolean apply(Map map) { - - for (Criteria criterion : getCriteria()) { + public boolean accept(Map map) { + for (Criteria criterion : this.criteria.values()) { if (!criterion.apply(map)) { return false; } } - return true; - } + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/IndefinitePathException.java b/json-path/src/main/java/com/jayway/jsonpath/IndefinitePathException.java index 8858f74b..2730a5d6 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/IndefinitePathException.java +++ b/json-path/src/main/java/com/jayway/jsonpath/IndefinitePathException.java @@ -1,10 +1,21 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/4/12 - * Time: 7:15 PM + * @author Kalle Stenflo */ @SuppressWarnings("serial") public class IndefinitePathException extends RuntimeException { diff --git a/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java b/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java index da6ed553..5bc3fc48 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java +++ b/json-path/src/main/java/com/jayway/jsonpath/InvalidCriteriaException.java @@ -1,10 +1,21 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/5/12 - * Time: 12:20 PM + * @author Kalle Stenflo */ public class InvalidCriteriaException extends RuntimeException{ public InvalidCriteriaException() { diff --git a/json-path/src/main/java/com/jayway/jsonpath/InvalidModelPathException.java b/json-path/src/main/java/com/jayway/jsonpath/InvalidModelPathException.java index 6c68ceb5..25c848d8 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/InvalidModelPathException.java +++ b/json-path/src/main/java/com/jayway/jsonpath/InvalidModelPathException.java @@ -1,10 +1,21 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/4/12 - * Time: 2:38 PM + * @author Kalle Stenflo */ @SuppressWarnings("serial") public class InvalidModelPathException extends RuntimeException { diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonModel.java b/json-path/src/main/java/com/jayway/jsonpath/JsonModel.java index 3de3d07c..2ce7012a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonModel.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonModel.java @@ -38,6 +38,7 @@ import static org.apache.commons.lang.Validate.notNull; public class JsonModel { private Object jsonObject; + private JsonProvider jsonProvider; // -------------------------------------------------------- // @@ -45,13 +46,11 @@ public class JsonModel { // // -------------------------------------------------------- - /** - * Creates a new JsonModel - * - * @param json json string - */ - public JsonModel(String json) { - this(JsonProviderFactory.getInstance().parse(json)); + private JsonModel(String jsonObject, JsonProvider jsonProvider) { + notNull(jsonObject, "json can not be null"); + + this.jsonProvider = jsonProvider; + this.jsonObject = jsonProvider.parse(jsonObject); } /** @@ -60,13 +59,13 @@ public class JsonModel { * * @param jsonObject the json object */ - private JsonModel(Object jsonObject) { + private JsonModel(Object jsonObject, JsonProvider jsonProvider) { notNull(jsonObject, "json can not be null"); if (!(jsonObject instanceof Map) && !(jsonObject instanceof List)) { throw new IllegalArgumentException("Invalid container object"); } - + this.jsonProvider = jsonProvider; this.jsonObject = jsonObject; } @@ -75,10 +74,10 @@ public class JsonModel { * * @param jsonInputStream the input stream */ - private JsonModel(InputStream jsonInputStream) { + private JsonModel(InputStream jsonInputStream, JsonProvider jsonProvider) { notNull(jsonInputStream, "jsonInputStream can not be null"); - - this.jsonObject = JsonProviderFactory.getInstance().parse(jsonInputStream); + this.jsonProvider = jsonProvider; + this.jsonObject = jsonProvider.parse(jsonInputStream); } /** @@ -87,13 +86,14 @@ public class JsonModel { * @param jsonURL the URL to read * @throws IOException */ - private JsonModel(URL jsonURL) throws IOException { + private JsonModel(URL jsonURL, JsonProvider jsonProvider) throws IOException { notNull(jsonURL, "jsonURL can not be null"); InputStream jsonInputStream = null; try { jsonInputStream = jsonURL.openStream(); - this.jsonObject = JsonProviderFactory.getInstance().parse(jsonInputStream); + this.jsonObject = jsonProvider.parse(jsonInputStream); + this.jsonProvider = jsonProvider; } finally { IOUtils.closeQuietly(jsonInputStream); } @@ -160,18 +160,18 @@ public class JsonModel { // JSON extractors // // -------------------------------------------------------- - public String toJson() { - return JsonProviderFactory.getInstance().toJson(jsonObject); + public String getJson() { + return jsonProvider.toJson(jsonObject); } - public String toJson(String jsonPath) { - return toJson(JsonPath.compile(jsonPath)); + public String getJson(String jsonPath, Filter... filters) { + return getJson(JsonPath.compile(jsonPath, filters)); } - public String toJson(JsonPath jsonPath) { + public String getJson(JsonPath jsonPath) { notNull(jsonPath, "jsonPath can not be null"); - return JsonProviderFactory.getInstance().toJson(get(jsonPath)); + return jsonProvider.toJson(get(jsonPath)); } // -------------------------------------------------------- @@ -180,8 +180,8 @@ public class JsonModel { // // -------------------------------------------------------- - public JsonModel getModel(String jsonPath) { - return getModel(JsonPath.compile(jsonPath)); + public JsonModel getModel(String jsonPath, Filter... filters) { + return getModel(JsonPath.compile(jsonPath, filters)); } public JsonModel getModel(JsonPath jsonPath) { @@ -193,7 +193,7 @@ public class JsonModel { throw new InvalidModelPathException("The path " + jsonPath.getPath() + " returned an invalid model " + (subModel != null ? subModel.getClass() : "null")); } - return new JsonModel(subModel); + return new JsonModel(subModel, this.jsonProvider); } // -------------------------------------------------------- @@ -205,7 +205,7 @@ public class JsonModel { return map(JsonPath.compile(jsonPath)); } - public MappingModelReader map(final JsonPath jsonPath) { + public MappingModelReader map(JsonPath jsonPath) { notNull(jsonPath, "jsonPath can not be null"); return new DefaultMappingModelReader(JsonModel.this.get(jsonPath)); @@ -219,25 +219,25 @@ public class JsonModel { public static JsonModel create(String json) { notEmpty(json, "json can not be null or empty"); - return new JsonModel(json); + return new JsonModel(json, JsonProviderFactory.getInstance()); } public static JsonModel create(Object jsonObject) { notNull(jsonObject, "jsonObject can not be null"); - return new JsonModel(jsonObject); + return new JsonModel(jsonObject, JsonProviderFactory.getInstance()); } public static JsonModel create(URL url) throws IOException { notNull(url, "url can not be null"); - return new JsonModel(url); + return new JsonModel(url, JsonProviderFactory.getInstance()); } public static JsonModel create(InputStream jsonInputStream) throws IOException { notNull(jsonInputStream, "jsonInputStream can not be null"); - return new JsonModel(jsonInputStream); + return new JsonModel(jsonInputStream, JsonProviderFactory.getInstance()); } // -------------------------------------------------------- @@ -456,9 +456,5 @@ public class JsonModel { public T to(Class targetClass) { return MappingProviderFactory.getInstance().convertValue(model, targetClass); } - - } - - } diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java index 0292b069..d5f6ff63 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -97,16 +97,9 @@ public class JsonPath { private static Pattern DEFINITE_PATH_PATTERN = Pattern.compile(".*(\\.\\.|\\*|\\[[\\\\/]|\\?|,|:\\s?\\]|\\[\\s?:|>|\\(|<|=|\\+).*"); - private static final Filter[] NO_FILTERS = new Filter[0]; - private PathTokenizer tokenizer; private LinkedList filters; - - private JsonPath(String jsonPath) { - this(jsonPath, new Filter[0]); - } - public JsonPath(String jsonPath, Filter[] filters) { if (jsonPath == null || jsonPath.trim().isEmpty() || diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayQueryFilter.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayQueryFilter.java index af772029..19beb88c 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayQueryFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayQueryFilter.java @@ -1,3 +1,17 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath.internal.filter; import com.jayway.jsonpath.Filter; @@ -8,10 +22,7 @@ import java.util.List; import java.util.Map; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/5/12 - * Time: 4:41 PM + * @author Kalle Stenflo */ public class ArrayQueryFilter extends PathTokenFilter { @@ -24,7 +35,8 @@ public class ArrayQueryFilter extends PathTokenFilter { Filter filter = filters.poll(); - return filter.doFilter((List>) obj); + return filter.doFilter((List)obj); + } @Override diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/JsonProviderFactory.java b/json-path/src/main/java/com/jayway/jsonpath/spi/JsonProviderFactory.java index e6fb0b43..ad8ef861 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/JsonProviderFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/JsonProviderFactory.java @@ -1,12 +1,23 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath.spi; import com.jayway.jsonpath.spi.impl.JsonSmartJsonProvider; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/2/12 - * Time: 9:45 PM + * @author Kalle Stenflo */ public abstract class JsonProviderFactory { diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProvider.java index e5ab7f0c..fda7f807 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProvider.java @@ -1,12 +1,23 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath.spi; import java.util.Collection; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/5/12 - * Time: 11:03 AM + * @author Kalle Stenflo */ public interface MappingProvider { diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProviderFactory.java b/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProviderFactory.java index 91019c8b..05ebed2a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProviderFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/MappingProviderFactory.java @@ -1,12 +1,23 @@ +/* + * Copyright 2011 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.jayway.jsonpath.spi; import com.jayway.jsonpath.spi.impl.JacksonProvider; /** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 3/5/12 - * Time: 11:03 AM + * @author Kalle Stenflo */ public class MappingProviderFactory { diff --git a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java index f058f62e..d6ad5164 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java @@ -2,13 +2,16 @@ package com.jayway.jsonpath; import org.junit.Test; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; import static com.jayway.jsonpath.Criteria.where; import static com.jayway.jsonpath.Filter.filter; import static java.util.Arrays.asList; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -56,29 +59,115 @@ public class FilterTest { "}"; + //------------------------------------------------- + // + // Single filter tests + // + //------------------------------------------------- @Test - public void a_single_is_filter_can_be_built_and_applied() throws Exception { - Map check = JsonPath.read(DOCUMENT, "store.book[0]"); - Filter filter = Filter.filter(Criteria.where("category").is("reference")); - assertTrue(filter.apply(check)); + public void is_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("foo", "foo"); + check.put("bar", null); + + assertTrue(filter(where("bar").is(null)).accept(check)); + assertTrue(filter(where("foo").is("foo")).accept(check)); + assertFalse(filter(where("foo").is("xxx")).accept(check)); + assertFalse(filter(where("bar").is("xxx")).accept(check)); } @Test - public void multiple_filters_can_be_built_and_applied() throws Exception { - Map check = JsonPath.read(DOCUMENT, "store.book[0]"); - - Filter filter = Filter.filter(Criteria - .where("category").is("reference") - .and("author").is("Nigel Rees") - .and("price").gt(8) - .and("price").gte(8) - .and("price").lt(10) - .and("price").lte(10) - .and("title").ne("is not") - .and("title").in("is not", "Sayings of the Century") - .and("title").nin("is not this", "is not that") - ); - assertTrue(filter.apply(check)); + public void ne_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("foo", "foo"); + check.put("bar", null); + + assertTrue(filter(where("foo").ne(null)).accept(check)); + assertTrue(filter(where("foo").ne("not foo")).accept(check)); + assertFalse(filter(where("foo").ne("foo")).accept(check)); + assertFalse(filter(where("bar").ne(null)).accept(check)); + } + + @Test + public void gt_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("foo", 12.5D); + check.put("foo_null", null); + + assertTrue(filter(where("foo").gt(12D)).accept(check)); + assertFalse(filter(where("foo").gt(null)).accept(check)); + assertFalse(filter(where("foo").gt(20D)).accept(check)); + assertFalse(filter(where("foo_null").gt(20D)).accept(check)); + } + + @Test + public void gte_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("foo", 12.5D); + check.put("foo_null", null); + + assertTrue(filter(where("foo").gte(12D)).accept(check)); + assertTrue(filter(where("foo").gte(12.5D)).accept(check)); + assertFalse(filter(where("foo").gte(null)).accept(check)); + assertFalse(filter(where("foo").gte(20D)).accept(check)); + assertFalse(filter(where("foo_null").gte(20D)).accept(check)); + } + + @Test + public void lt_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("foo", 10.5D); + check.put("foo_null", null); + + assertTrue(filter(where("foo").lt(12D)).accept(check)); + assertFalse(filter(where("foo").lt(null)).accept(check)); + assertFalse(filter(where("foo").lt(5D)).accept(check)); + assertFalse(filter(where("foo_null").lt(5D)).accept(check)); + } + + @Test + public void lte_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("foo", 12.5D); + check.put("foo_null", null); + + assertTrue(filter(where("foo").lt(13D)).accept(check)); + assertFalse(filter(where("foo").lt(null)).accept(check)); + assertFalse(filter(where("foo").lt(5D)).accept(check)); + assertFalse(filter(where("foo_null").lt(5D)).accept(check)); + } + + @Test + public void in_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("item", 3); + check.put("null_item", null); + + assertTrue(filter(where("item").in(1, 2, 3)).accept(check)); + assertTrue(filter(where("item").in(asList(1, 2, 3))).accept(check)); + assertFalse(filter(where("item").in(4, 5, 6)).accept(check)); + assertFalse(filter(where("item").in(asList(4, 5, 6))).accept(check)); + assertFalse(filter(where("item").in(asList('A'))).accept(check)); + assertFalse(filter(where("item").in(asList((Object) null))).accept(check)); + + assertTrue(filter(where("null_item").in((Object) null)).accept(check)); + assertFalse(filter(where("null_item").in(1, 2, 3)).accept(check)); + } + + @Test + public void nin_filters_evaluates() throws Exception { + Map check = new HashMap(); + check.put("item", 3); + check.put("null_item", null); + + assertTrue(filter(where("item").nin(4, 5)).accept(check)); + assertTrue(filter(where("item").nin(asList(4, 5))).accept(check)); + assertTrue(filter(where("item").nin(asList('A'))).accept(check)); + assertTrue(filter(where("null_item").nin(1, 2, 3)).accept(check)); + assertTrue(filter(where("item").nin(asList((Object) null))).accept(check)); + + assertFalse(filter(where("item").nin(3)).accept(check)); + assertFalse(filter(where("item").nin(asList(3))).accept(check)); } @Test @@ -86,77 +175,184 @@ public class FilterTest { Map check = new HashMap(); check.put("items", asList(1, 2, 3)); - - assertTrue(filter(where("items").all(1, 2, 3)).apply(check)); - assertFalse(filter(where("items").all(1, 2, 3, 4)).apply(check)); + assertTrue(filter(where("items").all(1, 2, 3)).accept(check)); + assertFalse(filter(where("items").all(1, 2, 3, 4)).accept(check)); } @Test public void size_filters_evaluates() throws Exception { Map check = new HashMap(); check.put("items", asList(1, 2, 3)); + check.put("items_empty", Collections.emptyList()); - - assertTrue(filter(where("items").size(3)).apply(check)); - assertFalse(filter(where("items").size(2)).apply(check)); + assertTrue(filter(where("items").size(3)).accept(check)); + assertTrue(filter(where("items_empty").size(0)).accept(check)); + assertFalse(filter(where("items").size(2)).accept(check)); } @Test public void exists_filters_evaluates() throws Exception { Map check = new HashMap(); check.put("foo", "foo"); + check.put("foo_null", null); + assertTrue(filter(where("foo").exists(true)).accept(check)); + assertFalse(filter(where("foo").exists(false)).accept(check)); - assertTrue(filter(where("foo").exists(true)).apply(check)); - assertFalse(filter(where("foo").exists(false)).apply(check)); + assertTrue(filter(where("foo_null").exists(true)).accept(check)); + assertFalse(filter(where("foo_null").exists(false)).accept(check)); - assertTrue(filter(where("bar").exists(false)).apply(check)); - assertFalse(filter(where("bar").exists(true)).apply(check)); + assertTrue(filter(where("bar").exists(false)).accept(check)); + assertFalse(filter(where("bar").exists(true)).accept(check)); } @Test public void type_filters_evaluates() throws Exception { Map check = new HashMap(); check.put("string", "foo"); + check.put("string_null", null); check.put("int", 1); check.put("long", 1L); check.put("double", 1.12D); + assertFalse(filter(where("string_null").type(String.class)).accept(check)); + assertTrue(filter(where("string").type(String.class)).accept(check)); + assertFalse(filter(where("string").type(Number.class)).accept(check)); - assertTrue(filter(where("string").type(String.class)).apply(check)); - assertFalse(filter(where("string").type(Number.class)).apply(check)); - - assertTrue(filter(where("int").type(Integer.class)).apply(check)); - assertFalse(filter(where("int").type(Long.class)).apply(check)); + assertTrue(filter(where("int").type(Integer.class)).accept(check)); + assertFalse(filter(where("int").type(Long.class)).accept(check)); - assertTrue(filter(where("long").type(Long.class)).apply(check)); - assertFalse(filter(where("long").type(Integer.class)).apply(check)); + assertTrue(filter(where("long").type(Long.class)).accept(check)); + assertFalse(filter(where("long").type(Integer.class)).accept(check)); - assertTrue(filter(where("double").type(Double.class)).apply(check)); - assertFalse(filter(where("double").type(Integer.class)).apply(check)); + assertTrue(filter(where("double").type(Double.class)).accept(check)); + assertFalse(filter(where("double").type(Integer.class)).accept(check)); } @Test public void pattern_filters_evaluates() throws Exception { Map check = new HashMap(); - check.put("string", "kalle"); + check.put("name", "kalle"); + check.put("name_null", null); - assertTrue(filter(where("string").regex(Pattern.compile(".alle"))).apply(check)); - assertFalse(filter(where("string").regex(Pattern.compile("KALLE"))).apply(check)); - assertTrue(filter(where("string").regex(Pattern.compile("KALLE", Pattern.CASE_INSENSITIVE))).apply(check)); + assertFalse(filter(where("name_null").regex(Pattern.compile(".alle"))).accept(check)); + assertTrue(filter(where("name").regex(Pattern.compile(".alle"))).accept(check)); + assertFalse(filter(where("name").regex(Pattern.compile("KALLE"))).accept(check)); + assertTrue(filter(where("name").regex(Pattern.compile("KALLE", Pattern.CASE_INSENSITIVE))).accept(check)); } - /* + //------------------------------------------------- + // + // Single filter tests + // + //------------------------------------------------- + @Test - public void or_filters_evaluates() throws Exception { + public void filters_can_be_combined() throws Exception { + Map check = new HashMap(); - check.put("string", "kalle"); + check.put("string", "foo"); + check.put("string_null", null); + check.put("int", 10); + check.put("long", 1L); + check.put("double", 1.12D); - - assertTrue(filter(where("string").is("x").orOperator(where("string").is("kalle"))).apply(check)); - }*/ + Filter shouldMarch = filter(where("string").is("foo").and("int").lt(11)); + Filter shouldNotMarch = filter(where("string").is("foo").and("int").gt(11)); + + assertTrue(shouldMarch.accept(check)); + assertFalse(shouldNotMarch.accept(check)); + } + + @Test + public void filters_can_be_extended() throws Exception { + + Map check = new HashMap(); + check.put("string", "foo"); + check.put("string_null", null); + check.put("int", 10); + check.put("long", 1L); + check.put("double", 1.12D); + + Filter filter = filter(where("string").is("foo").and("int").lt(11)); + + assertTrue(filter.accept(check)); + + filter.addCriteria(where("long").ne(1L)); + + assertFalse(filter.accept(check)); + + } + + + @Test + public void arrays_of_maps_can_be_filtered() throws Exception { + + + Map rootGrandChild_A = new HashMap(); + rootGrandChild_A.put("name", "rootGrandChild_A"); + + Map rootGrandChild_B = new HashMap(); + rootGrandChild_B.put("name", "rootGrandChild_B"); + + Map rootGrandChild_C = new HashMap(); + rootGrandChild_C.put("name", "rootGrandChild_C"); + + + Map rootChild_A = new HashMap(); + rootChild_A.put("name", "rootChild_A"); + rootChild_A.put("children", asList(rootGrandChild_A, rootGrandChild_B, rootGrandChild_C)); + + Map rootChild_B = new HashMap(); + rootChild_B.put("name", "rootChild_B"); + rootChild_B.put("children", asList(rootGrandChild_A, rootGrandChild_B, rootGrandChild_C)); + + Map rootChild_C = new HashMap(); + rootChild_C.put("name", "rootChild_C"); + rootChild_C.put("children", asList(rootGrandChild_A, rootGrandChild_B, rootGrandChild_C)); + + Map root = new HashMap(); + root.put("children", asList(rootChild_A, rootChild_B, rootChild_C)); + + + + Filter customFilter = new Filter.FilterAdapter>() { + @Override + public boolean accept(Map map) { + if(map.get("name").equals("rootGrandChild_A")){ + return true; + } + return false; + } + }; + + Filter rootChildFilter = filter(where("name").regex(Pattern.compile("rootChild_[A|B]"))); + Filter rootGrandChildFilter = filter(where("name").regex(Pattern.compile("rootGrandChild_[A|B]"))); + + List read = JsonPath.read(root, "children[?].children[?][?]", rootChildFilter, rootGrandChildFilter, customFilter); + + + System.out.println(read.size()); + } + + + @Test + public void arrays_of_objects_can_be_filtered() throws Exception { + Map doc = new HashMap(); + doc.put("items", asList(1, 2, 3)); + + Filter customFilter = new Filter.FilterAdapter(){ + @Override + public boolean accept(Object o) { + return 1 == (Integer)o; + } + }; + + List res = JsonPath.read(doc, "$.items[?]", customFilter); + assertEquals(1, res.get(0).intValue()); + } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonModelTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonModelTest.java index c88cce7b..2314fc77 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonModelTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonModelTest.java @@ -83,7 +83,7 @@ public class JsonModelTest { assertEquals("value", model.get("$child.key")); assertEquals(1, model.get("$items[1]")); - assertEquals("{\"child\":{\"key\":\"value\"},\"items\":[0,1,2]}", model.toJson()); + assertEquals("{\"child\":{\"key\":\"value\"},\"items\":[0,1,2]}", model.getJson()); } diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonPathFilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonPathFilterTest.java index aa67788b..48e9b312 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonPathFilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonPathFilterTest.java @@ -10,6 +10,7 @@ import java.util.regex.Pattern; import static com.jayway.jsonpath.Criteria.where; import static com.jayway.jsonpath.Filter.filter; import static java.util.Arrays.asList; +import static junit.framework.Assert.assertEquals; /** * Created by IntelliJ IDEA. @@ -53,20 +54,11 @@ public class JsonPathFilterTest { " }\n" + " }\n" + "}"; - - @Test - public void a_path_can_use_filters() throws Exception { - - Filter lowPricedBooksFilter = filter(where("price").lt(10)); - List read = JsonPath.read(DOCUMENT, "store.book[?]", lowPricedBooksFilter); - - System.out.println(read.size()); - } @Test - public void a_path_can_use_many_filters() throws Exception { + public void arrays_of_maps_can_be_filtered() throws Exception { Map rootGrandChild_A = new HashMap(); @@ -96,9 +88,9 @@ public class JsonPathFilterTest { - Filter customFilter = new Filter() { + Filter customFilter = new Filter.FilterAdapter>() { @Override - public boolean apply(Map map) { + public boolean accept(Map map) { if(map.get("name").equals("rootGrandChild_A")){ return true; } @@ -111,7 +103,26 @@ public class JsonPathFilterTest { List read = JsonPath.read(root, "children[?].children[?][?]", rootChildFilter, rootGrandChildFilter, customFilter); + System.out.println(read.size()); } + + @Test + public void arrays_of_objects_can_be_filtered() throws Exception { + Map doc = new HashMap(); + doc.put("items", asList(1, 2, 3)); + + Filter customFilter = new Filter.FilterAdapter(){ + @Override + public boolean accept(Integer o) { + return 1 == o; + } + }; + + List res = JsonPath.read(doc, "$.items[?]", customFilter); + + assertEquals(1, res.get(0).intValue()); + } + }