Results 1 to 4 of 4

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

  1. #1
    Join Date
    Jun 2011
    Posts
    16

    Default @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.
    Attached Files Attached Files

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    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.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3
    Join Date
    Aug 2006
    Location
    Brooklyn
    Posts
    556

    Default

    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?

  4. #4
    Join Date
    Jun 2011
    Posts
    16

    Default

    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

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •