我面临一个非常奇怪的问题。我在我的应用程序中使用Jackson databind版本2.7.4进行序列化。应用程序运行很好很多天,但有时会开始抛出数据序列化错误(解释类似于JsonMappingException: (was java.lang.ArrayIndexOutOfBoundsException) )
这是随机发生的,并在使用自定义序列化程序序列化日期字段时开始抛出ArrayOutOfBoundException。
异常跟踪
R] 2017-02-11 23:39:16 ERROR GlobalExceptionHandlerController:171 - Trace for 500:org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: (was java.lang.ArrayIndexOutOfBoundsException) (through reference chain: com.mycompany.model.DTO.ApiResponse["data"]->com.mycompany.model.Entity["date"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.ArrayIndexOutOfBoundsException) (through reference chain: com.mycompany.model.DTO.ApiResponse["data"]->com.mycompany.model.Entity["date"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:276)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:153)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:165)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:832)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.ArrayIndexOutOfBoundsException) (through reference chain: com.mycompany.model.DTO.ApiResponse["data"]->com.mycompany.model.Entity["date"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:378)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:338)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:342)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:686)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1428)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:930)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:269)
... 36 more
Caused by: java.lang.ArrayIndexOutOfBoundsException
似乎共享变量正在变为负值并导致此问题,但我无法识别代码。
实体类
public class Entity {
@JsonSerialize(using=CustomDateSerializer.class)
@JsonDeserialize(using=CustomDateDeserializer.class)
private Date date;
public Entity(){}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
解串
public class CustomDateDeserializer extends JsonDeserializer<Date>{
private SimpleDateFormat formatter =
new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Date date=null;
String str=p.getText();
try{
date=formatter.parse(str);
}catch(ParseException e){
throw new RuntimeException(e);
}
return date;
}
}
串行
public class CustomDateSerializer extends JsonSerializer<Date>{
private SimpleDateFormat formatter =
new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
@Override
public void serialize (Date value, JsonGenerator gen, SerializerProvider arg)
throws IOException, JsonProcessingException {
gen.writeString(formatter.format(value));
}
}
任何帮助将不胜感激。
答案 0 :(得分:5)
SimpleDateFormat
不是线程安全的,如javadoc中所述:
日期格式未同步。建议创建 每个线程的单独格式实例。如果有多个线程访问 同时格式化,必须在外部同步。
This blog post演示了该问题,并列出了可能遇到的错误选择,如果未遵循上述建议,则列出ArrayIndexOutOfBoundsException
。
我建议在日期格式化程序实例上进行同步。最简单的方法看起来像这样:
public void serialize (Date value, JsonGenerator gen, SerializerProvider arg)
throws IOException, JsonProcessingException {
synchronized(formatter) {
gen.writeString(formatter.format(value));
}
}
编辑:如果您使用的是Java 8,请考虑使用线程安全的DateTimeFormatter
类。
答案 1 :(得分:0)
我的java8解决方案:
timestampFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SS'Z'");
//java.sql.Timestamp x
String s = timestampFormatter.format(x.toInstant());