在spring web应用程序(而不是spring引导)中的JsonSerializer上引发异常时的错误处理



我在spring-web应用程序中定义了一个自定义JsonSerializer(非spring Boot(。

public class CalendarSerializer extends StdSerializer<Calendar>
{
public CalendarSerializer()
{
super(Calendar.class);
}
/** {@inheritDoc} */
@Override
public void serialize(Calendar value, JsonGenerator gen, SerializerProvider serializers) throws IOException
{
ZoneId zoneId = TimeZone.getDefault().toZoneId();
return value.toInstant().atZone(zoneId);
}
}

它已经包含在json映射器定义中,如果serialize()方法中没有抛出异常,那么一切都很好。

为了处理错误,我创建了一个ResponseEntityExceptionHandler

@ControllerAdvice
public class RestApiExceptionHandler extends ResponseEntityExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(RestApiExceptionHandler.class);
@ExceptionHandler(RestApiException.class)
protected ResponseEntity<RestApiErrorResponse> handleRestApiException(RestApiException ex)
{
RestApiErrorResponse apiErrorResponse = ex.getRestApiErrorResponse();
log.error("RestApiException occurs.", ex);
return new ResponseEntity<>(apiErrorResponse, apiErrorResponse.getHttpStatus());
}
[...]
@ExceptionHandler(Exception.class)
protected ResponseEntity<RestApiErrorResponse> handleUnexpectedError(Exception ex)
{
RestApiErrorResponse unexpectedError = RestApiErrorResponse.getUnexpectedError();
log.error("Unexpected exception. {}", unexpectedError, ex);
return new ResponseEntity<>(unexpectedError, unexpectedError.getHttpStatus());
}
}

它处理一些自定义异常,但无论如何,任何类型的异常都由handleUnexpectedError管理,并且调用者正确地接收RestApiErrorResponse的序列化。

但是,如果CalendarSerializer中发生异常,则绕过ResponseEntityExceptionHandler,调用方将接收到带有堆栈跟踪的默认tomcat错误页面

有没有一种方法可以管理JsonSerializers抛出的异常,以便调用方接收一个包含错误详细信息的自定义json?

这是堆叠式

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.foo.dataobjects.Holiday["startDate"])
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:296)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.foo.rest.web.RestApiAuthenticationFilter.doFilter(RestApiAuthenticationFilter.java:122)
Root Cause
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.foo.dataobjects.Holiday["startDate"])
com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:727)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400)
com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1392)
com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:287)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.foo.rest.web.RestApiAuthenticationFilter.doFilter(RestApiAuthenticationFilter.java:122)
Root Cause
java.lang.NullPointerException
com.foo.rest.serializers.CalendarSerializer.serialize(CalendarSerializer.java:44)
com.foo.rest.serializers.CalendarSerializer.serialize(CalendarSerializer.java:1)
com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer.serialize(StdDelegatingSerializer.java:168)
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400)
com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1392)
com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:287)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
com.foo.rest.web.RestApiAuthenticationFilter.doFilter(RestApiAuthenticationFilter.java:122)

更新:已解决将方法添加到RestApiExceptionHandler

@Override
protected ResponseEntity<Object> handleHttpMessageNotWritable(
HttpMessageNotWritableException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request)
{
String details = "Error exporting the results of the incoming request.";
RestApiErrorResponse error = new RestApiErrorResponse(details, RestApiErrorCode.SERIALIZATION_ERROR);
String uri = getUri(request);
log.error("Error serializing the results for request {}. {}", uri, error, ex);
return new ResponseEntity<>(error, error.getHttpStatus());
}

我自己解决了在RestApiExceptionHandler中添加方法

@Override
protected ResponseEntity<Object> handleHttpMessageNotWritable(
HttpMessageNotWritableException ex,
HttpHeaders headers,
HttpStatus status,
WebRequest request)
{
String details = "Error exporting the results of the incoming request.";
RestApiErrorResponse error = new RestApiErrorResponse(details, RestApiErrorCode.SERIALIZATION_ERROR);
String uri = getUri(request);
log.error("Error serializing the results for request {}. {}", uri, error, ex);
return new ResponseEntity<>(error, error.getHttpStatus());
}

最新更新