Spring Data Rest 2.0.0.RELEASE 打破了以前使用 RC1 的代码

Posted

技术标签:

【中文标题】Spring Data Rest 2.0.0.RELEASE 打破了以前使用 RC1 的代码【英文标题】:Spring Data Rest 2.0.0.RELEASE Breaks Code Working Previously With RC1 【发布时间】:2014-04-01 14:26:42 【问题描述】:

我有一个使用 Spring Data Rest 的项目。我最初在我的 pom.xml 中有版本 2.0.0.BUILD-SNAPSHOT,但在我上次更新期间,代码中断并在访问 大多数 端点时开始抛出以下 IllegalStateException

java.lang.IllegalStateException: No suitable resolver for argument [0]
[type=org.springframework.http.converter.HttpMessageNotReadableException]
HandlerMethod details: 
Controller [org.springframework.data.rest.webmvc.RepositoryEntityController]
Method [public org.springframework.http.ResponseEntity<org.springframework.data.rest.webmvc.support.ExceptionMessage> org.springframework.data.rest.webmvc.AbstractRepositoryRestController.handleNotReadable(org.springframework.http.converter.HttpMessageNotReadableException)]

at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:169)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:340)
at org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:60)
at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:138)
at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:75)
at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1164)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilter(WebRequestTraceFilter.java:114)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextFilterConfiguration$1.doFilterInternal(EndpointWebMvcAutoConfiguration.java:128)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:201)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:84)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:680)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1721)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)

然后Spring Boot Actuate会记录以下错误:

2014-02-28 07:58:54.986 错误 9232 --- [nio-8080-exec-6] osbactuate.web.BasicErrorController:org.springframework.http.converter.HttpMessageNotWritableException:无法写入 JSON:(是 java.lang.NullPointerException) (通过引用链:org.springframework.hateoas.Resource["content"]);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (通过引用链:org.springframework.hateoas.Resource["content"])

如果我修改我的 pom.xml 以使用 SDR 版本 2.0.0.RC1,那么一切似乎都按预期工作。

我想解决这个问题,因为我一直在等待的最新版本中包含错误修复,但是这个问题阻止了我升级。有解决方法吗?从堆栈跟踪中甚至很难判断问题出在哪里,但仅根据时间,我认为这个问题可能与这次提交有关:

https://github.com/spring-projects/spring-data-rest/commit/3e5914d84f9708015b36a8840a25e9fa10a7f6ae

根据要求,依赖项是:

spring-data-rest-webmvc 2.0.0.RELEASE

spring-boot-starter-web 1.0.0.BUILD-SNAPSHOT

spring-boot-starter-actuator 1.0.0.BUILD-SNAPSHOT

spring-boot-starter-security 1.0.0.BUILD-SNAPSHOT

spring-boot-starter-data-jpa 1.0.0.BUILD-SNAPSHOT

spring-boot-starter-shell-remote 1.0.0.BUILD-SNAPSHOT

spring-boot-starter-tomcat [提供]

spring-boot-starter-test 1.0.0.BUILD-SNAPSHOT

spring-security-ldap 3.2.0.RELEASE

似乎 spring-boot-starter-jpa 提供了比 spring-data-rest-webmvc 更旧版本的 spring-data-commons,但重新排序依赖项以提取 1.7.0.RELASE 而不是 1.7.0。 RC1 似乎没有效果。

【问题讨论】:

发布您的依赖项。看起来您正在混合不兼容的 jar 版本。 我同意 Marten 的观点,这可能只是你的传递依赖。如果您切换到 Spring Boot 的 SNAPSHOT,那么我们刚刚添加了一个 spring-boot-starter-data-rest(来自 Marten)。例如,我可以从 Data Rest 示例中看到 spring-data-commons:1.7.0.RELEASE 包含在内,所以我认为这可能会解决问题。 这里是依赖树的粘贴目录:pastebin.com/raw.php?i=KfqXQgZQ 这是使用 SDR 2.0.0.RELEASE 和 Boot 1.0.0.RC3 的树。我似乎仍然无法弄清楚可能导致此错误的原因... 看了一整天后,我几乎确信这是 SDR 中的一个错误。 Jackson 最终抛出异常,并且依赖版本 (2.3.1) 在 SDR 的 RC1 和 RELEASE 版本中是相同的。唯一可以改变的就是传入的 Resource 进行序列化。正如我还提到的,9 个端点中有 2 个(使用 SDR 2.0.0.RELEASE 时)正确返回分页结果。其他 7 个抛出此异常,但我终其一生都无法弄清楚共性是什么。 【参考方案1】:

这是一个已知且已修复的bug,基本上掩盖了我们这边的杰克逊序列化问题。 fix 已经存在并将在 2.0.1 版本和 2.1 M1 中。

请随意尝试快照。

【讨论】:

2.1.0-BUILD-SNAPSHOT 在某些关系上添加 @JsonIgnore 注释后正在工作。但是,我现在无法发布带有所需关联属性的实体。我得到:没有找到合适的 HttpMessageConverter 将请求正文读取到类型为 com.renovo.schedulerapi.domain.Reservation 的请求中,内容类型为 application/json!在帖子中应该如何将链接包含在 json 中?这样的事情以前工作过:“requestor”:“rel”:“users.User”,“href”:“localhost:8080/users/5”, 从 2.0 开始,只需提交关联的 URI: "requestor" : "…/users/5" 就可以了。 似乎仍然无法正常工作。在这里创建了一个新问题,因为它更具体:***.com/questions/22151572/…

以上是关于Spring Data Rest 2.0.0.RELEASE 打破了以前使用 RC1 的代码的主要内容,如果未能解决你的问题,请参考以下文章

排除 Spring-data-rest 资源的部分字段

如何在 Spring-Data-Rest 中实现细粒度的访问控制?

初入spring boot(八 )Spring Data REST

Spring-Data-Rest中时间的数据类型

您如何保护 Spring Boot / Spring-Data Rest 以便用户只能访问他自己的实体

spring-data-rest 集成测试因简单的 json 请求而失败