Browse Source

Added result cache for root ($) queries performed by predicates.

pull/57/head
Kalle Stenflo 10 years ago
parent
commit
c20917350e
  1. 16
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  2. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java
  3. 32
      json-path/src/main/java/com/jayway/jsonpath/internal/token/PredicateContextImpl.java
  4. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/token/PredicatePathToken.java
  5. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/token/ScanPathToken.java
  6. 7
      json-path/src/test/java/com/jayway/jsonpath/BaseTest.java
  7. 9
      json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java

16
json-path/src/main/java/com/jayway/jsonpath/Criteria.java

@ -208,8 +208,9 @@ public class Criteria implements Predicate {
MATCHES {
@Override
boolean eval(Object expected, final Object actual, final PredicateContext ctx) {
PredicateContextImpl pci = (PredicateContextImpl) ctx;
Predicate exp = (Predicate) expected;
return exp.apply(new PredicateContextImpl(actual, ctx.root(), ctx.configuration()));
return exp.apply(new PredicateContextImpl(actual, ctx.root(), ctx.configuration(), pci.documentPathCache()));
}
},
NOT_EMPTY {
@ -286,7 +287,7 @@ public class Criteria implements Predicate {
if (CriteriaType.EXISTS == criteriaType) {
boolean exists = ((Boolean) expected);
try {
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options().build();
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build();
path.evaluate(ctx.item(), ctx.root(), c).getValue();
return exists;
} catch (PathNotFoundException e) {
@ -299,8 +300,15 @@ public class Criteria implements Predicate {
Object expectedVal = expected;
if(expected instanceof Path){
Path expectedPath = (Path) expected;
Object doc = expectedPath.isRootPath()?ctx.root():ctx.item();
expectedVal = expectedPath.evaluate(doc, ctx.root(), ctx.configuration()).getValue();
if(ctx instanceof PredicateContextImpl){
//This will use cache for document ($) queries
PredicateContextImpl ctxi = (PredicateContextImpl) ctx;
expectedVal = ctxi.evaluate(expectedPath);
} else {
Object doc = expectedPath.isRootPath()?ctx.root():ctx.item();
expectedVal = expectedPath.evaluate(doc, ctx.root(), ctx.configuration()).getValue();
}
}
return criteriaType.eval(expectedVal, actual, ctx);

8
json-path/src/main/java/com/jayway/jsonpath/internal/token/EvaluationContextImpl.java

@ -22,7 +22,9 @@ import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static com.jayway.jsonpath.internal.Utils.notNull;
@ -37,8 +39,10 @@ public class EvaluationContextImpl implements EvaluationContext {
private final Object pathResult;
private final Path path;
private final Object rootDocument;
private final HashMap<Path, Object> documentEvalCache = new HashMap<Path, Object>();
private int resultIndex = 0;
public EvaluationContextImpl(Path path, Object rootDocument, Configuration configuration) {
notNull(path, "path can not be null");
notNull(rootDocument, "root can not be null");
@ -50,6 +54,10 @@ public class EvaluationContextImpl implements EvaluationContext {
this.pathResult = configuration.jsonProvider().createArray();
}
public HashMap<Path, Object> documentEvalCache() {
return documentEvalCache;
}
public void addResult(String path, Object model) {
configuration.jsonProvider().setProperty(valueResult, resultIndex, model);
configuration.jsonProvider().setProperty(pathResult, resultIndex, path);

32
json-path/src/main/java/com/jayway/jsonpath/internal/token/PredicateContextImpl.java

@ -16,17 +16,47 @@ package com.jayway.jsonpath.internal.token;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.spi.mapper.MappingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
public class PredicateContextImpl implements Predicate.PredicateContext {
private static final Logger logger = LoggerFactory.getLogger(PredicateContextImpl.class);
private final Object contextDocument;
private final Object rootDocument;
private final Configuration configuration;
private final HashMap<Path, Object> documentPathCache;
public PredicateContextImpl(Object contextDocument, Object rootDocument, Configuration configuration) {
public PredicateContextImpl(Object contextDocument, Object rootDocument, Configuration configuration, HashMap<Path, Object> documentPathCache) {
this.contextDocument = contextDocument;
this.rootDocument = rootDocument;
this.configuration = configuration;
this.documentPathCache = documentPathCache;
}
public Object evaluate(Path path){
Object result;
if(path.isRootPath()){
if(documentPathCache.containsKey(path)){
logger.debug("Using cached result for root path: " + path.toString());
result = documentPathCache.get(path);
} else {
result = path.evaluate(rootDocument, rootDocument, configuration).getValue();
documentPathCache.put(path, result);
}
} else {
result = path.evaluate(contextDocument, rootDocument, configuration).getValue();
}
return result;
}
public HashMap<Path, Object> documentPathCache() {
return documentPathCache;
}
@Override

8
json-path/src/main/java/com/jayway/jsonpath/internal/token/PredicatePathToken.java

@ -49,7 +49,7 @@ public class PredicatePathToken extends PathToken {
@Override
public void evaluate(String currentPath, Object model, EvaluationContextImpl ctx) {
if (ctx.jsonProvider().isMap(model)) {
if (accept(model, ctx.rootDocument(), ctx.configuration())) {
if (accept(model, ctx.rootDocument(), ctx.configuration(), ctx)) {
if (isLeaf()) {
ctx.addResult(currentPath, model);
} else {
@ -61,7 +61,7 @@ public class PredicatePathToken extends PathToken {
Iterable<?> objects = ctx.jsonProvider().toIterable(model);
for (Object idxModel : objects) {
if (accept(idxModel, ctx.rootDocument(), ctx.configuration())) {
if (accept(idxModel, ctx.rootDocument(), ctx.configuration(), ctx)) {
handleArrayIndex(idx, currentPath, model, ctx);
}
idx++;
@ -71,8 +71,8 @@ public class PredicatePathToken extends PathToken {
}
}
public boolean accept(final Object obj, final Object root, final Configuration configuration) {
Predicate.PredicateContext ctx = new PredicateContextImpl(obj, root, configuration);
public boolean accept(final Object obj, final Object root, final Configuration configuration, EvaluationContextImpl evaluationContext) {
Predicate.PredicateContext ctx = new PredicateContextImpl(obj, root, configuration, evaluationContext.documentEvalCache());
for (Predicate predicate : predicates) {
if (!predicate.apply (ctx)) {

2
json-path/src/main/java/com/jayway/jsonpath/internal/token/ScanPathToken.java

@ -161,7 +161,7 @@ public class ScanPathToken extends PathToken {
@Override
public boolean matches(Object model) {
return predicatePathToken.accept(model, ctx.rootDocument(), ctx.configuration());
return predicatePathToken.accept(model, ctx.rootDocument(), ctx.configuration(), ctx);
}
}

7
json-path/src/test/java/com/jayway/jsonpath/BaseTest.java

@ -1,9 +1,13 @@
package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.spi.json.GsonJsonProvider;
import com.jayway.jsonpath.internal.spi.mapper.GsonMappingProvider;
import com.jayway.jsonpath.internal.token.EvaluationContextImpl;
import com.jayway.jsonpath.internal.token.PredicateContextImpl;
import java.util.HashMap;
public class BaseTest {
/*
static {
@ -84,6 +88,7 @@ public class BaseTest {
"}";
public Predicate.PredicateContext createPredicateContext(final Object check) {
return new PredicateContextImpl(check, check, Configuration.defaultConfiguration());
return new PredicateContextImpl(check, check, Configuration.defaultConfiguration(), new HashMap<Path, Object>());
}
}

9
json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java

@ -37,4 +37,13 @@ public class InlineFilterTest extends BaseTest {
assertThat(none2.size()).isEqualTo(0);
}
@Test
public void document_queries_are_cached() {
Object read = reader.read("$.store.book[?(@.display-price <= $.max-price)]");
System.out.println(read);
}
}

Loading…
Cancel
Save