Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
805 views
in Technique[技术] by (71.8m points)

json - JsonMappingException: could not initialize proxy - no Session

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.ApplicationFilterCh

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...