Nested object JSON serialization in WebAPI - json

I am using .NET 4.0, MVC 4, Web API. I have following data structure:
Dictionary<Actor, Int32> TopActorToMovieCount = new Dictionary<Actor, Int32>(10);
And following entry in WebApiConfig:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
In my Controller, I am returning TopActorToMovieCount this way:
[HttpGet]
public HttpResponseMessage HighestMovies()
{
return Request.CreateResponse(HttpStatusCode.OK, MvcApplication.TopActorToMovieCount);
}
But the JSON output it is giving is:
{"api.Models.Actor":137,"api.Models.Actor":125,"api.Models.Actor":99,"api.Models.Actor":96,"api.Models.Actor":83,"api.Models.Actor":82,"api.Models.Actor":81,"api.Models.Actor":79,"....
Why it is not giving JSON structure for object of Actor?
I am sure that I am missing something, bout couldn't figure out. I tried adding following, but it didn't work:
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
PS: When I switch to XML output, it works fine.

See similar question here: Not ableTo Serialize Dictionary with Complex key using Json.net
In this case, you are using "Actor" as the Key of your dictionary. Dictionary stores key/value pairs. So when creating the JSON response, it interprets the "Actor" as a key which is converted to a string, and the "Int32" as the value thus giving you
{"api.Models.Actor":137} or {key:value}
because
Actor.ToString() would result in "api.Models.Actor"
Here's a link to the definition of Dictionary: https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx

Related

Why doesn't the json model's odata property have columns?

I am creating a JSON model in UI5 from a json object. But it is missing the columns array in the JSON model. I checked the model in the console and the odata property had no columns. Check image for proof.
https://ibb.co/hLmYpZb
Hence I want to know how I can get the column to show up.
Here is my code.
var emptyModel = {
"columns": []
};
this.setModel(new JSONModel(JSON.stringify(emptyModel)), "selcontent");
I expect column to show up in the JSON model under the odata property.
JSONModel awaits a plain object or a URL string as the first argument.
Either the URL where to load the JSON from or a JS object (source)
The result of the stringified emptyModel is "{"columns":[]}" which is neither an object nor a URL.

How can I define a ReST endpoint that allows json input and maps it to a JsonSlurper

I want to write an API ReST endpoint, using Spring 4.0 and Groovy, such that the #RequestBody parameter can be any generic JSON input, and it will be mapped to a Groovy JsonSlurper so that I can simply access the data via the slurper.
The benefit here being that I can send various JSON documents to my endpoint without having to define a DTO object for every format that I might send.
Currently my method looks like this (and works):
#RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<String> putTest(#RequestBody ExampleDTO dto) {
def json = new groovy.json.JsonBuilder()
json(
id: dto.id,
name: dto.name
);
return new ResponseEntity(json.content, HttpStatus.OK);
}
But what I want, is to get rid of the "ExampleDTO" object, and just have any JSON that is passed in get mapped straight into a JsonSlurper, or something that I can input into a JsonSlurper, so that I can access the fields of the input object like so:
def json = new JsonSlurper().parseText(input);
String exampleName = json.name;
I initially thought I could just accept a String instead of ExampleDTO, and then slurp the String, but then I have been running into a plethora of issues in my AngularJS client, trying to send my JSON objects as strings to the API endpoint. I'm met with an annoying need to escape all of the double quotes and surround the entire JSON string with double quotes. Then I run into issues if any of my data has quotes or various special characters in it. It just doesn't seem like a clean or reliable solution.
I open to anything that will cleanly translate my AngularJS JSON objects into valid Strings, or anything I can do in the ReST method that will allow JSON input without mapping it to a specific object.
Thanks in advance!
Tonya

Grails JSON Converter

I have a method in my main controller that return a string that I want to render as JSON.
So I am importing "import grails.converters.JSON" and calling
myMethod() as JSON
, and it works fine. But when I need to get some details of the json response in my integration test.
So in my integration test I have:
void testfoo() {
def bar = controller.myMethod();
def bar.name; //fails
JSON.parse(bar.toString()).name; // doesn't fail
....
..
}
any idea why I need to convert it to a string and then again to a JSON, since it already a JSON?
The value you get back from your method is a grails.converters.JSON, which is not a directly accessible JSON tree as such, but simply an object that knows how to serialize itself as JSON when required. If you want direct access to the JSON tree structure then you need to tell the grails.converters.JSON object to serialize itself and then pass that JSON to JSON.parse to turn it into a JSONElement (or one of its subclasses, in this case presumably a JSONObject).

Why is GSON not parsing these fields properly? (FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)

I have a JSONArray of JSONObjects that I'm trying to parse with GSON. I'm using FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES. It's parsing correctly for most fields (so the FieldNamingPolicy is set correct), but I'm getting null returned for
{
"image_sq_48x48_url": "url1",
"image_sq_64x64_url": "url2",
"image_sq_96x96_url": "url3"
}
with field names
imageSq48x48Url
imageSq64x64Url
imageSq96x96Url
Maybe a better question would be what is the proper camelCase? I have also tried
imageSq48X48Url
imageSq48X48url
If I map with #SerializedName("image_sq_96x96_url") it parses/populates correctly.
Unfortunately those fieldnames in your JSON don't conform to what Gson looks for using that strategy.
If you create a POJO and serialize it, you can see what the issue is:
class MyPojo
{
String imageSq48x48Url = "hi";
}
The resulting JSON from Gson using that strategy is:
{"image_sq48x48_url":"hi"}
It doesn't consider/look at numeric digits as leading indicators / start of a "word".
If you rename the field to:
String imageSq_48x48Url;
It would work with your JSON example and that strategy.
Basically, you either need to create your own class that implements FieldNamingStrategy that will handle those JSON fieldnames the way you want, or do what you're doing with the #SerializedName annotation.

GWT Autobean - how to handle lists?

I have been trying to evaluate GWT Autobean feature to decode/encode JSON object to domain objects for REST calls.
Following the example : http://code.google.com/p/google-web-toolkit/wiki/AutoBean#Quickstart
I was able to convert a singular JSON object to a domain object:
AutoBean<Person> personBean = AutoBeanCodex.decode(factory, Person.class, JsonResources.INSTANCE.json().getText());
where JsonResources.INSTANCE.json() is returning a JSON string.
However, I haven't been successful to convert a list of Person objects from JSON.
It would be helpful, if anyone has an example of this?
Thanks!
Well the only way I can think of is to create a special autobean, which will have List<Person> property. For example:
public interface Result {
void setPersons(List<Person> persons);
List<Person> getPersons();
}
And example json string:
{
persons:[
{"name":"Thomas Broyer"},
{"name":"Colin Alworth"}
]
}
UPDATE:
Workaround when input JSON is an array ( as suggested by persons[0] in comments).E.g. JSON looks like this:
[{"name":"Thomas Broyer"},{"name":"Colin Alworth"}]
And parsing code looks like this:
AutoBeanCodex.decode(factory, Result.class, "{\"persons\": " + json + "}").getPersons();