0

Below is some code for background:

InitiativeProfileQuestion.java:

@Entity
@Table
public class InitiativeProfileQuestion implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String question;

    @Column
    private String description;

    @Column
    private int sortOrder;

    @OneToMany(mappedBy = "initiativeProfileQuestion", fetch = FetchType.LAZY)
    private List<InitiativeProfileAnswer> answers;

    public List<InitiativeProfileAnswer> getAnswers() {
        return answers;
    }

    public void setAnswers(List<InitiativeProfileAnswer> answers) {
        this.answers = answers;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getQuestion() {
        return question;
    }

    public void setQuestion(String question) {
        this.question = question;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(int sortOrder) {
        this.sortOrder = sortOrder;
    }

}

InitiativeProfileAnswer.java:

@Entity
@Table
public class InitiativeProfileAnswer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column
    private String answer;

    @Column
    private int sortOrder;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "initiativeProfileQuestionId")
    @JsonIgnore
    private InitiativeProfileQuestion initiativeProfileQuestion;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getAnswer() {
        return answer;
    }

    public void setAnswer(String answer) {
        this.answer = answer;
    }

    public int getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(int sortOrder) {
        this.sortOrder = sortOrder;
    }

    public InitiativeProfileQuestion getInitiativeProfileQuestion() {
        return initiativeProfileQuestion;
    }

    public void setInitiativeProfileQuestion(InitiativeProfileQuestion initiativeProfileQuestion) {
        this.initiativeProfileQuestion = initiativeProfileQuestion;
    }
}

InitiativeProfileQuestionRepository.java:

public interface InitiativeProfileQuestionRepository extends JpaRepository<InitiativeProfileQuestion, Long> {

    @Query("select ipa from InitiativeProfileQuestion ipa join fetch ipa.answers")
    public List<InitiativeProfileQuestion> getAllQuestions();
}

InitiativeProfileService.java:

@Service
public class InitiativeProfileService {

    @Autowired
    private InitiativeProfileQuestionRepository initiativeProfileQuestionRepository;

    public List<InitiativeProfileQuestion> getAllQuestions() {
        return initiativeProfileQuestionRepository.findAll();
    }

    public List<InitiativeProfileQuestion> getAllQuestionsFetch() {
        return initiativeProfileQuestionRepository.getAllQuestions();
    }

}

BaseController.java:

@RestController
@RequestMapping("/api")
public class BaseController {

    @Autowired
    InitiativeProfileService initiativeProfileService;

    @RequestMapping("/question")
    public List<InitiativeProfileQuestion> getQuestions() {
        return initiativeProfileService.getAllQuestions();
    }

    @RequestMapping("/questionFetch")
    public List<InitiativeProfileQuestion> getQuestionsFetch() {
        return initiativeProfileService.getAllQuestionsFetch();
    }
}

Calling getQuestions() in my BaseController returns a "could not initialize proxy - no Session" error. However, calling getQuestionsFetch() in my BaseController loads just fine.

I want it to work in a way that if I call getQuestions(), the object will be returned with NO answers (since the lazy loaded object will not be called anywhere). However, it just gives me an error. If I'm doing a query with a join fetch, it works by showing the answers as well (expected behavior).

What am I doing wrong? I tried @Transactional in different places with no luck. I also have no .xml files- everything so far is done using annotations.

The error I get is:

exception

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"])
    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:185)
    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:776)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause

com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"])
    com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
    com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:177)
    com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:187)
    com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:647)
    com.fasterxml.jackson.databind.ser.std.BeanSerializerBase._serializeWithObjectId(BeanSerializerBase.java:558)
    com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:145)
    com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:100)
    com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:21)
    com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:183)
    com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:128)
    com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:1902)
    org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:231)
    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:185)
    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:776)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
    org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
user3397214
  • 187
  • 3
  • 10
  • "it just gives me an error" ... what error? In particular, the stacktrace would tell you who is accessing the lazy loaded object that "will not be called anywhere". – meriton Aug 09 '15 at 21:24
  • Could not write content: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"])‌​; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion – user3397214 Aug 09 '15 at 21:39
  • Use the "edit" link below your question to add this information to your answer (people don't usually read through an entire comment chain, there is no length limit, and you can format it better). Also, I asked for the *stacktrace*, not just the exception message. – meriton Aug 09 '15 at 21:46
  • Updated above. Thanks – user3397214 Aug 09 '15 at 22:06
  • 1
    After a few hours I was able to figure it out from this post: http://stackoverflow.com/questions/21708339/avoid-jackson-serialization-on-non-fetched-lazy-objects/21760361#21760361 – user3397214 Aug 09 '15 at 22:11

2 Answers2

0

For an exception in case of lazy loading you must be trying to fetch the associated objects outside the session. Either change the lazy loading to eager or put your code which is fetching the associated object inside the session. For e.g:

    public void test() {

            Session session = HibernateUtil.currentSession();
            session.beginTransaction();

            Vehicle  vehicle= (Vehicle) session.get(Vehicle.class, 2);

            System.out.println(vehicle.getVehicleName());

            session.getTransaction().commit();
            session.close();
            System.out.println(vehicle.getVehicleName()); //No exception here
            System.out.println(vehicle.getUser().getUserName()); 
// Exception here change the loading to EAGER or put this line of code within the session above. Put it before session.close() or  before session.getTransaction().commit();
        }
Goyal Vicky
  • 1,249
  • 16
  • 16
  • If i am not mistaken, OP wanted to avoid eager loading. – John Aug 09 '15 at 20:58
  • 2 options are their. Either use Eager or fetch the associated object within the session. – Goyal Vicky Aug 09 '15 at 21:02
  • user3360241 is correct. I wanted to avoid eager loading. There will be times I want to retrieve the InitiativeProfileQuestions object without the answers, therefore I think lazy loading is the best way to go. – user3397214 Aug 09 '15 at 21:02
  • From what i can tell, the answer shows only eager option. Comment in your last line indicates to avoid exception to fetch user eagerly. – John Aug 09 '15 at 21:04
  • I have provided an example as what might be the most probable cause in your code and 2 options to fix it. Other options are: you can use query to fetch or use FetchMode.EAGER if using criteria. – Goyal Vicky Aug 09 '15 at 21:06
  • Using the query to fetch works, but using a query without fetching the answers throws a no session error when it should just return the questions object without any answers. – user3397214 Aug 09 '15 at 21:08
  • Can you share your code where you are using session to fetch it. – Goyal Vicky Aug 09 '15 at 21:12
  • You must be getting "Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session" – Goyal Vicky Aug 09 '15 at 21:13
  • Could not write content: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion["answers"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.testApp.domain.InitiativeProfileQuestion.answers, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.testApp.domain.InitiativeProfileQuestion – user3397214 Aug 09 '15 at 21:16
  • The only time it gives the above error is if I do a query that does NOT join fetch answers. If I don't explicitly tell it to join fetch answers, shouldn't it just return a null answers object? Instead it throws that error. – user3397214 Aug 09 '15 at 21:18
  • I have made changes to last line. Try to make the change as suggested in the last line. – Goyal Vicky Aug 09 '15 at 21:19
0

As you can see from the stacktrace, the error occurs when Jackson is trying to access the lazily loaded object in order to serialize it to JSON. At this time, the spring transaction has already completed, and the Hibernate session closed, which is why Hibernate can no longer load that object.

If you do not intend that field to be serialized, you might wish to use @JsonIgnore, or Spring's Jackson Serialization View Support.

meriton
  • 68,356
  • 14
  • 108
  • 175