Is there a way to fetch Json values within Json? - java

I've got a Scenario Entity in my Spring boot app
private Long id;
private String scenarioName;
private HashMap<Integer, Object> scenarioAttributes;
Let's say we create a Scenario entity with following Json:
{
"scenarioName":"scenario1",
"scenarioAttributes":{
"1" : {
"goToURL":"https://google.com/"
},
"2" : {
"assertCurrentUrl":"https://google.com/"
}
}
}
In my ExecutorService, I've got following code:
public List<Object> getStepsFromScenarioAttributesValues(Long scenarioId){
List<Object> response = new ArrayList<>();
Scenario scenario = scenarioService.getScenario(scenarioId);
HashMap<Integer, Object> steps = scenario.getScenarioAttributes();
for (Map.Entry<Integer, Object> set : steps.entrySet()){
response.add(set.getValue());
System.out.println(response);
// prints out
//[{goToURL=https://google.com/}, {assertCurrentUrl=https://google.com/}]
}
return response;
}
public void executeSteps(List<Object> response){
for (Object obj : response){
JsonObject jsonObj = (JsonObject) obj;
if (jsonObj.has("goToUrl")) {
//goes to url
driverService.goToUrl(String.valueOf(jsonObj.get("goToUrl")));
return;
} else if (jsonObj.has("assertCurrentUrl")) {
//asserts cur url with value
driverService.assertCurrentUrl(String.valueOf(jsonObj.get("assertCurrentUrl")));
return;
}
}
}
public String executeScenario(Long scenarioId){
executeSteps(getStepsFromScenarioAttributesValues(scenarioId));
return "Scenario" + scenarioId + " has been executed successfully";
}
I've got a GetMapping for single scenario as follows:
#GetMapping("/scenarios/{id}/execute")
public List<Object> executeScenario(#PathVariable Long id){
return executorService.getStepsFromScenarioAttributesValues(id);
}
Which, upon sending one sample scenario and entering a site, provides us with, you guessed it, a List containing an Object, which is a Json.
Unfortunately, if I want to call executeSteps() function which has a list of Objects, I cannot do it since an Object is not a JsonObject.
I thought simple JsonObject jsonObj = (JsonObject) obj; would do a trick, but I'm greeted with
class java.util.LinkedHashMap cannot be cast to class com.google.gson.JsonObject (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; com.google.gson.JsonObject is in unnamed module of loader 'app')
How can I approach fetching values from scenarioAttributes Jsons to further interpret them?
Are there unnecessary lines of code that I could get rid of?
Feel free to point out my wrongdoings, just starting my journey with Spring

public class Scenario {
private String scenarioName;
private HashMap<Integer, Object> scenarioAttributes;
}
Use object mapper to print class object to JSON:
ObjectMapper objectMapper = new ObjectMapper();
Scenario scenario = objectMapper.readValue(response, Scenario.class);

When you say Object, which is a Json what do you mean by "Json"? Json is not a class. I assume that your Object is an instance of class String that contains text in Json format. Your exception though points out that it could be a Map. I would still assume that it is a String that holds Json. In your code you attempt to work with class JSONObject which is part of json-simple library. While it is a nice training library I would suggest that you don't use it. BTW great site about JSON with the list of most libraries for most languages is: https://www.json.org/json-en.html. Best options are (IMHO) are Jackson-Json (also known as Faster XML) or Gson (by Google) (Here is their user guide site). To parse your Json text to a class instance you can use ObjectMapper class which is part of Jackson-Json library. For example
public <T> T readValue(String content,
TypeReference valueTypeRef)
throws IOException,
JsonParseException,
JsonMappingException
See Javadoc. But I also may suggest a very simplified JsonUtils class which is a thin wrapper over Jackson-Json library. This class is part of Open-source library called MgntUtils written and maintained by me. Your code may be as simple as follows:
Scenario scenario;
try {
scenario = JsonUtils.readObjectFromJsonString(response, Scenario.class);
} catch(IOException ioe) {
....
}
Here is JsonUtils javadoc. MgntUtils library can be obtained as Maven artifact here or on Github (including source code and Javadoc)

Related

How extract response to String and save it to variable

Being new to Java/JSON/REST Assured topics, I would like to extract a parameter of "token": from a JSON response body as a String and store it as variable which I could take to some other classes and use there. However, I have tried it and have not found a way. Below is part of a code which I have created at the beginning in a same manner as other requests stored in this class, but this is the first one from which I need something from the response:
public FakeTokenVO fakeToken() {
String payload = "payloadthere";
return given(specBuilder.fakeTokenRequestSpecification()) .
body(payload)
.log().all()
.when()
.post(RestApiRoutes.FAKE_URI)
.then()
.log().all()
.extract()
.response()
.as(FakeTokenVO.class);
}
Don't mind about the payload and those VO classes as it is stored as data model somewhere else.
Response from the request made looks like this:
{
"createTokenResponse": {
"createTokenSuccess": {
"token": "token_with_somewhere_about_700_characters"
}
}
}
Here is how I have tried to modify it to get the part of response which I need later (the token to authorize other requests):
#Test
public void fakeToken()
{
String payload = "payloadthere";
String token = given(specBuilder.fakeTokenRequestSpecification())
.body(payload)
.log().all()
.when()
.post(RestApiRoutes.FAKE_URI)
.then()
.log().all()
.extract()
.response()
.body().path("createTokenResponse.createTokenSuccess.token");
System.out.print(token);
}
This test returns me a value which I needed, but I do not know how to implement it as a method instead of test. Please help how should I approach it? What am I missing there? I tried to search for answers, but I haven't found a solution yet or do not know how to implement it in my part of the code.
I assume that you can get your response as a String. So all you need to do is to parse your Json String. For that you can use any available Json parser. The most popular ones are Json-Jackson (also known as Faster XML) or Gson (by Google). Both are very well known and popular. (My personal preference is Jackson, but it is a matter of opinion).
However, For simplistic cases like this I wrote my own utility (a thin wrapper over Jackson library) that allows you to parse Json String very simply without learning relatively complex libraries. With my utility your code may look like this:
try {
Map<String, Object> map = JsonUtils.readObjectFromJsonString(jsonStr, Map.class);
Map<String, Object> innerMap = map.get("createTokenResponse");
Map<String, Object> innerMap2 = map.get("createTokenSuccess");
String token = innerMap.get("token");
} catch (IOException e) {
e.printStacktrace();
}
Or you can create your own classes such as
public class TokenResult {
String token;
//getter and setter
}
public class TokenHolder {
private TokenResult createTokenSuccess;
//setter and getter
}
public class TokenResponse {
private TokenHolder createTokenResponse;
//setter and getter
}
And than your code may look like this:
try {
TokenResponse response = JsonUtils.readObjectFromJsonString(jsonStr, TokenResponse .class);
String token = response.getCreateTokenResponse().getCreateTokenSuccess().getToken();
} catch (IOException e) {
e.printStacktrace();
}
Here is a Javadoc for JsonUtils class. This Utility comes as part of Open Source MgntUtils library written and maintained by me. You can get the library as maven artifact on Maven Central here or on the github (including source code and javadoc)

How to get the first data object of a data object (REST api)

I Have a REST api that contains the data like this way
{
...
... //<- more data here
...
"currencies": {
"BTN": {
"name": "Bhutanese ngultrum",
"symbol": "Nu."
},
"INR": {
"name": "Indian rupee",
"symbol": "₹"
}
}
...
... //<- more data here
...
}
i am doing a project in java where i need to use okhttp and show information about a country from an available rest api and before when i used this api it had all the data in currencies in an data array and that was helpful as you can just get the first zero object from the array , but after they updated the api they made all data in currencies an object and i only want the first object , any way i can get it?
OK, so you have two options here ...
Option 1.
Create two classes like this and use ObjectMapper class to do automatic deserealisation for you.
class CurrencyData {
String name;
String symbol;
}
class CurrencyJsonResponse {
CurrencyData INR;
CurrencyData BTN;
}
public static void main(String[] args) {
OkHttpClient client = // build an instance;
ObjectMapper objectMapper = new ObjectMapper();
ResponseBody responseBody = client.newCall(request).execute().body();
CurrencyJsonResponse currencyResponse = objectMapper.readValue(responseBody.string(), CurrencyJsonResponse.class);
//Get data by using getters on currencyResponse object
}
Option 2
You can write a custom deserealizer by extending the StdDeserializer<T> class. You'll have to programmatically inspect the JsonNode parse tree and assemble the object that you want.
This article explains how to do it and comes with a working code sample

Populate POJO with array (root JSON node) using Jackson

I'm using Jackson and RESTEasy to hook into an external API. The API mainly returns simple objects which I have managed to successfully populate into POJOs.
I'm hitting a problem where I get an array of objects back e.g.
[
{
"variable1": "someValue1",
"variable2": "someValue2",
"variable3": "someValue3"
}
{
"variable1": "someValue4",
"variable2": "someValue5",
"variable3": "someValue6"
}
{
"variable1": "someValue7",
"variable2": "someValue8",
"variable3": "someValue9"
}
]
I have 2 classes: one called VariableObject which looks like this:
public class VariableObject {
private String variable1;
private String variable2;
private String variable3;
}
and VariableResponse which looks like:
public class VariableResponse {
private List<VariableObject> variableObjects;
}
My client uses JAXRS Response class to read the entity into the class i.e
return response.readEntity(VariableResponse.class);
I get a stack trace which reads:
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of VariableResponse out of START_ARRAY token
I understand you can return these as a List of POJOs i.e List quite easily, but this is not what I want to do.
The question really is two parts:
a. Can I possibly populate the VariableResponse POJO using Jackson (some how) preferably without a customer deserialiser? Maybe some annotation exists (this would be ideal)?
b. Is there some way to detect if an Array is being retuned as the root JSON node in the response and then act accordingly?
Help greatly appreciated.
Your JSON is indeed an array of objects.
You can deserialize it with:
response.readEntity(new GenericType<List<VariableObject>>() {});
And then create a new instance of VariableResponse passing resulting List as a constructor parameter like this:
public class VariableResponse {
private final List<VariableObject> variableObjects;
public VariableResponse(List<VariableObject> variableObjects) {
this.variableObject = new ArrayList<>(variableObjects);
}
}
You might forget to add comma after each {..}. After correcting your JSON string, I converted it into ArrayList<VariableObject> using TypeReference and ObjectMapper.
sample code:
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
...
TypeReference<ArrayList<VariableObject>> typeRef = new TypeReference<ArrayList<VariableObject>>() {};
ObjectMapper mapper = new ObjectMapper();
try {
ArrayList<VariableObject> data = mapper.readValue(jsonString, typeRef);
for (VariableObject var: data) {
System.out.println(var.getVariable1()+","+var.getVariable2()+","+var.getVariable3());
}
} catch (Exception e) {
System.out.println("There might be some issue with the JSON string");
}
output:
someValue1,someValue2,someValue3
someValue4,someValue5,someValue6
someValue7,someValue8,someValue9
If you prefer your own response type direct.
Try just extending ArrayList?
public VariableResponse extends ArrayList<VariableObject> {
}

Deserializing a JSON-collection(potentially with another collection) of objects in GSON

I've been fighting with JSON parsing using GSON today and a lot of things went well with a minimum amount of hassle.
Though, for the following JSON string I started running into some issues;
{"success":1,"response":{"dvds":{"IronMan":{"rating":"awesome"},"BatMan":{"rating":"awesome"},"Smurfs":{"rating":"childish"}}}}
In this JSON I have a collection "response" containing a collection of responsetypes. In the example the only responsetype included is dvds.
But my issue lies here; I wish to have every child of "dvds" to be parsed to a List response , each child being a single Dvd-class object (containing a String "title" and a String "rating")
Thus far parsing seperate values/objects and parsing arrays went with no real issues, but I can't wrap my head around how to solve parsing such collections.
googling today kept referencing me to "TypeTokens" but looking at the code in various topics regarding this issue, I still haven't understood how to implement it for my use-scenario at all.
So, to be concrete;
"How can I make GSON correctly recognize both my responsetype and dvd-collections?"
Currently my ResponseData.class looks like this:
public class ResponseData {
public int success;
public List<ResponseTypes> responsetypes;
public class ResponseType{
public List<Dvd> Dvds;
}
public class Dvd{
public String title;
public String rating;
}
}
That's how i'd look at this problem in an array-based form, but this time i need to apply it in the case i run into a collection of objects instead. in all scenarios i can think of the Class of the object should be able to be recognized by the name of it's parent.
Currently the parsing is initiated as follows;
try{
Gson gson = new Gson();
Reader reader = new InputStreamReader(stream);
ResponseData responsedata = gson.fromJson(reader, ResponseData.class);
return responsedata;
}
I really hope someone can help me out! Thanks!
you have here some problems:
the class ResponseData should hold List<ResponseType> and not List<ResponseTypes>
the json that you supplied isnt matching the classes above.
an accurate classes for this json are:
public class ResponseData
{
public int success;
public Map<String, Map<String, Dvd>> response;
public class Dvd
{
public String rating;
}
}
in order to describe a list in json you should use: "[ ]". for example: [1,2,3]. you can read more about json here
if you want the json to describe the class hierarchy you describe above. it should looks like:
{"success":1,"responseTypes":[{"Dvds":[{"title":"IronMan","rating":"awesome"},{"title": "BatMan", "rating":"awesome"},{"title":"Smurfs", "rating":"childish"}]}]}
notice that unless you declare a mapping between the variable names and the json varible names then you should use the same names. for example "Dvds" and "responseTypes"

How to get nested attribute and images from Json response

I receive from server a response in this form
{"error":null,"id":1,"result":
{"admin":false,
"firstname":"Jason",
"id":346,"idHotel":109,
"idVendor":null,
"lastname":"Butcher",
"sessionkey":"3c8a17ae47a6d131b1a14b44a1d8f9a9",
"urlAvatar":"avatar_316_mjm.jpg",
"urlThumb":"thumb_316_mjm.jpg"}
}
And want to get the various singles attributes,
for example
Boolean error=..;
String admin=....;
String idHotel=...;
and also the images
You should create a wrapper class like this:
public class Response {
public boolean error;
public int id;
public Result result;
}
public class Result {
...
}
then is simple for you to deserialize the json via gson to you classes:
Response response = new Response();
Gson gson = new Gson();
response = gson.fromJson(response, Response.class);
And there's a lot of other nifty things you can do: https://sites.google.com/site/gson/gson-user-guide
Oh forgot one important thing!
Remember to change the namespace on the Gson library, I had problems get it running on htc telephones. You can do this with jar jar links: http://code.google.com/p/jarjar/downloads/list
docs: http://code.google.com/p/jarjar/wiki/CommandLineDocs

Categories