Spring MVC + Rest API - 无法懒惰地初始化集合

时间:2016-01-27 15:18:41

标签: java hibernate rest spring-mvc jpa

我正在使用Spring MVC构建应用程序。流程是非常基本的,即控制器 - >服务 - > DAO和回来。

现在,我正在创建一个RestController,它将调用服务并执行我想要的任何操作。我遇到了一个奇怪的问题,我需要帮助。

我有两个实体用户角色。一个用户可以拥有多个角色,并且可以将角色分配给许多用户 - 基本上是 ManyToMany 映射。我为这两个依赖项提供了 FetchType.LAZY

当我通过浏览器登录时,Web应用程序中的一切正常。但是,当我调用RESTController时,我收到以下错误

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.xx.yyy.entity.Role.users, could not initialize proxy - no Session (through reference chain: com.xx.yyy.entity.User["roles"]->org.hibernate.collection.internal.PersistentBag[0]->com.xx.yyy.entity.Role["users"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.xx.yyy.entity.Role.users, could not initialize proxy - no Session (through reference chain: com.xx.yyy.entity.User["roles"]->org.hibernate.collection.internal.PersistentBag[0]->com.xx.yyy.entity.Role["users"])
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:238)
org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:208)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:161)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101)
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:202)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)

这里奇怪的是,当我在用户界面上(例如,在我的网络应用程序中)时,这种方法非常好用

以下是我的实体

User.java

@Entity
@Table(name="USERS")

public class User {
    @Id
    @Column (name="USER_ID")
    private String id;

    @NotEmpty(message = "First Name is mandatory")
    @Column (name="FIRST_NAME")
    private String firstName;

    @Column (name="LAST_NAME")
    private String lastName;

    @NotEmpty(message= "Email ID is mandatory")
    @Column (name="EMAIL_ID")
    private String emailId;

    @NotEmpty(message="Primary Phone Number is mandatory")
    @Column (name="PHONE_1")
    private String primaryPhone;

    @Column (name="PHONE_2")
    private String secondaryPhone;

    @Column (name="PASS_WORD")
    private String password;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable( name="ROLESMAPPING", joinColumns={@JoinColumn(name="USER_ID")}, inverseJoinColumns={@JoinColumn(name="GROUP_ID")})
    private List<Role> roles = new ArrayList<Role>();


    @Transient
    private List<String> roleIDs = new ArrayList<String>();

    //Getters and Setters

}

Role.java

@Entity
@Table( name="ROLES" )
public class Role {

    @Id
    @Column( name="GROUP_ID")
    private String id;

    @Column( name="GROUP_DESC" )
    private String description;

    @ManyToMany(mappedBy="roles")
    @LazyCollection(LazyCollectionOption.TRUE)
    private List<User> users = new ArrayList<User>();

    //Getters and Setters go here
}

我在发布此问题之前添加了LazyCollection注释(在引用了许多其他帖子之后),但它没有帮助。

我认为将响应发送回我的客户端是有意义的,因为我试图在获取用户后在我的RestController中放置一个断点,令我惊讶的是,用户被取出。在执行return user;语句之后出现错误。这是我的Rest控制器

@RestController
@RequestMapping("/api/user")
public class GenericController {

    private static final Logger logger = LoggerFactory.getLogger(GenericController.class);

    @Autowired
    private UserService userService;

    @RequestMapping("/get/{userid}")
    public User get(@PathVariable(value="userid") String userId) {
        try{
            if(StringUtils.isEmptyString(userId)){
                userId = "admin";
            }
            User user = userService.getUserById(userId);
            return user;
        }catch(Exception e){
            logger.error(e.getMessage(),e);
            return null;
        }
    }
}

这是我尝试做的事情

我在同一个错误上引用了其他一些帖子,我尝试在我的两个实体上制作Fetch类型EAGER(即fetch=FetchType.EAGER)。接下来发生的事情是,用户详细信息与Roles一起获取,角色转而让用户随身携带,这种情况发生在无限循环中。我得到的JSON作为输出永无止境。

请帮助我了解我出错的地方。

1 个答案:

答案 0 :(得分:0)

感谢@Boris the Spider,我看了this post,答案就在那里!

我所做的就是将@JsonIgnore添加到我的Child类中的字段,该类引用Parent实体,就像这样

@Entity
@Table( name="ROLES" )
public class Role {

    @Id
    @Column( name="GROUP_ID")
    private String id;

    @Column( name="GROUP_DESC" )
    private String description;

    @ManyToMany(mappedBy="roles")
    @JsonIgnore
    private List<User> users = new ArrayList<User>();

    //Getters and Setters go here
}

这解决了无限循环问题。