Camel - json body is consumed after have used jsonpath - json

i'm using camel in a rest context and i've to manipulate a json got from a request . It's something like:
{
'field1':'abc',
'field2':'def'
}
All i've to do is to extract field1 and field2 and put them in 2 properties, so i tried something like that
<setProperty propertyName="Field1">
<jsonpath>$.field1</jsonpath>
</setProperty>
<setProperty propertyName="Field2">
<jsonpath>$.field2</jsonpath>
</setProperty>
but i get this error:
org.apache.camel.ExpressionEvaluationException:
com.jayway.jsonpath.PathNotFoundException: Expected to find an object with property ['field2'] in path $ but found 'java.lang.String'. This is not a json object according to the JsonProvider: 'com.jayway.jsonpath.spi.json.JsonSmartJsonProvider'.
and after some tests i found out my body was empty after the first use of jsonpath.
The same process applied to an XML using xpath doesn't give any error, and i'm wondering if it's possible to do the same with jsonpath instead to create a mapper object in java. thank you in advance

If the processed Camel message is of type InputStream, this stream can obviously be read only once.
To solve this:
either enable Camel stream caching (http://camel.apache.org/stream-caching.html)
or insert a step (before jsonpath queries) in your route to convert message body to a string (so that it can be read multiple times:
(eg <convertBodyTo type="java.lang.String" charset="ISO-8859-1">) )

Related

Prevent parsing a JSON node with common-lisp YASON library

I am using the Yason library in common-lisp, I want to parse a json string but would like the parser to keep one a its node unparsed.
Typically with an example like that:
{
"metadata1" : "mydata1",
"metadata2" : "mydata2",
"payload" : {...my long payload object},
"otherNodesToParse" : {...}
}
How can I set the yason parser to parse my json but skip the payload node and keep it as a string in the json format.
Use: let's say I just want the envelope data (everything that's not the payload), and to forward the payload as-is (as json string) to another system.
If I parse the whole json (so including payload) and then re-encode the payload to json, it is inefficient. The payload size could also be pretty big.
How do you know where the end of the payload object is in the stream? You do so by parsing the stream: if you don't parse the stream you simply can't know where the end of the object is: that's the nature of JSON's syntax (as it is the nature of CL's default syntax). For instance the only way you can know the difference between where to continue after
{x:1}
and after
{x:1.2}
is by parsing the two things.
So you must necessarily parse the whole thing.
So the answer to your question is: you can't do this.
You could (but not, I think, with YASON) decide that you did not want to build an object as a result of the parse. And perhaps, if the stream you are parsing corresponds to something with random access like a string or a file, you could note the start and end positions in the stream to later extract a string from it corresponding to the unparsed data (or you could perhaps build it up as you go).
It looks as if some or all of this might be possible with CL-JSON, but you'd have to work at it.
Unless the objects you are reading are vast the benefit of this seems questionable-to-none. If you really do want to do something like this efficiently you need a serialisation scheme which tells you how long things are.

escaping dots in json evaluation in WSO2 Datamapper

I have a JSON object as payload, which contains a dot (".") in one of the identifier names and I want to map this object to another JSON object using the datamapper mediator.
The problem I am facing is that the JSON evaluation uses the dot notation for nested elements. The field "example":
{ "a": { "b": "example"} }
is evaluated by asking for a.b
My object however looks like:
{ "a": { "b.c": "example"} }
I cannot evaluate a.b.c, because it thinks b and c are two seperate nested elements.
Escaping this identifier name in the datamapper.dmc javascript code does not seem to work. No matter what I try ('', "", [''], [""]) I get the error:
Error while reading input stream. Script engine unable to execute the script javax.script.ScriptException: <eval>:8:43 Expected ident but found [
This may not be exact solution as I did not specifically tried it for Data Mapper, but I had similar problem in WSO2 Property Mediator while parsing incoming JSON to get a value and set it to property. I was able to parse such JSON using following syntax
json-eval($.A.['b.c'])
Where 'A' is JSON object containing 'b.c' JSON element.
I saw you mentioned that you already tried something similar, but just wanted to give my working example in case it helps.

Jmeter parse and Assert Array of Json objects

In Jmeter when trying to extract data from Json object everything is ok and works great but, when i have array of Json objects can't extract it.
Result is:
[{"id":1,"name":"test"},{"id":2,"name":"test2"}]
it is my project JSON Extractor and JSR233 Assertion.
Inside Groovy script i'm making log.info but it doesn't captures variable value which is described inside JSON Extraxtor.
String id = vars.get("id");
log.info ("The example answer is " + id);
if (id == ""){
AssertionResult.setFailureMessage("The id is null");
AssertionResult.setFailure(true);
}
Please note that if Json response looks like this {"id":1,"name":"test"}
everything works correctly.
Change your JSON Path Expression to look like: $..id. .. is a deep scan operator so it will return all id attributes values.
Change Match No to -1
It will result in the following variables:
id_1=1
id_2=2
id_matchNr=2
I have no idea what exactly you need to assert, hopefully you will be able to amend your Groovy script yourself.
Also be aware that there is JSON Assertion test element available since JMeter 4.0 so you won't need to have separate extractor and assertion elements.

Verify whole json response in jmeter by value or sort Json

I'm not using JMeter too often, and I've run into very specific issue.
My REST response is always "the same", but nodes are not in the same order due to various reasons. As well, I can't put here whole response due to sensitive data, but let's use these dummy one:
First time response might be:
{
"properties":{
"prop1":false,
"prop2":false,
"prop3":165,
"prop4":"Audi",
"prop5":true,
"prop6":true,
"prop7":false,
"prop8":"1",
"prop9":"2.0",
"prop10":0
}
}
Then other time it might be like this:
{
"properties":{
"prop2":false,
"prop1":false,
"prop10":0,
"prop3":165,
"prop7":false,
"prop5":true,
"prop6":true,
"prop8":"1",
"prop9":"2.0",
"prop4":"Audi"
}
}
As you can see, the content it self is the same, but order of nodes it's not. I have 160+ nodes and thousand of possible response orders.
Is there an easy way to compare two JSON responses comparing matching key - values, or at least to sort the response, and then compare it with sorted one in assertion patterns?
I'm not using any plugins, just basic Apache JMeter.
Thanks
I've checked using Jython, you need to download the Jython Library and save to your jmeter lib directory.
I've checked 2 JSONs with Sampler1 and Sampler2, on Sampler1 I've add a BeanShell PostProcessor with this code:
vars.put("jsonSampler1",prev.getResponseDataAsString());
On Sampler2 I've add a BSF Assertion, specifying jython as the language and with the following code:
import json
jsonSampler1 = vars.get("jsonSampler1")
jsonSampler2 = prev.getResponseDataAsString()
objectSampler1 = json.loads(jsonSampler1)
objectSampler2 = json.loads(jsonSampler2)
if ( objectSampler1 != objectSampler2 ):
AssertionResult.setFailure(True)
AssertionResult.setFailureMessage("JSON data didn't match")
Yoy can find the whole jmx in this GistHub
You will most probably have to do this with a JSR223 Assertion and Groovy.
http://jmeter.apache.org/usermanual/component_reference.html#JSR223_Assertion
http://docs.groovy-lang.org/latest/html/api/groovy/json/JsonSlurper.html
Note that if you know Python, you might look at using Jython + JSR223.
I would just set up 10 jp#gc - JSON Path Assertions. Documentation for figuring out JSON Path format is here and you can test how it would work here.
For your example you would the assertion (Add > Assertion > jp#gc - JSON Path Assertions), then to test the prop 1 put:
$.properties.prop1
in the JSON Path field, click the Validate Against Expected Value checkbox, and put
false
in the expected value field. Repeat those steps for the other 9 changing the last part of the path to each key and the value you expected back in the expected value field.
This extractor is jmeter add on found here.

ATLANTBH jmeter-components: JSON Path Assertion

I'm trying to perform a JSON assertion using ATLANTBH jmeter JSON PATH Assertion. However I cant seem to write a correct expression to get the following fields from the JSON feed posted below:
123456789
1009
SOME RANDOM MESSAGE
{"api": {"status":"Success","callsremaining":36,"version":"x.x.x.x"}
,"result":{"errors":{"123456789":{"code":1009,"error":"SOME RANDOM MESSAGE"}}}
}
Has anyone here got any experience using this JMeter plugin?
I know I could use regex and Beanshell to validate but I'd rather use these JSON Path Assertion.
Any help you could provide would be most appreciated.
Looks like you can easily assert both 1009 and SOME RANDOM MESSAGE values using JSONPath expressions (in JSON Path Assertion components) but not sure about 123456789: that's not node value but bode name, and JSONPath implementation used by these components seems has no expressions to get node name.
Suppose you can easily use to assert 123456789 instead binding of JSON Path Extractor (from the same components collection) with jmeter's standard Response_Assertion.
Add 2 JSON Path Assertions as children to the sampler which returns json response you want to process:
Expressions will be $.result.errors..code and $.result.errors..error correspondingly.
Add JSON Path Extractor as child to the same sampler to extract full error entry:
Expression: $.result.errors..
This will extract {"123456789":{"error":"SOME RANDOM MESSAGE","code":1009}} and save into the pointed variable (${errorKey}).
Add Response Assertion as child to the same sampler, after previously added JSON Path Extractor:
This will assert name of the key (123456789) in the value of ${errorKey} variable.
So the final construction may look like
...
YOUR Sampler
JSON Path Extractor
JSON Path Assertion
JSON Path Assertion
Response Assertion
...