Spring JSON直接自引用导致循环(无限递归)

use*_*743 6 spring json hibernate spring-mvc spring-data

我正在使用 Spring Framework 和 Hibernate 编写一个简单的 Spring MVC REST Web 服务。

\n\n

我想序列化以下简单的用户实体:

\n\n

伪代码:

\n\n
@Entity\npublic class UserEntity implements Serializable\n{\n   @Id\n   @GeneratedValue(\n       strategy = GenerationType.IDENTITY)\n   @JsonView(Views.BaseView.class)\n   @JsonProperty(value = "id")\n   @Column(name = "id_user")\n   private Integer id;\n\n   @JsonView(Views.UserView.class)\n   @JsonProperty(value = "login")\n   @Column(name = "login")\n   private String login;\n\n   @JsonView(Views.UserView.class)\n   @JsonProperty(value = "password")\n   @Column(name = "password")\n   private String password;\n\n   @JsonView(Views.UserView.class)\n   @JsonProperty(value = "creator")\n   @ManyToOne(fetch = FetchType.LAZY)\n   @JoinColumn(name = "id_creator", \n        referencedColumnName = "id_user")\n   private UserEntity creator;\n\n   //Accessors\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

查看描述文件:

\n\n
public class Views\n{\n    public interface BaseView                          {}\n    public interface UserView extends BaseView         {}\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我想要以下 JSON 输出:

\n\n
{\n  "id": 2,\n  "login": "toto",\n  "password": "password2",\n  "creator": {\n      "id": 1,\n      "login": "tata",\n      "password": "password1"   \n\n   }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

不幸的是,我有以下例外:

\n\n
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Direct self-reference leading to cycle (through reference chain: com.az.metal.entity.UserEntity["creator"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle (through reference chain: com.az.metal.entity.UserEntity["creator"])\n    org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:292)\n    org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)\n    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:231)\n    org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:203)\n    org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)\n    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:132)\n    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)\n    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)\n    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)\n    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)\n    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)\n    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)\n    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)\n    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)\n    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)\n    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)\n    org.sitemesh.webapp.contentfilter.ContentBufferingFilter.bufferAndPostProcess(ContentBufferingFilter.java:169)\n    org.sitemesh.webapp.contentfilter.ContentBufferingFilter.doFilter(ContentBufferingFilter.java:126)\n    org.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:120)\n    org.sitemesh.config.ConfigurableSiteMeshFilter.doFilter(ConfigurableSiteMeshFilter.java:163)\n    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)\n    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)\n    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)\n    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)\n    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)\n    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)\n    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)\n    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)\ncause m\xc3\xa8re\n\ncom.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle (through reference chain: com.az.metal.entity.UserEntity["creator"])\n    com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:899)\n    com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:687)\n    com.fasterxml.jackson.databind.ser.impl.FilteredBeanPropertyWriter$SingleView.serializeAsField(FilteredBeanPropertyWriter.java:67)\n    com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)\n    com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)\n    com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)\n    com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1387)\n    com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:889)\n    org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:285)\n    org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)\n    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:231)\n    org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:203)\n    org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)\n    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:132)\n    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)\n    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)\n    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)\n    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)\n    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)\n    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)\n    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)\n    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)\n    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)\n    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)\n    org.sitemesh.webapp.contentfilter.ContentBufferingFilter.bufferAndPostProcess(ContentBufferingFilter.java:169)\n    org.sitemesh.webapp.contentfilter.ContentBufferingFilter.doFilter(ContentBufferingFilter.java:126)\n    org.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:120)\n    org.sitemesh.config.ConfigurableSiteMeshFilter.doFilter(ConfigurableSiteMeshFilter.java:163)\n    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)\n    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)\n    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)\n    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)\n    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)\n    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)\n    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)\n    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)\n    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我知道问题来自于 JSON 序列化过程中的无限递归。

\n\n

我找不到将我的用户实体与其创建者一起序列化的解决方案。

\n\n

预先非常感谢您的帮助!

\n

ali*_*os- 2

该类UserEntity有一个相同类型的字段(即creator),该类有一个相同类型的字段,依此类推。您无法按原样序列化它,因为它是一个永无止境的循环。

本指南有多种可能的解决方案http://www.baeldung.com/jackson-biorient-relationships-and-infinite-recursion,重申这些解决方案毫无意义。

附言。我意识到这是一个老问题,但其他人可能会登陆这里。