I have below json input String containing node TestInfo
{
"TestInfo" : [ {
}
]
}
I want to add container node to the TestInfo like below
{
"TestInfoContainer":{
"TestInfo" : [ {
}
]
}
}
Kindly suggest me way to do this with good performance as this could be applicable to actual big hierarchical structure
Is it easy with any JSON parser
Is it easy with string manipulation
With JSON parser its easy
JSONObject node = new JSONObject(nodeJsonString);
JSONObject container = new JSONObject(containerJsonString);
container.put("TestInfoContainer", node.getJSONArray("TestInfo"));
(EDIT) Given nested JSON object
{"TestInfo":[{}],"A":{"B":{"C":{"TestInfo":[{}]}}},"D":{"TestInfo":[{}]},"E":{"F":{"G":{"H":{"TestInfo":[{}]}}}}}
You get value down hierarchy by calling methods in chain
container.getJSONObject("TestInfoContainer").put("TestInfo1",jObject.getJSONArray("TestInfo"));
container.getJSONObject("TestInfoContainer").put("TestInfo2",jObject.getJSONObject("A")
.getJSONObject("B")
.getJSONObject("C")
.getJSONArray("TestInfo"));
container.getJSONObject("TestInfoContainer").put("TestInfo3",jObject.getJSONObject("D")
.getJSONArray("TestInfo"));
container.getJSONObject("TestInfoContainer").put("TestInfo4",jObject.getJSONObject("E")
.getJSONObject("F")
.getJSONObject("G")
.getJSONObject("H")
.getJSONArray("TestInfo"));
Related
I have some JSON documents. Here is the JSON structure.
{
"header":
{
"file1":0,
"file2":1,
"subfiles":{
"subfile1":"true",
"subfile2":"true",
}
},
"response":
{
"number":678,
"start":0,
"docs":[
{
"id":"d3f3d",
"code":"l876s",
"country_name":"United States",
"city":"LA"
},
{
"id":"d2f2d",
"code":"2343g",
"country_name":"UK",
"city":"London"
}
]
}
}
I want to get the value in "id" field using JsonNode. How to access to specific fields (id, city or country_name) in structure like this? I try to use:
JsonNode node = documentHandle.get();
String s = node.path("id").asText();
But I didn't get anything expect null.
Your node points to the root of the JSON document. To get to id, you have to traverse the path.
ArrayNode docs = node.path("response").path("docs");
for (JsonNode doc: docs) { // this is pseudo-code
String s = doc.path("id").asText();
}
Or use JsonPath.
Jayway's JsonPath works well for this:
JsonPath.read(jsonString, "$.response.docs[*].id");
I have been combing over multiple approaches with different JSON libraries, and cannot seem to find an elegant way to convert to and from with my JSON file in testing.
JSON file looks like this:
[
{
"LonelyParentKey": "Account",
"ProcessNames": [
{"Name": "ProcessOne",
"Sequence": "1"
},
{
"Name": "ProcessTwo",
"Sequence": "2"
},
{
"Name": "ProcessThree",
"Sequence": "3"
},
{
"Name": "ProcessFour",
"Sequence": "4"
}
]
}
]
In a QAF-based test using TestNG, am trying to import the values of the "ProcessName" key like this:
String lonelyParentKey = (String) data.get("LonelyParentKey");
ArrayList processNames = (ArrayList) data.get("ProcessNames");
I've seen that in the framework I'm using, I have multiple JSON library options, have been trying to use GSON after reading other SO posts.
So, next in the test code:
Gson gson = new Gson();
JSONArray jsa = new JSONArray(processNames);
What I am attempting to to create an object that contains 4 child objects in a data structure where I can access the Name and Sequence keys of each child.
In looking at my jsa object, it appears to have the structure I'm after, but how could I access the Sequence key of the first child object? In the REPL in IntelliJ IDEA, doing jsa.get(0) gives me "{"Name": "ProcessOne","Sequence": "1"}"
Seems like a situation where maps could be useful, but asking for help choosing the right data structure and suggestions on implementing.
TIA!
Not sure which library you're using, but they all offer pretty much the same methods. JSONArray looks like org.json.JSONArray, so that would be
JSONArray jsa = new JSONArray(processNames);
int sequenceFirstEntry = jsa.getJSONObject(0).getInt("Sequence");
Some JsonArray implementations also implement Iterable, then this also works
JSONArray jsa = new JSONArray(processNames);
for (JSONObject entry : jsa) {
int sequenceFirstEntry = entry.getInt("Sequence");
}
Any reason to not use DTO classes for your model?
e.g.
class Outer {
String lonelyParentKey;
List<Inner> processNames;
// getter/setter
}
and
class Inner {
String name;
String sequence;
// getter/setter
}
now your library should be able to deserialize your JSON string into a List. I have been using Jackson instead of GSON, but it should be similar in GSON:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
List<X> x = objectMapper.readValue(json, new TypeReference<List<X>>() {});
I have a json schema file which follows the custom rules I've created. This schema file is a valid json file. It follows the below pattern.
{
"name": {
"fname" : {
"displayName":"FirstName",
"dataType":"String"
}
"lname" : {
"displayName":"LastName",
"dataType":"String"
}
},
"address": {
"displayName":"Address",
"dataType":"String"
}
}
so based on the schema I need to create the below json with respective values.
{
"name": {
"FirstName": "test",
"LastName" : "test1"
},
"Address" : "someAddress"
}
So when I get the schema, what is the best way to find the config information node? That is the leaf node which has the displayName and dataType parameters. Currently I'm traversing this tree using Jackson json and finding the nodes with displayName and dataType keys. Because I cannot precisely say at which level this leaf node could be present. Is there a better way to handle this situation than traversing the whole json tree looking for the elements?
I was not sure wnat exactly is required (do you want the fname object or the value of its properties), however, JsonPath seems like a good fit here. It is the equivalent of xpath for json - search hierarchy model based on various criteria
I made a small demo to get you started. you just need to twaek the query string to suit your requirements. You can use the Jayway JsonPath Evaluator as REPL
import java.nio.file.*;
import com.jayway.jsonpath.*;
public class JsonPathDemo
{
public static void main(String[] args)
{
// query: get all json objects that have displayName and dataType properties
String jsonPathQuery = "$..*[?(#.displayName && #.dataType)]";
try {
String content = new String(Files.readAllBytes(Paths.get("C://temp/xx.json")));
Object parsedContent = Configuration.defaultConfiguration().jsonProvider().parse(content);
Object configElements = JsonPath.read(parsedContent, jsonPathQuery);
System.out.println(configElements.getClass());
System.out.println(configElements);
} catch (Exception e) {
e.printStackTrace();
}
}
}
output is
class net.minidev.json.JSONArray
[{"displayName":"Address","dataType":"String"},{"displayName":"FirstName","dataType":"String"},{"displayName":"LastName","dataType":"String"}]
EDIT: answer for question in comment:
It is possible to check for path existence (and make all sorts of other assertions) using json-path-assert:
import static com.jayway.jsonpath.matchers.JsonPathMatchers.*;
// query for specific path
String jsonSpecificPathQuery = "$..name.fname.displayName";
String content = new String(Files.readAllBytes(Paths.get("C://temp/xx.json")));
Object parsedContent = Configuration.defaultConfiguration().jsonProvider().parse(content);
System.out.println("hasJsonPath? " + hasJsonPath(jsonSpecificPathQuery).matches(parsedContent));
I need to create a JSON response with some dynamic fields in java. Here is an example of the JSON response I want to return :
{
"success": true,
"completed_at": 1400515821,
"<uuid>": {
type: "my_type",
...
},
"<uuid>": {
type: "my_type",
...
}
}
The "success" and the "completed_at" fields are easy to format. How can I format the fields? What would be the corresponding java object?
Basically I want to work with 2 java objects :
public class ApiResponseDTO {
private boolean success;
private DateTime completedAt;
...
}
and
public class AuthenticateResponseDTO extends ApiResponseDTO {
public List<ApplianceResponseDTO> uuids = new ArrayList<ApplianceResponseDTO>();
}
These java objects don't correspond to the expected JSON format. It would work if I could change the JSON format to have a list, but I can't change it.
Thanks a lot!
You can massage your data into JSON form using the javax.json library, specifically the JsonObjectBuilder and the JsonArrayBuilder. You'll probably want to nest a few levels of a toJson() method which will either give you the string representation you're looking for, or the JsonObject/JsonArray you desire. Something like this:
JsonArray value = null;
JsonArrayBuilder builder = Json.createArrayBuilder();
for (ApplianceResponseDTO apr : uuids) {
builder.add(apr.toJson());
}
value = builder.build();
return value;
I have a map of JSON objects as follows:
Map<String,Object> map = HashMap<String,Object>();
map.put("first_name", "prod");
JSONObject jsonObj = new JSONObject("some complex json string here");
map.put("data", jsonObj);
Gson gson = new Gson();
String result = gson.toJson(map);
Now if the "some complex JSON string here" was:
{"sender":{"id":"test test"},"recipients":{"id":"test1 test1"} }
and execute above code gives me something like:
{
"first_name": "prod",
"data": {
"map": {
"sender": {
"map": {
"id": "test test"
}
}
},
"recipients": {
"map": {
"id": "test1 test1"
}
}
}
}
}
I might have some syntax error up there, but basically I don't know why I am seeing objects wrapped around map's.
Update
according to comments, it is a bad idea to mix different json parsers.
i can understand that. but my case requires calling an external api which takes a hash map of objects that are deserialized using gson eventually.
is there any other object bedsides JSONObject that i can add to the map and still have gson create json out of it without extra 'map' structure? i do understand that i can create java beans and achieve this. but i'm looking for a simpler way since my data structure can be complex.
Update2
going one step back, i am given a xml string. and i have converted them to json object.
now i have to use an external api that takes a map which in turn gets converted to json string using gson in external service.
so i am given an xml data structure, but i need to pass a map to that function. the way i have described above produces extra 'map' structures when converted to json string using gson. i do not have control to change how the external service behaves (e.g. using gson to convert the map).
Mixing classes from two different JSON libraries will end in nothing but tears. And that's your issue; JSONObject is not part of Gson. In addition, trying to mix Java data structures with a library's parse tree representations is also a bad idea; conceptually an object in JSON is a map.
If you're going to use Gson, either use all Java objects and let Gson convert them, or use the classes from Gson:
JsonObject root = new JsonObject();
root.addProperty("first_name", "prod");
JsonElement element = new JsonParser().parse(complexJsonString);
root.addProperty("data", element);
String json = new Gson().toJson(root);
This has to do with the internal implementation of JSONObject. The class itself has an instance field of type java.util.Map with the name map.
When you parse the String
{"sender":{"id":"test test"},"recipients":{"id":"test1 test1"} }
with JSONObject, you actually have 1 root JSONObject, two nested JSONObjects, one with name sender and one with name recipients.
The hierarchy is basically like so
JSONObject.map ->
"sender" ->
JSONObject.map ->
"id" -> "test test",
"recipients" ->
JSONObject.map ->
"id" -> "test test1"
Gson serializes your objects by mapping each field value to the field name.
Listen to this man.
And this one.
I'd a similar problem and I finally resolved it using json-simple.
HashMap<String, Object> object = new HashMap<String,Object>;
// Add some values ...
// And finally convert it
String objectStr = JSONValue.toJSONString(object);
You may try out the standard implementation of the Java API for JSON processing which is part of J2EE.
JsonObject obj = Json
.createObjectBuilder()
.add("first_name", "prod")
.add("data", Json.createObjectBuilder()
.add("sender", Json.createObjectBuilder().add("id", "test test"))
.add("recipients", Json.createObjectBuilder().add("id", "test1 test1"))).build();
Map<String, Object> prop = new HashMap<String, Object>() {
{
put(JsonGenerator.PRETTY_PRINTING, true);
}
};
JsonWriter writer = Json.createWriterFactory(prop).createWriter(System.out);
writer.writeObject(obj);
writer.close();
The output should be:
{
"first_name":"prod",
"data":{
"sender":{
"id":"test test"
},
"recipients":{
"id":"test1 test1"
}
}
}