rest - smartgwt restdatasource json date validation -
i using spring 3.2 mvc controller , spring-ws create restful web-service. spring controller accepts object files update database correctly , returns json front-end. spring context set message converts json. have unit tests these, know spring controllers working , filing data accordingly.
the error, warning, comes when data/json web-service:
10:05:08.906[error[phonebook]10:05:08.902:xrp3:warn:restdatasource:restuserds:restuserds.userbirthdate:value:-99187200000 failed on validator {type:"isdate",typecastvalidator:true,_generated:true,defaulterrormessage:"must date."} com.smartgwt.client.core.jsobject$sgwt_warn: 10:05:08.902:xrp3:warn:restdatasource:restuserds:restuserds.userbirthdate: value: -99187200000 failed on validator: {type: "isdate",typecastvalidator: true,_generated: true,defaulterrormessage: "must date."} @ sun.reflect.nativeconstructoraccessorimpl.newinstance0(native method) @ sun.reflect.nativeconstructoraccessorimpl.newinstance(nativeconstructoraccessorimpl.java:39) @ sun.reflect.delegatingconstructoraccessorimpl.newinstance(delegatingconstructoraccessorimpl.java:27) @ java.lang.reflect.constructor.newinstance(constructor.java:513) @ com.google.gwt.dev.shell.methodadaptor.invoke(methodadaptor.java:105) @ com.google.gwt.dev.shell.methoddispatch.invoke(methoddispatch.java:71) @ com.google.gwt.dev.shell.oophmsessionhandler.invoke(oophmsessionhandler.java:172) @ com.google.gwt.dev.shell.browserchannelserver.reacttomessages(browserchannelserver.java:293) @ com.google.gwt.dev.shell.browserchannelserver.processconnection(browserchannelserver.java:547) @ com.google.gwt.dev.shell.browserchannelserver.run(browserchannelserver.java:364) @ java.lang.thread.run(thread.java:662)
so, here userdatasource:
package com.opensource.restful.client.datasource; import java.util.hashmap; import java.util.map; import com.google.gwt.core.client.javascriptobject; import com.opensource.restful.shared.constants; import com.smartgwt.client.data.dsrequest; import com.smartgwt.client.data.dsresponse; import com.smartgwt.client.data.operationbinding; import com.smartgwt.client.data.restdatasource; import com.smartgwt.client.data.fields.datasourcebooleanfield; import com.smartgwt.client.data.fields.datasourcedatefield; import com.smartgwt.client.data.fields.datasourceintegerfield; import com.smartgwt.client.data.fields.datasourcetextfield; import com.smartgwt.client.types.dsdataformat; import com.smartgwt.client.types.dsoperationtype; import com.smartgwt.client.types.dsprotocol; import com.smartgwt.client.util.jsohelper; import com.smartgwt.client.util.json; public class userdatasource extends restdatasource { private static userdatasource instance = null; public static userdatasource getinstance() { if (instance == null) { instance = new userdatasource("restuserds"); } return instance; } private userdatasource(string id) { setid(id); setclientonly(false); // set fetch use requests operationbinding fetch = new operationbinding(); fetch.setoperationtype(dsoperationtype.fetch); fetch.setdataprotocol(dsprotocol.getparams); dsrequest fetchprops = new dsrequest(); fetchprops.sethttpmethod("get"); fetch.setrequestproperties(fetchprops); // set add use post requests operationbinding add = new operationbinding(); add.setoperationtype(dsoperationtype.add); add.setdataprotocol(dsprotocol.postmessage); // =========================================== dsrequest addprops = new dsrequest(); addprops.sethttpmethod("post"); // addprops.setcontenttype("application/json"); add.setrequestproperties(addprops); // set update use put operationbinding update = new operationbinding(); update.setoperationtype(dsoperationtype.update); update.setdataprotocol(dsprotocol.postmessage); // =========================================== dsrequest updateprops = new dsrequest(); updateprops.sethttpmethod("put"); // updateprops.setcontenttype("application/json"); update.setrequestproperties(updateprops); // set remove use delete operationbinding remove = new operationbinding(); remove.setoperationtype(dsoperationtype.remove); dsrequest removeprops = new dsrequest(); removeprops.sethttpmethod("delete"); remove.setrequestproperties(removeprops); // apply operational bindings setoperationbindings(fetch, add, update, remove); init(); } private datasourceintegerfield useridfield; private datasourcebooleanfield useractivefield; private datasourcetextfield usernamefield; private datasourcetextfield passwordfield; private datasourcetextfield firstnamefield; private datasourcetextfield lastnamefield; private datasourcetextfield emailfield; private datasourcetextfield securityquestion1field; private datasourcetextfield securityanswer1field; private datasourcetextfield securityquestion2field; private datasourcetextfield securityanswer2field; private datasourcedatefield birthdatefield; private datasourceintegerfield positionidfield; protected void init() { setdataformat(dsdataformat.json); setjsonrecordxpath("/"); // set values datasource useridfield = new datasourceintegerfield(constants.user_id, constants.title_user_id); useridfield.setprimarykey(true); useridfield.setcanedit(false); useractivefield = new datasourcebooleanfield(constants.user_active, constants.title_user_active); usernamefield = new datasourcetextfield(constants.user_username, constants.title_user_username); passwordfield = new datasourcetextfield(constants.user_password, constants.title_user_password); firstnamefield = new datasourcetextfield(constants.user_first_name, constants.title_user_first_name); lastnamefield = new datasourcetextfield(constants.user_last_name, constants.title_user_last_name); emailfield = new datasourcetextfield(constants.user_email, constants.title_user_email); securityquestion1field = new datasourcetextfield(constants.user_security_question_1, constants.title_user_security_question_1); securityanswer1field = new datasourcetextfield(constants.user_security_answer_1, constants.title_user_security_answer_1); securityquestion2field = new datasourcetextfield(constants.user_security_question_2, constants.title_user_security_question_2); securityanswer2field = new datasourcetextfield(constants.user_security_answer_2, constants.title_user_security_answer_2); birthdatefield = new datasourcedatefield(constants.user_birthdate, constants.title_user_birthdate); positionidfield = new datasourceintegerfield(constants.user_position_id, constants.title_user_position_id); // positionactivefield = new datasourcebooleanfield(constants.user_active, constants.title_user_active); // positioncodefield; // positiondescriptionfield; setfields(useridfield, useractivefield, usernamefield, passwordfield, firstnamefield, lastnamefield, emailfield, birthdatefield, securityquestion1field, securityanswer1field, securityquestion2field, securityanswer2field, positionidfield); setfetchdataurl(getserviceroot() + "/userid/{id}"); // works great setadddataurl(getserviceroot() + "/create"); setupdatedataurl(getserviceroot() + "/update"); setremovedataurl(getserviceroot() + "/remove"); // works great } protected string getserviceroot() { return "rest/users"; } protected string getprimarykeyproperty() { return "userid"; } @override protected object transformrequest(dsrequest dsrequest) { system.out.println("userdatasource: transformrequest: start"); dsrequest.setcontenttype("application/json"); javascriptobject jso = dsrequest.getdata(); string jsotext = json.encode(jso); system.out.println("userdatasource: transformrequest: start: jsotext=" + jsotext); // ================================================================================ // string strdob = jsohelper.getattribute(jso, constants.user_birthdate); // date datedob = jsohelper.getattributeasdate(jso, constants.user_birthdate); // jsohelper.setattribute(jso, constants.user_birthdate, datedob.gettime()); // system.out.println("userdatasource: transformrequest: start2: jsotext2=" + jsotext); // ================================================================================ // user position id comes ui // name of field ui 'userpositionid' string userpositionid = jsohelper.getattribute(jso, constants.user_position_id); // create small javascriptobject used position // json string {"id":x} x = userpositionid map mappositionid = new hashmap(); mappositionid.put("id", userpositionid); javascriptobject jsopositionid = jsohelper.convertmaptojavascriptobject(mappositionid); // creates new json attribute: // ... , "position":{"id":x} jsohelper.setattribute(jso, "position", jsopositionid); // remove json attribute: ... , "userpositionid":x jsohelper.deleteattribute(jso, constants.user_position_id); string s1 = json.encode(jso); system.out.println("userdatasource: transformrequest: finish: s1=" + s1); return s1; // return super.transformrequest(dsrequest); } protected void transformresponse(dsresponse response, dsrequest request, object data) { system.out.println("userdatasource: transformresponse: start"); super.transformresponse(response, request, data); system.out.println("userdatasource: transformresponse: finish"); } }
i can confirm sending data/json fine. have make slight change add attribute sending back. , believe purpose of transformrequest. spring mvc controller receiving update looks like:
@requestmapping(value="/update", method=requestmethod.put,produces="application/json", headers="content-type=application/json") public @responsebody userdto updateuser(@requestbody userdto user) { system.out.println("usercontroller: start: updateuser: user=" + user); userentity userentity = service.update(user); userdto userdto = mapping.mappinguser(userentity); system.out.println("usercontroller: finish: updateuser: userdto=" + userdto); return userdto; }
and can confirm getting valid userdto. when @ transformresponse:
system.out.println("userdatasource: transformresponse: start"); super.transformresponse(response, request, data); system.out.println("userdatasource: transformresponse: finish");
i error on first println, haven't done super.transformresponse yet. when @ data coming back, json getting back.
{ "userid":1, "useractive":true, "position":{ "id":1, "active":true, "code":"admin", "description":"administrator" }, "username":"demo", "password":"demo", "otherpassword":null, "userfirstname":"demoxxx", "userlastname":"demoxxx", "useremail":"tom@tomholmes.netxxx", "usersecurityquestion1":"meaning of life?xxx", "usersecurityanswer1":"42xx", "usersecurityquestion2":"aaaxx", "usersecurityanswer2":"bbbxx", "userbirthdate":-99100800000, "contacts":[ { "contactid":2, "userid":1, "prefix":"mr.", "firstname":"updated_fn", "middlename":null, "lastname":"updated_ln", "suffix":"jr.", "address1":"123 main street", "address2":"apt. 456", "city":"randolph", "state":"ma", "zip":"12345-1234", "companyid":0, "enteredby":0, "entereddate":null, "editedby":0, "editeddate":null, "birthdate":null, "emails":null, "phones":null, "links":null } ], "userpositionid":null }
so ... how fix datasource or transformresponse remove warning? json appears correct, , issue "userbirthdate" when comes long negative number, presume milliseconds epoch. there change can make in json/jackson mapper change how dates formatted?
thanks help!
update 1: provided below helpful, , know not smartgwt or restdatasource issue , strictly how jackson converts java.util.date within object. conversion changes dates negative long number , should have format. using spring 3.2 , using old jackson 1.9.14. now, upgraded jackson 2, , pom.xml uses:
<dependency> <groupid>com.fasterxml.jackson.core</groupid> <artifactid>jackson-core</artifactid> <version>2.1.4</version> </dependency> <dependency> <groupid>com.fasterxml.jackson.core</groupid> <artifactid>jackson-databind</artifactid> <version>2.1.4</version> </dependency> <dependency> <groupid>com.fasterxml.jackson.core</groupid> <artifactid>jackson-annotations</artifactid> <version>2.1.4</version> </dependency>
within spring-servlext.xml:
<context:component-scan base-package="com.opensource.restful" /> <bean id="jsonhttpmessageconverter" class="org.springframework.http.converter.json.mappingjackson2httpmessageconverter"> <property name="supportedmediatypes" value="application/json"/> <property name="objectmapper"> <bean class="com.fasterxml.jackson.databind.objectmapper"> <property name="dateformat"> <bean class="java.text.simpledateformat"> <constructor-arg type="java.lang.string" value="yyyy-mm-dd't'hh:mm:ssz"></constructor-arg> </bean> </property> </bean> </property> </bean> <bean class="org.springframework.web.servlet.mvc.annotation.annotationmethodhandleradapter"> <property name="messageconverters"> <list> <ref bean="jsonhttpmessageconverter"/> </list> </property> </bean> <mvc:annotation-driven />
i have been googling few hours , looking solution uses jackson2 mapper within spring configuration, , after make sure bean definitions correct, userbirthdate still coming negative long. sure configuration can tweaked bit way want, date comes iso format: yyyy-mm-dd't'hh:mm:ssz
thanks helping me closer.
update 2: think did it. stated, upgraded jackson2 understand part of spring 3.2, version of spring using.
the spring-servlet.xml using, , work looks like:
<context:component-scan base-package="com.opensource.restful" /> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.json.mappingjackson2httpmessageconverter"> <property name="objectmapper"> <bean class="com.fasterxml.jackson.databind.objectmapper"> <property name="dateformat"> <bean class="java.text.simpledateformat"> <constructor-arg type="java.lang.string" value="yyyy-mm-dd't'hh:mm:ssz"></constructor-arg> </bean> </property> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean id="jsonhttpmessageconverter" class="org.springframework.http.converter.json.mappingjackson2httpmessageconverter"> <property name="supportedmediatypes" value="application/json"/> </bean> <bean class="org.springframework.web.servlet.mvc.annotation.annotationmethodhandleradapter"> <property name="messageconverters"> <list> <ref bean="jsonhttpmessageconverter" /> </list> </property> </bean> <bean id="resttemplate" class="org.springframework.web.client.resttemplate"> <property name="messageconverters"> <list> <ref bean="jsonhttpmessageconverter" /> </list> </property> </bean>
i had add mappingjackson2httpmessageconverter second time because, it's referenced in resttemplate ... if define once, fine. so, maybe can me define spring-servlet.xml better.
anyway, change works , result json date comes as:
"userbirthdate":"1966-11-03t00:00:00-0500"
so, that's progress far.
from validation error - defaulterrormessage:"must date"
since birthdatefield datasourcedatefield, userdto.userbirthdate
must java.util.date
or similar , have date getuserbirthdate()
.
, constants.user_birthdate
must set "userbirthdate"
.
if above alright, due default serialization of java.util.date object json.
check following additional information on that.
http://java.dzone.com/articles/how-serialize-javautildate (do not use static simpledateformat)
spring 3.1 json date format
jackson2 json iso 8601 date jodatime in spring 3.2rc1
smartgwt works best when following date format used (e.g.- 2013-05-09t00:00:00).
yyyy-mm-dd't'hh:mm:ss
system.out.println()
can not used in smartgwt/gwt client side code converted javascript , run inside browser, without jvm.
you won't need use transformresponse()
in case.
Comments
Post a Comment