Spring Boot – Jackson EntityNotFoundException returns 200 instead of 500 response



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 = "PARENT_ENTITY")
public class ParentEntity {

    @JsonView({MyViews.ParentEntity.class})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="CHILD_KEY")
    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 = "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())        
  }
}

Sample Output of Service:

Response Code: 200

Body:

[
    {
        "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;        (through reference chain: java.util.ArrayList[40]->com.test.entity.ParentEntity["childKey"])",                    
                "stackTrace": "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
            ",
                "headers": 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.

Answer

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


Source: stackoverflow