标签存档: gson

慎用gson

今天是辛苦1个半月代金券上线的日子。但很不幸。因为线上环境和预发布环境存在不一致问题。导致本次发布失败!

抓取到错误的日志。如下:

[01 17:03:48,567 DEBUG] ["http-bio-80"-exec-3] conn.SingleClientConnManager - Releasing connection org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@287b2e39
[01 17:03:48,568 ERROR] ["http-bio-80"-exec-3] impl.LotteryProcessServiceImpl - 处理异常[order=LotteryUseOrder [lotteryTypeCode=USE, accountId=5556067, cardNo=A00088754, passwd=null, skuId=null, origPayAmount=127.00, favorableAmount=20.00, orderId=1000000090, sceneType=MAYMAY]]:
com.google.gson.JsonSyntaxException: 2011-07-05 17:41:12
        at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserializeToDate(DefaultTypeAdapters.java:376)
        at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserialize(DefaultTypeAdapters.java:351)
        at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserialize(DefaultTypeAdapters.java:307)
        at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:51)
        at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:92)
        at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler(JsonObjectDeserializationVisitor.java:117)
        at com.google.gson.ReflectingFieldNavigator.visitFieldsReflectively(ReflectingFieldNavigator.java:63)
        at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:120)
        at com.google.gson.JsonDeserializationContextDefault.fromJsonObject(JsonDeserializationContextDefault.java:76)
        at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:54)
        at com.google.gson.Gson.fromJson(Gson.java:551)
        at com.google.gson.Gson.fromJson(Gson.java:498)
        at com.google.gson.Gson.fromJson(Gson.java:467)
        at com.google.gson.Gson.fromJson(Gson.java:417)
        at com.google.gson.Gson.fromJson(Gson.java:389)
        at com.mbb.payengine.lottery.integration.AcctransMaymayQueryServiceClientImpl.genAccountMaymayInfo(AcctransMaymayQueryServiceClientImpl.java:146)
        at com.mbb.payengine.lottery.integration.AcctransMaymayQueryServiceClientImpl.getAccountByAccountId(AcctransMaymayQueryServiceClientImpl.java:72)
        at com.mbb.payengine.lottery.domainservice.process.impl.use.UseTransProcessor.process(UseTransProcessor.java:69)
        at com.mbb.payengine.lottery.domainservice.template.LotteryTemplate.process(LotteryTemplate.java:46)
        at com.mbb.payengine.lottery.domainservice.factory.impl.LotteryDomainFactoryImpl.processUseTemplate(LotteryDomainFactoryImpl.java:171)
        at com.mbb.payengine.lottery.domainservice.factory.impl.LotteryDomainFactoryImpl.compose(LotteryDomainFactoryImpl.java:104)
        at com.mbb.payengine.lottery.service.api.impl.LotteryProcessServiceImpl$1.doInTransaction(LotteryProcessServiceImpl.java:101)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
        at com.mbb.payengine.lottery.service.api.impl.LotteryProcessServiceImpl.process(LotteryProcessServiceImpl.java:85)
        at com.mbb.payengine.lottery.web.api.LotteryProcessServiceController.process(LotteryProcessServiceController.java:114)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
Caused by: java.text.ParseException: Unparseable date: "2011-07-05 17:41:12"
        at java.text.DateFormat.parse(DateFormat.java:337)
        at com.google.gson.DefaultTypeAdapters$DefaultDateTypeAdapter.deserializeToDate(DefaultTypeAdapters.java:374)
        ... 57 more
[01 17:03:48,571 INFO ] ["http-bio-80"-exec-3] impl.LotteryProcessServiceImpl - 代金券使用失败[order=LotteryUseOrder [lotteryTypeCode=USE, accountId=5556067, cardNo=A00088754, passwd=null, skuId=null, origPayAmount=127.00, favorableAmount=20.00, orderId=1000000090, sceneType=MAYMAY],result=LotteryProcessResult [orgiAmount=0.00, cardNo=null, useFrequence=0, alreadyUseFrequence=0, validityBegin=null, validityEnd=null, lotteryDiscount=null, lotteryScope=null, lotteryUseCondition=null, lotteryFee=null, lotteryCarriage=null, activeId=null]]

问题在gson解析json时间时,出错。但日志显示。出差的地方是2011-07-05 17:41:12。

经过部门同事帮忙,找到原因:线上环境采用en_US.UTF-8编码。线下环境一直用的是zh_CN.UTF-8编码。

Gson默认会使用系统环境的时间解析器来解析时间.显然en_US.UTF-8和zh_CN.UTF-8的默认时间不一致。修改代码如下,可以修复问题

Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();

 

建议使用fastjson替代gson. 相关的问题会少很多~