How can I get data from the api graphQL? - java

I make a request on api graphQL and have the responce of body:
{
"dataRequests": [
{
"status": "success",
"title": "token",
"values": {
"limit": 1,
"offset": 0,
"count": 1,
"total": 1,
"elements": [
{
"type": "DOMAIN",
"permission": "default",
"properties": [
{
"name": "property:id",
"value": 390
},
{
"name": "setting:crawler:token",
"value": "token(here's real token)"
}
],
"filters": []
}
]
}
}
]
}
I want to get value of the field "value" with token. But i have a problem to desirialize it.
My code can get the list of maps of 'dataRequests' field(using RestAssured):
GraphQLSteps graphQLSteps = new GraphQLSteps();
Response response = graphQLSteps.postProjectToken(id);
List<Map<String, String>> dataRequest = response.jsonPath().getList("dataRequests");
but, if i try to get the list of maps of 'value' field:
List<Map<String, String>> dataRequest = response.jsonPath().getList("value");
i get the "null" value. I think it's because i have to wrap it through the whole tree: values - elements - properties and only then value. But it's very complicated and i tried to get it in this way, but obtain only the same result "null".
I noticed that if i print an entrySet of an existing map from list:
List<Map<String, String>> dataRequest = response.jsonPath().getList("dataRequests");
for (Map<String, String> map : dataRequest) {
System.out.println(map.entrySet());
}
I get the result:
[status=success, title=token, values={limit=1, offset=0, count=1, total=1, elements=[{type=DOMAIN, permission=default, properties=[{name=property:id, value=390}, {name=setting:crawler:token, value=someToken}], filters=[]}]}]
And can see value with token there.
Can you prompt me, how can i get the "value" with token either from this List<Map<String, String>> or by other way with deserialitation api?

Your json is kind of complicated with many nested level. I would recommend to use lib jsonpath, instead of using jsonpath provided by rest-assured.
Example:
List<String> values = JsonPath.read(response.toString(), "$..value");
System.out.println(values);
//[390,"token(here's real token)"]
add jsonpath to pom.xml
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.6.0</version>
</dependency>

Related

How do I access triple nested values in JSON using Java?

I am trying to access the "text" values in the below JSON and create an ArrayList with those values. How would I approach that? I am trying to use com.fasterxml.jackson.
{
"searchApiFormatVersion": "1.0",
"searchName": "SalaryAccessRole",
"description": "",
"totalRowCount": "2",
"returnedRowCount": "2",
"startingReturnedRowNumber": "1",
"basetype": "Person",
"columnCount": "1",
"columnHeaders": [
{
"text": "EMPLID",
"dataType": "string"
}
],
"resultSet": {
"rows": [
{
"values": [
{
"text": "2270127",
"dataType": "string",
"columnHeader": "EMPLID"
}
]
},
{
"values": [
{
"text": "1050518",
"dataType": "string",
"columnHeader": "EMPLID"
}
]
}
]
}
}
I've used this to success for the searchName but am trying to get the text under resultSet->rows->values->text.
JsonNode salaryExcludePersonNode = new ObjectMapper().readTree(sourceJson);
String person = salaryExcludePersonNode.get("searchName").textValue();//this works
String person2 = salaryExcludePersonNode.get("resultSet")
.get("rows")
.get("values")
.get("text")
.textValue());//this says that com.fasterxml.jackson.databind.JsonNode.get(String) is null
I know you tagged this question as a Jackson question, but I think JSONPath may be a good fit here.
The JSONPath library is available as a Maven dependency:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.7.0</version>
</dependency>
For the JSON in your question, all of the "text" values can be selected using a single JSONPath selector:
$.resultSet.rows..text
$ - start at the root of the JSON.
.resultSet.rows - navigate to the rows array.
..text - recursively find all text entries.
The results are automatically added to a Java List:
String jsonAsString = "{...}";
List<String> textList = JsonPath.read(jsonAsString, "$.resultSet.rows..text");
You can also read from a java.io.File directly:
File jsonFile = "/your/path/to/file.json";
List<String> textList = JsonPath.read(jsonFile, "$.resultSet.rows..text");
The list will be populated with 2 entries:
2270127
1050518
References:
JSONPath syntax overview
JavaDocs

Java Spring custom JSON response

I have a data that looks like so:
{
"name":{
"first": "<firstName>",
"last": "<lastName>"
},
"info": "<info>",
"place":{
"location": "<location>",
},
"test": "<test>"
}
However, I want to customize the Response json and group the data by the location.
In other words I would like to have a response like this:
"location":[{
"name": <location>,
user: [{
"name": <firstName> + <lastName>,
"info": <info>,
"test": <test>
}]
}]
I have tried to the it into a map like so:
List<Data> data= newArrayList(repository.findAll(Sort.by(Sort.Direction.ASC, "location")));
Map<String, Object> result= new HashMap<>();
for (Data d : data) {
result.put("name", d.getLocation());
result.put("user", d.getFirstName());
...
and so on, but this does not work. What is the best approach to achieve my desired result?
As of now you have a single result map, which you are then overwriting in the loop, so it will contain data for a location only, the last one. What you probably wanted to do is creating a list of those maps, which requires creating a new map inside the loop, and collecting them in a list:
List<Map<String, Object>> result=new ArrayList<>();
for(Data d : data) {
Map<String, Object> item = new HashMap<>();
item.put("name", d.getLocation());
item.put("user", d.getFirstName());
...
result.add(item);
}

Get json object in Array based on key and value in Java

I have a Json body like the example below. I need to extract the value from a key that has another key with a specific value in an array. I am passing in a JsonNode with everything in the detail component of the message, I can easily extract from each level, however, I'm struggling with the array.
In this case, I need to extract the value of "value" (Police/Fire/Accident Report) from the object in the array which has a key/value pair of "name":"documentTitle". I understand this is a JSONArray, but I can't find a good example that shows me how to extract the values for an object in the array that contains a certain key/value pair, I don't think I can rely on getting the object in position [2] in the array as the same objects may not always be present in the additionalMetadata array.
Sample Json:
"sourceVersion": "1.0",
"eventId": "8d74b892-810a-47c3-882b-6e641fd509eb",
"clientRequestId": "b84f3a7b-03cc-4848-a1e8-3519106c6fcb",
"detail": {
"stack": "corona",
"visibilityIndicator": null,
"documentUid": "b84f3a7b-03cc-4848-a1e8-3519106c6fcb",
"additionalMetadata": [
{
"name": "lastModifiedDate",
"value": "2021-05-21T04:53:53Z"
},
{
"name": "documentName",
"value": "Police/Fire Report, 23850413, 2021-05-20 14:51:23"
},
{
"name": "documentTitle",
"value": "Police/Fire/Accident Report"
},
{
"name": "documentAuthor",
"value": "System Generated"
},
{
"name": "lastModifiedBy",
"value": "System Updated"
},
{
"name": "createdBy",
"value": "System Generated"
},
{
"name": "documentDescription",
"value": "Police/Fire Report received"
},
{
"name": "organizationCode",
"value": "Claims"
}
]
}
}```
Loop through the json array and extract the json object with name documentTitile. From that json object you can get the value
Well, either the JSON framework you're using supports this out of the box (check the documentation) or you could convert it manually to a map:
List<AdditionalMetadataEntry> additionalMetadata;
[...]
Map<String, String> additionalMetadataMap = additionalMetadata.stream().collect(Collectors.toMap(AdditionalMetadataEntry::getName, AdditionalMetadataEntry::getValue));
I was able to figure it out. I created a new node off the existing notificationBody JsonNode, then parsed through the metadata key/value pairs:
String docTitle = "";
JsonNode additionalMetadata = notificationBody.get("detail").get("additionalMetadata");
for (JsonNode node: additionalMetadata) {
String name = node.get("name").asText();
String value = node.get("value").asText();
if(name.equals("documentTitle")){
docTitle = value;
}
}

Jackson converting dynamic json to map

I have a problem where some structure of the json is fixed while some part is dynamic. The end output has to be an object of type
Map<String,List<Map<String,String>>>
I am pasting a sample json code for which the jackson work -
{
"contentlets": [
{
"template": "8f8fab8e-0955-49e1-a2ed-ff45e3296aa8",
"modDate": "2017-01-06 13:13:20.0",
"cachettl": "0",
"title": "New Early Warnings",
"subscribeToListIi": "am#zz.com",
"inode": "15bd497-1d8e-4bc7-b0f4-c799ed89fdc9",
"privacySetting": "public",
"__DOTNAME__": "New gTLD Early Warnings",
"activityStatus": "Completed",
"host": "10b6f94a-7671-4e08-9f4b-27bca80702e7",
"languageId": 1,
"createNotification": false,
"folder": "951ff45c-e844-40d4-904f-92b0d2cd0c3c",
"sortOrder": 0,
"modUser": "dotcms.org.2897"
}
]
}
ObjectMapper mapper = new ObjectMapper();
Map<String,List<Map<String,String>>> myMap=mapper.readValue(responseStr.getBytes(), new TypeReference<HashMap<String,List<Map<String,String>>>>() {});
The above code is working fine but when the json changes to (basically a metadata tag is added) it is not able to convert to map.
{
"contentlets": [
{
"template": "8f8fab8e-0955-49e1-a2ed-ff45e3296aa8",
"modDate": "2017-01-06 13:13:20.0",
"cachettl": "0",
"title": "New gTLD Early Warnings",
"subscribeToListIi": "aml#bb.com",
"inode": "15bd4057-1d8e-4bc7-b0f4-c799ed89fdc9",
"metadata": {
"author": "jack",
"location": "LA"
},
"privacySetting": "public",
"__DOTNAME__": "New gTLD Early Warnings",
"activityStatus": "Completed",
"host": "10b6f94a-7671-4e08-9f4b-27bca80702e7",
"languageId": 1,
"createNotification": false,
"folder": "951ff45c-e844-40d4-904f-92b0d2cd0c3c",
"sortOrder": 0,
"modUser": "dotcms.org.2897"
}
]
}
This is expected since the type of the value of metadata is not a String. If you change the type of the map accordingly then it works:
Map<String,List<Map<String,Object>>> myMap = mapper.readValue(reader, new TypeReference<HashMap<String,List<Map<String,Object>>>>() {});
Of course you are left with the problem that values in the map are not of the same type. so you need to ask yourself what is the desired data structure you want and how you further process it. However, one cannot deserialize a json structure into a simple String.

How to get specific nodes from a Json Tree without iterating through the entire list

Consider the following Json structure:
{ "ubds": [
{
"id": "33",
"metaData": {
"lineInfo": {
"poNumber": "PO_123",
"poLineNumber": 1
}
},
"confirmedDeliveryDate": "2016-05-26T16:15:51",
"quantity": 99
},
{
"id": "34",
"metaData": {
"lineInfo": {
"poNumber": "PO_123",
"poLineNumber": 2
}
},
"confirmedDeliveryDate": "2016-05-26T16:15:51",
"quantity": 99
},
{
"id": "35",
"metaData": {
"lineInfo": {
"poNumber": "PO_123",
"poLineNumber": 3
}
},
"confirmedDeliveryDate": "2016-05-26T16:15:51",
"quantity": 99
}]}
Using JsonNode, is there a way to get the entire child node {id through quantity} with the poLineNumber attribute value of 3 without having to iterate through all the nodes and returning on a match? Do I need to use JsonPath for this?
You can have a look to JsonPath.
You can first use ObjectMapper to create a Map<String, Object> from the given json string, and read it and evaluate a JsonPath expression. For example:
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> mappedObject = mapper.readValue(jsonString, Map.class);
// Evaluate that expression
Object result = JsonPath.read(mappedObject, "$.ubds[?(#.metaData.lineInfo.poLineNumber==3)]");
or directly read the json string with JsonPath:
Object result = JsonPath.parse(jsonString).read("$.ubds[?(#.metaData.lineInfo.poLineNumber==3)]");

Categories