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.
Related
Heyy,
I want to take a list of data in my request param,here "personIdCollection" is a set of list but when i am hitting through postman i am getting a bad request.
Here is my code.
controller
#PostMapping("/face-tag-data")
public String getFaceTaggedData(#RequestParam String projectId,#RequestParam List<String> personIdCollection) {
return null;
}
and here is my ajax
var data = {};
data.personIdCollection = personIdCollection;
data.projectId = $("#projectId").val();
$.ajax({
type:'POST',
url:contextPath+'/face-tag-data',
data:data,
success:function(resp){
console.log(resp);
},
failure:function(resp){
console.log(resp);
}
});
This is working for me. I do not use an ajax-request but instead submit my form directly but it should work either way.
My controller looks like:
#RequestMapping(value="addSingleArticles", method=RequestMethod.POST)
public #ResponseBody String addSingleArticles(
ArticleSubmitData pupilPackageData,
HttpServletRequest request) {
... // do something with the data
}
As you can see I have defined my own composite type which consists of three lists. So you obviously can use it with only one list directly.
public class ArticleSubmitData {
private List<Article> singleArticles;
private List<Article> packageArticle;
private List<Article> popupArticles;
... // getter & setter, inner classes etc.
}
In my server page oder faclet I use the following html-code to make this work
...
<input id="" class="" type="text" name="singleArticles[${line.index}].engraving" />
...
So the trick is to define the variables on your webpage as an array and use this in your controller as a list. As you can see in my example I also use an inner class in my composite class which has extra attributes.
I'm trying to create a list of objects from form inputs. The objects are the same but their values may differ, it's essentially a menu.
I'm still getting to grips with Spring/Thymeleaf which is adding some level of complexity to what feels like a simple task.
I've a class for the menu, a simple POJO, there is then a list of these defined as a data member in the bean itself:
private ArrayList<GuestMenuOptions> guestMenus;
I've read many posts, tried many things and am on the verge of softly resting my head against the table.
I've had several errors, most of which either tell me that the list cannot be found or that the list is empty - it's currently in stable condition where the list, no matter what I try, will not be populated, even when I load in default values...unfortunately my debugger has died which is not helping.
Any help is appreciated. thank you
EntryController:
#RequestMapping(method=RequestMethod.GET, value="/")
public String indexPage(Model model) {
model.addAttribute("childMenuOptions", generateChildMenus());
//not sure if this is neccesary...
ArrayList<GuestMenuOptions>guestMenus = new ArrayList<>();
GuestMenuOptions ad1 = new GuestMenuOptions();
GuestMenuOptions ad2 = new GuestMenuOptions();
guestMenus.add(ad1);
guestMenus.add(ad2);
GuestContactBean ctb = new GuestContactBean();
ctb.setGuestMenus(guestMenus);
model.addAttribute("guestContactBean", ctb);
model.addAttribute("formBackingBean", new FormBackingBean());
return "index";
}
Form:
<form modelAttribute="guestBean" class="contact_form" name="rsvp" role="form" th:object="${formBackingBean}" th:action="#{/sendRsvp}" method="post">
<div class="row">
<div class="form-group">
<select name="ad1Starter" id="starterMealAdult1">
<option value="!!!">-Starter-</option>
<option th:field="${guestContactBean.guestMenus[0].starter}" th:each="entry : ${adultMenuOptions.get('starter').entrySet()}" th:value="${entry.key}" th:text="${entry.value}">
</option>
</select>
</div>
<input type="submit"guest name="submit" class="btn default-btn btn-block" value="Send RSVP">
RequestController:
#RequestMapping(value = "/sendRsvp", method = RequestMethod.POST)
public String sendRsvp(#ModelAttribute("guestContactBean") GuestContactBean guestContactBean,
#ModelAttribute("guestMenus") ArrayList<GuestMenuOptions>menus,
BindingResult result) throws MessagingException {
smtpMailSender.send(guestContactBean);
return "thanksMessage";
}
Beans:
FormBacking is POJO with no reference to the menus at all.
GuestMenuOptions is the same with just starter, desert members
guestContactbean has not much more going on, basic fields with the addition of the list of GuestMenuOptions
private String numberOfAdults;
private String eventAttending;
private ArrayList<GuestMenuOptions> guestMenus;
public ArrayList<GuestMenuOptions> getGuestMenus() {
return guestMenus;
}
EDIT:
The field that populates the drop downs in working fine, it's declared as private Map<String, Map<String, String>> adultMenuOptions;
private Map<String, Map<String, String>> childMenuOptions;
they are then built in the controller so that each may have several options under 'starter', 'main' and desert' for example:
starter.put("salmon", "Smoked Salmon");
starter.put("pate", "Chicken Liver Pate");
this is then populating both the value and text of the dropdown.
If I could save the state of this Map and pass it back to the controller instead, that would also be fine but I wasn't able to why then spawned the creation of the there wrapper list.
Please revisit http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dropdownlist-selectors. It should be as simple as
class Animal {
int id;
String name;
}
then in your template:
<select th:field="*{animalId}">
<option th:each="animal : ${animals}"
th:value="${animal.id}"
th:text="${animal.name}">Wireframe</option>
</select>
I think your code is all over the place and you're mixing up menu selection with menu item types.
Is it possible to wrap an object which contain some String and a List of another object as property from requst in spring mvc?
My classes are :
public class MyObj {
private String ma;
private String mb;
private List<SecObj> mc;
}
and:
public class SecObj {
private String sa;
private String sb;
}
I want to get an object of MyObj from the request.
In my JSP
<form:form action="" method="POST" commandName="myObj" >
<form:input path="ma" />
<form:input path="mb" />
.........
3 or 4 mc
..........
</form:form>
If it is possible then
what should i write int <form:input path="?" /> path?
how i receive it in the request parameter #RequestParam ?
If it not possible at once then
please tell me an good way to wrap this type of one to many relationship from request parameter
Regarding the list, take a look at this issue: Spring MVC : List<E> need to pass as command object . The example shows that you can then fill in each field of SecObj individually, assuming SecObj has a public default constructor.
You could also register a formatter for SecObj to allow Spring to silently convert a whole user input String to SecObj. See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#format-configuring-formatting-mvc for details.
Below is the request attribute set in struts action
ArrayList<HistoryTeardownHeader> list = new ArrayList<HistoryTeardownHeader>();
// add values to list
request.setAttribute("tdbList",list);
Below i have shown how i am getting the list.I am not able to get the value weldtype from this line of code
<c:forEach var="post" items="${requestScope.tdbList}">
<c:out value="${ post.weldType}"></c:out>
<html:hidden property="currentWeld" value="${post.weldType}"/>
</c:forEach>
The below bean is declared in the HistoryTeardownHeader class.
private String weldType;
public String getWeldType() {
return weldType;
}
public void setWeldType(String weldType) {
this.weldType = weldType;
}
Sorry Guys!
The weldType property didnt fetch the value from DB correctly so it didnt reflect correctly.
So the EL code given above is actually correct and working fine!
I'm trying to get some validators working with Spring 3. I keep getting an error:
org.springframework.beans.NotReadablePropertyException: Invalid property 'name' of bean class [java.lang.String]: Bean property 'name' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
My question is, is this what that error referring to. I believe that in the rejectValue method, it is calling getName() on myobj. Is it saying that myobj.getName() does not exist? Because I can tell you it does. Otherwise this method would not even compile.
public void validate(Object target, Errors errors) {
MyObject myobj = (MyObject)target;
String name = myobj.getName();
if(name.length() >100 || name.length() < 10) {
errors.rejectValue("name", "fieldLength");
}
}
Here is MyObject:
public class MyObject {
public MyObject() {
super();
// TODO Auto-generated constructor stub
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And in my jsp:
<form:form name="MyForm" commandName="myobj" method="post" action="${testurl}">
<table id="mytable" width="100%">
<tbody>
<tr>
<td colspan="2">
<form:errors path="name"/>
</td>
</tr>
<tr>
<td>
Name:
</td>
<td>
<form:input path="name"/>
</td>
</tr>
</tbody>
</table>
My controller:
#ActionMapping(params="myaction=test")
public void test(#ModelAttribute("myobj") MyObject myobj, BindingResult bindingResult,
ActionRequest request, ActionResponse response, SessionStatus sessionStatus) {
}
testValidator.validate(myobj, bindingResult);
if (!bindingResult.hasErrors()) {
response.setRenderParameter("myaction", "nextpage");
} else {
response.setRenderParameter("myaction", "test");
}
}
This is most likely telling you that some EL expression is failing, because Spring cannot figure out what the type of the 'name' property is based on the getter/setter signatures. If you showed us the declaration of (all of) the getters and setters for 'name', maybe we can be more specific.
Annoyingly, it seems like the code was right the whole time. I finally ran maven clean and then rebuilt and redeployed, along with clearing all cache, etc, and now it is working with that code. I am going to modify it to try to get something closer to what I actually want to happen (nested validations) and see where I get with that.
I guess your problem has nothing to do with validation per se. I can only suspect that the code you're pasting is not your exact example, but a hand-made one inspired by the code really executed.
There has to be some basic problem with MyObject property name. My personal guess is that the getter is defined in the super class of MyObject and only the setter is re-defined (or overriden) in the MyObject class.
Anyway, the best advice I can have for you is to try to extract a minimal example of your code and try to run it. Even if for some reasons you can't share the example with us, that will make it easier for you to find the reason of your troubles.
This happened to me with a Spring Validator that kept complaining about two unreadable properties on my domain POJO. One was a java.lang.Boolean, the other was a java.lang.Integer and they both had proper JavaBeans conventional getters and setters.
After some digging around I discovered I initialized the Boolean property with:
#Value("T{Boolean.FALSE}")
and the Integer property with:
#Value("0")
This was residue of a previous instructional project. Anyway, once removed, those annoying unreadable property errors ceased and the validator started doing it's job.