I have an Json string return by facebook api and I want to cast it to an object, I tried using both Newton Json and JavaScriptSerializer.
https://graph.facebook.com/v1.0/1111111111111/comments?limit=25&after=NTA\u00253D
After I cast it to a strongly typed object or a dynamic object, the url will be changed to
https://graph.facebook.com/v1.0/1111111111111/comments?limit=25&after=NTA%3D
What is the cause of this issue?
I have tried url encoding and decoding, but it didn't work.
In JSON, any character can be represented by a unicode escape sequence, which is defined as \u followed by 4 hexadecimal digits (see JSON.org). When you deserialize the JSON, each escape sequence is replaced by the actual unicode character. You can see this for yourself if you run the following example program:
class Program
{
static void Main(string[] args)
{
string json = #"{ ""Test"" : ""\u0048\u0065\u006c\u006c\u006f"" }";
Foo foo = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(foo.Test);
}
}
class Foo
{
public string Test { get; set; }
}
Output:
Hello
In your example URL, \u0025 represents the % character. So the two URLs are actually equivalent. There is no issue here.
Related
I am having some problems with create with JSON.Net. When I try to parse it, it gives me following error:
Additional text encountered after finished reading JSON content:
I tried validating it with http://json.parser.online.fr/ and it says "SyntaxError: Unexpected token ,".
My JSON is as below:
{"StaffID":"S01","StaffRank":"Manager"},{"StaffID":"S02","StaffRank":"Waiter"}
How to deserialize it?
You need to surround that with square brackets, which denotes that it's an array:
[{"StaffID":"S01","StaffRank":"Manager"},{"StaffID":"S02","StaffRank":"Waiter"}]
As of Release 11.0.1, Json.NET now natively supports parsing comma-delimited JSON in the same way it supports parsing newline delimited JSON:
New feature - Added support for reading multiple comma delimited values with JsonReader.SupportMultipleContent.
Thus the answer to Line delimited json serializing and de-serializing by Yuval Itzchakov should work here also. Define an extension method:
public static partial class JsonExtensions
{
public static IEnumerable<T> FromDelimitedJson<T>(TextReader reader, JsonSerializerSettings settings = null)
{
using (var jsonReader = new JsonTextReader(reader) { CloseInput = false, SupportMultipleContent = true })
{
var serializer = JsonSerializer.CreateDefault(settings);
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.Comment)
continue;
yield return serializer.Deserialize<T>(jsonReader);
}
}
}
}
Then, given a data model created to hold an individual item in the comma-separated list such as:
public class RootObject
{
public string StaffID { get; set; }
public string StaffRank { get; set; }
}
You can deserialize the JSON string shown like so:
var jsonString = #"{""StaffID"":""S01"",""StaffRank"":""Manager""},{""StaffID"":""S02"",""StaffRank"":""Waiter""}";
var list = JsonExtensions.FromDelimitedJson<RootObject>(new StringReader(jsonString)).ToList();
This approach may be preferable when deserializing a very large sequence of comma-delimited objects from a large file, because it is not necessary to load the entire file into a string then add '[' and ']' to the beginning and end. In Performance Tips: Optimize Memory Usage Newtonsoft recommends deserializing large files directly from a stream, so instead a StreamReader can be passed into JsonExtensions.FromDelimitedJson() which will then stream through the file deserializing each object separately.
I'm developing a Rest Client using Spring Boot and Spring Framework (spring-boot-starter-parent 2.1.6.RELEASE)
I have a class representing a response object as shown below:
public class ValidateResponse {
private String ResponseCode;
private String ResponseDesc;
//getters and setters
//constructors using fields
//empty constructor
}
I'm creating a web-hook for an external api and I need to return a JSON object to for a specific endpoint (the JSON object properties must start with uppercase(s)). I'm calling returning the object from a PostMapping method nested in a RequestMapping root path:
#PostMapping("hooks/validate")
public ValidateResponse responseObj(#RequestHeader Map<String, String> headersObj) {
ValidateResponse response = new ValidateResponse("000000", "Success");
logger.info("Endpoint = hooks/validate | Request Headers = {}", headersObj);
return response;
}
However, when I hit the endpoint from postman I'm getting duplicate varialbes
{
"ResponseCode": "000000",
"ResponseDesc": "Success",
"responseCode": "000000",
"responseDesc": "Success"
}
I understand that the pojo-json conversion is handled by spring but I don't understand why the conversion is yielding duplicate variables.
Note: I know the ResponseDesc and the ResponseCode are not declared using the best standards for naming variables (camelCasing).
I've done some digging and according to the Java Language Specification
An identifier is an unlimited-length sequence of Java letters and Java digits, the first of which must be a Java letter.
and
The "Java letters" include uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons, the ASCII underscore (_, or \u005f) and dollar sign ($, or \u0024). The $ character should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems.
So, I'm assuming its syntactically correct to define a variable using the Camelcase format [Need clarification on this].
I'm considering having to create the JSON object manually but I'd like to know the cause of this behaviour first. Any pointers are appreciated.
Jackson deserializes all the public fields that it comes across. However if you want Jackson to return the response in your expected element names (in your case elements starting with capital letters), make the fields private and annotate them with the #JsonProperty(expected_name_here). Your class file will typically looks as shown below
public class ValidateResponse {
#JsonProperty("ResponseDesc")
private String responseCode;
#JsonProperty("ResponseDesc")
private String responseDesc;
//getters and setters
//constructors using fields
//empty constructor
}
Note: The getters and setters for these fields should be public, otherwise Jackson won't see anything to deserialize in the class.
public class ValidateResponse {
#JsonProperty("ResponseDesc")
public String responseCode;
#JsonProperty("ResponseDesc")
public String responseDesc;
//getters and setters
//constructors using fields
//empty constructor
}
This must fix your problem, however I do not know the reason as it requires deep Jackson investigation.
EDIT
I found out the reason.
The field got duplicated because in you case you had:
2 public fields named in upper case -> they are to be processed by jackson
2 getters getResponseCode and getResponseDesc -> they are to be resolved
as accessors for properties responseCode and responseDesc accordingly.
Summing this up - you have 4 properties resolved by Jackson. Simply making your fields private will resolve your issue, however I still advise using JsonProperty approach.
I added a com.google.code.gson dependency in the projects pom.xml file to configure Spring Boot to use Gson (instead of the default jackson).
The Json object returned from the hooks/validate endpoint must have its property names starting with a capital letter. Using a java class to generate the response object was resulting to camelCased property names so I resolved to create the JSON response object manually. Here's the code for creating the custom JSON object:
public ResponseEntity<String> responseObj(#RequestHeader Map<String, String> headersObj) {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
JsonObject response = new JsonObject();
response.addProperty("ResponseCode", "00000000");
response.addProperty("ResponseDesc" , "Success");
logger.info("Endpoint = hooks/validate | Request Headers = {}", headersObj);
return ResponseEntity.ok().headers(responseHeaders).body(response.toString());
}
Note The JSON object is returned as a String so the response from the endpoint must have an additional header to define MediaType to inform the calling system that the response is in JSON format:
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
then add the header to the response:
return ResponseEntity.ok().headers(responseHeaders).body(response.toString());
If I do this:
import { MyType } from 'somewhere';
class MyClass {
myObj: MyType = new MyType();
updateObject(newVal: string): void {
myObj.thing = newVal;
this.saveStuff(JSON.stringify(myObj));
}
saveStuff(json: JSON): void {
// http request...
}
}
I get an error that I'm passing a string, not JSON. (I understand that I am in fact passing a string) How can I make it take the string as JSON?
I tried casting the string as JSON, ie: JSON.stringify(foo) as JSON or <JSON> JSON.stringify(foo). But I get a "Type 'string' cannot be converted to type 'JSON'." error both ways.
What you are doing with the TypeScript type annotation is to announce the type you expect a value to have (you don't declare the type). More often than never it happens that you set a type annotation and when you run the code you discover that the actual type is something else.
In this case though the TS compiler can evaluate the types beforehand. It knows that JSON.stringify returns a string. Since you have annotated the saveStuff method to accept a JSON object, it will give you a compiler error for the type mismatch.
Regardless of its content, a string remains a string. It may contain JSON, XML or a poem. It will still be nothing else than a string. The JSON class is just a utility class that provides you with a way to serialize and deserialize a JavaScript object into and from a string (with JSON content).
JSON is not a type. When you parse a string by calling JSON.parse(str), what you get is an object literal.
In your code, as you call JSON.stringify(foo), you are converting the object literal foo to a string.
Thus, your saveStuff() receives a string.
JSON stands for JavaScript Object Notation. It is just a specification on how to represent an object.
I am trying to serialize a string that is returned from a http response and I am using netstandard1.0. Not a lot of serializing functions work in this framework, but I finally found a working function. Here is my code so far:
HttpResponseMessage Response = // initialized else where
var jsonTask = Response.Content.ReadAsStringAsync();
if (!jsonTask.IsCompleted) jsonTask.RunSynchronously();
string json = jsonTask.Result;
Data = JsonConvert.DeserializeObject<MyModel>(json);
However this does not deserialize I get from the http response. It throws an error that the DeserializeObject function is looking for a different format. When I run Result.Content.ReadAsStringAsync(), I get the result in the following format.
"[{\"key\":\"Password\",\"errors\":[\"The Password field is required.\"]},{\"key\":\"UserName\",\"errors\":[\"The UserName field is required.\"]},{\"key\":\"OrganizationUserName\",\"errors\":[\"The OrganizationUserName field is required.\"]}]"
Does anyone know how to deserialize this format?
If you define your MyModel as follows:
public class MyModel
{
public string key { get; set; }
public List<string> errors { get; set; }
}
You can deserialize as follows:
var list = JsonConvert.DeserializeObject<List<MyModel>>(json);
Notes:
I generated the c# definition for MyModel by uploading your JSON to http://json2csharp.com/.
The reason for the exception you are seeing trying to deserialize directly to MyModel is that your outer JSON container is an array, not an object. As explained in the standard, JSON has two types of container:
An array which is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
An object which is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace).
In the Json.NET Serialization Guide: IEnumerable, Lists, and Arrays it is explained that JSON arrays are converted from and to .Net types implementing IEnumerable. So that's what you need to do.
If you know the array will contain no more than one element, you can use SingleOrDefault() to extract that single element:
Data = list.SingleOrDefault();
However, in the example included in you question, the outer array has 3 items, so this is not appropriate.
Sample fiddle.
When a Json string contains 'key1:value1', this can be converted to the Dictionary type.
But in my case, it also contains an array of strings along with the above key:value, ie:
{k1:v1; "key2\":[{\"Key11\":{\"key21\":\"Val21\",\"key22\":\"val22\"}]
(The Json data contains some strings and some arrays.)
When I use Dictionary<string, string[]> or Dictionary<string, ArrayList> -- it is failing at the value as string - cannot convert string to string[], etc.
Still Dictionary<string, object> can be used, but is there any better way to handle this?
thanks
Phani
If you don't know the structure at compile-time, then there's no other way to serialize a JSON string-- it has to be Dictionary<string,object>. However, if you're using C# 4.0, you can use DynamicObject. Since dynamic typing defers type resolution until runtime, if you serialize using this approach, you can treat your serialized object as strongly-typed (albeit without compile-time support). That means you can use JSON-style dot notation to access properties:
MyDynamicJsonObject.key2
To accomplish this, you can inherit from DynamicObject, and implement the TryGetMember method (quoted from this link, which has a full implementation):
public class DynamicJsonObject : DynamicObject
{
private IDictionary<string, object> Dictionary { get; set; }
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
this.Dictionary = dictionary;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.Dictionary[binder.Name];
if (result is IDictionary<string, object>)
{
result = new DynamicJsonObject(result as IDictionary<string, object>);
}
else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
{
result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
}
else if (result is ArrayList)
{
result = new List<object>((result as ArrayList).ToArray());
}
return this.Dictionary.ContainsKey(binder.Name);
}
}
Note that dynamic typing currently doesn't support indexer notation, so for arrays, you'll need to implement a workaround using notation like this:
MyDynamicJsonObject.key2.Item(0)
Your example is not valid JSON, e.g. every key and value should be surrounded by ", e.g. {"k1":"v1"}, the number of opening and closing curly brackets must match, if you escape the " character by using \" you must add a another " character, e.g. "key2\""
Use a tool such as JSONLint to validate that your JSON is correct.