JsonMappingException: could not initialize proxy - no Session

45,529

Solution 1

This typically happens when you are returning an object via @Responsebody (or in your case response body by way of @RestController) and an object is being serialized but has children in a LAZY collection that have not been referenced. By the time you are in your controller there is no longer a transaction active that will facilitate them being fetched (like the one your started in your @Service). You can either make your fetch strategy EAGER, bring in your collections by reference while still in your transaction or make your LAZY collections JSON Transient.

Solution 2

First download jackson-datatype-hibernate4-2.2.3.jar or higher version according to jackson-core version. Then use this code in config file and you can use fetch strategy LAZY without any error.

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module;


public class ApplicationConfig extends WebMvcConfigurerAdapter
{
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
    MappingJackson2HttpMessageConverter messageConverter = new  MappingJackson2HttpMessageConverter();

    ObjectMapper mapper = new ObjectMapper();
    //Registering Hibernate4Module to support lazy objects
    mapper.registerModule(new Hibernate4Module());

    messageConverter.setObjectMapper(mapper);
    return messageConverter;

}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    //Here we add our custom-configured HttpMessageConverter
    converters.add(jacksonMessageConverter());
    super.configureMessageConverters(converters);
}

Solution 3

@JsonIgnore annotation might solve your problem, but it causes that particular field that you initially set as FetchType.LAZY to be completely ignored. A better alternative is given here https://stackoverflow.com/a/21760361/3609067

Solution 4

Solved for Spring Boot 2.3.0 by adding to gradle.build:

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:2.11.3'

And declaring one more bean:

@Bean
public Module datatypeHibernateModule() {
    return new Hibernate5Module();
}

Solution 5

I've met the same error, but no answer helped me.

It appeared that the problem was in jpa.open-in-view=false. I've removed it and now everything works as expected.

Share:
45,529
greyfox
Author by

greyfox

I'm a web developer from Columbus, Ohio. I studied Computer Science at Capital University in Columbus, where I received my bachelor's degree. In college I was heavy into C++ and Python. I dabbled my hands in Objective-C/Cocoa as well. After college I began doing web development using PHP/MySQL. I really fell in love with web development. Now I'm transitioning into Java/Spring MVC. At some point I would like to get more into ASP.NET MVC.

Updated on July 05, 2022

Comments

  • greyfox
    greyfox almost 2 years

    I am building a RESTful Web Service that consumes and returns JSON. I am encountering the following stack trace when I try to fetch an ESRBRating object from the database through the service layer. However when I inject the Spring Data JPA repository directly to the controller and use that to fetch the ESRBRating by ID it works fine. However when calling through the service layer it does not work. I have provided the stack trace and code below. Can someone explain to me why this is happening when going through a service layer but not when going through the Spring Data JPA repository directly? How do I resolve this issue?

    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());
    
        /**
         * Returns all ESRB ratings in database
         * 
         * @return List of ESRBRating objects
         * @see ESRBRating
         */
        @RequestMapping(value = {"","/"}, method = RequestMethod.GET)
        public ResponseEntity<List<ESRBRating>> getESRBRatings() {
            List<ESRBRating> esrbRatings = esrbRatingService.getESRBRatings();
            return new ResponseEntity<>(esrbRatings, HttpStatus.OK);
        }
    
        /**
         * Returns a single ESRB rating object if exists, otherwise returns HTTP status code 404
         *
         * @param id ID of the ESRB Rating
         * @return ESRB Rating when found
         * @see ESRBRating
         */
        @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);
            //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);
            }
        }
    
    }
    

    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());
    
    /**
     * Returns all ESRB ratings in database
     * 
     * @return List of ESRBRating objects
     * @see ESRBRating
     */
    @RequestMapping(value = {"","/"}, method = RequestMethod.GET)
    public ResponseEntity<List<ESRBRating>> getESRBRatings() {
        List<ESRBRating> esrbRatings = esrbRatingService.getESRBRatings();
        return new ResponseEntity<>(esrbRatings, HttpStatus.OK);
    }
    
    /**
     * Returns a single ESRB rating object if exists, otherwise returns HTTP status code 404
     *
     * @param id ID of the ESRB Rating
     * @return ESRB Rating when found
     * @see ESRBRating
     */
    @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 Harleigh advice and set the reverse collection with @JsonIgnore. However now I am getting an entirely different stack trace. It seems now Jackson / Spring doesn't know how to serialize ESRBRating. Any tips on this one?

    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:

    I ended up putting @Proxy(lazy = false) on the ESRBRating class and now it works fine. However I'm curious what kind of performance impacts this could have?

    @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();
        }
    }
    

    As requested here is the Game class

    @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();
        }
    }