Browse Source
The fault is in the Parameter object which obviously cached its value and when the outside reference changes its oblivious to that state change due to its internal cached instance of the state. Cache.getCache()... that singleton call inside of JsonContext then grabs an instance of the cached parameter, it would be thread unsafe to simple invalidate the cache because who knows for whom the cache is being invalidated. Not caching function paths isn't an answer -- the input to a function could itself be another function - meaning the input (parameter) value would never be observed to the wrapping function and things such as take the $.max(3, 4, 5, $.avg(...)) would yield an answer without average being computed.pull/335/head
mattg
8 years ago
11 changed files with 126 additions and 14 deletions
@ -0,0 +1,10 @@
|
||||
package com.jayway.jsonpath.internal.function.latebinding; |
||||
|
||||
/** |
||||
* Obtain the late binding value at runtime rather than storing the value in the cache thus trashing the cache |
||||
* |
||||
* Created by mattg on 3/27/17. |
||||
*/ |
||||
public interface ILateBindingValue { |
||||
Object get(); |
||||
} |
@ -0,0 +1,22 @@
|
||||
package com.jayway.jsonpath.internal.function.latebinding; |
||||
|
||||
import com.jayway.jsonpath.internal.function.Parameter; |
||||
import com.jayway.jsonpath.spi.json.JsonProvider; |
||||
|
||||
/** |
||||
* Created by mattg on 3/27/17. |
||||
*/ |
||||
public class JsonLateBindingValue implements ILateBindingValue { |
||||
private final JsonProvider jsonProvider; |
||||
private final Parameter jsonParameter; |
||||
|
||||
public JsonLateBindingValue(JsonProvider jsonProvider, Parameter jsonParameter) { |
||||
this.jsonProvider = jsonProvider; |
||||
this.jsonParameter = jsonParameter; |
||||
} |
||||
|
||||
@Override |
||||
public Object get() { |
||||
return jsonProvider.parse(jsonParameter.getJson()); |
||||
} |
||||
} |
@ -0,0 +1,33 @@
|
||||
package com.jayway.jsonpath.internal.function.latebinding; |
||||
|
||||
import com.jayway.jsonpath.Configuration; |
||||
import com.jayway.jsonpath.internal.Path; |
||||
import com.jayway.jsonpath.internal.function.ParamType; |
||||
|
||||
/** |
||||
* Defines the contract for late bindings, provides document state and enough context to perform the evaluation at a later |
||||
* date such that we can operate on a dynamically changing value. |
||||
* |
||||
* Acts like a lambda function with references, but since we're supporting JDK 6+, we're left doing this... |
||||
* |
||||
* Created by mattg on 3/27/17. |
||||
*/ |
||||
public class PathLateBindingValue implements ILateBindingValue { |
||||
private final Path path; |
||||
private final Object rootDocument; |
||||
private final Configuration configuration; |
||||
|
||||
public PathLateBindingValue(ParamType type, Path path, Object rootDocument, Configuration configuration) { |
||||
this.path = path; |
||||
this.rootDocument = rootDocument; |
||||
this.configuration = configuration; |
||||
} |
||||
|
||||
/** |
||||
* Evaluate the field type |
||||
* @return |
||||
*/ |
||||
public Object get() { |
||||
return path.evaluate(rootDocument, rootDocument, configuration).getValue(); |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
package com.jayway.jsonpath.internal.function; |
||||
|
||||
import com.jayway.jsonpath.JsonPath; |
||||
import org.assertj.core.util.Maps; |
||||
import org.junit.Test; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* TDD for Issue #234 |
||||
* |
||||
* Verifies the use-case where-in the function path expression is cached and re-used but the JsonPath includes a function |
||||
* whose arguments are then dependent upon state that changes externally from the internal Cache.getCache state. The |
||||
* prior implementation had a bug where-in the parameter values were cached -- the present implementation (as of Issue #234) |
||||
* now uses a late binding approach to eval the function parameters. Cache invalidation isn't an option given the need |
||||
* for nested function calls. |
||||
* |
||||
* Once this bug is fixed, most of the concern then centers around the need to ensure nested functions are processed |
||||
* correctly. |
||||
* |
||||
* @see NestedFunctionTest for examples of where that is performed. |
||||
* |
||||
* Created by mattg on 3/27/17. |
||||
*/ |
||||
public class Issue234 { |
||||
|
||||
@Test |
||||
public void testIssue234() { |
||||
Map<String, String> context = Maps.newHashMap(); |
||||
context.put("key", "first"); |
||||
Object value = JsonPath.read(context, "concat(\"/\", $.key)"); |
||||
assertThat(value).isEqualTo("/first"); |
||||
context.put("key", "second"); |
||||
value = JsonPath.read(context, "concat(\"/\", $.key)"); |
||||
assertThat(value).isEqualTo("/second"); |
||||
} |
||||
} |
Loading…
Reference in new issue