What is wrong with this JSON file? Can't be deserialized - json

I have an issue with a JSON file, which is a list of country objects, as below:
{
"Countries": [
{
"Code": "AFG",
"Name": "Afghanistan",
"Population": 38928346
},
{
"Code": "ALA",
"Name": "Åland Islands",
"Population": 28007
},
{
"Code": "ALB",
"Name": "Albania",
"Population": 2877797
},
{
"Code": "DZA",
"Name": "Algeria",
"Population": 43851044
},
{
"Code": "ASM",
"Name": "American Samoa",
"Population": 55191
}
]
}
I am trying to use this code to read it and deserialize it into a List object:
Stream? countriesResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyProject.Countries.json");
if (countriesResourceStream == null)
{
return;
}
var countries = new List<Country>();
using (StreamReader reader = new StreamReader(countriesResourceStream))
{
var serializer = new JsonSerializer();
countries = serializer.Deserialize<List<Country>>(new JsonTextReader(reader));
}
However the serializer.Deserialize method throws the exception:
'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[MyProject.Models.EntityFramework.Country]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
What is the issue with my JSON? I have tried both Newtonsoft and System.Text.Json.

The problem is that your JSON does not represent a list of countries, it represents an object that contains a list of countries. You need another class:
class CountryListContainer
{
public List<Country> Countries { get; set; }
}
Deserialize into the container class and then you can get your country list from that:
using (StreamReader streamReader = new StreamReader(countriesResourceStream))
using (JsonTextReader jsonReader = new JsonTextReader(streamReader))
{
var serializer = new JsonSerializer();
countries = serializer.Deserialize<CountryListContainer>(jsonReader).Countries;
}
Fiddle: https://dotnetfiddle.net/5DM4il
Alternatively, you could change your JSON as #Charles Duffy suggested in the comments. If the JSON looked like this (without the outer object) then your existing code would work:
[
{
"Code": "AFG",
"Name": "Afghanistan",
"Population": 38928346
},
{
"Code": "ALA",
"Name": "Åland Islands",
"Population": 28007
},
{
"Code": "ALB",
"Name": "Albania",
"Population": 2877797
},
{
"Code": "DZA",
"Name": "Algeria",
"Population": 43851044
},
{
"Code": "ASM",
"Name": "American Samoa",
"Population": 55191
}
]
Fiddle: https://dotnetfiddle.net/gMHhcX

Related

parsing json object with number as its key fields?

I'm trying to parse json into kotlin objects but the problem is that its key fields are numbers any idea how can parse them , I've tried serialized name but still facing problem.
The json response looks like this :
{
"Id": [{
"1": {
"name": "name1",
"class": "11a"
}
},
{
"2": {
"name": "name2",
"class": "11b"
}
}
]
}
I'm using gson and the main thing i'm trying to do is to store this number fields as some other string objects.
You can parse them into a list of maps, then "map" those to your data classes instead:
val input = """{
"Id": [{
"1": {
"name": "name1",
"class": "11a"
}
},
{
"2": {
"name": "name2",
"class": "11b"
}
}
]
}"""
val gson = Gson()
val parsed: Map<String, List<Map<String, Any>>> =
gson.fromJson(input, (object : TypeToken<Map<String, List<Map<String, Any>>>>(){}).type)
println(parsed["Id"]?.get(0)?.get("1")) // {name=name1, class=11a}
It will have some nasty generic signature, though.
If you're working with Kotlin, take a look at Klaxon, it will improve your experience.

Groovy - Parse JSON where only certain values exists in response

I am trying to parse a JSON response that has repeating objects with JsonSlurper to compare to a JDBC query. However, I only want to compare objects where a certain values exist within that object.
If I had a response that looks like this, how would I only parse the objects where the country equals USA or Canada, therefore ignoring anything else?
{
"info": [{
"name": "John Smith",
"phone": "2125557878",
"country": {
"value": "USA"
}
},
{
"name": "Jane Smith",
"phone": "2125551212",
"country": {
"value": "USA"
}
},
{
"name": "Bob Jones",
"phone": "4165558714",
"country": {
"value": "Canada"
}
},
{
"name": "George Tucker",
"phone": "4454547171",
"country": {
"value": "UK"
}
},
{
"name": "Jean Normand",
"phone": "4454547171",
"country": {
"value": "France"
}
}]
}
This is what I have in groovy:
def jsonResponse = context.expand('${RESTRequest#Response}')
def parsedJson = new JsonSlurper().parseText(jsonResponse)
def info = parsedJson.info
def jsonDataObjects = []
info.each { json ->
jsonDataObjects.add(Model.buildJSONData(json))
}
I am building a collection of the elements that I need to compare to a database. How do I only add to that collection where the info.country.value = USA or Canada?
I tried using .findAll like this just to test if I could get it to filter by just one of the countries:
def info = parsedJson.info.country.findAll{it.value == "USA"}
But, when I do that, only the value field is kept. I lose the name and phone from the parse.
Thanks in advance for any assistance.
Did you try
def info = parsedJson.info.findAll{it.country.value == "USA"}
?

Rest assured, using Gpath query gives an error "The parameter "..." was used but not defined. Define parameters using the JsonPath.params(...)"

I'm new to rest-assured and I'm currently spiking it in order to implement it in our testing framework.
The problem I'm facing is to extract an object from a Json array from the REST response.
The example json I'm using:
{
"MRData": {
"xmlns": "http://ergast.com/mrd/1.4",
"series": "f1",
"url": "http://ergast.com/api/f1/2016/drivers.json",
"limit": "30",
"offset": "0",
"total": "24",
"DriverTable": {
"season": "2016",
"Drivers": [
{
"driverId": "alonso",
"permanentNumber": "14",
"code": "ALO",
"url": "http://en.wikipedia.org/wiki/Fernando_Alonso",
"givenName": "Fernando",
"familyName": "Alonso",
"dateOfBirth": "1981-07-29",
"nationality": "Spanish"
},
{
"driverId": "bottas",
"permanentNumber": "77",
"code": "BOT",
"url": "http://en.wikipedia.org/wiki/Valtteri_Bottas",
"givenName": "Valtteri",
"familyName": "Bottas",
"dateOfBirth": "1989-08-28",
"nationality": "Finnish"
}
]
}
}
}
Things i have tried so far:
This assertion is working
RestAssured.rootPath = "MRData.DriverTable.Drivers";
given()
.when()
.get("http://ergast.com/api/f1/2016/drivers.json")
.then()
.assertThat()
.body("find { find { d -> d.driverId == 'alonso' }.code }.code", equalTo("ALO"));
But I'm trying to actually get the Json of the particular array item
RestAssured.rootPath = "MRData.DriverTable.Drivers";
given()
.when()
.get("http://ergast.com/api/f1/2016/drivers.json")
.then()
.extract()
//.jsonPath().param("driverId", "alonso").get("find { d -> d.driverId == driverId }");
.path("find { d -> d.driverId == 'alonso' }");
Tried with both ways (one is commented out). But I get an error :
"The parameter "driverId" was used but not defined. Define parameters using the JsonPath.params(...)"
RestAssured.rootPath = "MRData.DriverTable.Drivers"; works only for body expectations. For extraction you have to use full path to paramter e.g. MRData.DriverTable.Drivers.find { it.#driverId == 'alonso' }

Convert JSON string to HashMap in Java

How can I convert JSON string to HashMap. My JSON string is like
{
"AvailableDeliveries": {
"500": {
"code": "INOFFICE",
"desc": "In Office",
"id": 500,
"name": "IN OFFICE"
},
"502": {
"code": "TELEPHONE",
"desc": "Telephone",
"id": 502,
"name": "TELEPHONE"
},
"503": {
"code": "DIY DOC ACCESS",
"desc": "Online Documents",
"id": 503,
"name": "DIY DOC ACCESS"
}
}
}
I looked on other examples which have collection of object but I have this extra top level object "AvailableDeliveries" not sure how to handle that level.
import jackson-all-1.8.2.jar
create a mapper for the object mapper
ObjectMapper objectMapper = new ObjectMapper();
create a hashmap
map = objectMapper.readValue( json, HashMap.class );
Hope this will work

Appending a key value pair to a json object

This is the json object I am working with
{
"name": "John Smith",
"age": 32,
"employed": true,
"address": {
"street": "701 First Ave.",
"city": "Sunnyvale, CA 95125",
"country": "United States"
},
"children": [
{
"name": "Richard",
"age": 7
},
{
"name": "Susan",
"age": 4
},
{
"name": "James",
"age": 3
}
]
}
I want this as another key-value pair :
"collegeId": {
"eventno": "6062",
"eventdesc": "abc"
};
I tried concat but that gave me the result with || symbol and I cdnt iterate. I used spilt but that removes only commas.
concattedjson = JSON.stringify(JSON.parse(json1).concat(JSON.parse(json2)));
How do I add a key pair value to an existing json object ?
I am working in javascript.
This is the easiest way and it's working to me.
var testJson = {
"name": "John Smith",
"age": 32,
"employed": true,
"address": {
"street": "701 First Ave.",
"city": "Sunnyvale, CA 95125",
"country": "United States"
},
"children": [
{
"name": "Richard",
"age": 7
},
{
"name": "Susan",
"age": 4
},
{
"name": "James",
"age": 3
}
]
};
testJson.collegeId = {"eventno": "6062","eventdesc": "abc"};
Just convert the JSON string to an object using JSON.parse() and then add the property. If you need it back into a string, do JSON.stringify().
BTW, there's no such thing as a JSON object. There are objects, and there are JSON strings that represent those objects.
You need to make an object at reference "collegeId", and then for that object, make two more key value pairs there like this:
var concattedjson = JSON.parse(json1);
concattedjson["collegeId"] = {};
concattedjson["collegeId"]["eventno"] = "6062";
concattedjson["collegeId"]["eventdesc"] = "abc";
Assuming that concattedjson is your json object. If you only have a string representation you will need to parse it first before you extend it.
Edit
demo for those who think this will not work.
const newTestJson = JSON.parse(JSON.stringify(testJson));
newTestJson.collegeId = {"eventno": "6062","eventdesc": "abc"};
testJson = newTestJson;