英文:
Spring Boot Exception Handling -> Not Return Generic Exception
问题
I understand that you're facing an issue with returning the ErrorDTO
from a Generic Exception. To fix this, you can update the handleGenericException
method in your GlobalExceptionHandler
as follows:
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorDTO> handleGenericException(HttpServletRequest request, Exception ex) {
List<String> details = new ArrayList<>();
details.add(ex.getMessage());
ErrorDTO error = ErrorDTO.builder()
.timestamp(LocalDateTime.now())
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.errorDetails(details)
.path(request.getServletPath())
.httpStatus(HttpStatus.INTERNAL_SERVER_ERROR)
.build();
LOGGER.error("GlobalExceptionHandler | handleGenericException", error);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
This modification ensures that the handleGenericException
method returns a ResponseEntity<ErrorDTO>
containing the error information. This way, it will return an ErrorDTO
in response to the Generic Exception, as desired.
Please apply this change and test your application again. If you encounter any further issues, feel free to let me know.
英文:
I have a problem to return the ErrorDTO from Generic Exception.
When I send a request to http://localhost:8080/v1/locations with this response body shown below, I get this issue underneath GlobalExceptionHandler.
{
    "code" : "DELHI_IN_QWERTYUI", -> IT thows an error because of its length (length is 12)
    "city_name" : "New Delhi",
    "region_name" : "Delhi",
    "country_name" : "India",
    "country_code" : "IN",
    "enabled" : true
}
Here is the method defined in controller shown below?
@PostMapping
public ResponseEntity<Location> addLocation(@RequestBody @Valid Location location) {
Location addedLocation = service.add(location);
URI uri = URI.create("/v1/locations/" + addedLocation.getCode());
return ResponseEntity.created(uri).body(addedLocation);
}
How can I fix the issue?
Here is the ErrorDTO below.
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ErrorDTO {
private LocalDateTime timestamp;
private int status;
private String path;
private HttpStatus httpStatus;
List<String> errorDetails;
}
Here is the GlobalExceptionError shown below
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
// handleMissingServletRequestParameter : triggers when there are missing parameters
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
List<String> details = new ArrayList<String>();
StringBuilder builder = new StringBuilder();
builder.append(ex.getMessage() + " is not supported");
details.add(builder.toString());
HttpStatus httpStatus = HttpStatus.valueOf(status.value());
ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
.timestamp(LocalDateTime.now())
.status(status.value())
.errorDetails(details)
.path(request.getContextPath())
.httpStatus(httpStatus)
.build();
LOGGER.error("GlobalExceptionHandler | handleHttpRequestMethodNotSupported", error);
return ResponseEntity.status(status).body(error);
}
// handleMethodArgumentNotValid : triggers when @Valid fails
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(err -> errors.put(err.getField(), err.getDefaultMessage()));
LOGGER.error("GlobalExceptionHandler | handleMethodArgumentNotValid", errors);
return ResponseEntity.badRequest()
.body(errors);
}
// handleMissingServletRequestParameter : triggers when there are missing parameters
@Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
List<String> details = new ArrayList<String>();
StringBuilder builder = new StringBuilder();
builder.append(ex.getParameterName());
details.add(builder.toString());
HttpStatus httpStatus = HttpStatus.valueOf(status.value());
ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
.timestamp(LocalDateTime.now())
.status(status.value())
.errorDetails(details)
.path(request.getContextPath())
.httpStatus(httpStatus)
.build();
LOGGER.error("GlobalExceptionHandler | handleMissingServletRequestParameter", error);
return ResponseEntity.status(status).body(error);
}
// handleHttpMessageNotReadable : triggers when the JSON is malformed
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
List<String> details = new ArrayList<String>();
StringBuilder builder = new StringBuilder();
builder.append(ex.getMessage());
details.add(builder.toString());
HttpStatus httpStatus = HttpStatus.valueOf(status.value());
ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
.timestamp(LocalDateTime.now())
.status(status.value())
.errorDetails(details)
.path(request.getContextPath())
.httpStatus(httpStatus)
.build();
LOGGER.error("GlobalExceptionHandler | handleHttpMessageNotReadable", error);
return ResponseEntity.status(status).body(error);
}
@ExceptionHandler(Exception.class)
public ErrorDTO handleGenericException(HttpServletRequest request, Exception ex) {
List<String> details = new ArrayList<String>();
details.add(ex.getMessage());
ErrorDTO error = new ErrorDTO.ErrorDTOBuilder()
.timestamp(LocalDateTime.now())
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.errorDetails(details)
.path(request.getServletPath())
.httpStatus(HttpStatus.INTERNAL_SERVER_ERROR)
.build();
LOGGER.error("GlobalExceptionHandler | handleGenericException", error);
return error;
}
}
Here is the error shown below.
{
    "timestamp": "2023-02-17T12:56:02.341+00:00",
    "status": 404,
    "error": "Not Found",
    "trace": "org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:273)\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566)\r\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)\r\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)\r\n\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\r\n\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752)\r\n\tat org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)\r\n\tat com.skyapi.weatherforecast.location.LocationService$$SpringCGLIB$$0.add(<generated>)\r\n\tat com.skyapi.weatherforecast.location.LocationApiController.addLocation(LocationApiController.java:21)\r\n\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:578)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:1589)\r\nCaused by: org.hibernate.exception.DataException: could not execute statement\r\n\tat org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:53)\r\n\tat org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:56)\r\n\tat org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)\r\n\tat org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)\r\n\tat org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)\r\n\tat org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3429)\r\n\tat org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:4058)\r\n\tat org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:103)\r\n\tat org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:612)\r\n\tat org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:483)\r\n\tat java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:729)\r\n\tat org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:480)\r\n\tat org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:329)\r\n\tat org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)\r\n\tat org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)\r\n\tat org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1425)\r\n\tat org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:477)\r\n\tat org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2234)\r\n\tat org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1930)\r\n\tat org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)\r\n\tat org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)\r\n\t... 58 more\r\nCaused by: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column 'code' at row 1\r\n\tat com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:104)\r\n\tat com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:916)\r\n\tat com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1061)\r\n\tat com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1009)\r\n\tat com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1320)\r\n\tat com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:994)\r\n\tat com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)\r\n\tat com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)\r\n\tat org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)\r\n\t... 77 more\r\n",
    "message": "could not execute statement; SQL [n/a]",
    "path": "/v1/locations"
}
Here is the console output shown
org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation
It return this kind of exception message rather than ErrorDTO.
Here is the repo : Link
How can I fix the issue?
答案1
得分: 0
在ErrorDTO上添加@Data
注解后,问题消失了。
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ErrorDTO {
private LocalDateTime timestamp;
private int status;
private String path;
private HttpStatus httpStatus;
List<String> errorDetails;
}
英文:
After adding @Data
annotation to ErrorDTO, the issue disappeared.
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ErrorDTO {
private LocalDateTime timestamp;
private int status;
private String path;
private HttpStatus httpStatus;
List<String> errorDetails;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论