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 :-( )
Related
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){...}
I am using Node.js to query MongoDB and have a field that is a Date (ISODate). In Node.js after querying the Date format that is returned looks like this
DT : 2014-10-02T02:36:23.354Z
What I am trying to figure out is how based on the code i have below, can efficiently convert the DT field from UTC to Local Time ISOString. In other words if local time is EDT then something like this
DT : 2014-10-02T23:36:23.354Z
I don't think there is anything I can do in the query itself from Mongo. Should I traverse the Array result set and manually change the dates? Is there a better approach here? I am sending the response to an HTTP client.
collection.find(query,options).toArray(function (err, items) {
if (err) {
logAndSendDebugError(500, "Error issuing find against mongo Employees Collection -" + type, res);
} else {
var response = {
'type': type,
'employees': items
};
res.jsonp(response);
}
});
In ES5, Date.parse should be able to parse that format, however it isn't reliable. Manually parsing it isn't hard:
// Parse ISO 8601 UTC string like 2014-10-02T23:36:23.354Z
function parseISOUTC(s) {
var b = s.split(/\D/);
return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]));
}
The date instance that is created will have a local timezone offset calculated from system settings. To get a UTC ISO 8601 string from a local date you can use toISOString:
var date = new Date();
console.log(date.toISOString());
Note that toISOString is ES5 so may need a polyfill if this is used in older browsers. See MDN Date.prototype.toISOString().
I would have thought the most efficient way to handle dates between the client and server would be to use the EJSON package. This covers a few things that are skirted around in other discussion here and the importance is placed on maintaining "type fidelity" when handling JSON conversion.
So what you are getting right now is the result of a "string" which is called from the "Date" object in response to a JSON.stringify call. Whatever the method being used, this is essentially what is happening where the .toJSON() method is being called from the "Date" prototype.
Rather than muck around with the prototypes or other manual processing of coversions, the EJSON package allows you to call EJSON.stringify instead which has some built in behavior to preserve types, where specifically the generated JSON string would look like this for a Date element:
{ "myCreatedDate": { "$date": 1412227831060 } }
The value there is an epoch timestamp, essentially obtained from the .valueOf() prototype method, but the field is given a special structure automagically as it were. The same is true for types other than dates as well.
The corresponding "client" processing which you can add with simple includes to your web application in the browser, e.g:
<script src="components/ejson/base64.js"></script>
<script src="components/ejson/ejson.js"></script>
This allows a same EJSON object to be present where you can process the received JSON with EJSON.parse. The resulting JavaScript Object is maintained as a "Date" type when the de-serialize is done.
var obj = EJSON.parse( "{ \"myCreatedDate\": { \"$date\": 1412227831060 } }" );
{
myCreatedDate: /* Actually a Date Object here */
}
So now in your client browser, you have a real Date object without any other processing. Any .toString() method called on that object is going to result in a value represented in a way that matches the current locale settings for that client.
So if you use this to pass the values around between server and client in a way that is going to maintain an actual "Date" object, then the correct Object values are maintained on either client and server and needs no further conversion.
Very simple to include in your project and it takes a lot of the heavy lifting of maintaining "timezone" conversions off your hands. Give it a try.
Probably worth noting that the "core" of this comes from a MongoDB specification for Extended JSON Syntax. So aside from this (partial) implementation in the EJSON package, the same "type identifiers" are supported in several MongoDB tools as well as within several driver implementations with a custom JSON parser that will automatically convert the types. Notably the Java and C# drivers have this capability shipped with the driver libraries.
It's fairly easy to follow the convention outlined in that link, and it is intended to "map" to the BSON type specifications as well. At the worst, you can always "inspect" the results from a standard JSON parser and implement custom routines to "re-instantiate" the "types". But as noted, the software is already in place with several libraries.
<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 need to send a post value to my MVC controller.
My model for this MVC has the following property.
public List<Guid> ReceiverUserIDs { get; set; }
I've tried the following formats
ReceiverUserIDs=db9dd11a-4fea-4e03-9520-26c9b9c4bc6a,3a9780f4-2860-4af0-a728-0596c52326b3
ReceiverUserIDs[]=db9dd11a-4fea-4e03-9520-26c9b9c4bc6a,3a9780f4-2860-4af0-a728-0596c52326b3
ReceiverUserIDs=["db9dd11a-4fea-4e03-9520-26c9b9c4bc6a","3a9780f4-2860-4af0-a728-0596c52326b3"]
I'm not sure what format the controller/model will accept.
The only format .NET will get is list of strings. So the third js format seams about right, but the accepting format needs to be a List.
If I'm understanding your question right, you're just trying to initialize your list of guids from string values, which would be done like this:
ReceiverUserIDs = new List<Guid>
{
new Guid("db9dd11a-4fea-4e03-9520-26c9b9c4bc6a"),
new Guid("3a9780f4-2860-4af0-a728-0596c52326b3")
};
This is driving me crazy, similar to this. If I use a standard form and no javascript the controller correctly binds the datetime. However when I'm posting from a form it always binds as null:
"MyObject.Name": "Test name",
"MyObject.Date": "5/1/2001"
I've tried a couple of variations, 5-1-2001, etc. but cannot seem to get it to take. I can confirm that it is being passed to the server as it shows up in the Request.Form string. My culture is Gregorian and I've set:
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
In Application_BeginRequest(). What gives?
Did you try using leading zeros, like "05/01/2001"?
The invariant culture's standard date formats include "MM/dd/yyyy" but not "M/d/yyyy", so if it works, that's why. Ideally you would use one of the non-culture-specific formats like the 'O' roundtrip pattern. Then it wouldn't matter what culture you were using on the server:
http://msdn.microsoft.com/en-us/library/az4se3k1.aspx#Roundtrip
Could it be a localization issue? This blog post describes a common localization pitfall with DateTime.
DateTime is value type and not reference type and it takes DateTime.MinValue if you don't initialize it.
you have to declare it as:
DateTime? dt;
Or
Nullable<DateTime> dt;
DateTime? is shorthand for Nullable<DateTime>