paulcwarren/spring-content

Regression: NPE in StoreResourceResolver

tgeens opened this issue · 3 comments

Describe the bug

Since Spring Content 2.0.0, trying to access an entity over the REST API fails with a NullPointerException in StoreResourceResolver when:

  • there is no associated content
  • the Accept header contains */* (for example: when requesting a resource with a browser)

To Reproduce

Steps to reproduce the behavior:

  1. Use any example model - I'm using Document as an example
  2. Create the entity (printing only response header here for brevity)
$ http --print h :8080/documents name=Foo
HTTP/1.1 201 
Content-Type: application/json
Location: http://localhost:8080/documents/1b70ee9c-d716-4963-857e-20b335597f92
[snipped]
  1. Request the created entity from the Location header
$ http http://localhost:8080/documents/1b70ee9c-d716-4963-857e-20b335597f92
HTTP/1.1 500 
Connection: close
Content-Type: application/json
Date: Wed, 27 Apr 2022 15:56:33 GMT
Transfer-Encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

{
    "error": "Internal Server Error",
    "path": "/documents/1b70ee9c-d716-4963-857e-20b335597f92",
    "status": 500,
    "timestamp": "2022-04-27T15:56:33.153+00:00"
}

Notes:

  • Using Acccept: application/json request header returns the expected result for spring-content 2.0.0-2.2.0
  • In spring-content 1.2.7 this works fine with Accept: */*

Stacktrace

java.lang.NullPointerException: null
        at internal.org.springframework.content.rest.controllers.resolvers.StoreResourceResolver.resolve(StoreResourceResolver.java:21) ~[spring-content-rest-2.0.0.jar:na]
        at internal.org.springframework.content.rest.controllers.ResourceHandlerMethodArgumentResolver.resolveArgument(ResourceHandlerMethodArgumentResolver.java:129) ~[spring-content-rest-2.0.0.jar:na]
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122) ~[spring-web-5.3.18.jar:5.3.18]
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179) ~[spring-web-5.3.18.jar:5.3.18]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146) ~[spring-web-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.18.jar:5.3.18]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:645) ~[javax.servlet-api-4.0.1.jar:4.0.1]

A clear and concise description of what the bug is.

Looks like I was missing a test case for this.

I have restored the behavior that I am seeing in 1.2.7 when requesting http://localhost:8080/documents/1b70ee9c-d716-4963-857e-20b335597f92 and that is to return a 404 - meaning content no found - because the store controller has higher precedence than the repository controller and therefore tries to satisfy this request.

But I wanted to check with you that that was the behavior you actually expected. You mention using Accept: application/json which makes me think that you might expect a response from the repository controller instead?

  1. Thanks for fixing the NPE / HTTP 500
  2. No, this is not the way I would want it to work (but that's just my opinion)

If I had the choice, I wouldn't want to expose the Spring Content REST Entity Resources endpoint /{store}/{id}:

  • The content is available via the Spring Content REST Property Resource endpoint /{store}/{id}/{property} anyway
  • REST API consumers (including me) get confused, because you create a resource, get an HTTP 201 with a Location header, but when you request the resource again you get an HTTP 404 - this is surprising and is at least a usability problem
  • The Entity-Resource endpoint does not support application/json - the Property Resource endpoint should be able to ?
  • I'm not even sure what the expected behaviour is for the Entity Resource, when you have multiple @ContentId properties ?

@tgeens here are the updated docs