I keep getting an error 500 from Tomcat when I return a list of entities from my service layer in Spring. If I just make the entities on the fly in memory I don't get the error and they return fine, so it's something to do specifically with the 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 gets invoked, tomcat displays a error 500 and no stack trace at all. I've even wrapped it in a try catch and nothing appears in that stacktrace.
This service just calls a dao...
@Service("examService")
public class ExamServiceImpl implements ExamService{
@Autowired
private ExamDao examDao;
@Override
@Transactional(readOnly = true)
public List<Exam> getAllExams() {
return examDao.getAllExams();
}
And this 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();
}
Originally, I thought it was something to do with the entities being lazy loaded, my entities are below as you can see, they're 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 entity
@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;
}
}
Answer entity
@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'm using Jackson 2.2.0 - now the following code works fine, so it's definitely some issue with either the joins (which were originally lazy loaded but removed 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's nothing in the Tomcat logs - how can I force some sort of stacktrace? Hibernate version = 4.1.10.Final, Spring version 3.1.4.