SpringMVC + Hibernate Tomcat 500, json no stack trace

I get a 500 error message from Tomcat when I return a list of objects from my service level in Spring. If I just make the entities “on the fly” in memory, I won’t get an error and they will be back in order, so do something specifically with transactions.

I have the following method in my controller ...

@RequestMapping(value = "{examid}", method = RequestMethod.GET) @ResponseBody public List<Exam> getExam(@PathVariable String examid, Model model) { return examService.getAllExams(); } 

When this method is called, tomcat displays a 500 error and has no stack trace at all. I even wrapped it in a catch attempt and nothing appears in this stacktrace.

This service just calls dao ...

 @Service("examService") public class ExamServiceImpl implements ExamService{ @Autowired private ExamDao examDao; @Override @Transactional(readOnly = true) public List<Exam> getAllExams() { return examDao.getAllExams(); } 

And that dao just returns a simple HQL script ...

 @Repository("examDao") public class ExamDaoImpl implements ExamDao { @Autowired private SessionFactory sessionFactory; @Override public List<Exam> getAllExams() { return sessionFactory.getCurrentSession().createQuery("from Exam") .list(); } 

Initially, I thought that this is due to the fact that objects are loaded lazy, my entities are lower, as you can see, they are very simple

 @Entity @Table(name = "exams") public class Exam implements Serializable { private static final long serialVersionUID = -5109075534794721930L; @Id @GeneratedValue(generator="system-uuid") @GenericGenerator(name="system-uuid", strategy = "uuid") @Column(name = "examid", unique = true) private String examId; @OneToMany(mappedBy = "exam") private Set<Question> questions; public String getExamId() { return examId; } public void setExamId(String examId) { this.examId = examId; } /** * @return the questions */ @JsonManagedReference public Set<Question> getQuestions() { return questions; } /** * @param questions the questions to set */ public void setQuestions(Set<Question> questions) { this.questions = questions; } } 

Question Object

 @Entity @Table(name = "questions") public class Question implements Serializable { private static final long serialVersionUID = 8804841647267857850L; private String questionId; private Exam exam; private Set<Answer> answers; /** * @return the answer */ @JsonManagedReference @OneToMany(mappedBy = "question") public Set<Answer> getAnswers() { return answers; } /** * @param answer * the answer to set */ public void setAnswers(Set<Answer> answers) { this.answers = answers; } /** * @return the exam */ @JsonBackReference @ManyToOne @JoinColumn(name = "examid", nullable = false) public Exam getExam() { return exam; } /** * @param exam * the exam to set */ public void setExam(Exam exam) { this.exam = exam; } /** * @return the questionId */ @Id @GeneratedValue(generator = "system-uuid") @GenericGenerator(name = "system-uuid", strategy = "uuid") @Column(name = "questionid", unique = true) public String getQuestionId() { return questionId; } /** * @param questionId * the questionId to set */ public void setQuestionId(final String questionId) { this.questionId = questionId; } } 

Response object

 @Entity @Table(name = "answers") public class Answer implements Serializable { private static final long serialVersionUID = -3922870865886851018L; @Id @GeneratedValue(generator="system-uuid") @GenericGenerator(name="system-uuid", strategy = "uuid") @Column(name = "answerid", unique = true) private String answerId; @ManyToOne() @JoinColumn(name = "questionid", nullable = false) private Question question; /** * @return the question */ @JsonBackReference public Question getQuestion() { return question; } /** * @param question the question to set */ public void setQuestion(Question question) { this.question = question; } /** * @return the answerId */ public String getAnswerId() { return answerId; } /** * @param answerId the answerId to set */ public void setAnswerId(final String answerId) { this.answerId = answerId; } } 

I am using Jackson 2.2.0 - now the following code works fine, so definitely the problem is either with the joins (which were originally downloaded but deleted for debugging). Just returning the following code from the controller works fine ...

  Exam exam = new Exam(); Question presidentQuestion = new Question(); presidentQuestion.setExam(exam); Question skyQuestion = new Question(); skyQuestion.setExam(exam); Set<Question> questions = new HashSet<>(); questions.add(skyQuestion); questions.add(presidentQuestion); exam.setQuestions(questions); Answer answer = new Answer(); answer.setQuestion(skyQuestion); Answer answer1 = new Answer(); answer1.setQuestion(skyQuestion); Answer answer2 = new Answer(); answer2.setQuestion(presidentQuestion); Set<Answer> answers1 = new HashSet<>(); answers1.add(answer2); Set<Answer> answers = new HashSet<>(); answers.add(answer); answers.add(answer1); presidentQuestion.setAnswers(answers1); skyQuestion.setAnswers(answers); return Arrays.asList(exam); 

There is nothing in Tomcat logs - how can I force some kind of stack? Hibernate version = 4.1.10. Final, Spring version 3.1.4.

+4
source share
1 answer

Got a job with a few changes & hellip;

1) main/resources/log4j.xml should be installed in debug to see the error:

 <logger name="org.springframework.context"> <level value="debug" /> </logger> <logger name="org.springframework.web"> <level value="debug" /> </logger> <!-- Root Logger --> <root> <priority value="debug" /> <appender-ref ref="console" /> </root> 

At first I mistakenly edited test/resources/log4j.xml . Did you do the same? Otherwise, maybe your IDE is in the way, because as soon as I set the correct level on log4j.xml , I saw that the entry in the terminal is just fine.

Initially, I thought the error was due to Chrome requesting /favicon.ico immediately after logging in and Spring Security denied access.

DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - query matching: '/favicon.ico'; vs '/'

DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - query matching: '/favicon.ico'; against '/ exam **'

DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - query matching: '/favicon.ico'; against '/ exam / **'

DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Protected object: FilterInvocation: URL: /favicon.ico; Attributes: [denyAll]

DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - previously authenticated: org.springframew ork.security.authentication.UsernamePasswordAuthenticationToken@ fb77dfdd: Principal: org.springframework.security.core.userdetails.User@36ebcb : Username: user; Password Protected]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Authorization granted: ROLE_ADMIN, ROLE_USER; Credentials: [PROTECTION]; Authenticated: true; Details: org.sprin gframework.security.web.authentication.WebAuthenticationDetails@ 0: RemoteIpAddress: 0: 0: 0: 0: 0: 0: 0: 1; SessionId: 1qtptnbw65j3g145c9ni63ucw1; Authorization granted: ROLE_ADMIN, ROLE_USERDEBUG: org.springframework.security.access.vote.AffirmativeBased - Elector: org.sp ringframework.security.web.access.expression.WebExpressionVoter@ 96f613, returned: -1

DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access denied (user is not anonymous) ; delegation AccessDeniedHandlerorg.springframework.security.access.AccessDeniedException: access denied

I added <http pattern="/favicon.ico" security="none" /> to security-context.xml to remove this problem, although after adding it turned out to be something else.

The next error was that the dreaded “not lazily initialized collection”, which has been repeatedly examined on SO, for example:

DEBUG: org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - permission to exception from the handler [public java.util.List com.securetest.app.controller.ExamController.getExam (java.lang.String, org. Springframework.ui .Model)]: org.springframework.http.converter.HttpMessageNotWritableException: could not write JSON: could not lazily initialize the role collection: com.securetest.app.entity.Exam.questions , could not initialize the proxy - no session (via the link chain : java.util.ArrayList [0] → com.securetest.app.entity.Exam ["questions"]); The nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize the role collection: com.securetest.app.entity.Exam.questions, failed to initialize the proxy - no session (via the link chain: java.util. ArrayList [ 0] → [com.securetest.app.entity.Exam "questions"])

DEBUG: org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returns to DispatcherServlet with the name "appServlet": it is assumed that the handler handler is the HandlerAdapter

DEBUG: org.springframework.web.servlet.DispatcherServlet - successfully completed request

I decided this quick way to just manually get the associated data while still in the transaction:

 @Override @Transactional(readOnly = true) public List<Exam> getAllExams() { List<Exam> exams = examDao.getAllExams(); for (Exam e : exams) { for (Question q : e.getQuestions()) { q.getAnswers().size(); } } return exams; } 

which allowed to successfully complete the request.

Hope this helps!

+6
source

Source: https://habr.com/ru/post/1484274/


All Articles