Spring form not submitting - java

I am using Spring SimpleFormController for my forms and for some reason it won't go to the onSubmit method
Here's my code:
public class CreateProjectController extends SimpleFormController {
ProjectDao projectDao;
public CreateProjectController() {
setCommandClass(Project.class);
setCommandName("Project");
setSessionForm(true);
}
#Override
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
String id = request.getParameter("id");
Project project = projectDao.getProjectByOutsideId(id);
System.out.println("#formbacking object method");
System.out.println("the success view is "+getSuccessView());
return project;
}
#Override
protected ModelAndView onSubmit(Object command) throws Exception {
Project project = (Project) command;
System.out.println("this is the project title: "+project.getTitle());
System.out.println("the success view is "+getSuccessView());
projectDao.insert(project);
return new ModelAndView(getSuccessView());
}
I know because it prints "#formbacking object method" string but not the "the success view is..." string and the :"this is the pr..." string. I see "#formback.." string in the console but not the last two whenever I hit submit. I don't know where the problem is.
This is my jsp
<form:form method="POST" commandName="Project">
Name: <form:input path="title"/><br/>
Description: <form:input path="description"/><br/>
Link: <form:input path="url" disabled="true"/><br/>
Tags: <form:input path="tags"/><br/>
Assessors <form:input path="assessors"/><br/><br/>
<input type="submit" value="submit"/>
</form:form>
I am running on Google App Engine btw. Maybe the problem is there?
UPDATE: The problem seems to be with the formBackingObject method. When I removed it, the form now goes to the onSubmit when I click submit.
But I'd like to have values from of the command class from the database in my forms.
Another piece of code that doesn't work:
#Override
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
String id = request.getParameter("id");
Project projectFromConsumer = projectDao.getProjectByOutsideId(id);
Project project = new Project();
String title = projectFromConsumer.getTitle();
project.setTitle(title);
project.setUrl("projectUrl");
return project;
}
but this does work:
#Override
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
String id = request.getParameter("id");
Project projectFromConsumer = projectDao.getProjectByOutsideId(id);
Project project = new Project();
String title = projectFromConsumer.getTitle();
project.setTitle("projectTitle");
project.setUrl("projectUrl");
return project;
}
Now I am really confused. haha.

I was thinking along the same lines as axtavt. You are only going to have an id request parameter on updates, so you should add some code for creation forms:
FYI, formBackingObject requires a non-null object to be returned. To save some memory, you can have a final constant member variable that is the default return value. Your code satisfies this though since you're transferring objects, but I don't get why you're transferring data (creating an extra object) when you're not using a DTO. You could simply do this:
private final static Project PROJECT_INSTANCE = new Project();
static {
PROJECT_INSTANCE.setTitle("defaultProjectTitle");
}
#Override
protected Project formBackingObject(HttpServletRequest request) throws Exception {
String id = request.getParameter("id");
if(id == null || id.trim().length() == 0 || !id.matches("\\d+")) {
return PROJECT_INSTANCE;
}
return projectDao.getProjectByOutsideId(id);
}
You don't need a hidden id input field. You would use formBackingObject() for initializing the form input fields for updating (by navigating to page.jsp?id=111).

Look at the String id = request.getParameter("id");. There is no such field in your form, so probably you get an error there during submit process, maybe, getProjectByOutsideId returns null.
P.S. It's strange that your formBackingObject is executing when you press submit, it shouldn't if you really set setSessionForm(true).

Try turning the spring debugging up. It provides a lot of information, which can be helpful. Do this by editing the log4j.properties file.
log4j.logger.org.springframework=DEBUG
Have you added logging to make sure the formBackingObject is returning something?
System.out.println("#formbacking object method is returning: " + project);
It will make sure something is being returned. In general the formBackingObject should always return something.
EDIT:
Id is not being passed during submission in the snippet. Maybe it is during the load, e.g. /page.do?id=4, but it doesn't appear in the form.
Add <form:hidden path="id"/> to your form during on submit. Otherwise the id will not be a parameter and the getProjectByOutsideId will fail.

Related

How to perform validation on #RequestParam in Spring

I'm a newbie in java spring. I have checked for solutions online and I can't seem to get my hands on anything helpful.
I have a form that has been bound to an Entity, however, I have a field in that form that was not bound, which I receive as a requestParam.
So when the field is submitted I need to validate that parameter to ensure it's not empty.
#PostMapping("/store")
public String store(#Valid Quote quote,BindingResult result, Model model,#RequestParam(required=false) String [] tagsFrom) {
if(result.hasErrors()) {
model.addAttribute("jsontags", returnTagsAsJson(tagRepo.findAll()));
return "admin/quotes/create";
}
List<Tag> listtags = new ArrayList<Tag> ();
for(String tag : tagsFrom) {
Tag theTag = new Tag();
theTag.setTag(tag);
theTag.setCreatedAt(new Date());
theTag.setUpdatedAt(new Date());
if(tagRepo.findByTag(tag) == null) {
tagRepo.save(theTag);
}
listtags.add(tagRepo.findByTag(tag));
}
quote.setTags(listtags);
quoteRepo.save(quote);
return "redirect:/dashboard/quotes";
}
What I have tried;
I created a custom validation and added the annotation to the parameter but that gave an error "The annotation #EmptyArrayString is disallowed for this location"
public String store(#Valid Quote quote,BindingResult result, Model model,
#RequestParam(required=false) #EmptyArrayString String [] tagsFrom)
I have tried using #NotEmpty on the parameter which throws NullPointerException
I need a solution that allows me to display the error on the HTML form like this
<span th:if="${#fields.hasErrors('tags')}"
th:errors="${quote.tags}" class="errors">
</span>
So when the field is submitted I need to validate that parameter to ensure it's not empty.
,#RequestParam(required=false) String [] tagsFrom
By default, required is set to true. So, if the URL must have the param, you shouldn't do required=false.
String [] tagsFrom implies you expect a bunch of tag params. But, is it of the form http://localhost:xxx?param=1,2,3 or
http://localhost:xxx?param1=1&param2="stringvalue" ?
For the first one, you can have the mapping method as:
public String store(...#RequestParam List<String> param)
For the second one, you can do:
public String store(...#RequestParam Map<String,String> allQueryParameters)
You can then do your necessary validations.
Read more here

Object exists and can be used on JSP page but I don't know WHY it works

alright so this is a bit tricky to explain well but I will do my best and hopefully someone has an idea.
So this project in built using the Spring Framework. I did not write this code but a previous dev who is no longer here.
here is a snippet from the controller.
#RequestMapping(value = "/affidavit/{id}/{userid}", method = RequestMethod.GET)
public String getProgramAffidavit(#PathVariable("id")
Program program, #PathVariable("userid")Attendee attendee, Model model) {
model.addAttribute("affidavitDetailDtoTest",affidavitDetailDto);
return "affidavit/program_affidavit";
}
I won't bother with the code that constructs the affidavitDetailDto object for now as I don't think it is relevant.
so you will see that this adds an attribute called affidavitDetailDTO to the model.
then over on my view page which is a jsp page I have a form with a model attribute of "affidavitDetailDTO" and my related information.
so now is the part I don't understand. I click the 'submit' button and my page and the form posts and calls the following controller method.
#RequestMapping(value = "/affidavit", method = RequestMethod.POST)
public String post(AffidavitDetailDto affidavitDetail, HttpServletRequest request, HttpServletResponse response, Model model) {
String out;
if(request.getParameter("programID")!= null)
out = request.getParameter("programID");
else
return "redirect: " + request.getContextPath()+ "/home";
//Session Information Section
//gets a list of program sessions and assigns it to affidavitProgramSessions dto list
List<AffidavitProgramSessionDto> affidavitProgramSessions = affidavitDetail.getAffProgramSessionList();
//Iterates through list of session in affidavitProgramSessions
for (Iterator<AffidavitProgramSessionDto> iter = affidavitProgramSessions.listIterator(); iter.hasNext(); ){
//create AffidavitProgramSession DTO object and fill it with value from list
AffidavitProgramSessionDto session = iter.next();
//get the programs session ID and assign it to a string
String programSessionDetailId = session.getProgramSessionDetailId();
logger.debug("programSessionDetailId:: " + programSessionDetailId);
//if there was no program session id then remove the item from list
if(StringUtil.isBlank(programSessionDetailId)) {
iter.remove();
}else{
// set the program session detail from value in the program session detail repo found by program session ID
session.setProgramSessionDetail(psdRepo.findOne(UUID.fromString(programSessionDetailId)));
}
}
//End oF Session Information Section
out = "affidavit/summary";
return out;
}
now on the summary jsp page there is the following loop to spit out the results.
c:forEach items="${affidavitDetailDto.affProgramSessionList}" var="session">
so here is my issues.. how the hell is it working. where is that affidavitDetailDto object coming from?
it isn't the GET method in the controller adding it because I can rename the attribute and the summary page still works.
any ideas?
EDIT
Showing how affidavitDetailDto is created in controller.
in the class this is done
#Controller
public class AffidavitController extends BaseController {
private AffidavitDetailDto affidavitDetailDto;
then in the GET Request.
#RequestMapping(value = "/affidavit/{id}/{userid}", method = RequestMethod.GET)
public String getProgramAffidavit(#PathVariable("id") Program program, #PathVariable("userid")Attendee attendee, Model model) {
affidavitDetailDto = new AffidavitDetailDto();
List<AffidavitProgramSessionDto> affProgramSessionList = affidavitDetailDto.getAffProgramSessionList();
Set<ProgramSessionDetail> programSessionDetails = ps.getProgramSessionDetail();
if(programSessionDetails != null) {
for (ProgramSessionDetail programSessionDetail : programSessionDetails) {
AffidavitProgramSessionDto affidavitProgramSessionDto = new AffidavitProgramSessionDto();
AffidavitAttendeeTypeDetailDto affidavitAttendeeTypeDetailDto = new AffidavitAttendeeTypeDetailDto();
affidavitProgramSessionDto.setAffidavitAttendeeTypeDetailDto(affidavitAttendeeTypeDetailDto);
affProgramSessionList.add(affidavitProgramSessionDto);
}
}
model.addAttribute("affidavitDetailDto",affidavitDetailDto);
Also on the model attribute level.
#ModelAttribute
private void addAttributes(Model model) {
logger.debug("call addAttributes.....");
if(affidavitDetailDto != null && affidavitDetailDto.getAffProgramSessionList().size() != 0) {
logger.debug("add affidavitDetailDto to model......");
model.addAttribute("affidavitDetailDto", affidavitDetailDto);
}
If I change the line
model.addAttribute("affidavitDetailDto", affidavitDetailDto);
to be something like
model.addAttribute("testing1234", affidavitDetailDto);
then the affidavitDetailDto objects STILL work on the summary post page.
Edit 2
This is the form tag that the for each loop runs in.
<form:form acceptCharset="utf-8" method="POST" enctype="multipart/form-data" action="${CTX_PATH}/approvedProgram" modelAttribute="affidavitDetailDto" id="jpFormInput">
however.. I can change the modelAtttrbute to equal "Madeupnothing123" and the jsp page still functions as normal.. this is why I am so confused.

Bind Collection to Form - why is it not working?

Could someone please help me find out why my attempt to bind Collection to the form in Spring MVC is not working?
Here is how my object looks like -
public class TestObj {
private Integer testNumber;
private String home;
private String destination;
}
Here is my form object that contains list of above object -
public class TestForm {
private List<TestObj> testList;
//contains getter and setter for testList
}
In my controller, I have implemented formBackingObject method -
public class MyController extends SimpleFormController {
public MyController() {
setCommandClass(TestForm.class);
setCommandName("testForm");
}
protected Object formBackingObject(HttpServletRequest request) throws Exception {
if (isFormSubmission(request)) {
testForm = (TestForm) super.formBackingObject(request);
//THIS ALWAYS RETURNS NULL ON FORM SUBMISSION
List<TestObj> testList = testForm.getTestList();
} else {
//load initial data using hibernate. TestObj is hibernate domain object.
List<TestObj> testList = myService.findTestList();
testForm = new TestForm(testList);
}
return testForm;
}
Here is my JSP snippet -
<form:form commandName="testForm" method="post">
<c:forEach items="${testForm.testList}" var="testvar" varStatus="testRow">
<tr>
<td>
<form:hidden path="testList[${testRow.index}].home" />
<c:out value="${testvar.home}" />
</td>
<td>
<form:input path="testList[${testRow.index}].destination" />
</td>
</tr>
</c:forEach>
<tr><td><input type="submit"></td></tr>
</form:form>
While the first time I load the data shows up fine on the form, when I press submit button the control goes to the formBackingObject method and the isFormSubmission returns true. However, when I get the command object using super.formBackingObject(request), it returns the form object with the testList value as null. I am unable to figure out why this simple case is not working?
I will really appreciate any help in getting this to work.
Are you using Spring 3? If so, you should take a look at this post.
With respect to list processing and object binding, take a look at this post.
Try using the following code. May be that can solve your problem.
private List<TestObj> operationParameterses = LazyList.decorate(new ArrayList<TestObj>(), FactoryUtils.instantiateFactory(TestObj.class));
It won't return you all null list.
Hope that helps you.
Cheers.
I guess my understanding of formBackingObject method must be wrong. I removed that method from the implementation, used referenceData for initial form load and onSubmit to process it on submit. This works fine and does get collection in the form back as expected.
Thanks all for the help though.

What is the "correct" or "safe" way to update a persisted object with Spring MVC 3 + Hibernate?

Given a very simple object:
class User {
private Integer id;
private String name;
public User() {}
public Integer getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
and a very simple controller action:
#RequestMapping(value="/edit/{id}/**", method=RequestMethod.POST)
public String editFromForm(#PathVariable("id") Integer id, #Valid User user, BindingResult bindingResult, Model model) {
// If we have errors, don't save
if(bindingResult.hasErrors()) {
// Put what they did in the model and send it back
model.addAttribute(user);
return "users/edit";
} else {
userDAO.save(user);
}
// Show them the updated page on success
return "redirect:/users/" + user.getId() + "/" + user.getName();
}
and a very simple form:
<sf:form method="POST" modelAttribute="user">
<label for="user_name">Name:</label>
<sf:input path="name" id="user_name" />
<input type="submit" value="save" /><sf:errors path="name" cssClass="error" />
</sf:form>
How should I be updating the entity in the database? Currently (since saveOrUpdate() is the actual hibernate call behind my DAO's save() method, a new object is persisted instead of updating the existing one because the id field is not being set on the object created from the form submission.
A couple of possible solutions have come to me, but I am not sure which is best in terms of keeping things clean and also secure (so that a malicious user cannot just fire in edits to whatever object Id's they wish).
Insert the id from the URL parameter into the object coming from the model binder
Have a hidden id field in the form and let the model binder attach the id
In both of those cases, there is no check in place to make sure that the object is still the same one, such as a checksum of some sort. How do others deal with this? Are there any clear example that walk through this issue?
Another issue that comes up is that I'd rather not need a setId() method since Hibernate is managing all of the id's. From what I have been able to determine, the Spring MVC model binder can only bind a field if it has the expected getter and setter. Is there some other way to apply the new state, such as getting the current User from the db by the URL's id parameter and then applying the new state to it, but without having to explicitly code all of the field copies?
I am sure there is a fairly simple, straightforward way to handle this, but my heat-addled brain does not seem to be able to come up with a suitable solution.
I'm fairly new to Spring + Hibernate so forgive me if this is one of those mundane, highly covered topics, but I have not been able to find any clear example that covers my very simple situation. If this has been covered sufficiently elsewhere, please point me in the right direction.
A couple of possible solutions have come to me, but I am not sure which is best in terms of keeping things clean and also secure (so that a malicious user cannot just fire in edits to whatever object Id's they wish).
Neither of the two approaches you mention will really handle a user who is attempting to edit objects that the user is not authorized to. At the end of the day, the user submitting the form needs to tell you which object they are submitting data for - whether it is in the URL parameter or in a hidden form parameter. I would say which of the two you choose is a matter of style and personal preference, really.
But what you need to be doing regardless of choice is to verify that the currently-logged-in user is authorized to change the object when processing the form submission. This would mean you need to check that this user is entitled to edit the current object ID, using whatever logic comprises "is allowed to do this" for your application.
Still have the same User POJO
class User {
private Integer id;
private String name;
public User() {}
public Integer getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
#RequestMapping("/create/userCreate.do")
public String createUser(Model model) {
User user = new User();
model.addAttribute(user);
return "userCreate";
}
Here I don't send the Id or any parameter, just pass the User form model attribute
#RequestMapping(value="/edit/userEdit.do", method=RequestMethod.POST)
public String editFromForm(#ModelAttribute("user") #Valid User user, BindingResult bindingResult, Model model) {
// If we have errors, don't save
if(bindingResult.hasErrors()) {
// Put what they did in the model and send it back
model.addAttribute(user);
return "users/edit";
} else {
userDAO.saveOrUpdate(user);
}
// Show them the updated page on success
return "redirect:/users/" + user.getId() + "/" + user.getName();
}
Here, the User object is bind user name and id. If there is no Id then the object will be saved and if the user object already is having Id then it will be updated. You don't have to pass id or parameter and make it visible on the address bar. Sometimes I don't like the idea of showing parameters to the users. I hope that helps
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<head>
<title> User Edit
</title>
</head>
<body>
<form:form method="post" action="userEdit.do" commandName="user">
<form:hidden path="id" />
<form:label path="username">User name:</form:label>
<form:input path="username" type="text" maxlength="20" />
<form:errors path="username" />
</form:form>
</body>
</html>
Im a bit late, but maybe it will be useful to someone.
Today I solved the same problem. I think your problem was there:
} else {
userDAO.save(user);
}
If it was hibernate session save, then new id was generated each time it was called. I used
session.saveOrUpdate(user)
instead of
session.save(user)
I agree 100% on what #matt b says. I have worked with similar products where at the end of the day you don't have any way of knowing if the user is editing the right object. Your only option is to make sure the user is permitted to do so. If you have a user who is editing their profile then obviously they shouldn't be editting any other person.
Now the easiest way to do what you are trying to do is actually niether. YOu don't want to use the url or hidden attributes. YOu should be able to use #ModelAttribute to do this. Here is an example
#RequestMapping(method = RequestMethod.GET)
public ModelAndView setupForm(#RequestParam("petId") int petId) {
User user = ...
model.addAttribute("user", user);
return model;
}
Then you should be able to do
#RequestMapping(method = RequestMethod.POST)
public ModelAndView submit(#ModelAttribute("user") User user) {
...
}
There is no setters or hidden fields. All the loading and binding is handled via Spring. More documentation here.

Spring MVC, generating a form backing object from a request?

I am using Spring MVC 2.5, and I am trying to get a JSTL form object to load from a GET request. I have Hibernate POJOs as my backing objects.
There is one page directing to another page with a class id (row primary key) in the request. The request looks like "newpage.htm?name=RowId". This is going into a page with a form backing object,
The newpage above, loads the fields of the object into editable fields, populated with the existing values of the row. The idea is, that you should be able to edit these fields and then persist them back into the database.
The view of this page looks something like this
<form:form commandName="thingie">
<span>Name:</span>
<span><form:input path="name" /></span>
<br/>
<span>Scheme:</span>
<span><form:input path="scheme" /></span>
<br/>
<span>Url:</span>
<span><form:input path="url" /></span>
<br/>
<span>Enabled:</span>
<span><form:checkbox path="enabled"/></span>
<br/>
<input type="submit" value="Save Changes" />
</form:form>
The controller has this in it,
public class thingieDetailController extends SimpleFormController {
public thingieDetailController() {
setCommandClass(Thingie.class);
setCommandName("thingie");
}
#Override
protected Object formBackingObject(HttpServletRequest request) throws Exception {
Thingie thingieForm = (Thingie) super.formBackingObject(request);
//This output is always null, as the ID is not being set properly
logger.debug("thingieForm.getName(): [" + thingieForm.getName() + "]");
//thingieForm.setName(request.getParameter("name"));
SimpleDAO.loadThingie(thingieForm);
return thingieForm;
}
#Override
protected void doSubmitAction(Object command) throws Exception {
Thingie thingie = (Thingie) command;
SimpleDAO.saveThingie(thingie);
}
}
As you can see from the commented code, I've tried manually setting the object id (name is this case) from the request. However Hibernate complains about the object being desynched when I try and persist the data in the form.
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
This error seems to do something to the entire session, which stops working for my entire web application, continually throwing the Stale Object State Exception seen above.
If anyone familiar with Spring MVC can help me with this or suggest a workaround, I would really appreciate it.
EDIT:
Session factory code.
private static final SessionFactory sessionFactory;
private static final Configuration configuration = new Configuration().configure();
static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml)
// config file.
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
One of the major flaws with using Spring MVC + hibernate is that the natural approach is to use the hibernate domain object as the backing object for the form. Spring will bind anything in the request based on name by DEFAULT. This inadvertently includes things like ID or name (usually the primary key) or other hibernate managed properties being set. This also makes you vulnerable to form injection.
In order to be secure under this scenario you must use something like:
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception {
String[] allowedFields = {"name", "birthday"}
binder.setAllowedFields(allowedFields);
}
and EXPLICITLY set the ALLOWED fields to only those in your form, and exclude the primary key or you will end up with a mess!!!
To answer your immediate question, the problem you are having with Hibernate has to do with the following sequence of events:
One Hibernate session is opened (let's call it session A) in formBackingObject
Using session A, you load a Thingie object in formBackingObject
You return the Thingie object as the result of formBackingObject
When you return the Thingie object, session A is closed, but Thingie is still linked to it
When doSubmitAction is called, the same instance of the Thingie backing object is passed as the command
A new Hibernate session (call it session B) is opened
You attempt to save the Thingie object (originally opened with session A) using session B
Hibernate doesn't know anything about session A at this point, because it's closed, so you get an error. The good news is that you shouldn't be doing it that way, and the correct way will bypass that error completely.
The formBackingObject method is used to populate a form's command object with data, prior to showing the form. Based on your updated question, it sounds like you are simply trying to display a form populated with information from a given database row, and update that database row when the form is submitted.
It looks like you already have a model class for your record; I'll call that the Record class in this answer). You also have DAO for the Record class, which I will call RecordDao. Finally, you need a UpdateRecordCommand class that will be your backing object. The UpdateRecordCommand should be defined with the following fields and setters/getters:
public class UpdateRecordCommand {
// Row ID of the record we want to update
private int rowId;
// New name
private int String name;
// New scheme
private int String scheme;
// New URL
private int String url;
// New enabled flag
private int boolean enabled;
// Getters and setters left out for brevity
}
Then define your form using the following code:
<form:form commandName="update">
<span>Name:</span>
<span><form:input path="name" /></span><br/>
<span>Scheme:</span>
<span><form:input path="scheme" /></span><br/>
<span>Url:</span>
<span><form:input path="url" /></span><br/>
<span>Enabled:</span>
<span><form:checkbox path="enabled"/></span><br/>
<form:hidden path="rowId"/>
<input type="submit" value="Save Changes" />
</form:form>
Now you define your form controller, which will populate the form in formBackingObject and process the update request in doSubmitAction.
public class UpdateRecordController extends SimpleFormController {
private RecordDao recordDao;
// Setter and getter for recordDao left out for brevity
public UpdateRecordController() {
setCommandClass(UpdateRecordCommand.class);
setCommandName("update");
}
#Override
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
// Use one of Spring's utility classes to cleanly fetch the rowId
int rowId = ServletRequestUtils.getIntParameter(request, "rowId");
// Load the record based on the rowId paramrter, using your DAO
Record record = recordDao.load(rowId);
// Populate the update command with information from the record
UpdateRecordCommand command = new UpdateRecordCommand();
command.setRowId(rowId);
command.setName(record.getName());
command.setScheme(record.getScheme());
command.setUrl(record.getUrl());
command.setEnabled(record.getEnabled());
// Returning this will pre-populate the form fields
return command;
}
#Override
protected void doSubmitAction(Object command) throws Exception {
// Load the record based on the rowId in the update command
UpdateRecordCommand update = (UpdateRecordCommand) command;
Record record = recordDao.load(update.getRowId());
// Update the object we loaded from the data store
record.setName(update.getName());
record.setScheme(update.getScheme());
record.setUrl(update.getUrl());
record.setEnabled(update.setEnaled());
// Finally, persist the data using the DAO
recordDao.save(record);
}
}
Your issue may be related to Detached Objects. Because your DAO has been modified outside a Hibernate session, you need to reattach the object to the Hibernate session before saving. You can do this either by explicitly bringing the object into the session before saving using Merge() or update(). Experiment with both, and read the documentation for those actions, as they have different effects depending on the structure of your data objects.
What was going on is that the ?name=rowId was somehow messing up the form post. Once I changed that to a name that didn't reflect a parameter in the object, everything worked fine. No change to the DAO or controller code necessary.
Thanks to everyone for your answers. It helped me narrow down what was going on.

Categories