Because of the project requirement, I have to use com.fasterxml.jackson.databind library to parse JSON data cannot use other JSON libraries available.
I am new to JSON parsing, so not sure if there are better options here?
I would like to know how can I update a string value in an Array node in the JSON file.
Following is a sample JSON. Please note this is not the entire file content, it's a simplified version.
{
"call": "SimpleAnswer",
"environment": "prod",
"question": {
"assertions": [
{
"assertionType": "regex",
"expectedString": "(.*)world cup(.*)"
}
],
"questionVariations": [
{
"questionList": [
"when is the next world cup"
]
}
]
}
}
Following is the code to read JSON into java object.
byte[] jsonData = Files.readAllBytes(Paths.get(PATH_TO_JSON));
JsonNode jsonNodeFromFile = mapper.readValue(jsonData, JsonNode.class);
To update a root level node value e.g. environment in the JSON file , I found following approach on some SO threads.
ObjectNode objectNode = (ObjectNode)jsonNodeFromFile;
objectNode.remove("environment");
objectNode.put("environment", "test");
jsonNodeFromFile = (JsonNode)objectNode;
FileWriter file = new FileWriter(PATH_TO_JSON);
file.write(jsonNodeFromFile.toString());
file.flush();
file.close();
QUESTION 1: Is this the only way to update a value in JSON file and is it the best way possible? I'm concerned on double casting and file I/O here.
QUESTION 2: I could not find a way to update the value for a nested Array node e.g. questionList. Update the question from when is the next world cup to when is the next soccer world cup
You can use ObjectMapper to parse that JSON, it is very easy to parse and update JSON using pojo class.
use link to convert your json to java class, just paste your json here n download class structure.
You can access or update nested json field by using . (dot) operator
ObjectMapper mapper = new ObjectMapper();
String jsonString="{\"call\":\"SimpleAnswer\",\"environment\":\"prod\",\"question\":{\"assertions\":[{\"assertionType\":\"regex\",\"expectedString\":\"(.*)world cup(.*)\"}],\"questionVariations\":[{\"questionList\":[\"when is the next world cup\"]}]}}";
TestClass sc=mapper.readValue(jsonString,TestClass.class);
// to update environment
sc.setEnvironment("new Environment");
System.out.println(sc);
//to update assertionType
Question que=sc.getQuestion();
List assertions=que.getAssertions();
for (int i = 0; i < assertions.size(); i++) {
Assertion ass= (Assertion) assertions.get(i);
ass.setAssertionType("New Type");
}
I'm making many HTTP request with JSON Payload and I'm reading one file for every single request to get JSON Payload as below.
postPayload1 = val postPayload = ElFileBody("Test_case1.json")
val TC1 = feed(accountNumberFeeder1)
.exec(http(testCase1).post(appendPathToUrl).headers(common_header).body(postPayload).asJSON
.check(status.is(200)
)
But, it becomes so many JSON files inside my resources directory now. So can I merge all my JSON together in one file as below.
{"testCase1":{
"activationSource": "HH",
"accountStatus": null,
}
}
{"testCase2":{
"activationSource": "HH",
"accountStatus": null,
}
}
and access it with my keys "testCase1", "testCase2" etc ?
val postPayload = ElFileBody("Test_case.json")
From official Gatling Documentation, I found http://gatling.io/docs/2.2.1/session/feeder.html
JSON feeders
Some might want to use data in JSON format instead of CSV:
val jsonFileFeeder = jsonFile("foo.json")
val jsonUrlFeeder = jsonUrl("http://me.com/foo.json")
For example, the following JSON:
[
{
"id":19434,
"foo":1
},
{
"id":19435,
"foo":2
}
]
will be turned into:
record1: Map("id" -> 19434, "foo" -> 1)
record2: Map("id" -> 19435, "foo" -> 2)
Note that the root element has of course to be an array.
I am using libraries provided by ch.systemsx.cisd.hdf5.HDF5Factory(JHDF5) for reading an HDF5 file. Their documentation link is not working as well and I do not know whom to approach to get a solution for this.
Does anyone here know how to read attribute value from HDF5 file using above java libraries ?
After lot of trial and error found a solution for this. Please find code below to read attribute value from HDF5 file.
nwbFile - Name of HDF5 file (It should be opened).
attributeName: Name of the attribute.
path - path of the Node in file whose attribute needs to be read.
DataFormat dataset = (Dataset) FileFormat.findObject(nwbFile, path);
List<Attribute> attributes = dataset.getMetadata();
for(Attribute a : attributes)
{
if(a.getName().equals(attributeName))
{
Object obj = a.getValue();
if (obj instanceof double[])
{
Double d = ((double[]) obj)[0];
return d.toString();
}
else if (obj instanceof String[])
{
return ((String[]) obj)[0];
}
}
}
I have JSON as a string and a JSONPath as a string. I'd like to query the JSON with the JSON path, getting the resulting JSON as a string.
I gather that Jayway's json-path is the standard. The online API, however, doesn't have have much relation to the actual library you get from Maven. GrepCode's version roughly matches up though.
It seems like I ought to be able to do:
String originalJson; //these are initialized to actual data
String jsonPath;
String queriedJson = JsonPath.<String>read(originalJson, jsonPath);
The problem is that read returns whatever it feels most appropriate based on what the JSONPath actually finds (e.g. a List<Object>, String, double, etc.), thus my code throws an exception for certain queries. It seems pretty reasonable to assume that there'd be some way to query JSON and get JSON back; any suggestions?
Java JsonPath API found at jayway JsonPath might have changed a little since all the above answers/comments. Documentation too. Just follow the above link and read that README.md, it contains some very clear usage documentation IMO.
Basically, as of current latest version 2.2.0 of the library, there are a few different ways of achieving what's been requested here, such as:
Pattern:
--------
String json = "{...your JSON here...}";
String jsonPathExpression = "$...your jsonPath expression here...";
J requestedClass = JsonPath.parse(json).read(jsonPathExpression, YouRequestedClass.class);
Example:
--------
// For better readability: {"store": { "books": [ {"author": "Stephen King", "title": "IT"}, {"author": "Agatha Christie", "title": "The ABC Murders"} ] } }
String json = "{\"store\": { \"books\": [ {\"author\": \"Stephen King\", \"title\": \"IT\"}, {\"author\": \"Agatha Christie\", \"title\": \"The ABC Murders\"} ] } }";
String jsonPathExpression = "$.store.books[?(#.title=='IT')]";
JsonNode jsonNode = JsonPath.parse(json).read(jsonPathExpression, JsonNode.class);
And for reference, calling 'JsonPath.parse(..)' will return an object of class 'JsonContent' implementing some interfaces such as 'ReadContext', which contains several different 'read(..)' operations, such as the one demonstrated above:
/**
* Reads the given path from this context
*
* #param path path to apply
* #param type expected return type (will try to map)
* #param <T>
* #return result
*/
<T> T read(JsonPath path, Class<T> type);
Hope this help anyone.
There definitely exists a way to query Json and get Json back using JsonPath.
See example below:
String jsonString = "{\"delivery_codes\": [{\"postal_code\": {\"district\": \"Ghaziabad\", \"pin\": 201001, \"pre_paid\": \"Y\", \"cash\": \"Y\", \"pickup\": \"Y\", \"repl\": \"N\", \"cod\": \"Y\", \"is_oda\": \"N\", \"sort_code\": \"GB\", \"state_code\": \"UP\"}}]}";
String jsonExp = "$.delivery_codes";
JsonNode pincodes = JsonPath.read(jsonExp, jsonString, JsonNode.class);
System.out.println("pincodesJson : "+pincodes);
The output of the above will be inner Json.
[{"postal_code":{"district":"Ghaziabad","pin":201001,"pre_paid":"Y","cash":"Y","pickup":"Y","repl":"N","cod":"Y","is_oda":"N","sort_code":"GB","state_code":"UP"}}]
Now each individual name/value pairs can be parsed by iterating the List (JsonNode) we got above.
for(int i = 0; i< pincodes.size();i++){
JsonNode node = pincodes.get(i);
String pin = JsonPath.read("$.postal_code.pin", node, String.class);
String district = JsonPath.read("$.postal_code.district", node, String.class);
System.out.println("pin :: " + pin + " district :: " + district );
}
The output will be:
pin :: 201001 district :: Ghaziabad
Depending upon the Json you are trying to parse, you can decide whether to fetch a List or just a single String/Long value.
Hope it helps in solving your problem.
For those of you wondering why some of these years-old answers aren't working, you can learn a lot from the test cases.
As of September 2018, here's how you can get Jackson JsonNode results:
Configuration jacksonConfig = Configuration.builder()
.mappingProvider( new JacksonMappingProvider() )
.jsonProvider( new JacksonJsonProvider() )
.build();
JsonNode node = JsonPath.using( jacksonConfig ).parse(jsonString);
//If you have a json object already no need to initiate the jsonObject
JSONObject jsonObject = new JSONObject();
String jsonString = jsonObject.toString();
String path = "$.rootObject.childObject"
//Only returning the child object
JSONObject j = JsonPath.read(jsonString, path);
//Returning the array of string type from the child object. E.g
//{"root": "child":[x, y, z]}
List<String> values = sonPath.read(jsonString, path);
Check out the jpath API. It's xpath equivalent for JSON Data. You can read data by providing the jpath which will traverse the JSON data and return the requested value.
This Java class is the implementation as well as it has example codes on how to call the APIs.
https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java
Readme -
https://github.com/satyapaul/jpath/blob/master/README.md
I have the following XML file :
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:process id="process_1" isExecutable="true">
<bpmn2:subProcess id="SubProcess_1" name="Sub Process 1">
<bpmn2:task id="Task_4" name="Task 4">
</bpmn2:task>
<bpmn2:task id="Task_2" name="Task 2">
</bpmn2:task>
<bpmn2:startEvent id="StartEvent_2" name="">
</bpmn2:startEvent>
<bpmn2:endEvent id="EndEvent_2" name="">
</bpmn2:endEvent>
<bpmn2:task id="Task_3" name="Task 3">
</bpmn2:task>
</bpmn2:subProcess>
<bpmn2:subProcess id="SubProcess_2" name="Sub Process 2">
<bpmn2:startEvent id="StartEvent_3" name="">
</bpmn2:startEvent>
<bpmn2:endEvent id="EndEvent_3" name="">
</bpmn2:endEvent>
<bpmn2:task id="Task_5" name="Task 5">
</bpmn2:task>
</bpmn2:subProcess>
</bpmn2:process>
I want to generate the Json String for this xml.
I have already writen the code for generating the Json String if inside the <bpmn2:process> </bpmn2:process> tags there is only one <bpmn2:subProcess> node, but now I don't know how to do when I have more than one bpmn2:subProcess node.
My code so far is :
Node nodeSubProcess = getNode("bpmn2:subProcess");
jw = new JSONStringer();
jw.object(); //create a new object for bpmn2:subProcess
generateChildNodesDefinitions(nodeSubProcess);
jw.endObject(); // close the object for bpmn2:subProcess
System.out.println(jw.toString());
And inside the generateChildNodesDefinitions(nodeSubProcess) method I have the code how I want to generate the Json string for my xml file, when I have only one subProcess node:
public static void generateChildNodesDefinitions(Node node) throws JSONException
{
if (node != null && node.hasChildNodes())
{
jw.key("nodes").array();
NodeList childnodelist = node.getChildNodes();
for (int k = 0; k < childnodelist.getLength(); k++)
{
Node childn = childnodelist.item(k);
if (childn.hasAttributes())
{
ArrayList<String> list = (ArrayList<String>) jsonValues.get(childn.getNodeName()); //where jsonValues is e Map where I have defined some new values I want to generate for each node I have inside pbmn2:subProcess node
// get attributes for each childnode
NamedNodeMap nnmchildnodes = childn.getAttributes();
// for each node create a JsonObject
jw.object();
if (list != null && !list.isEmpty())
{
jw.key("stencil").value(list.get(0));
jw.key("category").value("NODE");
if (list.get(1) != null)
{
jw.key(list.get(1)).value(list.get(2));
}
}
jw.endObject();
}
}
jw.endArray();
}
}
Try the JSON in Java API. It does all of the hard work for you.
public String xmlToJSON(String xmlString){
try {
JSONObject xmlJSONObj = XML.toJSONObject(xmlString);
String jsonString = xmlJSONObj.toString(4);
}catch (JSONException je){
je.printStackTrace();
}
return jsonString;
}
You might be better off to use Jackson both for parsing the xml and for writing the json back. Especially if you plan to process your data in java. If you only want a conversion, Jackson might be overkill. If you want your conversion to work in both ways, Jackson might provide an elegant solution. Jackson is meant for json (de-)serialization and can be extended to be used with xml.
Parsing your xml into your data classes is as simple as:
ObjectMapper xmlMapper = new XmlMapper();
YourRootClass yourRootObject = xmlMapper.readValue(xml, YourRootClass.class);
Writing your json back is as simple as:
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(fileOutput, yourRootObject);
You need to annotate your data classes in order for Jackson to work.
Jackson Annotations
Additional XML Annotations