Confusion in Json Structure - json

I am creating a json configuration to create a dashboard with multiple widgets.
I will read that json file and create pojo from it using Gson. The structure of the Java classes is like:
public class Widgets {
//Some other variables
private List<Widget> widgets = new ArrayList<>();
//some more variables and methods
}
public interface Widget{}
public class MeterWidget implements Widget{
//some meter widget variables
}
public class GraphWidget implements Widget{
//some graph widget variables
}
Now I want to declare widgets in json with multiple widgets of the same kind possible. Something like below:
{
"widgets": [
{
"meterWidget": {
},
"meterWidget": {
},
"graphWidget": {
}
}
]
}
I know this json is not correct as we can't have multiple items with the same name(meterWidget in this case) inside a single object, but I can't think of any structure that will help me with the class structure above. Also having widgets in an array is not necessary as I am not maintaining any order in this structure. Please help.
Thanks
Raman

You could have the type be a parameter in json like this:
{
"widgets": [
{
"type": "meterWidget",
"someParam": "stuff"
},
{
"type": "meterWidget",
"someParam": "stuff"
}
]
}

Related

How to deserialize list JSON using entity class?

I am getting a JSON in which it include list. Now I want to use only some property rather than all the properties.
JSON
{
"instance_pools" : [
{
"instance_pool_name":"pool1",
"node_type_id":"standard",
"azure_attributes":{
"availability":"on"
},
"instance_pool_id":"poool2345",
"status":{}
},
{
"instance_pool_name":"pool1",
"node_type_id":"normal",
"azure_attributes":{
"availability":"on"
},
"instance_pool_id":"poool2345",
"status":{}
},
{
"instance_pool_name":"pool1",
"node_type_id":"high",
"azure_attributes":{
"availability":"on"
},
"instance_pool_id":"poool2345",
"status":{}
}
]
}
Now at .Net side, I only want instance_pool_name and corresponding instance_pool_id.
I am new to .Net, Can somebody please help me with how to deserialize this complex JSON and use only some properties.
Thank you
You can create the classes as you want. You must not map all json properties into C# class' property. Therefore you can write the C# classes with the properties you need:
public class InstancePoolCollection
{
public InstancePool[] instance_pools{get;set;}
}
public class InstancePool
{
public string instance_pool_id{get;set;}
public string instance_pool_name{get;set;}
}
Deserializing using System.Text
var obj = JsonSerializer.Deserialize<InstancePoolCollection>(jsonObj);
Deserializing using Newtonsoft.Json
var obj = JsonConvert.DeserializeObject<InstancePoolCollection>(jsonObj);
Note: Your JSON was not conform. I have changed it.

AppSettings Deserialize to an unknown or dynamic class

I'm trying to set up a series of complex app settings in a separate settings.json file - I won't go into detail as to why...
So I have a JSON file which looks like this:
{
"Website": {
"Name": "Website Name",
"api_key": "----------",
"domain": "-----------"
},
"Pages": {
"Index": {
"Name": "Index",
"Widgets": {
"BestSellers": {
"Name": "BestSellers",
"Type": "ProductCollection",
"Data": {
"Limit": "8",
"Sort": {
"SortType": 3
},
"GetFullProducts": true,
"GroupVariations": false
}
}
}
}
}
}
The first section "Website" simply fetches string settings, all working fine.
The section section "Pages" is more complicated. I have classes that look like this:
public class PageSettings
{
public string Name { get; set; }
public Dictionary<String, Widget> Widgets { get; set; }
public class Widget
{
public string Name { get; set; }
public string Type { get; set; }
public Dictionary<String, object> Data { get; set; } // THIS IS THE PROPERTY THIS QUESTION IS ABOUT
}
}
I use this code to deserialise the above:
IConfigurationSection pagessection = root.GetSection("Pages");
if (pagessection.Exists())
{
_Pages = new Dictionary<String, PageSettings>();
pagessection.Bind(_Pages);
}
With the JSON File exactly as above, this will fail. For some reason, the nested Object Sort in the Data property cannot be deserialised as Object:
"Sort": {
"SortType": 3
}
If I take the above nested object out then all the code so far will work. However, there are use cases where I need that nested object.
I have tried using ExpandoObject which is very cool and clever, but because it expects KeyValuePairs, it then only serialises the nested object in Data, ignoring the simple properties Limit, GetFullroduct etc.
So what I need is a form of ExpandoObject which can also be ExpandoString or something?!
Alternatively... I need to be able to get the Data property from the settings.json file in String form and explicitly deserialise it using JsonConvert.Deserialize at the point of use, because at that point I can declare the proper class that it needs to be deserialised to, but i can't seem to find a way to get the IConfigurationSection code to get the value as a string, rather than a JSON object.
I can't find a solution to this, the nested object breaks everything I have tried.
The helpful comment from #Fei Han has helped a little in highlighting the flexibility of the JObject class, so the solution I have come to is this:
The complex class has to be stored as an HTML encoded string in the settings.json file:
"Data": "{"Limit": "8","GetFullProducts":true,"GroupVariations":true, "Sort": {"SortType": 3}}"
it has to be HTMLEncoded because it is the only way I can find to make the ConfigurationBuilder treat it as a string so that I can cast it correctly later.
The corresponding Class for this now has these properties:
public string ModelString { get; set; }
public Newtonsoft.Json.Linq.JObject Model
{
get
{
string s = ModelString.HtmlDecode();
if (s.EmptyStr())
{
return new JObject();
} else {
return JObject.Parse(s);
}
}
}
From this I am able to easily cast my Data to the eventually required class using .ToObject<MyObject>()
For some reason, this works. I am able to deserialise the string to a JObject in this method, but not directly using the Bind command on IConfigurationSection.
If anyone has any tips on why Bind won't do it, that'd be interesting!

#JsonProperty to be used only for deserialization from JSON, not for serilization to JSON

I have the following POJO. It contains data about my airport.
class MyClass
{
#JsonProperty("AirportCode")
String airportCode;
#JsonProperty("AirportID")
Integer airportId;
}
The POJO objects are created using a JSON received from an API. the API sample output is like below.
[
{
"AirportCode": "BBA",
"AirportID": 4276802,
},
{
"AirportCode": "SCQ",
"AirportID": 5325651,
}
]
My code is to function as follows
void func()
{
//Get JSON from API and convert to POJO
//Do some processing on the POJO
//Convert POJO into JSON and write to file
}
The file contents are as follows
[
{
"AirportCode": "BBA-IN",
"AirportID": 4276802,
},
{
"AirportCode": "SCQ-USA",
"AirportID": 5325651,
}
]
I however require the output to be in camel case (like the POJO)
[
{
"airportCode": "BBA-IN",
"airportId": 4276802,
},
{
"airportCode": "SCQ-USA",
"airportId": 5325651,
}
]
Is there anyway I can get #JsonProperty to be honored only during deserialisation to POJO and not during serialization to JSON?
Have you tried to annotate getters and setters with different jsonProperty values? Directly it won't work but if you change the getter/setter name it should as both methods will be processed as if they belonged to different fields.
Something like this:
class MyClass {
String airportCode;
Integer airportId;
#JsonProperty("airportCode")
public String getAirportCodeForJson() {
return airportCode;
}
#JsonProperty("AirportCode")
public void setAirportCode(String airportCode) {
this.airportCode = airportCode;
}
#JsonProperty("airportID")
public Integer getAirportIdForJson() {
return airportId;
}
#JsonProperty("AirportID")
public void setAirportId(Integer airportId) {
this.airportId = airportId;
}
}
You could deserialize into a Dictionary and then camel-case all keys. Afterwards you'd be able to use it as intended.

Including Class name in POJO - JSON Marshalling

Following this example.
GET response is:
{
"singer":"Metallica",
"title":"Enter Sandman"
}
If more objects were included output should be like this:
[{
"singer":"Metallica",
"title":"Enter Sandman"
}, {
"singer":"Elvis",
"title":"Rock"
}]
I want to get the 'classname' written too. Something like this:
{"Track":[ {
"singer":"Metallica",
"title":"Enter Sandman"
}, {
"singer":"Elvis",
"title":"Rock"
}]}
Any simple ways to achieve this?
Looking forward to get data directly into Datatables from a JAX-RS Resteasy (Jackson) Server. Also trying to avoid DTO.
class TrackList
{
private List<Track> Track = new ArrayList<Track>();
// setter, getter
}
GET method
public TrackList getTrackInJSON() {
EDIT
GET method
public String getTrackInJSON() {
// ... create list of objects
return convertToString(objects);
}
utility method
static <T> String convertToString(List<T> list) throws IOException
{
final String json = new ObjectMapper().writeValueAsString(list);
return new StringBuilder()
.append("{\"")
.append(list.get(0).getClass().getSimpleName())
.append("\":")
.append(json)
.append("}")
.toString();
}

APEX JSON Deserialize

I have JSON string that has nested objects with dynamic names that vary each time. For an instance:
{
"Objects": {
"dynamicName1": {
"name": "test"
},
"dynamicName2": {
"name": "test"
}
}
}
I was wondering how can you deserialize this string in APEX using wrapper classes?
I tried this:
public class masterobj
{ public childobj Objects;
}
public class childobj
{ public el dynamicName1;
public el dynamicName2;
}
public class el
{ public string name;
}
String s = '{"Objects":{"dynamicName1":{"name":"test"},"dynamicName2":{"name":"test"}}}';
masterobj mo = (masterobj)JSON.deserialize(s, masterobj.class);
which works well when you have declared the dynamic variable names in the class for each nested object.
The problem and the question is how can I make this work using a dynamic variable in the wrapper class. Because the object names will vary and also the number of the objects, I can't hard-code the names as they are different each time.
Any ideas?
You won't be able to deserialize a structure like that with the data binding features of the json parser, you'll need to use the streaming json parser to read it.
Use a Map:
public class masterobj
{
Map<String, el> Objects;
}