diff --git a/json-path/src/main/java/com/jayway/jsonpath/Configuration.java b/json-path/src/main/java/com/jayway/jsonpath/Configuration.java index bdffa116..9dea0e79 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Configuration.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Configuration.java @@ -76,19 +76,28 @@ public class Configuration { notNull(jsonProvider, "jsonProvider can not be null"); notNull(mappingProvider, "mappingProvider can not be null"); notNull(options, "setOptions can not be null"); - notNull(evaluationListeners, "evaluationListener can not be null"); + notNull(evaluationListeners, "evaluationListeners can not be null"); this.jsonProvider = jsonProvider; this.mappingProvider = mappingProvider; this.options = Collections.unmodifiableSet(options); this.evaluationListeners = Collections.unmodifiableCollection(evaluationListeners); } + /** + * Creates a new Configuration by the provided evaluation listeners to the current listeners + * @param evaluationListener listeners + * @return a new configuration + */ + public Configuration addEvaluationListeners(EvaluationListener... evaluationListener){ + return Configuration.builder().jsonProvider(jsonProvider).mappingProvider(mappingProvider).options(options).evaluationListener(evaluationListener).build(); + } + /** * Creates a new Configuration with the provided evaluation listeners * @param evaluationListener listeners * @return a new configuration */ - public Configuration evaluationListener(EvaluationListener... evaluationListener){ + public Configuration setEvaluationListeners(EvaluationListener... evaluationListener){ return Configuration.builder().jsonProvider(jsonProvider).mappingProvider(mappingProvider).options(options).evaluationListener(evaluationListener).build(); } @@ -96,7 +105,7 @@ public class Configuration { * Returns the evaluation listeners registered in this configuration * @return the evaluation listeners */ - public Collection evaluationListeners(){ + public Collection getEvaluationListeners(){ return evaluationListeners; } diff --git a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java index 529190c6..5f78a21f 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java @@ -70,7 +70,18 @@ public interface ReadContext { */ T read(JsonPath path, Class type); + /** + * Stops evaluation when maxResults limit has been reached + * @param maxResults + * @return the read context + */ + ReadContext limit(int maxResults); + /** + * Adds listener to the evaluation of this path + * @param listener listeners to add + * @return the read context + */ ReadContext withListeners(EvaluationListener... listener); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java index 01e88966..df307fe3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java @@ -145,8 +145,12 @@ public class JsonReader implements ParseContext, ReadContext { return convert(read(path), type, configuration); } + public ReadContext limit(int maxResults){ + return withListeners(new LimitingEvaluationListener(maxResults)); + } + public ReadContext withListeners(EvaluationListener... listener){ - return new JsonReader(json, configuration.evaluationListener(listener)); + return new JsonReader(json, configuration.setEvaluationListeners(listener)); } @@ -154,4 +158,23 @@ public class JsonReader implements ParseContext, ReadContext { return configuration.mappingProvider().map(obj, targetType, configuration); } + + private final class LimitingEvaluationListener implements EvaluationListener { + + final int limit; + + private LimitingEvaluationListener(int limit) { + this.limit = limit; + } + + + @Override + public EvaluationContinuation resultFound(FoundResult found) { + if(found.index() == limit - 1){ + return EvaluationContinuation.ABORT; + } else { + return EvaluationContinuation.CONTINUE; + } + } + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java b/json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java index f7fdf64f..b98e7879 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java @@ -63,9 +63,9 @@ public class EvaluationContextImpl implements EvaluationContext { configuration.jsonProvider().setProperty(valueResult, resultIndex, model); configuration.jsonProvider().setProperty(pathResult, resultIndex, path); resultIndex++; - if(!configuration().evaluationListeners().isEmpty()){ + if(!configuration().getEvaluationListeners().isEmpty()){ int idx = resultIndex - 1; - for (EvaluationListener listener : configuration().evaluationListeners()) { + for (EvaluationListener listener : configuration().getEvaluationListeners()) { EvaluationListener.EvaluationContinuation continuation = listener.resultFound(new FoundResultImpl(idx, path, model)); if(EvaluationListener.EvaluationContinuation.ABORT == continuation){ throw new EvaluationAbortException(); diff --git a/json-path/src/test/java/com/jayway/jsonpath/EvaluationListenerTest.java b/json-path/src/test/java/com/jayway/jsonpath/EvaluationListenerTest.java index 0d7b22a4..c5c4bf4c 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/EvaluationListenerTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/EvaluationListenerTest.java @@ -53,6 +53,17 @@ public class EvaluationListenerTest extends BaseTest { assertThat(idxs).containsExactly(0, 1, 2, 3); } + + @Test + public void evaluation_results_can_be_limited() { + + List res = JsonPath.parse(JSON_DOCUMENT).limit(1).read("$..title", List.class); + assertThat(res).containsExactly("Sayings of the Century"); + + res = JsonPath.parse(JSON_DOCUMENT).limit(2).read("$..title", List.class); + assertThat(res).containsExactly("Sayings of the Century", "Sword of Honour"); + } + @Test public void multiple_evaluation_listeners_can_be_added() { @@ -92,9 +103,9 @@ public class EvaluationListenerTest extends BaseTest { }; Configuration configuration1 = Configuration.builder().evaluationListener(listener).build(); - Configuration configuration2 = configuration1.evaluationListener(); + Configuration configuration2 = configuration1.setEvaluationListeners(); - assertThat(configuration1.evaluationListeners()).hasSize(1); - assertThat(configuration2.evaluationListeners()).hasSize(0); + assertThat(configuration1.getEvaluationListeners()).hasSize(1); + assertThat(configuration2.getEvaluationListeners()).hasSize(0); } }