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

org.springframework.batch.item.file.FlatFileParseException:
Running Test Groups in same class parallel
How to make a number triangle java
What difference will static methods in a JAX-RS class make?
Json parsing error using Java
How to import gradle project into STS 3.7.2
How to run cbioportal tomcat war using heroku's webapp-runner.jar
Looking to write info to a file using print writer from button inputs on a simple GUI application
I cannot understand the purpose of using and not using “void”,(what does returning a value mean?" [duplicate]
How to remove “org.restlet.engine.application.StatusInfo” on JSON response
How to print stack trace without error occurance
LibGDX: Problems with getting Bounds
Timeout logs in Rivr Dialogues
freemarker template syntax spring boot
Generate ranges from list of values
Distribute Software Tokens using RSA SecurID API/SDK for JAVA

Categories

HOME
cakephp
testing
hive
gerrit
amazon-ec2
keras
server
angular-material
stock
android-4.4-kitkat
electronics
jgroups
ckeditor
retrofit
autotools
primary-key
session-variables
dacpac
quickbooks
iron-router
jsprit
clojurescript
libtiff
grails3
jasonette
jndi
icloud-api
cas
chromebook
assistant
atlassian-crucible
nat
stormpath
http-status-code-503
exuberant-ctags
ioio
jspresso
pim
uiswipegesturerecognizer
form-data
rotational-matrices
wallpaper
google-api-nodejs-client
mmenu
dartium
automake
espeak
hue
ensembles
galen
elmah
spring-security-kerberos
arena-simulation
gpx
reactive-cocoa-5
babel-core
dotcover
chain-builder
nativeapplication
nsarray
boost-preprocessor
nbconvert
orthogonal
angular-strap
xcb
google-feed-api
master-slave
jfugue
r-tree
teamcity-8.0
t4mvc
wireshark-dissector
mono-embedding
angular-local-storage
inmobi
lustre
umbraco6
geonetwork
xcode-6.2
device-manager
jboss-weld
multiprocessor
mysqltuner
dataadapter
sqlperformance
lcs
specification-pattern
typoscript2
transactionscope
qt-jambi
psi
hamachi
netbeans-7.1
imac
visitor-statistic
perfect-hash
firefox-5
microsoft-virtualization
mediarss
defensive-programming
django-notification
uiq3

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App