Announcement Announcement Module
Collapse
No announcement yet.
@ModelAttribute detached object binding from <form:form> tag has a problem with 3.1.1 Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @ModelAttribute detached object binding from <form:form> tag has a problem with 3.1.1

    After migrating to spring 3.1.0 from spring 3.0.5 hibernate save method is encountering problem with detached object - when trying to save new object with saveOrUpdate(Object obj) method where obj has no id.

    Here are the code samples and unimportant parts are omitted
    Domains:
    Code:
    @Entity
    @Table(name = "task")
    public class Task implements java.io.Serializable {
    
    	private Long id;
    	private Set<TaskComment> taskComments = new HashSet<TaskComment>(0);
    
    	@OneToMany(fetch = FetchType.LAZY, mappedBy = "task", cascade = CascadeType.REMOVE)
    	@OrderBy("date")
    	public Set<TaskComment> getTaskComments() {
    		return this.taskComments;
    	}
    
    }
    and the object I'm really trying to save is task_comment:

    Code:
    @Entity
    @Table(name = "task_comment")
    public class TaskComment implements java.io.Serializable {
    
    	private Long id;
    	private Task task;
    	private String content;
    	public TaskComment() {
    	}
    
    	@ManyToOne(fetch = FetchType.LAZY)
    	@JoinColumn(name = "task_id")
    	public Task getTask() {
    		return this.task;
    	}
    
    }
    Controller:
    Code:
           @RequestMapping(value="/{id}", method=RequestMethod.GET)
    	public String getDretail(@PathVariable("id") long id, Model model){
    		model.addAttribute("task", taskDao.find(id));
    		model.addAttribute("taskComment", new TaskComment());
    		return "task-detail";
    	}
    	
    	@RequestMapping(value="/{id}", method=RequestMethod.POST)
    	public String postComment(@PathVariable("id") long id, @ModelAttribute("taskComment") TaskComment taskComment, Model model){
    		Task task = taskDao.find(id);
    		taskComment.setUsers(securityService.getCurrentUser());
    		taskComment.setTask(task);
    		taskComment.setDate(new Date());
    	
    
    		taskCommentDao.saveOrUpdate(taskComment);
    
    		return "redirect:/dashboard/task/" + id;
    	}
    HibernateFilter extends which extends from OpenSessionInViewFilter:

    Code:
    public class HibernateFilter extends OpenSessionInViewFilter {
    
    	@Override
    	protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
    	Session session = SessionFactoryUtils.getSession(sessionFactory, true);
    	//set the FlushMode to auto in order to save objects.
    	session.setFlushMode(FlushMode.AUTO);
    	return session;
    	}
    
    	@Override
    	protected void closeSession(Session session, SessionFactory sessionFactory) {
    	try{
    	   if (session != null && session.isOpen() && session.isConnected()) {
    	try {
    	    session.flush();
    	}
    	catch (HibernateException e) {
    	throw new CleanupFailureDataAccessException("Failed to flush session before close: " + e.getMessage(), e);
    	}
    	catch(Exception e){
    	}
    	}
    	}
    	finally{
    	super.closeSession(session, sessionFactory);
    	}
    	}
    	}
    jsp exerpt:
    Code:
    <form:form modelAttribute="taskComment" method="post" cssClass="formFrm" style="padding:0;">
         <form:textarea path="content" cssStyle="width:99%;"/>
        <input id="submit-btn" type="submit" value="Add comment" class="buttons" style="float:right;margin:0;">							
    </form:form>
    Problem: overriding all the previous comments. In other words, Task domain contains only one taskComment after post which was the last entered. However, when I tried unit testing it had no problem, so I think it's the problem with @ModelAttribute binding.

    Work around:

    Code:
    public String postComment(@PathVariable("id") long id, @ModelAttribute("taskComment") TaskComment taskComment, Model model){
    
                    TaskComment taskComment2 = new TaskComment();
                    taskComment2.setContent(taskComment.getContent());
    		Task task = taskDao.find(id);
    		taskComment2.setUsers(securityService.getCurrentUser());
    		taskComment2.setTask(task);
    		taskComment2.setDate(new Date());
    
    		taskCommentDao.saveOrUpdate(taskComment2);
    		return "redirect:/dashboard/task/" + id;
    	}
    So I tried in multiple ways to get this working. I wrapped it in a transaction, played with the entity annotations... Only initializing new TaskComment then copying properties from bound taskComment then saving works fine.

    I could do this to all my objects but would really painful and ugly refactoring. Any ideas? Please, help.

    p.s I'm using hibernate 3.5.6-Final and spring security 3.1.0 and included pom file if it helps.

  • #2
    And the problem is, doesn't it save, do you get an exception what exactly?!

    Also not sure why you have your own HibernateFilter, flushing after execution isn't something I would do. In general such a "solution" is only to solve improper transaction management.

    Comment


    • #3
      Have you noticed what's actually different in the content of taskComment and taskComment2? I can't quite see what could could possibly cause it override all the other comments. Without knowing anything else about your controller, I would expect taskComment was created by calling its default constructor. Can you confirm if that's the case through a breakpoint or log statements?

      Comment


      • #4
        Sorry for not posting back that I figured out the problem.

        @PathVariable("id") long id
        was the problem. The new feature in 3.1 got me confused. Task ID was bound to TaskComment ID,
        Thanks for your replies

        Comment

        Working...
        X