java


Spring MVC complex bean binding


I have transfer object that contains two beans: Student and User.
#Entity
#Table(name = "student")
public class Student implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "middleName")
private String middleName;
#Column(name = "surname")
private String surname;
#ManyToOne
#JoinColumn(name = "idSpeciality")
private Speciality speciality;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Speciality getSpeciality() {
return speciality;
}
public void setSpeciality(Speciality speciality) {
this.speciality = speciality;
}
}
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "email")
private String email;
#Column(name = "password")
private String password;
#Transient
private String passwordConfirm;
#ManyToMany
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
private Set<Role> role;
public String getPasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
public Set<Role> getRole() {
return role;
}
public void setRole(Set<Role> roles) {
this.role = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Transfer object:
public class RegistrationTO implements Serializable{
private User user;
private Student student;
public RegistrationTO() {
user = new User();
student = new Student();
student.setSpeciality(new Speciality());
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
Also I have registration page with form:
<form:form method="POST" modelAttribute="registrationForm" commandName="registrationForm" class="col s12">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
<div class="row">
<div class="input-field col s12 ${status.error ? 'has-error' : ''}">
<i class="material-icons prefix">email</i>
<form:input type="email" path="user.email" class="validate"
placeholder="Email" id="loginInput" autofocus="true" />
<form:errors path="user.email"></form:errors>
<label for="loginInput">Email</label>
</div>
</div>
<div class="row">
<div class="input-field col s6 ${status.error ? 'has-error' : ''}">
<i class="material-icons prefix">vpn_key</i>
<form:input type="password" path="user.password" class="form-control"
placeholder="Пароль" id="passwordInput"></form:input>
<form:errors path="user.password"></form:errors>
<label for="passwordInput">Пароль</label>
</div>
<div class="input-field col s6 ${status.error ? 'has-error' : ''}">
<form:input type="password" path="user.passwordConfirm" class="form-control"
placeholder="Повторите пароль" id="secondPasswordInput"></form:input>
<form:errors path="user.passwordConfirm"></form:errors>
<label for="secondPasswordInput">Повторите пароль</label>
</div>
</div>
<div class="row">
<div class="input-field col s4 ${status.error ? 'has-error' : ''}">
<i class="material-icons prefix">account_circle</i>
<form:input type="text" path="student.surname" class="validate"
placeholder="Фамилия" id="stSurnameInput"></form:input>
<form:errors path="student.surname"></form:errors>
<label for="stSurnameInput">Фамилия</label>
</div>
<div class="input-field col s4 ${status.error ? 'has-error' : ''}">
<form:input type="text" path="student.name" class="validate"
placeholder="Имя" id="stNameInput"></form:input>
<form:errors path="student.name"></form:errors>
<label for="stNameInput">Имя</label>
</div>
<div class="input-field col s4 ${status.error ? 'has-error' : ''}">
<form:input type="text" path="student.middleName" class="validate"
placeholder="Отчество" id="stMiddleNameInput"></form:input>
<form:errors path="student.middleName"></form:errors>
<label for="stMiddleNameInput">Отчество</label>
</div>
</div>
<div class="input-field">
<i class="material-icons prefix">list</i>
<select name = "university" id="university">
<option value="" selected>Choose your option</option>
<c:forEach var="univer" items="${universities}">
<option value="${univer.id}">${univer.name}</option>
</c:forEach>
</select>
<label for="university">Выберите университет</label>
</div>
<div class="input-field">
<i class="material-icons prefix">list</i>
<select id="faculty">
<option value="" selected>Choose your option</option>
</select>
<label for="faculty">Выберите факультет</label>
</div>
<div class="input-field">
<i class="material-icons prefix">list</i>
<form:select path="student.speciality.id" id="speciality">
<option value="" selected>Choose your option</option>
</form:select>
<label for="speciality">Выберите специальность</label>
</div>
<button class="btn waves-effect waves-light right" type="submit" name="action">Принять
<i class="material-icons right">send</i>
</button>
</form:form>
Controller for get and post requests:
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public ModelAndView registration(#ModelAttribute("registrationForm") RegistrationTO registrationForm,
ModelMap modelMap) {
ModelAndView modelAndView = new ModelAndView("registrationTemplate");
if (registrationForm == null) {
registrationForm = new RegistrationTO();
}
modelAndView.addObject("registrationForm", registrationForm);
modelAndView.addObject("universities", universityService.getAllUniversities());
//modelAndView.addObject(BindingResult.MODEL_KEY_PREFIX + "registrationForm", modelMap.get("error"));
return modelAndView;
}
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(#ModelAttribute("registrationForm") RegistrationTO registrationForm,
BindingResult bindingResult,
RedirectAttributes attributes) {
User userForm = registrationForm.getUser();
Student studentForm = registrationForm.getStudent();
userValidator.validate(userForm, bindingResult);
/*if (bindingResult.hasErrors()) {
attributes.addFlashAttribute("error", bindingResult);
attributes.addFlashAttribute("userForm", userForm);
return "redirect:/registration";
}*/
userService.createUser(userForm);
securityService.autologin(userForm.getEmail(), userForm.getPasswordConfirm());
return "redirect:/index";
}
After filling fields, I click submit button and get next message:
"HTTP Status 500 - Request processing failed; nested exception is org.springframework.beans.NotReadablePropertyException: Invalid property 'email' of bean class [by.bsuir.ceres.bean.TO.RegistrationTO]: Bean property 'email' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?"
It looks like spring doesn't search properties in nested beans, but why?
Spring did support nested properties binding. In your jsp, you are missing spring bind tag in some places. Try something like this.
<form:form method="POST" modelAttribute="registrationForm" commandName="registrationForm" class="col s12">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
<spring:bind path="user.email">
<div class="row">
<div class="input-field col s12 ${status.error ? 'has-error' : ''}">
<i class="material-icons prefix">email</i>
<form:input type="email" path="user.email" class="validate"
placeholder="Email" id="loginInput" autofocus="true" />
<form:errors path="user.email"></form:errors>
<label for="loginInput">Email</label>
</div>
</div>
</spring:bind>
<div class="row">
<spring:bind path="user.password">
<div class="input-field col s6 ${status.error ? 'has-error' : ''}">
<i class="material-icons prefix">vpn_key</i>
<form:input type="password" path="user.password" class="form-control"
placeholder="Пароль" id="passwordInput"></form:input>
<form:errors path="user.password"></form:errors>
<label for="passwordInput">Пароль</label>
</div>
</spring:bind>
<spring:bind path="user.passwordConfirm">
<div class="input-field col s6 ${status.error ? 'has-error' : ''}">
<form:input type="password" path="user.passwordConfirm" class="form-control"
placeholder="Повторите пароль" id="secondPasswordInput"></form:input>
<form:errors path="user.passwordConfirm"></form:errors>
<label for="secondPasswordInput">Повторите пароль</label>
</div>
</spring:bind>
</div>
<div class="row">
<spring:bind path="student.surname">
<div class="input-field col s4 ${status.error ? 'has-error' : ''}">
<i class="material-icons prefix">account_circle</i>
<form:input type="text" path="student.surname" class="validate"
placeholder="Фамилия" id="stSurnameInput"></form:input>
<form:errors path="student.surname"></form:errors>
<label for="stSurnameInput">Фамилия</label>
</div>
</spring:bind>
<spring:bind path="student.name">
<div class="input-field col s4 ${status.error ? 'has-error' : ''}">
<form:input type="text" path="student.name" class="validate"
placeholder="Имя" id="stNameInput"></form:input>
<form:errors path="student.name"></form:errors>
<label for="stNameInput">Имя</label>
</div>
</spring:bind>
<spring:bind path="student.middlename">
<div class="input-field col s4 ${status.error ? 'has-error' : ''}">
<form:input type="text" path="student.middleName" class="validate"
placeholder="Отчество" id="stMiddleNameInput"></form:input>
<form:errors path="student.middleName"></form:errors>
<label for="stMiddleNameInput">Отчество</label>
</div>
</spring:bind>
</div>
<div class="input-field">
<i class="material-icons prefix">list</i>
<select name = "university" id="university">
<option value="" selected>Choose your option</option>
<c:forEach var="univer" items="${universities}">
<option value="${univer.id}">${univer.name}</option>
</c:forEach>
</select>
<label for="university">Выберите университет</label>
</div>
<div class="input-field">
<i class="material-icons prefix">list</i>
<select id="faculty">
<option value="" selected>Choose your option</option>
</select>
<label for="faculty">Выберите факультет</label>
</div>
<div class="input-field">
<i class="material-icons prefix">list</i>
<form:select path="student.speciality.id" id="speciality">
<option value="" selected>Choose your option</option>
</form:select>
<label for="speciality">Выберите специальность</label>
</div>
<button class="btn waves-effect waves-light right" type="submit" name="action">Принять
<i class="material-icons right">send</i>
</button>

Related Links

Does jspInit() run only once?
Reading standard input via command line java
Rendering multiple lines through click and unclick libgdx java
Separating variables/arrays from an expression, and deleting duplicates?
execution of task in java within specified time
Why Does (a) print (0)?
Get other query columns with Parse
Java create file if does not exist
Android google ads error (null reference ?)
BGN Implementation in Java
How can a Global Variable be recognize in two different window (Java Swing GUI)
Java socket stop reading from DataOutputStream
Errorchart.toURLString() in charts4j
How authenticate a rest call from behind a corporate proxy using Rest-Assured?
set path of JSESSIONID cookie created with HttpServletRequest.getSession(true)
Precision of double when dealing with whole numbers? Datatype to represent whole numbers of money? [duplicate]

Categories

HOME
openlayers
wso2-am
image
clips
asp.net-core
plone
stock
office365api
syntax
xmpp
framework7
baqend
ojdbc
yum
onelogin
multiple-records
volttron
spring-xd
n-gram
progressive-web-apps
code-review
scriptcs
excel-2007
wijmo
icloud-api
qhull
internet-explorer-9
traffic
fopen
linkerd
spring-mybatis
elasticsearch-ruby
exuberant-ctags
ioio
google-qpx-express-api
usbserial
webtest
geopositioning
rotational-matrices
streamreader
squib
glew
angular-resource
taffy
xml-documentation
jquery-validate
python-webbrowser
dandelion
datastax-startup
dropbox-php
carrot
forever
slickedit
pg-dump
redundancy
account-kit
pintos
url-pattern
ado.net-entity-data-model
home-directory
impresspages
gstreamer-0.10
blackberry-10
essence
associative-array
ford-fulkerson
python-3.2
0xdbe
ideamart
twirl
php-ci
sailfish-os
remobjects
angular-local-storage
pretty-print
googlemock
php-5.4
article
heisenbug
funcunit
seaside
ember-charts
mbr
mysqltuner
access-rights
jquery-mobile-dialog
frameset
datawindow
tridion-worldserver
viewswitcher
appconkit
inotifycollectionchanged
mysql-error-1005
floating
lang
digest-authentication
coda-slider
fixed-width
memory-size
swing-app-framework
zend-decorators
ugc
document-conversion

Resources

Database Users
RDBMS discuss
Database Dev&Adm
javascript
java
csharp
php
android
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App