Validate Array JSON response with Multiple records in Java - java

We have API which gives following responses
[
{
"subject": "English",
"Marks": "79"
},
{
"subject": "Maths",
"Marks": "89"
}
]
We need to validate that
Subject=English and Marks =79
Subject=Maths and Marks =89
we have tried but not successful.
JSONArray jsonarray = new JSONArray(strindentify);
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject jsonobject = jsonarray.getJSONObject(i);
String type = jsonobject.getString("subject");
Assert.assertEquals(type, "English");
String value = jsonobject.getString("Marks");
Assert.assertEquals(value, "79");
System.out.println(" The Subject and Marks:-" +type +"and" +value );
}
Need to assert that Subject=English then Marks=79 etc

There is a problem in your assertion. You have to pass 2 strings to assertEquals:
Assert.assertEquals(type, "English");

Your for loop checks both subjects in each iteration. Instead you will want to get the single values of 'subject' and 'marks' in each iteration, and check your conditions based on the subject.
Such as:
JSONArray jsonarray = new JSONArray(strindentify);
Assert.assertEquals(2, jsonarray.length, "Expected exactly 2 entries in array"); //optional
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject jsonobject = jsonarray.getJSONObject(i);
String type = jsonobject.getString("subject");
String value = jsonobject.getString("Marks");
System.out.println(" The Subject and Marks:-" +type +"and" +value );
switch(type) {
case "English": Assert.assertEquals(value, "79"); break;
case "Maths": Assert.assertEquals(value, "89"); break;
default: throw new RuntimeException("Unexpected subject"); //optional
}
}
Note the '//optional' lines, which respectively will fail the test if there is anything more or less than 2 items in the array, or if any subject other than English or Maths is encountered.
Note that this doesn't fail the edge case where the array contains 2 entries, but both are English or both are Maths.
I used a switch which would allow you to easily add other subjects/marks combinations. An if/else construct would be just as valid. Just remember to break if you use switch!

#Test
public void test_validJson() {
String input = "Your_string_json_here";
JSONArray jsonarray = new JSONArray(input);
Assert.assertNotNull(jsonarray);
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject jsonobject = jsonarray.getJSONObject(i);
Assert.assertNotNull(jsonobject);
String subject = jsonobject.getString("subject");
String value = jsonobject.getString("Marks");
Assert.assertNotNull(subject);
Assert.assertNotNull(value);
switch(subject) {
case "English" :
Assert.assertEquals(value, "79");
break;
case "Maths" :
Assert.assertEquals(value, "89");
break;
default:
// Fail on unrecognized subject?
throw new AssertionException();
}
}
}
Note that this will fail if the subject and/or value is missing and will also fail on unknown subject(s). This makes no guarantees for the length of the array or the ordering of the elements, eg English MUST be the first array item etc. Duplicate subjects will also not fail the test.This simply validates that if given subjects are included in the response then their respective marks are as those given.
Modify this to your liking.
EDIT:
If you want to validate only selected subjects are included:
List<String> knownSubjects = Arrays.asList("History", "Maths", "English", "whatever");
Assert.assertTrue(knownSubjects.contains(subject));
If you want to validate only known subjects WITH known marks:
Map<String, String> subjectMarks = new HashMap<>();
subjectMarks.put("English", "89");
subjectMarks.put("Maths", "79");
subjectMarks.put("Whatever", "10");
Assert.assertTrue(subjectMarks.keySet().contains(subject));
Assert.assertEquals(value, subjectMarks.get(subject));

Related

Nested JSONArray

I need to read a JSON file with following form:
{
"Data":[{
"foo":"22",
"bar":"33",
"array":[
{
"1foo":"22",
"1bar":"33"
},
{
"2foo":"22",
"2bar":"33",
}
],
"anotherData":{
"foofoo":"22",
"barbar":"33"
},
"some more data":"11",
"some more data":"11"
},
{and the cycle here starts again from -->
"foo":"22",
"bar":"33",
"array":[
My question stands : How do I access individual elements given it's sometimes JSONObject and sometimes JSONArray. I tried using org.json library but I'm failing to access anything after this line -> "array":[. I tried various combinations of JSONObject and JSONArray up to no avail.
My latest code looked something like this:
List<Data> data= new ArrayList<>();
String rawJson = getJsonAsString();
JSONObject outer = new JSONObject(rawJson);
JSONArray jArr= outer.getJSONArray("Data");
JSONObject inner= outer.getJSONObject("array");
for(int i =0; i<jArr.length(); i++){
JSONObject jsonEvent = jArr.getJSONObject(i);
String foo = jsonEvent.getString("foo"); <-- this works,
String 1foo = jsonEvent.getString("1foo"); <-- but this doesn't and i cant access it
I tried dozens of different solutions(tried myself and tried to find something here as well, but every case with those nested arrays is different and I can't add those solutions together to get answer for my case)
You can increase your readability if you beautify your raw JSON string:
{
"Data":[
{
"foo":"22",
"bar":"33",
"array":[
{
"1foo":"22",
"1bar":"33"
},
{
"2foo":"22",
"2bar":"33"
}
],
"anotherData":{
"foofoo":"22",
"barbar":"33"
},
"some more data":"11",
"some more data":"11"
},
{ and the cycle here starts again from -->
"foo":"22",
"bar":"33",
"array":[
...
],
...
}
]
}
So, stick to the following code:
JSONArray jArr = outer.getJSONArray("Data");
jArr is now filled with array of your Object.
And to loop through your Object array, you can use a for-loop which you have done it correctly.
for (int i = 0; i < jArr.length(); i++) {
// The below gets your Object
JSONObject jsonEvent = jArr.getJSONObject(i);
}
And now each jsonEvent contains your Object, which you can access the Object by their type.
For example, if you would like to access foo, you can use:
String foo = jsonEvent.getString("foo"); // foo = "22"
String bar = jsonEvent.getString("bar"); // bar = "33"
// Note that your array is another Array, you need to get it as JSONArray first
JSONArray arrayJson = jsonEvent.getJSONArray("array");
And as 1foo is in the first Object for your array, you need to access it like this:
JSONObject firstObjectInArray = arrayJson.getJSONObject(0);
String target = firstObjectInArray.getString("1foo"); // target = "22"
And to access foofoo, as it is an attribute of the JSON Object anotherData, so you should obtain anotherData as JSONObject first, and then you can access foofoo:
JSONObject anotherDataObject = jsonEvent.getJSONObject("anotherData");
String foofoo = anotherDataObject.getString("foofoo"); // foofoo = "22"
So the full code within your for-loop should look like this:
for (int i = 0; i < jArr.length(); i++) {
// The below gets your Object
JSONObject jsonEvent = jArr.getJSONObject(i);
String foo = jsonEvent.getString("foo");
JSONArray arrayJson = jsonEvent.getJSONArray("array");
String target = arrayJson.getJSONObject(0).getString("1foo");
// Add to get foofoo
JSONObject anotherDataObject = jsonEvent.getJSONObject("anotherData");
String foofoo = anotherDataObject.getString("foofoo");
}

Best way to convert string of data to JSON object

I have a string containing information in the following format:
Maltese Age: 2 Price: $500
https://images.google/image
Staffy Age: 1 Price: $500
https://images.google/image
Yorkie Age: 2 Price: $300
https://images.google/image
My goal, is to turn the above into something like this:
Dogs:
{
"dog": "Pomeranian",
"info": {
"url": "https://images.google.com/image",
"age": 2,
"price": 1000
}
And of course loop around back and fourth for all of the pets I have in the string.
If you use regular expressions you can get the values like this:
JSONArray arr = new JSONArray();
Matcher m = Pattern.compile("([^ \\r\\n]*) Age: ?(\\d+) Price: ?\\$?(\\d+(?:\\.\\d*)?)\\r?\\n(http[^ \\r\\n]*)").matcher(str);
while (m.find()) {
String dog = m.group(1);
String age = m.group(2);
String price = m.group(3);
String url = m.group(4);
// Add to a JSON object using your preferred JSON library
// Example:
JSONObject obj = new JSONObject();
obj.put("dog",dog);
JSONObject info = new JSONObject();
info.put("age",age);
info.put("price",price);
info.put("url",url);
obj.put("info",info);
arr.put(obj);
}
There are probably multiple ways to do it, but one way to do it may be something as follows.
You can start by splitting your text into lines.
var lines = text.split("\n");
Then you know that odd lines are URLs, and even lines are dog information.
List<JsonObject> objects = new ArrayList<>();
for(int i=0; i < lines.length; i++) {
var line = lines[i];
if(i % 2 == 0) {
// apply regex solution given in the other answer
// to extract the dog information
} else {
url = line;
// since json objects are complete on odd lines
// build json and add it to the list
var jsonObject = ...;
objects.add(jsonObject);
}
}

Get Arraylist file json using java

I have problems with my code, I need to extract the "materias" markup in the arraylist. Example data:
[{
"name": "A114",
"grupo": "DAW2",
"tutor": 15,
"materias": ["DWES", "DWEC", "IW", "DAW", "IE"]
}]
I tried this, work but i need the content of the arraylist:
try { // this read the JSON file
line = new String(Files.readAllBytes(Paths.get("fileAulas")));
} catch (Exception ex) {
ex.printStackTrace();
}
JSONArray recs = new JSONArray(line);
for (Object rec : recs) {
Aula datos = new Aula();
JSONObject obj = ((JSONObject) rec);
String name = obj.getString("name");
//datos.setNombre(name);
String grupo = obj.getString("grupo");
//datos.setGrupo(grupo);
int tutor = obj.getInt("tutor");
//datos.setTutor(tutor);
}
My objetive is to read the arraylist and then datos.setArraylist to my another class. All works fine except read the arraylist
PD: I use java downloaded from Maven, to execute i use "javac -cp ./*: program.java"
materias is also an array, so you need something like:
JSONArray materias = obj.getJsonArray("materias");
List<String> materiasList = materias.getValuesAs(String.class);
This is not type-safe so you need to make sure the array will only have String values.
Also, if you are using Java 8, you can iterate over the values and store them manually (JsonArray is also a Collection<JsonValue>)
Quickly created short test implementation of your needs:
String json = "[{ \"name\":\"A114\",\"grupo\": \"DAW2\",\"tutor\":15,\"materias\": [\"DWES\",\"DWEC\",\"IW\",\"DAW\",\"IE\"]}]";
JSONArray objectArray = new JSONArray(json);
for (int x = 0; x < objectArray.length(); x++) {
JSONObject obj = objectArray.getJSONObject(x);
System.out.println("Name: " + obj.get("name"));
System.out.println("Grupo: " + obj.get("grupo"));
System.out.println("Tutor: " + obj.get("tutor"));
JSONArray materias = obj.getJSONArray("materias");
for (int y = 0; y < materias.length(); y++) {
System.out.println("Materia " + y + ": " + materias.get(y));
}
}
Output
Name: A114
Grupo: DAW2
Tutor: 15
Materia 0: DWES
Materia 1: DWEC
Materia 2: IW
Materia 3: DAW
Materia 4: IE
First gotta make your JSON Valid.
[{
"name": "A114",
"grupo": "DAW2",
"tutor": 15,
"materias": ["DWES", "DWEC", "IW", "DAW", "IE"]
}]
Secondly, you can try the following :
for (JsonElement rec : recs) {
Aula datos = new Aula();
JSONObject obj = rec.getAsJsonObject();
String name = obj.get("name").getAsString();
//datos.setNombre(name);
String grupo = obj.get("grupo").getAsString();
//datos.setGrupo(grupo);
int tutor = obj.get("tutor").getAsInt();
JsonObject obj = rec.getAsJsonObject();
JsonArray materias = obj.getAsJsonArray("materias");
List<String> materiasList = new ArrayList<>();
for (JsonElement item:
materias) {
materiasList.add(item.getAsString());
}
}
I believe that the syntax for an array in json is different that what you have in your file. For example - a simple complete json that contains an array of simple elements would be:
{"contacts":[
{ "firstName":"John", "lastName":"Doe" },
{ "firstName":"Jen", "lastName":"Smith" },
{ "firstName":"David", "lastName":"Jones" }
]}
In your text, you specify an array, without the opening and closing JSON '{' and '}'. Also, You would need to name the array element ("contacts" in the example above). I think that what you want would be (I used "arrayName" for the array element name):
{"arrayName":[{ "name":"A114","grupo": "DAW2","tutor":15,"materias":["DWES","DWEC","IW","DAW","IE"] },
{ "name":"121","grupo": "DAW1","tutor":8,"materias":["PROGRA","BD","SIS","LM","FOL"] },
{ "name":"A112","grupo": "AUTO1","tutor":5 },
{ "name":"A127","grupo": "ASIR1","tutor":2 },
{ "name":"A114","grupo": "SMR2","tutor":11 },
{ "name":"A128","grupo": "ASIR2","tutor":9,"materias":["IAW","ABD","ASIS","SI","IE"] },
{ "name":"A125","grupo": "ADM2","tutor":12 } ] }

Comma is causing unwanted string split

I have an array of data sent from my database - Once received, I save it in shared preferences - here is my getter:
public List getAnswerStringEdit() {
return answer_edit;
}
I save it as so:
editor.putString(Constants.ANSWER_EDIT,resp.getAnswer().getAnswerStringEdit().toString().trim());
Then retrieve it here:
String answerString = pref.getString(Constants.ANSWER_EDIT, "").trim();
answerString = answerString.substring(1, answerString.length() - 1).trim();
String[] array = answerString.split(",");
Finally, I access the array as so:
et_answer1_edit.append(array[0]);
My problem is this - Say I add a questions which has a comma in the middle of it, like -
Question 1- "Why is this broke, I don't know?"
Currently, when I retrieve my question, the string is getting split, even though there are quotation marks around the whole question/answer- So in the example above, in position 0 in the array, I should have:
"Why is this broke, I don't know?"
However, instead I am getting in position 0:
Why is this broke - then position 1 as: I don't know
I know this sounds daft because clearly, I am calling for the split to happen on the comma, but I expect that at the end of the whole string object, not in the middle of it.
The retrieved JSON is as follows:
{
"result": "success",
"message": "Answer Has Been Selected",
"answer": {
"answer_edit": ["Why is this broke, I don't know?", "What is your favorite song, because I want to know"]
}
}
Any help/advice that can help me to understand what is causing this, would be really appreciated.
Dont split the string using ',' use this
JSONObject jsonObject = new JSONObject(answerString );
JSONArray jsonArray = jsonObject.getJSONObject("answer").getJSONArray("answer_edit");
Log.e("Json Array elements are","First Element : "+jsonArray.get(0)+"\nSecond Element : "+jsonArray.get(1));
String QuestionString1 = jsonArray.get(0).toString();
String QuestionString2 = jsonArray.get(1).toString();
try this one
JSONObject jsonObject = new JSONObject("your json response");
try
{
JSONObject answer= jsonObject.getJSONObject("answer");
JSONArray jsonArrayAnswerEdit = answer.getJSONArray("answer_edit");
Log.e("=>", "" + jsonArrayAnswerEdit);
for (int i = 0; i < jsonArrayAnswerEdit.length(); i++){
String que= jsonArrayAnswerEdit.getString(i);
Log.e("json", i + "=" + que);
}
} catch (JSONException e) {
e.printStackTrace();
}
Try this
JSONObject jsonObject = new JSONObject("your json response");
try
{
JSONObject data = jsonObject.getJSONObject("answer");
JSONArray jsonArray = data.getJSONArray("answer_edit");
Log.e("=>", "" + jsonArray);
for (int i = 0; i < jsonArray.length(); i++)
{
String value = jsonArray.getString(i);
String[] parts = value.split(Pattern.quote(","));
for (int j=0; j<parts.length; j++)
{
Log.e("Answer String ", "=" + parts[j]);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
OUTPUT
E/=>: ["Why is this broke, I don't know?","What is your favorite song, because I want to know"]
E/Answer String: =Why is this broke
E/Answer String: = I don't know?
E/Answer String: =What is your favorite song
E/Answer String: = because I want to know
After reading all the suggest answers, figured out a simple solution:
First I stored my answers sent from my external database as so -
final String jsonAnswers = gson.toJson (resp.getAnswer().getAnswerStringEdit());
Then saved in shared pref -
editor.putString(Constants.ANSWER_EDIT,jsonAnswers);
Next to read the answer back out:
String answerString = pref.getString(Constants.ANSWER_EDIT, "").trim();
final String[] array = gson.fromJson (answerString, String[].class);
Finally, I could set my Edittext with data from the array:
et_answer1_edit.append(array[0].trim());
et_answer2_edit.append(array[1].trim());

Java: Gson change property name without serialization

Is it possible to change the name of a Json property without serialization with Gson? For example, given this Json
{
"1": {
...
},
"2": {
...
}
}
could I change the "1" to a "3" without removing its contents. I know that the addProperty method adds a new property, or overwrites an existing property with a new value, but I want to change the name of a property without affecting its value. Also, pasting the existing value as the second argument of addProperty will not suffice.
EDIT: To add more context, I will explain the bigger picture. I have a JSON string that is a couple thousand lines long. I'm writing a program leveraging Gson in order to change the values in that JSON string. I am at a point where I not only want to change the values of properties, but the names of the properties themselves. I have done everything so far without serialization.
Here is a snippet of the Java I wrote:
String file = "\\temp.json";
FileReader reader = new FileReader(file);
JsonStreamParser parser = new JsonStreamParser(reader);
// Parse entire JSON
JsonElement element = parser.next();
// Get root element
JsonObject sites = element.getAsJsonObject();
// Get first child element
JsonObject site1 = sites.getAsJsonObject("1");
JsonObject clust1 = site1.getAsJsonObject("CLUST");
for(int i = 1; i < 12; i++) {
// "Dynamic" variable
String num = Integer.toString(i);
// Get property whose name is a number, has siblings
JsonObject one = custCluster1.getAsJsonObject(num);
one.getAsJsonObject().addProperty("name", "cluster" + i);
JsonObject subOne = one.getAsJsonObject("SUB");
subOne.getAsJsonObject().addProperty("name", "aName" + i);
for(int n = 1; n < 1002; n++) {
// "Dynamic" variable
String inst = Integer.toString(n);
// Get property whose name is a number, has siblings
JsonObject subSub = subOne.getAsJsonObject(inst);
// If the property doesn't exist, then don't execute
if(subSub != null) {
JsonArray subSubArray = subSub.getAsJsonArray("SUBSUB");
subSub.getAsJsonObject().remove("name");
int m = 0;
while(m < subSubArray.size()) {
subSubArray.get(m).getAsJsonObject().remove("SR");
subSubArray.get(m).getAsJsonObject().remove("FI");
subSubArray.get(m).getAsJsonObject().remove("IND");
subSubArray.get(m).getAsJsonObject().addProperty("ST", "1");
subSubArray.get(m).getAsJsonObject().addProperty("ID", "2");
subSubArray.get(m).getAsJsonObject().addProperty("DESCR", "hi");
m++;
}
m = 0;
}
}
}
Thanks to #mmcrae for helping and suggesting this method.
Since I'm already saving the (key, value) pairs in variables, you can remove the property whose name you want to change from the parent, and then add it back with a new name and the content that was already saved.
Like this:
JsonObject sites = element.getAsJsonObject();
JsonObject site1 = sites.getAsJsonObject("1");
JsonObject clust1 = site1.getAsJsonObject("CLUST");
site1.remove("CLUST");
site1.add("NEWCLUST", clust1);

Categories