JSON deserialize with array and non-Array - arrays

I have a JSON string. which has a part like this
"Result": {
"AdditionalInfo": {
"SubCategoryID": "978",
"SellerPartNumber": "04-VO7T-14PP",
"ManufacturerPartNumberOrISBN": "04-VO7T-14PP",
"UPC": null
},
"ErrorList": {
"ErrorDescription": [
{
"#cdata-section": "Error(s). Item not created."
},
{
"#cdata-section": "Error:[Item does not exist. Please create a new list.]"
}
]
}
}
However, sometimes that part is an array as well.
like
"Result": [
{
"AdditionalInfo": {
"SubCategoryID": "1512",
"SellerPartNumber": "TY-SZT1-358V",
"ManufacturerPartNumberOrISBN": "TY-SZT1-358V",
"UPC": null
},
"ErrorList": {
"ErrorDescription": [
{
"cdata-section": "Error(s). Item not created."
},
{
"cdata-section": "CufflinkMaterial - Property: [CufflinkMaterial] value error. The submitted value: [MPS.Domain.SubCategoryProperty] is not recognized for this property."
},
{
"cdata-section": "CufflinkType - Property: [CufflinkType] value error. The submitted value: [MPS.Domain.SubCategoryProperty] is not recognized for this property."
}
]
}
},
{
"AdditionalInfo": {
"SubCategoryID": "1512",
"SellerPartNumber": "UF-T05C-T6XG",
"ManufacturerPartNumberOrISBN": "UF-T05C-T6XG",
"UPC": null
},
"ErrorList": {
"ErrorDescription": [
{
"cdata-section": "Error(s). Item not created."
},
{
"cdata-section": "CufflinkMaterial - Property: [CufflinkMaterial] value error. The submitted value: [MPS.Domain.SubCategoryProperty] is not recognized for this property."
},
{
"cdata-section": "CufflinkType - Property: [CufflinkType] value error. The submitted value: [MPS.Domain.SubCategoryProperty] is not recognized for this property."
}
]
}
},
{
"AdditionalInfo": {
"SubCategoryID": "1512",
"SellerPartNumber": "5B-1137-WT3O",
"ManufacturerPartNumberOrISBN": "5B-1137-WT3O",
"UPC": null
},
"ErrorList": {
"ErrorDescription": [
{
"cdata-section": "Error(s). Item not created."
},
{
"cdata-section": "CufflinkMaterial - Property: [CufflinkMaterial] value error. The submitted value: [MPS.Domain.SubCategoryProperty] is not recognized for this property."
},
{
"cdata-section": "CufflinkType - Property: [CufflinkType] value error. The submitted value: [MPS.Domain.SubCategoryProperty] is not recognized for this property."
}
]
}
}
]
Is there a generic way that I can Deserlize both JSON without defining different objects? So like, I define an array of Result object, and when there is single entity, it will create one index in the object array, and when there are multiple, it may create multiple indexes in the array.
Ultimate goal is to use object object and use that to parse both single Result object or multiple.
Is that something possible?
thanks
Sameers

Thanks Brian Rogers
The answer was in your link.
How to handle both a single item and an array for the same property using JSON.net
I converted that to VB.NET using this code.
Class SingleOrArrayConverter(Of T)
Inherits Newtonsoft.Json.JsonConverter
Public Overrides Function CanConvert(ByVal objectType As Type) As Boolean
'Return (objectType = GetType(List(Of T)))
Return objectType.Equals(GetType(Generic.List(Of T)))
End Function
Public Overrides Function ReadJson(ByVal reader As Newtonsoft.Json.JsonReader, ByVal objectType As Type, ByVal existingValue As Object, ByVal serializer As Newtonsoft.Json.JsonSerializer) As Object
Dim token As Newtonsoft.Json.Linq.JToken = Newtonsoft.Json.Linq.JToken.Load(reader)
If token.Type = Newtonsoft.Json.Linq.JTokenType.Array Then
Return token.ToObject(Of Generic.List(Of T))()
End If
Dim list As New Generic.List(Of T)
list.Add(token.ToObject(Of T)())
Return list
End Function
Public Overrides ReadOnly Property CanWrite() As Boolean
Get
Return False
End Get
End Property
Public Overrides Sub WriteJson(ByVal writer As Newtonsoft.Json.JsonWriter, ByVal value As Object, ByVal serializer As Newtonsoft.Json.JsonSerializer)
Throw New NotImplementedException()
End Sub
End Class
and applied this attribute to my data definition.
<Newtonsoft.Json.JsonProperty("Result")> _
<Newtonsoft.Json.JsonConverter(GetType(Utilities.JSONUtilities.SingleOrArrayConverter(Of FeedResultType)))> _
Public Property Result() As Generic.List(Of FeedResultType)
Get
Return m_Result
End Get
Set(ByVal value As Generic.List(Of FeedResultType))
m_Result = value
End Set
End Property
and its all good now.
thanks
Sameers
Yes, I was using NewtonSoft library

Related

Generate Interface from an object in Typescript

I have a Typescript project in which I want to generate an Interface from the data I have in an object, I don't know if this is possible but I can't do it.
What I do is the following:
I get the JSON Database Object with the results of a query
From the values of that object I need to create a dynamic interface to add an ArrayList to each of those values, and thus avoid modifying the interface every time the database values change
This is the object I get from database:
interface Auto {
autoType: string
}
let autoActive: Auto[] = [
{ "autoType": "Car"},
{ "autoType": "Motorcycle"},
{ "autoType": "Truck"},
{ "autoType": "Plane"}
]
console.log(autoActive.map(Object.values).toString()); // Car,Motorcycle,Truck,Plane
This is the interface I need to create from the above data (AutoBrand) from the genericObject model:
interface genericObject {
[key: string]: any;
}
interface AutoBrand extends genericObject {
"Car": Array<string>,
"Motorcycle": Array<string>,
"Truck": Array<string>,
"Plane": Array<string>
}
What I want to obtain from this is to generate a constant object to assign the titles to each final file, this is an example of the final class that I want to obtain, and then extract the titles from here:
export class HeaderConst {
static readonly headerConst: AutoBrand = {
"Car": [
"Model",
"Total",
"Age"
],
"Motorcycle": [
"Model",
"Total",
"Age"
],
"Truck": [
"Model",
"Total",
"Age"
],
"Plane": [
"Model",
"Total",
"Age"
]
}
public static getConstants(elem: string) {
return elem.split(".").reduce((elm: any, i: any) => {
return elm[i];
}, this.headerConst);
}
}
That's not possible. Your JSON only exists at runtime, and TypeScript interfaces do not exist at runtime at all.

Convert JSON array objects to .net Classes

I am having issues with the below JSON String on converting it to .net class. The class that I have created so far is below as well. The particular section that I cannot get to work is group_access and roles tags. I know these are an array of objects but when I try to convert the objects i get the following error; Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Array' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
I also tried using visual studio tool (Edit>Paste Special > JSON) and jscon2csharp.com it errors out on converting the roles and group_access tags.
JSON data:
{
id: 122404,
email: 'mike#email.com',
fname: 'Mike',
lname: 'Doe',
full_name: 'Mike Doe',
resource_id: '001002',
title: '',
last_login: '2016-11-01 09:15:23',
tags: [
'Math Department', 'New Teachers'
],
grades: [
4, 5, 6
],
targets: [
'Option 1: 3 Informal Obs.'
],
caseload_tags: [],
group_access: [
10: 2
25527: 1
25645: 1
25653: 4
],
roles: [
10: [
2015: 2,
2016: 2
],
25527: [
2015: 2,
2016: 1
]
25645: [
2015: 1,
2016: 1
]
25653: [
2015: 3,
2016: 4
]
]
}
My code:
Public Class Item
Public Property id As Integer
Public Property email As String
Public Property fname As String
Public Property lname As String
Public Property full_name As String
Public Property resource_id As String
Public Property title As String
Public Property tags As IList(Of String)
Public Property grades As IList(Of String)
Public Property targets As IList(Of String)
Public Property group_access As Array
Public Property roles As Array
End Class
Public Class RootObject
Public Property type As String
Public Property limit As Integer
Public Property offset As Integer
Public Property total As Integer
Public Property time As String
Public Property items As List(Of Item)
Public Property items_count As Integer
End Class
The JSON is not valid - array elements must be separated with commata.

Objectmapper get array of one item within JSON

So I have the following JSON, which I am using together with ObjectMapper and Realm.
{
"result": [
{
"id": 20,
"types": [
"now"
],
"url": "/nl/whereto/ezrhgerigerg",
"categories": [
{
"id": 39,
"name": "Food "
},
{
"id": 21,
"name": "Varia"
}
]
},
My problem is getting the data from "types", which for some items in the array says "now" or "later", and is empty for other items (hence, no types item is given).
I tried to do the following in my mapping:
class Publication: Object, Mappable {
dynamic var id:Int = 0
var typez = List<getType>()
dynamic var url:String?
required convenience init?(_ map: Map) {
self.init()
}
override static func primaryKey() -> String? {
return "id"
}
func mapping(map: Map) {
id <- map["id"]
typez <- map["types"]
url <- map["url"]
}
}
class getType: Object, Mappable {
dynamic var text: String = ""
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
text <- map[""]
}
}
When I check the Realm database, you can see that typez, an array of [getType] was made, but it's empty for all items (even the ones where types is "now"). The other two items (id and url) are filled in in the database.
What am I doing wrong that it won't save to the database?
Because Realm cannot detect assigning List properties since List property is not Objective-C type. So List properties should be declared as let, and should not be nil. You should use append/remove.../insert...method to modifying theList`.
So your code
typez <- map["types"]
doesn't work, since you assign values to the typez property directly.
The workaround is like the following:
func mapping(map: Map) {
...
var typez: [String]? = nil
typez <- map["types"]
typez?.forEach { t in
let obj = getType()
obj.text = t
self.typez.append(obj)
}
...
First, store the mapped value to the local variable (it is string array). Then convert the string array to objects. Then append the objects to the List property.

how to add a complextype object dynamically to an array

We have created an array of complextype(Carrier field) objects. See below metadata
{ shortName : 'Person',
namespace : 'Demo',
autoGeneratedKeyType : breeze.AutoGeneratedKeyType.Identity,
"dataProperties": [
{
"name": "carriers",
"complexTypeName":"Carrier:#Test",
"isScalar":false
}]
}
The Carrier entity is defined as below:
{
"shortName": "Carrier",
"namespace": "Test",
"isComplexType": true,
"dataProperties": [
{
"name": "Testing",
"isScalar":true,
"dataType": "String"
}
]
}
We have the following matching data for the above entities:
{
carriers: [
{
Testing : 'InputBox1'
},
{
Testing : 'InputBox2'
}
]
}
We are trying to dynamically add the complextype object(Carrier) to the above carriers array by using the following approach:
var test = {
"Testing" : "Test"
};
var result = manager.createEntity('Carrier', test);
The above code throws an exception(undefined is not a function) inside breeze.debug.js at line number 12457(see below code)
entity = entityType.createEntity(initialValues);
The exception is thrown since the complextype entity does not have 'createEntity' function in it.
What are we missing here?
Excellent question - Sorry I didn't have a chance to address this earlier.
When adding a complexType object you need to use the createInstance() method instead of the createEntity.
var thisEntityType = manager.metadataStore.getEntityType('Carrier');
var thisEntity = thisEntityType.createInstance(initialValues);
Basically you get the complexType and then create an instance of it using the values you want assigned. Keep in mind the initial values should be a hash object of course. Often I will include a helper function to do this for me like this -
function createComplexType(entityType, constructorProperties) {
var thisEntityType = manager.metadataStore.getEntityType(entityType);
var thisEntity = thisEntityType.createInstance(constructorProperties);
return thisEntity;
}

WebAPI return KeyValue list for select box

I want a WebApi controller to return a Dictionary (keyvalue pairs) for a drop down box. This is using angularjs $http.get() method. When I get the data back to my controller and inspect the javascript, it appears I'm getting an Object with properties that are named like my keys in the Dictionary. This does not work and the dropdown remains empty.
JavaScript result from $http.get()
Object
test1: "test 1"
test2: "test 2"
WebAPI code:
[HttpGet]
public Dictionary<string, string> Get()
{
return new Dictionary<string, string>(){
{ "test1", "test 1"},
{ "test2", "test 2"}
};
Code in my view:
<select name="originType" class="form-control"
ng-model="OriginType"
ng-options="type.Key as type.Value for type in values">
</select>
And my controller:
$http.get('/api/mycontroller');
.success(function (values) {
$scope.values= values;
})
Try ng-options="key as value for (key, value) in values". I think the problem is that you are attempting to use both the key and value of an object, whilst trying to reference, .Key & .Value, which don't actually exist.
If you wanted to do your ng-options your original way, your returned object should look like:
var result = [
{ Key: 'test1', Value: 'test1Value' },
{ Key: 'test2', Value: 'test2Value' }
]
To return the object from WebAPI like this the method should look like:
[HttpGet]
public List<KeyValuePair<string, string>> Get()
{
return new Dictionary<string, string>(){
{ "test1", "test 1"},
{ "test2", "test 2"}
}.ToList<KeyValuePair<string, string>>();
}

Resources