I have problem with send data between my two apps. I serialize data to JSON in C# using this code:
public static string SerializeToJson<T>(this T obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, obj);
byte[] array = ms.ToArray();
return Encoding.UTF8.GetString(array, 0, array.Length);
}
and then i send this using socket communication to my second application which is implemented in TypeScript. I deserialize it using:
JSON.parse
function and it works fine, but if in data is special characters for example 8211 'ā' it throw exception
SyntaxError: Unexpected token in JSON at position 907
Maybe it is problem with different encoding with serialize and deserialize, but I don't know which encoding is used in JSON.parse.
Anyone can help me?
An alternative is to use Newtonsoft Json.Net (available from nuget).
It's easy to use and very powerfull.
public static string SerializeToJson<T>(this T obj)
{
returnĀ JsonConvert.SerializeObject(obj);
}
And you can even add some formating or what you want.
I resolve this problem using convert to base64 my string and then decode it in my second application.
The following code worked for me. The following solution also ensures the type of underlying objects. To Convert C# object to typescript object.
Convert your object to json format using any of the JSON libraries. (newtonsoft is most suggested one)
string output = JsonConvert.SerializeObject(product); // product =new Product(); <= Product is custom class. substitute your class here
Pass this string to your application. (ActionResult or ajax call)
Now in the javascript access the value using Model (Razor or ajax result)
YourTSClass.ProcessResults('#Model') // using razor in js
or
.done(response => {ProcessResults(response)}) // using ajax success result
You need not apply JSON.Parse this way.
In the typescript you can get the result by declaring the function like this.
public static ProcessResults(result: Product){...}
Related
I am developing a Spring Boot MVC application that uses Thymeleaf templates on the front end.
I am trying to bind a HashMap from my MVC model to a JavaScript variable in one of my Thymeleaf templates. This is what has been done so far: -
In my MVC controller class, I created a HashMap that represents user skills organised into categories. The Skill class is a data object containing name and id properties: -
Map<String, List<Skill>> skillsMap = new HashMap();
I populated this map with all the category and skill information and then added it to my Model: -
model.addAttribute("skillsMap", skillsMap);
On my Thymeleaf template in a script section, I am attempting to bind this HashMap to a variable. As a second step I then attempt to retrieve one of the lists from the map and assign to a second variable: -
var skillsMapMap = [[${skillsMap}]];
var adminList = skillsMapMap.get('Admin');
When I debugged this, I could see that the HashMap was being read and an attempt was being made to bind it to my JavaScript variable: -
var skillsMapMap = {Languages=[Python, SQL, PL/SQL, Java], Databases=[MySQL, Oracle, Mongo], Editors=[Word, TextPad, Notepad]};
This looked good at first glance and I could see that it contained all my data, but it was throwing the following error: -
Uncaught Syntax Error: invalid shorthand property initializer
Having researched this, I realized that this error was caused because Java does not by default serialize the map in valid JSON format and so the attempted bind to a JavaScript variable failed. So, instead of just adding the HashMap straight to the Model as in step 2, I added some code to use Jackson to convert it into a JSON String first: -
//Populate the map with all required data then....
String objectMapper = null;
try {
objectMapper = new ObjectMapper().writeValueAsString(skillsMap);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
model.addAttribute("skillsMap", objectMapper);```
This time When I attempt to bind this to my JavaScript variable, the object looks like this when I debug in my browser: -
var skillsMapJson = {"Languages_OD":[{"id":66,"name":"SQL"},{"id":67,"name":"PL/SQL"}], etc, etc};
The JSON now looks valid, but all the quotes are escaped and it now throws a different exception: -
```Uncaught SyntaxError: Unexpected token &```
I feel that if the JSON string contained actual quotes instead of " the Map would successfully bind to my variable. I would appreciate any advice as to how to deal with this. Many thanks for reading.
EDIT: Screenshot of error added below: -
I did eventually get round this problem and so am offering a solution in case it helps anyone else. However, I feel that the solution is a bit 'hacky' and so would welcome any further answers that improve on this or offer a more elegant solution.
The problem was in the way I was trying to retrieve my map from the Model and assign to a JavaScript variable. Initially, I was trying this: -
var skillsMapRawString = [[${skillsMapJson}]];
The trouble is that this way of referencing skillsMapJson forces JavaScript to treat it as an Object and it cannot deal with the encoding issue described in the original post when attempting to deserialize it into JSON. The above line therefore threw the exception "unexpected token &".
By adding single quotes around the object reference, JavaScript is forced to treat skillsMapJson as a String and not an object: -
var skillsMapRawString = '[[${skillsMapJson}]]';
The above variable assignment now works successfully, but we still have the problem that it contains encoded quotes which prevent it being parsed to a JSON Object. This is where it feels like a bit of a hack, because I got round this by doing a global replace on the String: -
var skillsMapJSONString = skillsMapRawString.replace(/"/g, "\"");
Having replaced the encoded sections that were causing problems before, the String can now be parsed as JSON: -
var skillsMapParsed = JSON.parse(skillsMapJSONString);
And finally, I have my map of lists successfully assigned to a JavaScript variable! :)
Symbols """ and similar are HTML escapes. So your info is HTML escaped. You can unescape it back by using class org.apache.commons.text.StringEscapeUtils from the library apache.commons/commons-text. The info found at: How to unescape HTML character entities in Java?
I'm facing an issue when converting ODATA string into JSON while posting on my Dynamics CRM.
When I'm trying to serialize that way:
var phoneCallAssociationJsonData = '{'
+'"#odata.id" : "https://contoso.crm4.dynamics.com/api/data/v8.1/phonecalls('+ phoneCallUid +')"'
+'}';
And serialize it in the request like that: JSON.stringify(phoneCallAssociationJsonData);
I get a BAD REQUEST response. But When I use POSTMAN to post data and I copy the following JSON:
{"#odata.id" : "https://contoso.crm4.dynamics.com/api/data/v8.1/phonecalls(12a59ec0-76b5-e611-80ed-5065f38a8ad1)"}
It works perfectly.
Does someone know if there is a special way way to serialize string with odata format ?
I've tried to create a javascript object but adding a object.#odata.id is not possible because # is not an allowed character.
Firstly, rather than creating a string, which you then stringify, create an OBJECT
var phoneCallAssociationJsonData = {
"#odata.id" : "https://contoso.crm4.dynamics.com/api/data/v8.1/phonecalls("+ phoneCallUid +")"
};
then
JSON.stringify(phoneCallAssociationJsonData);
should now work
I've problem with serializing object using JSONRenderer.
I'm using django-rest-framework and I've serialized object:
pk = kwargs['pk']
tube = Tube.objects.get(id=pk)
serialized_tube = TubeSerializer(tube)
serialized_tube.data looks like this:
{'id': '11122211133311'}
Unfortunately I can't serialize this using JSONRenderer, because the code
tube_json = JSONRenderer().render(serialized_tube.data)
return Response(tube_json)
gives following error
b'{"id":"11122211133311"}' is not JSON serializable
whereas
tube_json = json.dumps(serialized_tube.data)
return Response(tube_json)
works well...
I'm using Python3.4.3
The issue is not in your JSONRenderer() line, but in the line below it where you return it as a Response.
Django REST framework provides a custom Response object that will automatically be rendered as whatever the accepted renderer was, converting native Python structures into a rendered version (in this case, JSON structures). So a Python dictionary will be converted to a JSON object, and a Python list will be converted to a JSON array, etc.
Right now you are serializing your data to a JSON string then passing it to Response, where you are expecting it to be re-serialized into JSON. You can't serialize a string into JSON (you need an object or array wrapping it), which is why you are seeing the error.
The solution is to not call JSONRenderer ahead of time, and just pass the serializer data to Response.
<script th:inline="javascript" type="text/javascript">
//expose list data to javascript
var listObject = /*[[${listObject}]]*/ [];
</script>
the replacement text printed into the file is different than what Jackson library's ObjectMapper does.
With Thymeleaf in above example, listObject will be
{
"dataType":{
"$type":"DataType",
"$name":"STRING"
},
"friendlyName":"Customer Key"
}
If I print the object with ObjectMapper(which is also used with Spring #RequestBody/#ResponseBody), it will be
{
"dataType":"STRING",
"friendlyName":"Customer Key"
}
Is there a way I can force thymeleaf to be compatible with ObjectMapper.
I think this has to say something about Jackson and JSON inlining in thymeleaf.
To summarize, the possibility to switch to custom TextInliners is considered for
3.0 thymeleaf milestone.
So, currently there is no "clean" way to switch to Jackson json serialization.
What you can do however, is sneak your own TextInliner. That is:
Create a class org.thymeleaf.standard.inliner.StandardJavaScriptTextInliner.
Implement your own version of formatEvaluationResult(Object) method,
where you can call the Jackson ObjectMapper .
Put this new StandardJavaScriptTextInliner class in a proper place, so that it is loaded before the original class (f.e. in tomcat put it in classes dir under correct package structure).
Another option:
when you set listObject in the thymeleaf context, set it to the string that is obtained by converting listObject to a JSON string using Jackson
then use JS eval() or the better method - JSON.parse to convert the string into a JS object.
I want to implement transparent data passing between my server (using Spring) and client (in ExtJS).
On the server side I have Spring Controllers returning ModelAndView objects (using JSPs). I usually don't create model objects, I just put items into a model Map.
I want easy transparent Java to Javascript object conversion. On the server side I put a Java Date object into the map and I get a Javascript Date object on the client.
I.e. on the server I write such code:
public ModelAndView getModelAndView(User user) {
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("date", new Date());
modelMap.put("intarray", new int[] {1,2,3});
return new ModelAndView("mainpage", modelMap);
}
and on the client I write in JSP:
var model = <someMagicTagOrSomething />
and in the rendered HTML I get:
var model = {
date: Date.parse('2012-01-01 12:12:12', 'Y-m-d H:m:s'), //JS Date object
intarray: [1,2,3]
}
Most of what I've seen in the Spring documentation involves specifying object formatting on the server using annotations like #NumberFormat(style=Style.PERCENT) and then getting them on the client using form:input tags. This is not something I want, because I want to format date on the client and not worry about in what format they're transmitted to the client.
What's the best way to accomplish this? Is there an out-of-the-box solution or do I need to write something myself? I know I can use a library like Gson to translate my model into JSON, but this returns the Java Dates as strings and I'd like to get Javascript date objects right away and not have to worry about formatting.
Thanks for any advice,
Piotr
You won't avoid serializing dates to some format. Javascript doesn't understand java objects so there has to be some serialization step (be it json, xml or whatever).
Your best shot is to send dates as ISO strings and use Date.parse(isostring) on them. You don't need to specify the format string then, so you have to type less and at least you work with format most clients understand.
<c:set var="myModelObject" value="${myObjectFromServer}"/>
<script>
var myJSvar = "${myModelObject}";
</script>
And yeah, you'll have to serialize/deserialize dates ... I extend the PropertyEditor :
public class LocalDateEditor extends PropertyEditorSupport{
#Override
public void setAsText(String text) throws IllegalArgumentException{
setValue(DateTimeFormat.forPattern("dd MMM yyyy").print(text));
}
and then register that in yr controller (you can also set a global one, but I can't remember how) :
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDate.class, new LocalDateEditor());
}
for what its worth I use a global date formatter, and on the user interface a global jquery ui datepicker class - not much coding required at all really. And everything works out of the box - after the initial set up. I never liked the iso standard dates (that might be because I am british :-( )