I am creating a RESTful web service that consumes and returns JSON. I encounter the following stack trace when I try to retrieve an ESRBRating object from a database through a service level. However, when I insert the Spring Data JPA data repository directly into the controller and use it to get ESRBRating by ID, it works fine. However, when called through the service level, it does not work. I have provided the stack trace and code below. Can someone explain to me why this happens when viewing the service level, but not when directly accessing the Spring Data JPA data repository? How to solve this problem?
Stack trace
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286) at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) at net.jkratz.igdb.model.ESRBRating_$$_jvst319_0.getId(ESRBRating_$$_jvst319_0.java) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:466) at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639) ... 76 more
controller
@RestController @RequestMapping(produces = "application/json", value="/esrbrating") public class ESRBRatingController { @Inject ESRBRatingService esrbRatingService; @Inject ESRBRatingRepository esrbRatingRepository; private Logger logger = LoggerFactory.getLogger(getClass()); @RequestMapping(value = {"","/"}, method = RequestMethod.GET) public ResponseEntity<List<ESRBRating>> getESRBRatings() { List<ESRBRating> esrbRatings = esrbRatingService.getESRBRatings(); return new ResponseEntity<>(esrbRatings, HttpStatus.OK); } @RequestMapping(value = "/{id}", method = RequestMethod.GET) public ResponseEntity<?> getUser(@PathVariable("id") Long id) { logger.debug("Attempting to fetch ESRB rating with ID: {}", id); ESRBRating esrbRating = esrbRatingService.getESRBRating(id);
Service
@Service @Transactional public class ESRBRatingServiceImpl implements ESRBRatingService { @Value("#{paging.games.maxPageSize}") private static int DEFAULT_PAGE_SIZE; @Value("#{paging.games.maxPageSize}") private static int MAX_PAGE_SIZE; @Inject private ESRBRatingRepository esrbRatingRepository; @Override public List<ESRBRating> getESRBRatings() { List<ESRBRating> ratings = esrbRatingRepository.findAll(); return ratings; } @Override public ESRBRating getESRBRating(Long id) { return esrbRatingRepository.getOne(id); } @Override public ESRBRating saveESRBRating(ESRBRating esrbRating) { return esrbRatingRepository.saveAndFlush(esrbRating); } @Override public boolean deleteESRBRating(Long id) { esrbRatingRepository.delete(id); return true; } }
Repository
package net.jkratz.igdb.repository; import net.jkratz.igdb.model.ESRBRating; import org.springframework.data.jpa.repository.JpaRepository; public interface ESRBRatingRepository extends JpaRepository<ESRBRating, Long> { }
Model
@Entity @Table(name = "esrb_rating", schema = "igdb") @JsonIgnoreProperties(ignoreUnknown = true) public class ESRBRating implements Serializable { private static final long serialVersionUID = 1L; @Id @NotNull @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", nullable = false) private Long id; @NotNull @Size(min = 1, max = 255) @Column(name = "title", nullable = false, length = 255) private String title; @Size(max = 65535) @Column(length = 65535) private String description; @OneToMany(cascade = CascadeType.ALL, mappedBy = "esrbRating") private List<Game> games; public ESRBRating() { } public ESRBRating(Long id, String title, String description) { this.id = id; this.title = title; this.description = description; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ESRBRating that = (ESRBRating) o; return Objects.equal(this.id, that.id) && Objects.equal(this.title, that.title) && Objects.equal(this.description, that.description); } @Override public int hashCode() { return Objects.hashCode(id, title, description); } @Override public String toString() { return Objects.toStringHelper(this) .add("id", id) .add("title", title) .add("description", description) .toString(); } }
This controller code works fine, going through the repository directly.
@RestController @RequestMapping(produces = "application/json", value="/esrbrating") public class ESRBRatingController { @Inject ESRBRatingService esrbRatingService; @Inject ESRBRatingRepository esrbRatingRepository; private Logger logger = LoggerFactory.getLogger(getClass()); @RequestMapping(value = {"","/"}, method = RequestMethod.GET) public ResponseEntity<List<ESRBRating>> getESRBRatings() { List<ESRBRating> esrbRatings = esrbRatingService.getESRBRatings(); return new ResponseEntity<>(esrbRatings, HttpStatus.OK); } @RequestMapping(value = "/{id}", method = RequestMethod.GET) public ResponseEntity<?> getUser(@PathVariable("id") Long id) { logger.debug("Attempting to fetch ESRB rating with ID: {}", id); ESRBRating esrbRating = esrbRatingRepository.findOne(id); if (esrbRating == null) { return new ResponseEntity<>("ESRB Rating not found", HttpStatus.NOT_FOUND); } else { return new ResponseEntity<>(esrbRating, HttpStatus.OK); } }
}
UPDATE:
I followed Randall Harley's advice and installed a reverse build with @JsonIgnore. However, now I get a completely different stack trace. It seems now Jackson / Spring doesn't know how to serialize ESRBRating. Any tips on this?
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: net.jkratz.igdb.model.ESRBRating_$$_jvstb5c_0["handler"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: net.jkratz.igdb.model.ESRBRating_$$_jvstb5c_0["handler"]) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:238) at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:208) at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:158) at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:138) at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:122) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) 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:150) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:155) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) 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.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 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.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) Caused by: com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: net.jkratz.igdb.model.ESRBRating_$$_jvstb5c_0["handler"]) at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59) at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26) at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505) at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639) at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:114) at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:1887) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:231) ... 72 more
Update 2:
In the end, I included @Proxy (lazy = false) in the ESRBRating class, and now it works great. However, I am curious what impact this might have on performance?
@Entity @Table(name = "esrb_rating", schema = "igdb") @JsonIgnoreProperties(ignoreUnknown = false) @Proxy(lazy = false) public class ESRBRating implements Serializable { private static final long serialVersionUID = 1L; @Id @NotNull @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", nullable = false) private Long id; @NotNull @Size(min = 1, max = 255) @Column(name = "title", nullable = false, length = 255) private String title; @Size(max = 65535) @Column(length = 65535) private String description; @OneToMany(cascade = CascadeType.ALL, mappedBy = "esrbRating") private List<Game> games; public ESRBRating() { } public ESRBRating(Long id, String title, String description) { this.id = id; this.title = title; this.description = description; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @JsonIgnore public List<Game> getGames() { return games; } public void setGames(List<Game> games) { this.games = games; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ESRBRating that = (ESRBRating) o; return Objects.equal(this.id, that.id) && Objects.equal(this.title, that.title) && Objects.equal(this.description, that.description); } @Override public int hashCode() { return Objects.hashCode(id, title, description); } @Override public String toString() { return Objects.toStringHelper(this) .add("id", id) .add("title", title) .add("description", description) .toString(); } }
According to the Game class requested here
@Entity @Table(name = "game", schema = "igdb", indexes = {@Index(name = "idx_game_title", columnList = ("title"), unique = false), @Index(name = "idx_game_developer", columnList = ("developer"), unique = false), @Index(name = "idx_game_publisher", columnList = ("publisher"), unique = false)}) @JsonIgnoreProperties(ignoreUnknown = true) public class Game implements Serializable { private static final long serialVersionUID = 1L; @Id @NotNull @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", nullable = false) private Long id; @NotNull @Size(min = 1, max = 255) @Column(name = "title", nullable = false, length = 255) private String title; @Size(max = 65535) @Column(name = "description", length = 65535) private String description; @Size(max = 255) @Column(name = "developer", length = 255) private String developer; @Size(max = 255) @Column(name = "publisher", length = 255) private String publisher; @NotNull @Size(max = 4) @Column(name = "players", nullable = false) private short players; @NotNull @Column(name = "cooperative", nullable = false) private boolean cooperative; @NotNull @Column(name = "release_date", nullable = false) @Temporal(TemporalType.DATE) private Date releaseDate; @Size(max = 255) @Column(name = "image", length = 255) private String image; @JoinColumn(name = "esrb_rating_id", referencedColumnName = "id", nullable = false) @ManyToOne(optional = false, fetch = FetchType.EAGER) private ESRBRating esrbRating; @OneToMany(cascade = CascadeType.ALL, mappedBy = "game") private List<GamePlatformMap> gamePlatformMap; @OneToMany(cascade = CascadeType.ALL, mappedBy = "game") private List<GameGenreMap> gameGenreMap; public Game() { } public Game(Long id, String title, String description, String developer, String publisher, short players, boolean cooperative, Date releaseDate, String image, ESRBRating esrbRating) { super(); this.id = id; this.title = title; this.description = description; this.developer = developer; this.publisher = publisher; this.players = players; this.cooperative = cooperative; this.releaseDate = releaseDate; this.image = image; this.esrbRating = esrbRating; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getDeveloper() { return developer; } public void setDeveloper(String developer) { this.developer = developer; } public String getPublisher() { return publisher; } public void setPublisher(String publisher) { this.publisher = publisher; } public short getPlayers() { return players; } public void setPlayers(short players) { this.players = players; } public boolean isCooperative() { return cooperative; } public void setCooperative(boolean cooperative) { this.cooperative = cooperative; } public Date getReleaseDate() { return releaseDate; } public void setReleaseDate(Date releaseDate) { this.releaseDate = releaseDate; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public ESRBRating getEsrbRating() { return esrbRating; } public void setEsrbRating(ESRBRating esrbRating) { this.esrbRating = esrbRating; } @JsonIgnore public List<GamePlatformMap> getGamePlatformMap() { return gamePlatformMap; } public void setGamePlatformMap(List<GamePlatformMap> gamePlatformMap) { this.gamePlatformMap = gamePlatformMap; } @JsonIgnore public List<GameGenreMap> getGameGenreMap() { return gameGenreMap; } public void setGameGenreMap(List<GameGenreMap> gameGenreMap) { this.gameGenreMap = gameGenreMap; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Game that = (Game) o; return Objects.equal(this.id, that.id) && Objects.equal(this.title, that.title) && Objects.equal(this.description, that.description) && Objects.equal(this.developer, that.developer) && Objects.equal(this.publisher, that.publisher) && Objects.equal(this.players, that.players) && Objects.equal(this.cooperative, that.cooperative) && Objects.equal(this.releaseDate, that.releaseDate) && Objects.equal(this.image, that.image) && Objects.equal(this.esrbRating, that.esrbRating); } @Override public int hashCode() { return Objects.hashCode(id, title, description, developer, publisher, players, cooperative, releaseDate, image, esrbRating); } @Override public String toString() { return Objects.toStringHelper(this) .add("id", id) .add("title", title) .add("description", description) .add("developer", developer) .add("publisher", publisher) .add("players", players) .add("cooperative", cooperative) .add("releaseDate", releaseDate) .add("image", image) .add("esrbRating", esrbRating) .toString(); } }