concurrency issue / race condition
Author: DarkvaterCreated Dec 21, 2023Updated May 13, 2026
LabelsBUG
Hi,
I've been investigating strange behaviour in wiremock (see https://github.com/wiremock/wiremock/issues/706#issuecomment-1862732727) and over the course of several days narrowed the issue down to a race condition in json-path. While I am still trying to pin down the exact culprit please find my findings below. Maybe someone with intimate knowledge of the library can see immediately what is wrong which would save me a lot of time.
- version used: json-path 2.8.0 (but json-path 2.7.0 exhibits the same behaviour)
- issue:
JsonPath.read(<<json>>, "concat($.keys())")returns the keys from a json called in a different thread
log and explanation
- I have annotated certain classes with logging.
- the log format is
[<thread-id> - <class-instance-hash>] <class-name>::<method> ... parameters of interest] - I have simplified the log here a bit to give the same simple name to all objects that are the same. So everywhere you see
<<BODY>>it means the same JSON payload; everywhere you see<<CONFIG>>it is the same object instance. - you can see from the log there is a recursive call here to evaluate
$.keysand thenconcat() - somewhere after correctly evaluating
$.keysto "transactionId-ZFOr/PRIIPS" the result of EvaluationContext::addResult onconcat()is suddenly "transactionId-ZFOr/MIFID" which is another call. You can see this between the section highlighted in ----- EVALUATIONCONTEXTIMPL::addResult-1is on callingaddResultmethodEVALUATIONCONTEXTIMPL::addResult-2is after adding valueResult inaddResultEVALUATIONCONTEXTIMPL::addResult-3is after adding pathResult inaddResult
notes
- I'm adding some more logging to check evaluation context's valueResult and indexes there, but each run takes a while as it really only happens occasionally, and even less so with the extra logging added
[qtp1615908941-218 - <<JSON_PATH_1>>] JSONPATH::read jsonObject: <<BODY>>, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_1>>] COMPILEDPATH::evaluate-1.0 document: <<BODY>>, rootDocument: <<BODY>>, configuration: <<CONFIG>>
[qtp1615908941-218 - <<COMPILED_PATH_1>>] COMPILEDPATH::evaluate-2.0 path: $.concat(...), document: <<BODY>>, rootDocument: <<BODY>>, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_1>>] COMPILEDPATH::evaluate-2.1 ctx: <<EVALUATIONCTX>>, path: $.concat(...), configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_2>>] COMPILEDPATH::evaluate-1.0 document: <<BODY>>, rootDocument: <<BODY>>, configuration: <<CONFIG>>
[qtp1615908941-218 - <<COMPILED_PATH_2>>] COMPILEDPATH::evaluate-2.0 path: $.keys(), document: <<BODY>>, rootDocument: <<BODY>>, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_2>>] COMPILEDPATH::evaluate-2.1 ctx: <<EVALUATIONCTX_2>>, path: $.keys(), configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_1>>] EVALUATIONCONTEXTIMPL::addResult-1 path: $.keys, model: [transactionId-ZFOr/PRIIPS], configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_1>>] EVALUATIONCONTEXTIMPL::addResult-2 valueResult: [[transactionId-ZFOr/PRIIPS]], resultIndex: 0, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_1>>] EVALUATIONCONTEXTIMPL::addResult-3 valueResult: [[transactionId-ZFOr/PRIIPS]], resultIndex: 0, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_2>>] COMPILEDPATH::evaluate-2.2 ctx: <<EVALUATIONCTX_2>>, path: $.keys(), configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_2>>] COMPILEDPATH::evaluate-2.4 ctx: <<EVALUATIONCTX_2>>, path: $.keys(), configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_2>>] COMPILEDPATH::evaluate-1.1 result: <<EVALUATIONCTX_2>>, document: <<BODY>>, rootDocument: <<BODY>>, configuration: <<CONFIG>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_1>>] EVALUATIONCONTEXTIMPL::getValue-1.1 value: [transactionId-ZFOr/PRIIPS], unwrap: true
[qtp1615908941-218 - <<EVALUATION_CONTEXT_1>>] EVALUATIONCONTEXTIMPL::getValue-1.2 result: [transactionId-ZFOr/PRIIPS], unwrap: true
--------------------------------------------------------------------------------------------------------------------------------------------
[qtp1615908941-218 - <<EVALUATION_CONTEXT_2>>] EVALUATIONCONTEXTIMPL::addResult-1 path: $.concat, model: [transactionId-ZFOr/MIFID], configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_2>>] EVALUATIONCONTEXTIMPL::addResult-2 valueResult: [[transactionId-ZFOr/MIFID]], resultIndex: 0, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_2>>] EVALUATIONCONTEXTIMPL::addResult-3 valueResult: [[transactionId-ZFOr/MIFID]], resultIndex: 0, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_1>>] COMPILEDPATH::evaluate-2.2 ctx: <<EVALUATIONCTX>>, path: $.concat(...), configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_1>>] COMPILEDPATH::evaluate-2.4 ctx: <<EVALUATIONCTX>>, path: $.concat(...), configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - <<COMPILED_PATH_1>>] COMPILEDPATH::evaluate-1.1 result: <<EVALUATIONCTX>>, document: <<BODY>>, rootDocument: <<BODY>>, configuration: <<CONFIG>>
[qtp1615908941-218 - <<EVALUATION_CONTEXT_2>>] EVALUATIONCONTEXTIMPL::getValue-1.1 value: [transactionId-ZFOr/MIFID], unwrap: true
[qtp1615908941-218 - <<EVALUATION_CONTEXT_2>>] EVALUATIONCONTEXTIMPL::getValue-1.2 result: [transactionId-ZFOr/MIFID], unwrap: true
--------------------------------------------------------------------------------------------------------------------------------------------
[qtp1615908941-218 - <<JSON_PATH_1>>] JSONPATH::read-3 result: [transactionId-ZFOr/MIFID], jsonObject: <<BODY>>, configuration: <<CONFIG>>, jsonProvider: <<JSONPROVIDER>>
[qtp1615908941-218 - 1482307509] JSONPROVIDER::parse json: <<BODY>>Source: json-path/JsonPath