Spring Boot – Jackson EntityNotFoundException返回200而不是500的响应

huangapple go评论60阅读模式
英文:

Spring Boot - Jackson EntityNotFoundException returns 200 instead of 500 response

问题

以下是你提供的内容的翻译部分:

当遇到这个异常时,异常处理程序返回了200响应,尽管我已经在处理程序中指定在遇到此异常时返回500(HttpStatus.INTERNAL_SERVER_ERROR)。

我正在使用Spring Boot v1.5.4.RELEASE。

我正在调用返回JSON对象的Spring Boot服务,并且正在使用自定义的异常处理程序。

当在反序列化过程中发生EntityNotFoundException时,它不会返回500响应,而是返回200响应,并将错误嵌入到输出主体中。这是由于数据错误引起的,数据库中找不到ManyToOne关系,因为外键无效。

请注意,我正在使用本机查询来检索实体。

@Entity
@Table(name = "PARENT_ENTITY")
public class ParentEntity {

    @JsonView({MyViews.ParentEntity.class})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="CHILD_KEY")
    protected ChildEntity childKey;	
   
}

如何使服务返回500响应而不是200?

代码示例:

@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler{

  @ExceptionHandler(EntityNotFoundException.class)
  @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "INTERNAL_SERVER_ERROR")	   
  protected ResponseEntity<Object> handleEntityNotFoundException(EntityNotFoundException ex) {
       
    ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR);
    apiError.setMessage(ex.getMessage());	   
    apiError.setStackTrace(StringUtil.jsonEscapeNewlines(ExceptionUtils.getStackTrace(ex)));  
    return new ResponseEntity<>(apiError, apiError.getStatus());	       
  }
}

服务的示例输出:

响应代码:200

主体:

[
	{
		"field1": "data1",
		"childEntity": {
			"childKey":"100100"
		}		
	},
	{
		"field1":"data2",
		"childEntity": {
			"childKey": {
				"status": "INTERNAL_SERVER_ERROR",    				
				"message": "Could not write JSON: Unable to find com.test.entity.ChildEntity with id 123456; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unable to find com.test.entity.ChildEntity with id 123456;...",
				"stackTrace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unable to find com.test.entity.ChildEntity with id 123456...",
				"headers": null
			}
		}
	}
]

注意:此处仅提供了翻译部分,以满足你的需求。

英文:

Exception handler is returning 200 response even though I have specified it to return 500 in the handler (HttpStatus.INTERNAL_SERVER_ERROR) when encountering this exception.

I am using Spring Boot v1.5.4.RELEASE.

I am calling a Spring Boot service returning a JSON object. I am using a custom exception handler.

When an EntityNotFoundException occurs during deserialization, instead of returning 500 response, it returns 200 response and embeds the error in the body output. This is caused by a data error where a ManyToOne relationship not being found in Database because the foreign key is invalid.

Note that I am using a native query to pull the entities.

@Entity
@Table(name = &quot;PARENT_ENTITY&quot;)
public class ParentEntity {

    @JsonView({MyViews.ParentEntity.class})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name=&quot;CHILD_KEY&quot;)
    protected ChildEntity childKey;	
   
}

How can I make it so the service returns a 500 response instead of 200?

Code Example:

@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler{

  @ExceptionHandler(EntityNotFoundException.class)
  @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = &quot;INTERNAL_SERVER_ERROR&quot;)	   
  protected ResponseEntity&lt;Object&gt; handleEntityNotFoundException(EntityNotFoundException ex) {
	   
    ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR);
    apiError.setMessage(ex.getMessage());	   
    apiError.setStackTrace(StringUtil.jsonEscapeNewlines(ExceptionUtils.getStackTrace(ex)));  
    return new ResponseEntity&lt;&gt;(apiError, apiError.getStatus())	       
  }
}

Sample Output of Service:

Response Code: 200

Body:

[
{
&quot;field1&quot;: &quot;data1&quot;,
&quot;childEntity&quot;: {
&quot;childKey&quot;:&quot;100100&quot;
}		
},
{
&quot;field1&quot;:&quot;data2&quot;
&quot;childEntity&quot;: {
&quot;childKey&quot;: {
&quot;status&quot;: &quot;INTERNAL_SERVER_ERROR&quot;,    				
&quot;message&quot;: &quot;Could not write JSON: Unable to find com.test.entity.ChildEntity with id 123456; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unable to find com.test.entity.ChildEntity with id 123456;        (through reference chain: java.util.ArrayList[40]-&gt;com.test.entity.ParentEntity[\&quot;childKey\&quot;])&quot;,    				
&quot;stackTrace&quot;: &quot;org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unable to find com.test.entity.ChildEntity with id 123456       ; nested exception is com.fasterxml.jackson.databind.JsonMappingException: ... org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:299)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:106)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:231)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:174)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:113)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:751)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:844)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:346)
at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:115)
at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:59)
at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:90)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:108)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:137)
at java.security.AccessController.doPrivileged(Native Method)
at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:460)
at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:120)
at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:217)
at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:81)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:220)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3456)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3422)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:323)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2280)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2196)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2174)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1632)
at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:256)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unable to find com.test.entity.ChildEntity with id 123456;
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348)
at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:343)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:698)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:112)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:416)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1425)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:951)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:292)
... 58 more\
Caused by: javax.persistence.EntityNotFoundException: Unable to find com.test.entity.ChildEntity with id 123456;
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:144)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:242)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:159)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
at com.test.entity.ParentEntity_$$_jvst2de_11.getChildKey(ParentEntity_$$_jvst2de_11.java)
at com.test.entity.ParentEntity.getChildKey(ParentEntity.java:887)
at sun.reflect.GeneratedMethodAccessor5472.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:664)
at com.fasterxml.jackson.databind.ser.impl.FilteredBeanPropertyWriter$SingleView.serializeAsField(FilteredBeanPropertyWriter.java:69)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
... 66 more\
&quot;,
&quot;headers&quot;: null
}

#note: I did not cut this off just for this example. This is cut off in the actual json response resulting in badly formatted json.

答案1

得分: 0

我想知道您的请求是否由相同的异常处理程序处理。

您已将用户消息设置为“数据问题”,但是您的输出响应却显示为 null。

apiError.setUserMessage("数据问题:" + ex.getMessage());

// 根据您的代码,它至少应为“数据问题:”
"userMessage": null,

请确保验证您发布的代码是否作为此请求的一部分被调用。当然,您可以添加日志消息来确认是否相同。如果您能够在本地复制此问题,那么您可以设置断点并确认是否调用了相同的异常处理程序。

英文:

I wonder if your request is being handled by the same exception handler.

You have set the user message to the "Data issue" but whereas your output response is showing it as null.

apiError.setUserMessage(&quot;Data issue:&quot; + ex.getMessage());
//based on your code it should have at least &quot;Data issue:&quot;
&quot;userMessage&quot;: null,

Please make sure to validate the code you have posted is being invoked as part of this request. Certainly, you can add a log message to confirm the same. If you are able to replicate the issue on local then you can keep a breakpoint and confirm if the same exception handler is invoked.

答案2

得分: 0

你可以通过在查询中使用内连接来避免实体未找到的错误。以下示例使用本机查询格式。这更像是一种变通的解决方案,但对于我当时的情况足够解决我的问题。我暂时将其标记为答案。

select pe.* from PARENT_ENTITY pe 
inner join CHILD_ENTITY ce on pe.CHILD_KEY = ce.rowid_org_cust
英文:

You can avoid the entity not found error by inner joining in the query. Below example uses native query format. This is more of a workaround solution, but it was sufficient to resolve my issue for my situation. I am marking as answer for now.

select pe.* from PARENT_ENTITY pe 
inner join CHILD_ENTITY ce on pe.CHILD_KEY = ce.rowid_org_cust

huangapple
  • 本文由 发表于 2020年10月22日 06:43:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/64472722.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定