java - ModelMapper 在将实体转换为 DTO 时产生异常

标签 java spring hibernate jpa modelmapper

我正在尝试将实体转换为在 Rest 服务中使用的 DTO。

我的实体如下:

@Entity
@Table(name = "USERS")
public class User extends AbstractEntity {
    @Column(name = "LOGIN")
    private String login;
    @Column(name = "PASSWORD")
    private String password;
    @Column(name = "ENABLED")
    private Boolean enabled;
    @Column(name = "FIRST_NAME")
    private String firstName;
    @Column(name = "LAST_NAME")
    private String lastName;
    @Column(name = "EMAIL")
    private String email;
    @Column(name = "DATE_FORMAT")
    private String dateFormat;
    @Column(name = "CREATION_DATE")
    private LocalDateTime creationDate;
    @Column(name = "LAST_ACCESS_DATE")
    private LocalDateTime lastAccessDate;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "USER_ROLES", joinColumns = {
            @JoinColumn(name = "USER_ID", referencedColumnName = "id") }, inverseJoinColumns = {
            @JoinColumn(name = "ROLE_ID", referencedColumnName = "id") })
    private List<Role> roles = new ArrayList<>();

以及相关的 DTO:
public class UserDto extends AbstractDto {

    private String login;
    private String password;
    private Boolean enabled;
    private String firstName;
    private String lastName;
    private String email;
    private String dateFormat;
    private LocalDateTime creationDate;
    private LocalDateTime lastAccessDate;
    private List<RoleDto> roles = new ArrayList<>();

我正在使用 ModelMapper 将我的实体转换为 DTO,反之亦然。但是,当我向 Rest API 发送请求时,出现以下错误:
Converter org.modelmapper.internal.converter.MergingCollectionConverter@67aa8104 failed to convert org.hibernate.collection.internal.PersistentBag to java.util.List.

1 error
    at org.modelmapper.internal.Errors.throwMappingExceptionIfErrorsExist(Errors.java:380) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:81) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.ModelMapper.mapInternal(ModelMapper.java:573) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.ModelMapper.map(ModelMapper.java:406) ~[modelmapper-2.3.3.jar:na]
    at eu.voiceweb.business.services.MapperService.getMappedObject(MapperService.java:49) ~[Reporting-3.2.0.jar:na]
    at eu.voiceweb.business.services.MapperService.getDto(MapperService.java:31) ~[Reporting-3.2.0.jar:na]
    at eu.voiceweb.business.services.UserService.getUserByLogin(UserService.java:63) ~[Reporting-3.2.0.jar:na]
    at eu.voiceweb.restapi.UserController.getUserByUsername(UserController.java:45) ~[dialogManager-3.2.0.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) ~[spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) [spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) [spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) [servlet-api.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) [spring-webmvc-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [servlet-api.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [catalina.jar:9.0.12]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.12]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-websocket.jar:9.0.12]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:9.0.12]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:9.0.12]
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45) [tomee-catalina-8.0.0-M2.jar:8.0.0-M2]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [catalina.jar:9.0.12]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [catalina.jar:9.0.12]
    at org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97) [tomee-catalina-8.0.0-M2.jar:8.0.0-M2]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [catalina.jar:9.0.12]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [catalina.jar:9.0.12]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-coyote.jar:9.0.12]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:9.0.12]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770) [tomcat-coyote.jar:9.0.12]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-coyote.jar:9.0.12]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:9.0.12]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:9.0.12]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: eu.voiceweb.persistence.entities.User.roles, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:602) ~[hibernate-core-5.4.2.Final.jar:5.4.2.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217) ~[hibernate-core-5.4.2.Final.jar:5.4.2.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:161) ~[hibernate-core-5.4.2.Final.jar:5.4.2.Final]
    at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:287) ~[hibernate-core-5.4.2.Final.jar:5.4.2.Final]
    at org.modelmapper.internal.util.Iterables.getLength(Iterables.java:50) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:44) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.converter.MergingCollectionConverter.convert(MergingCollectionConverter.java:31) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.convert(MappingEngineImpl.java:303) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:110) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.setDestinationValue(MappingEngineImpl.java:242) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.propertyMap(MappingEngineImpl.java:188) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.typeMap(MappingEngineImpl.java:152) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:115) ~[modelmapper-2.3.3.jar:na]
    at org.modelmapper.internal.MappingEngineImpl.map(MappingEngineImpl.java:72) ~[modelmapper-2.3.3.jar:na]
    ... 47 common frames omitted
2019-05-15 13:25:26,065 ERROR [http-nio-18000-exec-9] [AbstractAuthenticationProcessingFilter.java:221] An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:123) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:200) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [catalina.jar:9.0.12]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [catalina.jar:9.0.12]
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45) [tomee-catalina-8.0.0-M2.jar:8.0.0-M2]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [catalina.jar:9.0.12]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [catalina.jar:9.0.12]
    at org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97) [tomee-catalina-8.0.0-M2.jar:8.0.0-M2]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668) [catalina.jar:9.0.12]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [catalina.jar:9.0.12]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [catalina.jar:9.0.12]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-coyote.jar:9.0.12]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-coyote.jar:9.0.12]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770) [tomcat-coyote.jar:9.0.12]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-coyote.jar:9.0.12]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-coyote.jar:9.0.12]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:9.0.12]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226) ~[gson-2.8.5.jar:na]
    at com.google.gson.Gson.fromJson(Gson.java:927) ~[gson-2.8.5.jar:na]
    at com.google.gson.Gson.fromJson(Gson.java:892) ~[gson-2.8.5.jar:na]
    at com.google.gson.Gson.fromJson(Gson.java:841) ~[gson-2.8.5.jar:na]
    at com.google.gson.Gson.fromJson(Gson.java:813) ~[gson-2.8.5.jar:na]
    at eu.voiceweb.services.UserService.getUserFromResponse(UserService.java:104) ~[classes/:na]
    at eu.voiceweb.services.UserService.getUserByUsername(UserService.java:78) ~[classes/:na]
    at eu.voiceweb.services.UserService.loadUserByUsername(UserService.java:115) ~[classes/:na]
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:108) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    ... 41 common frames omitted
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385) ~[gson-2.8.5.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:215) ~[gson-2.8.5.jar:na]
    ... 49 common frames omitted

最初,实体中的提取类型是 LAZY,我已将其更改为 EAGER 并且它可以工作。但是我读到这对项目的性能不利。我在 web 应用程序初始化器类中尝试了 OpenSessionInViewFilter 没有结果。任何想法如何解决这个问题?

最佳答案

错误是

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: eu.voiceweb.persistence.entities.User.roles, could not initialize proxy - no Session



所以这意味着在对象被序列化时角色列表没有被初始化。

您必须确保初始化发生在您读取数据的地方。

例如,在您的查询中使用 JOIN FETCH、EntityGraph 或通过简单地访问数据访问层中的集合。

关于java - ModelMapper 在将实体转换为 DTO 时产生异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56147329/

相关文章:

java - 该类没有定义 IdClass

java - 将 MD5 messageDigest 从 Java 转换为 Digest::MD5 Ruby

java - Spring Boot 元空间内存泄漏

java - Spring JsonDeserializer 不适用于 String 类型

java - @OneToMany 通过mappedBy 而不使用@JoinColumns

mysql - Java中如何将Date类型实体字段转换为字符串?

java - 我的 Java 程序如何处理 JS 文件以提取函数名称?

java.lang.AssertionError : Response content

java - 我如何使用 java、RestAssured 测试 Web 服务自动替换 Json 对象文件中的两个单独的 ID

SpringBoot : Large Streaming File Upload Using Apache Commons FileUpload