REST assured - compare two JSON objects - java

Suppose the GET request returns me some JSON object:
{
"a": 1, "b": 2, "c": 3, "date": "current_date"
}
And I have in my hand a similar object, which I'd like to check it's identical for the the keys "a", "b", "c" and ignore the "date" key.
How can I do that?

I have been using JsonUnit and it really helps
String json1 = "{\r\n" + " \"a\": 1,\r\n" + " \"b\": 2,\r\n" + " \"c\": 3,\r\n"
+ " \"date\": \"30-07-2020\"\r\n" + "}";
String json2 = "{\r\n" + " \"a\": 1,\r\n" + " \"b\": 2,\r\n" + " \"c\": 3,\r\n"
+ " \"date\": \"31-07-2020\"\r\n" + "}";
assertThatJson(json1).whenIgnoringPaths("date").isEqualTo(json2);
Static Import :
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
Dependency :
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>2.18.1</version>
<scope>test</scope>
</dependency>
You will have to add json.org or Jackson 1.x or Jackson 2.x or Johnzon or Gson to the classpath as well
I use Jackson

You can transform it to the Json object and delete the unwanted key. Follow the link for details: Remove key from a Json inside a JsonObject

I found out that rest-assured has some interesting functionalities.
You could do:
#Test
public void test() {
get("/xxxx").then().statusCode(200).assertThat()
.body("a", equalTo(1));
}
More info here

You can transform the JSON into a JS object, then compare each property of that object if that property has a key not equal to "date"
In the code below is comparing obj1 to obj2 and ignoring the date property.
It prints "identical" if they are both the same and "not identical" if they are not (ignoring the date property)
var obj1 = JSON.parse ('{ "a":"1","b":"2", "c":"3", "date":"current_date"}' );
var obj2 = JSON.parse ('{ "a":"1","b":"2", "c":"3", "date":"another_date"}' );
let s1 = Object.keys(obj1).length; // length of obj1
let s2 = Object.keys(obj2).length; // length of obj2
let identical = true ;
for ( let i = 0 ; i < s1 ; i ++ ){
if (i >= s2) {
identical = false ;
break ;
}
let current_key = Object.keys(obj1)[i];
let current_value = obj1[current_key];
if (current_key.localeCompare("date") != 0){
if (current_value.localeCompare(obj2[current_key]) != 0){
identical = false ;
break;
}
}
}
if (identical){
console.log ("Identical");
}else {
console.log ("Not identical");
}

Use AssertJ ignoring fields in the comparison
For than it's needed to deserialize json from response (for Spring Test: MvcResult.getResponse().getContentAsString()) to Object.
It is possible to deserialize json response with REST Assured Content-Type based Deserialization
Use unstrict compare with JSONassert.
In order to not creating json by hand, it is possible serialize expected object with Jackson ObjectMapper. For fields exclusion:
Map<String, Object> map = objectMapper.convertValue(obj, new TypeReference<Map<String, Object>>() {});
map.remove(...);
objectMapper.writeValueAsString(obj)

Related

parse strange Json response to a list

I want to parse this object to a list of string. I do not need the key but just want the value as a list of string.
I cannot have a simple model classes because the keys object are more than 1000 in some responses and are random.
So please any idea how to parse it to list in kotlin or java?
{
"data": {
"21": "593754434425",
"22": "4560864343802",
"23": "7557134347529",
"24": "5937544344255",
"25": "45608643438024",
"26": "75571343475293"
}
}
You could first deserialize it as it is, and then convert to a list.
The JSON can be represented this way:
data class Response(val data: Map<String, String>)
You can mark this class #Serializable and use Kotlinx Serialization to deserialize it, or you can use other libraries like Moshi or Jackson (with jackson-module-kotlin).
Once it's deserialized, simply get the values of the map (it's a collection):
val response = Json.decodeFromString<Response>(yourJsonString)
// this is a Collection, not List, but it should be good enough
val stringValues = response.data.values
// if you really need a List<String>
val list = stringValues.toList()
If you want to get the values in the natural order of the keys, you can also use something like:
val values = response.data.toSortedMap(compareBy<String> { it.toInt() }).values
You can use this to parse your data:
val it: Iterator<String> = json.keys()
val arrayList = ArrayList<String>()
while (it.hasNext()) {
val key = it.next()
arrayList.add(json.get(key))
}
A better way is to change the json model, if you access it.
{
"data": [
"593754434425","4560864343802",
"7557134347529","5937544344255",
"45608643438024","75571343475293"
]
}
For this problem, its handy to use the libriary org.json.
See following code snippet:
import org.json.JSONObject;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// Defining the input
String input = "{\n" +
" \"data\": {\n" +
" \"21\": \"593754434425\",\n" +
" \"22\": \"4560864343802\",\n" +
" \"23\": \"7557134347529\",\n" +
" \"24\": \"5937544344255\",\n" +
" \"25\": \"45608643438024\",\n" +
" \"26\": \"75571343475293\"\n" +
" }\n" +
"}\n";
// Parsing it to a json object with org.json
JSONObject inputJson = new JSONObject(input);
// If inputJson does not contain the key data, we return
if(!inputJson.has("data")) return;
// Else we read this data object to a new JSONObject
JSONObject dataJson = inputJson.getJSONObject("data");
// Define an array list where all the values will be contained
ArrayList<String> values = new ArrayList<>();
// Get a key set of the dat json object. For each key we get its respective value and add it to our value array list
for (String key : dataJson.keySet()) values.add(dataJson.getString(key));
// Print all values
for (String value : values) System.out.println(value);
}
}
=>
4560864343802
7557134347529
5937544344255
45608643438024
75571343475293
593754434425
Installing org.json is the easiest with a package manager like maven or gradle.
Guys i have comeup with a similar solution for the problem here
this is my model class
data class UnVerifiedTagIds(
#SerializedName("data")
val data: Object
)
and this is how i parse the respone here
val values: ArrayList<String> = ArrayList()
val list_of_tag_ids: ArrayList<String> =response.data as ArrayList<String>
The ist one is the dataclass for the response
and the 2nd one is the ApiCallInterface m using Retrofit...
and the last one is the apicall itself
I am using Kotlin language
do class name with name like this data class Result(val data:Map<String,String>)
and using library GSON for convert string json to this model
val json = "{\n" +
" \"data\": {\n" +
" \"21\": \"593754434425\",\n" +
" \"22\": \"4560864343802\",\n" +
" \"23\": \"7557134347529\",\n" +
" \"24\": \"5937544344255\",\n" +
" \"25\": \"45608643438024\",\n" +
" \"26\": \"75571343475293\"\n" +
" }\n" +
"}"
val dat = Gson().fromJson(json,Result::class.java)
if (dat.data.isNotEmpty()){
val list= dat.data.values.toMutableList()
print(list)
}
that works fine with me

Java Extract key values from nested json

i do have following JSON and i am trying to extract objects inside result
{
"status":true,
"results":{
"type1":{
"id":"type1"
},
"type2":{
"id":"type2"
}
}
}
Desired output is
type1,type2
I am using Gson for serialization and deserialization.
These are the steps you should be doing when using gson
get keys of the json objects which are inside "results" alone
get it as json object which has keys and values
collect the entry set our of the JSON
create an iterator so that later you can extract the keys
Here is code that does the same job:
public static void main(String[] args) throws Exception {
String json = "{\r\n" +
" \"status\":true,\r\n" +
" \"results\":{\r\n" +
" \"type1\":{\r\n" +
" \"id\":\"type1\"\r\n" +
" },\r\n" +
" \"type2\":{\r\n" +
" \"id\":\"type2\"\r\n" +
" }\r\n" +
" }\r\n" +
"}";
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(json).getAsJsonObject();
//get keys of the json objects which are inside "results" alone
//get it as json object which has keys and values
//collect the entry set our of the JSON
//create an iterator so that later you can extract the keys
Iterator<Entry<String, JsonElement>> iterator = obj.get("results")
.getAsJsonObject()
.entrySet()
.iterator();
while(iterator.hasNext()) {
//here you will get the keys like - type1 and type2
System.out.println(iterator.next().getKey());
}
}
Code Edit: What #fluffy pointed makes complete sense. Made the change

How To Return First And Last Element Of Json

Using gson how can I return the first and last element from my json so I get the data in this format?
System.out.println("Student: BobGoblin - result: 59");
I have tried this, but it still returns the full JSON object
JsonObject jsonObject = new Gson().fromJson(content.toString(), JsonObject.class);
return jsonObject.get(domain) + " - " + jsonObject.get(result.toString());
First of all: toJson converts something to json. You want to convert json to some kind of object. So use fromJson instead.
Second build an object where you can put that data into. There are plenty examples on the manual site for gson: https://github.com/google/gson/blob/master/UserGuide.md
Let me code that for you. It's not that hard:
import java.util.Map;
import com.google.gson.Gson;
public class GsonTest {
public static void main(String args[]) {
Gson gson = new Gson();
String json = "{\"name\":\"Bog\", \"foo\":\"bar\", \"result\": 59}";
// Using a map
#SuppressWarnings( "unchecked" )
Map<String,Object> map = gson.fromJson( json, Map.class );
System.out.println( "Name: " + map.get( "name" ) + " result: " + map.get( "result" ) );
// Better: using an object
Student student = gson.fromJson( json, Student.class );
System.out.println( "Name: " + student.name + " result: " + student.result );
}
public static class Student {
public String name;
public String foo;
public int result;
}
}
which will result in:
Name: Bog result: 59.0
Name: Bog result: 59
The general Method is: Take the json String and put it in some kind of java object. Then access that java object to get to your data.
Note that you get more control over the kind of data you will receive using the second method. Since json doesn't specify the datatype the parser guesses float/double for age while it uses int in the second example because the class said so.

hashmap to JSON using GSON

I am using Gson for converting my Java Objects to GSON. I wanted to convert my HashMap to JSON.
Assuming my Object1 has structure:
public class Object1 {
String a;
String b;
String c;
String toString() {
return "a: " + a + " b: " + b + " c: " + c;
}
}
and my Object2 has Structure:
public class Object2 {
String e;
String f;
}
I wanted my final JSON to look like
{
{
"a" : "aValue",
"b" : "bValue",
"c" : "cValue"
} : {
"e" : "eValue",
"f" : "fValue"
}
}
Bit I am getting it as
{
"a: aValue b: bValue c: cValue" : {
"e" : "eValue",
"f" : "fValue"
}
}
Is this possible to have it in desired form.
I tried using TypeToken given in JSON documentation. That didn't help.
You cannot get your expected form.
JSON's element is always a key-value paar and the key is always a text (or String). But in your case the key is an object.
From my understanding, if you wanna to consume the key as an Object, you could get it as a String and then use ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper) to convert it to your expected class.
final ObjectMapper mapper = new ObjectMapper();
Object1 object1 = mapper.readValue(object1String, Object1.class)
Your toString() method may be causing issues, Gson will process the map itself, there is no need to provide a toString() like you have. That's why your output is giving you that.
Also take a look at Jackson, it would be fit for your purpose and is very easy to use.
Map map = new HashMap();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(map);
// write json to file
You can write your toString method as:
public String toString() {
return "{a: " + a + ", b: " + b + ", c: " + c + "}";
}
In your main class, you call:
public static void main(String[] args) {
Object1 object1 = new Object1("aValue", "bValue", "cValue");
Object2 object2 = new Object2("eValue", "fValue");
Map<String, Object2> map = new HashMap<String, Object2>();
map.put(object1.toString(), object2);
String json = new Gson().toJson(map);
}
Then, your output like: {"{a: aValue, b: bValue, c: cValue}":{"e":"eValue","f":"fValue"}}

How to generate JSON string in Java using net.sf.json?

I am struggling to generate JSON String in Java.
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
JSONArray ja = new JSONArray();
JSONObject js = new JSONObject();
JSONObject j = new JSONObject();
String s = "[{\"shakil\",\"29\",\"7676\"}]";
js.put("id", "1");
js.put("data", s);
ja.add(js);
j.put("rows", ja);
System.out.println(j.toString());
actual output:
{"rows":[{"id":"2","data":"[{\"shakil\",\"29\",\"7676\"}]"}]}
expected output:
{"rows":[{"id":"2","data":["shakil", "29","7676"]}]};
Your s is a String which is not unquoted when put into a JSONObject. You must build another JSONArray for the value of data:
// using http://jettison.codehaus.org/
JSONObject outerObject = new JSONObject();
JSONArray outerArray = new JSONArray();
JSONObject innerObject = new JSONObject();
JSONArray innerArray = new JSONArray();
innerArray.put("shakil");
innerArray.put("29");
innerArray.put("7676");
innerObject.put("id", "2");
innerObject.put("data", innerArray);
outerArray.put(innerObject);
outerObject.put("rows", outerArray);
System.out.println(outerObject.toString());
Result:
{
"rows": [
{
"id": "2",
"data": [
"shakil",
"29",
"7676"
]
}
]
}
Write
String[] s = new String[] {"shakil", "29" , "7676"};
instead of
String s = "[{\"shakil\",\"29\",\"7676\"}]";
Check out gson, it'll provide you with a whole lot of options for serializing/deserializing your Java objects to/from JSON.
Example taken from the page
Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
//(Serialization)
gson.toJson(ints); ==> prints [1,2,3,4,5]
gson.toJson(strings); ==> prints ["abc", "def", "ghi"]
//(Deserialization)
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
Finally found answer for net.sf.json
JSONArray data1 = new JSONArray();
data1.add("shakil");
data1.add("29");
data1.add("100");
JSONObject inner1 = new JSONObject();
inner1.put("id", "1");
inner1.put("data", data1);
JSONArray list2 = new JSONArray();
list2.add(inner1);
JSONObject finalObj = new JSONObject();
finalObj.put("rows", list2);
System.out.println(finalObj);
Not being able to declare a JSON string in Java is huge pain. Mainly due to (a) no multiline strings (b) escaping double quotes makes it a mess wrt readability.
I work around this by using single quotes to declare the JSON string (using the standard multiline concatenation). Nothing fancy:
String jsonStr =
"{" +
"'address': " +
"{" +
"'name': '" + name + "'," +
"'city': '" + city + "'," +
"'street1': '"+ street1 +"'," +
"'street2': '"+ street2 +"'," +
"'zip': '" + zip + "', " +
"'state':'" + state + "'," +
"'country': '" + country + "'," +
"'phone': '" + phone + "'" +
"}" +
"}";
jsonStr = MyUtil.requote(jsonStr);
System.out.println(jsonStr);
MyUtil
public static String requote(String jsonString) {
return jsonString.replace('\'', '"');
}
Some might find this more cumbersome than declaring a Map but this works for me when I have to build a JSON with just string syntax.
I see a lot of problems when writing a json as String directly without using a Objectmapper or similar.
I would suggest you to write your Json (as you defined it):
{"rows":[{"id":"2","data":["shakil", "29","7676"]}]}
and then simply use this little online tool: http://www.jsonschema2pojo.org/
Which can convert a simply Json a Java-Class also with multiple classes. You can there choose during generation if you want to use Gson or Jackson later.
Gson is a little bit lightweighter and may is better for beginning. I prefer Jackson because you can create something like a computed property - but that's already to much detail.
https://code.google.com/p/google-gson/
After adding Gson all you need to do is:
Gson gson = new Gson();
MyGeneratedClass target = new MyGeneratedClass();
String json = gson.toJson(target);
As voila: you have generated a simple json without thinking about how to change it later!

Categories