I know there have been a lot of questions on this topic already, but I'm stuck here and I'm sure it's something quite stupid.
I'm parsing a JSON Api that looks like this (renamed & simplified here):
{
"merchant": {
"name": "TestCo",
"id": 108
},
"category": [
{
"merchant_id": 108,
"category_name": "Baby Supplies",
"category_id": 57,
},
{
"merchant_id": 108,
"category_name": "Dining",
"category_id": 59,
}
]}
I have a wrapper class, defined as:
public class WrapperObject {
public MerchantObject merchant;
public List<CategoryObject> category;}
Both merchant & category are properly defined classes of their own. Then I try to deserialize like so:
collectionType = new TypeToken<List<WrapperObject>>() {}.getType();
List<WrapperObject> wrapperObject = new Gson().fromJson(response, collectionType);
This blows up, GSON reports back "This is not a JSON Array".
This worked perfectly right up until last week, when the API changed. The only difference in the JSON was that it used to look like this (note the extra wrapping array around the data):
[{
"merchant": {
"name": "TestCo",
"id": 108
},
"category": [
{
"merchant_id": 108,
"category_name": "Baby Supplies",
"category_id": 57,
},
{
"merchant_id": 108,
"category_name": "Dining",
"category_id": 59,
}
]}]
How do I adjust my code to parse the new JSON? NB, I have no control over the JSON. Thanks!
The square brackets around the old response denote an array (of one element in this case). It looks like the new API returns just a wrapper object, not an array of wrapper objects. Does this work?
wrapperType = new TypeToken<WrapperObject>() {}.getType();
WrapperObject wrapperObject = new Gson().fromJson(response, wrapperType);
Related
I have this Json. I want to map my json data. But i get some error.
{
"Id": 0,
"Product_Id": 0,
"Quantity": 0,
"User_Id": "a49a10d2-fc3f-477a-b087-5b0d07545964",
"Active": false,
"CartProducts": null,
"Products": [
{
"Id": 116,
"Shop_Id": 1,
"Offer": 0.0,
"Quantity": 1,
"Price": 100.0,
"Category_Id": 0,
"Description": null,
"Name": "Lacoste Product",
"Active": false,
"Size": "small",
"Color": "black",
"Is_External_Product": true,
"External_Link": "https://www.lacoste.com.tr/urun/kadin-kirmizi-polo-pf0504-007-4/",
"Currency": null,
"ProductImages": null
}
]
}
I am decoding Json here
if(jsonObject['Products']!=null){
productItems = ProductItem.getListFromJson(jsonObject['Products']);
}
static List<ProductItem> getListFromJson(List<dynamic> jsonArray) {
log("getListFromJson");
List<ProductItem> list = [];
for (int i = 0; i < jsonArray.length; i++) {
list.add(ProductItem.fromJson(jsonArray[i]));
}
return list;
}
But i get this error. "[log] type 'List' is not a subtype of type 'String'"
You are trying to assign a value of type String to the product items array. There might be a possibility one of your responses is returning a String and you are expecting an array. Please inspect the response.
It's a JSON parsing issue, and it might not directly related to "Products" as being a list or string.
So instead, for better diagnosing this error, or other error on the future, you could need to enable the dart debugger, while checking the "uncaught exception" option, which will guide you to the broken type casting issue.
I want to parse a JSON with Typescript, where object names can vary and I have no way to know them all. For example:
{
"planets": {
"Alderaan": {
"available_items": {
"Cinamone": {
"available": 74,
"buy_price": 6,
"sell_price": 6
},
"Dwimeryt": {
"available": 42,
"buy_price": 12,
"sell_price": 11
}
}
}
}
Where there can be many planets with different names.
I figured out that in order to parse JSON object successfully, we need to have corrent variable names, so for example that works:
interface MyObj {
x: number;
y: number:
}
let json_string = `{
"x": 5,
"y": 12
}`;
let test: MyObj = JSON.parse(json_string);
But if we change variable name in interface from "x" to lets say "xx" it becomes undefined after parsing. That creates seemingly unsolvable problem if we cant know all of the JSON object names, because I cant create an interface withh all of the planet names. Am I missing something? How would you parse a JSON I have posted?
Do you have any influence on the JSON itself? To me it seems that it is not the best way to use JSON. If I would try to design this, your JSON would look more like this:
{
"planets": [
{
"name": "Alderaan",
"available_items": [
{
"name": "Cinamone",
"available": 74,
"buy_price": 6,
"sell_price": 6
}, {
"name": "Dwimeryt",
"available": 42,
"buy_price": 12,
"sell_price": 11
}]
}]
}
This way you would always know the name of the fields and also their types. I do not think that this could be achieved easily with the current JSON format.
What is the difference between the following serialization methods?
First Method
JsonConvert.SerializeObject(list or datatable)
and the output is
i.e. (3) [Object, Object, Object]
Second Method
Dim parent = Prtdata
Dim lGridColumns = New With {
Key .data = parent
}
Dim Setting = New JsonSerializerSettings
Setting.PreserveReferencesHandling = PreserveReferencesHandling.Objects
Dim jsonObject = JsonConvert.SerializeObject(lGridColumns, Formatting.Indented)
Return jsonObject
and its output is
{
"data": [
{
"RecID": 2383,
"PrtStatus": 0,
"PtFilenum": 15090248,
"PrtFilenum": 13090701,
"FullName": "asdasd",
"DOB": "04 Oct 1985"
},
{
"RecID": 3387,
"PrtStatus": 1,
"PtFilenum": 15090248,
"PrtFilenum": 15120996,
"FullName": "marwam mohmmad saleem",
"DOB": "24 May 2017"
},
{
"RecID": 3388,
"PrtStatus": 1,
"PtFilenum": 15090248,
"PrtFilenum": 170227111,
"FullName": "asd dsf as a",
"DOB": "27 Feb 2017"
}
]
}
why the output looks different in the browser console?
As the first comment, you can find a Serialization Guide on the website of NewtonSoft.json, in my answer I just provide a more elaborate version of my comment earlier.
The first scenario, where you are serializing something implemented IEnumerable (eg: list, array), will be represented by an array in Json, eg:
[{ "property": "value", "id": 0 }, {"property": "value", "id": 1}]
For the second scenario, you are doing several things differently, for example you are providing the PreserveReferencesHandling in the JsonSerializerSettings which would also preveserve any references made in the objects you are serializing, eg:
[{"$id": 1, "title": "item1"}, {"$id": 2, "title": "item2", "previous": { "$ref": 1 }]
This would make sure that when deserialized, the second object would contain a reference to the first object, inside the property previous.
Another thing you are doing differently is providing the Formatting.Indented, which will create a more reader friendly json document, having line breaks and indentation. The previous Json would then become something similar to this:
[{
"$id": 1,
"title": "item1"
},
{
"$id": 2,
"title": "item2",
"previous": {
"$ref": 1
}
}]
And, the last big difference is that in the last example, you are serializing a single object, cause it's public properties to be serialized, eg:
{
"data": [
...
]
}
Where data is a property on the object you are serializing.
I'm using the next Json
{
"ID": 8,
"MenuItems": [
{
"ID": 38,
"Name": "Home",
"URL": "{\"PageLayout\":\"Home\",\"Icon\":\"home\"}",
"Culture": "en",
"Children": null
},
{
"ID": 534,
"Name": "GUIDE ",
"URL": "{''PageLayout'':''Page A'', ''Icon'':''A''}",
"MenuType": 1,
"PageID": 0,
"Culture": "en",
"Children": [
{
"ID": 6,
"Name": "Form A",
"URL": "[''Type'':''Form A'',''Icon'':''Form'',''ItemID'':\"358\"]",
"Culture": "he",
"RuleID": 0
},
{
"ID": 60,
"Name": "Drama",
"URL": "[''Type'':''Form B'',''Icon'':''Form'',''ItemID'':\"3759\"]",
"Culture": "en",
"RuleID": 0
}
]
}
]
}
i'm using Groovy script in soapUI and i need to:
Assert the exitance of node that has the name GUIDE
Extract a list of all Itemsid
You can parse the JSON content using JsonSlurper and then work with the results like so:
import groovy.json.JsonSlurper
// Assuming your JSON is stored in "jsonString"
def jsonContent = new JsonSlurper().parseText(jsonString)
// Assert node exists with name GUIDE
assert(jsonContent.MenuItems.Name.contains("GUIDE"))
// Get list of ItemIDs
def itemList = jsonContent.MenuItems.Children.URL.ItemID[0].toList()
// List the items
itemList.each {log.info it}
Note that the above will fail given your current example, because of a few issues. Firstly, Name contains "GUIDE " (trailing space) rather than "GUIDE" (so you will need to adapt accordingly). Secondly, it is invalid JSON; the URL nodes have various erroneous characters.
On a side note, if you first need to retrieve your JSON from the response associated with a previous TestStep (say one called "SendMessage") within the existing testCase, this can be done as follows:
def jsonString = context.testCase.getTestStepByName("SendMessage").testRequest.response.getContentAsString()
example json (snippet taken from a valid json
"items": {
"average": 564,
"head": {
"id": 99161,
i already know how to display and select values from this i currently use
average.text = If(jResults("average") Is Nothing, "", jResults("average").ToString())
id.text =If(jResults("items")("head") Is Nothing, "", jResults("items")("head")("id").ToString())
however i am unsure how to extract the stat values from the following snippet as stat is used multiple times
"items": {
"averageItemLevel": 564,
"averageItemLevelEquipped": 564,
"head": {
"id": 99161,
"stats": [
{
"stat": 32,
"amount": 651,
"reforgedAmount": -434
},
{
"stat": 5,
"amount": 2001
},
{
"stat": 36,
"amount": 1544
},
{
"stat": 7,
"amount": 3362
},
{
"stat": 49,
"amount": 434,
"reforged": true
}
],
"armor": 2244
},
im unsure how to extract each stat and place it in a different box using the string i used before
average.text = If(jResults("average") Is Nothing, "", jResults("average").ToString())
i understand i may have to use select case but im not sure how to use my existing string to determine each stat
thanks
Looks like you'd have to use an array index on "stats", so that in your example JSON, you could get the first two values using
jResults("items")("head")("stats")(0)("stat").ToString() ' = "32"
and
jResults("items")("head")("stats")(1)("stat").ToString() ' = "5"
So if for instance you wanted to total all of the "stat" fields, you could do it like so:
Dim statTotal As Integer = 0
For i As Integer = 0 To jResults("items")("head")("stats").Count - 1
statTotal += CInt(jResults("items")("head")("stats")(i)("stat"))
Next
(Of course, in the real world you'd check to make sure each one is not Nothing and that IsNumeric() is true before just throwing a CInt() in there.)
Hope that helps!