Non bean property throwing Bean property is not readable or has an invalid getter method - spring-boot

So my issue is a bit different from others. The error that it is throwing is not a field name but rather the input in a form. I've never encountered this error before
Error. The contents of '' is what I key for password
org.springframework.beans.NotReadablePropertyException: Invalid
property 'Yijian#123' of bean class [com.Alex.UserPackage.User]: Bean
property 'Yijian#123' is not readable or has an invalid getter method:
Does the return type of the getter match the parameter type of the
setter? at
org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:622)
~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE] at
org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:612)
~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE] at
org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:104)
~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
Entity class
#Entity
#ValidPassword
public class User {
#Pattern(regexp="[a-zA-Z]+", message = "Enter letters only!")
private String firstName;
#Pattern(regexp="[a-zA-Z]+", message = "Enter letters only!")
private String lastName;
private String password;
private String matchingPassword;
private String passportNumber;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMatchingPassword() {
return matchingPassword;
}
public void setMatchingPassword(String matchingPassword) {
this.matchingPassword = matchingPassword;
}
}
#ValidPassword custom annotation. The error started to occur after I used the getters for password and matchingPassword
private String message;
#Override
public boolean isValid(User user, ConstraintValidatorContext context) {
String password = user.getPassword();
String matchingPassword = user.getMatchingPassword();
if (password== null || matchingPassword == null) {
return false;
}
System.out.println("PASSWORDS: " + password + matchingPassword);
boolean flag = Pattern.matches("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{8,}$", password);
boolean flag1 = password.equals(matchingPassword);
if ( !flag1 ) {
message = "Passwords do not match!";
}
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(password).addConstraintViolation();
return flag && flag1;
}
//Show default message if no special message is set
#Override
public void initialize(ValidPassword validPassword) {
message = validPassword.message();
}
Form password portion
<div class = "row">
<div class="col-sm-6 form-group">
<label>Password : </label> <Input type="password"
th:field="*{password}" th:required="required" class="form-control" />
<p th:if="${#fields.hasErrors('password')}"
th:errors="*{password}" class="alert alert-danger"></p>
</div>

You are passing the property value instead of the property name to addPropertyNode(password).
Replace the following:
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(password).addConstraintViolation();
with:
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode("password").addConstraintViolation();

Related

Annotation #AssertTrue is not working properly

My poblem is connected with #AssertTrue annotation and some how with Thymeleaf. Actualy I should scheck password for the equality on a registration web page, for this I hava a parameters in my Registrartion Form class, they are Name,password, check_password,check_password_condition, adress. Actually I have made several changes in y code since I have aske my question here. I have used equals() method instead of == and acording this post
Spring validation #AssertTrue
have set a validation property boolean check_password_condition but my code still does not work. This way I use Errors interface to ask my page for validation rules. I think that using of the annotation #AssertTue for my method sould automatically call my method isCheckpassword() from RegistrationForm class and then in #PostMapping method of the Controller asked for the validation rule this.password.equals(this.check_password)
Am I right or not????
#AssertTrue(message = "{RegistrationForm.check_password.AssertTrue}")
public boolean isCheckpassword(){
if(this.password.equals(this.check_password)){
return this.check_password_condition=true;
}
else return this.check_password_condition=false;
}
#PostMapping("/register")
String registerNew(#Valid RegistrationForm form, Errors result) {
if (result.hasErrors()) {
return "register";
}
customerManagement.createCustomer(form);
return "redirect:/";
}
But I get whitepage error when the conditions for the creating new user are not met.
here additionally I provide my Thymeleaf code:
<div class="field">
<label th:text="#{register.check_password}" for="check_password">Repasswort</label>
<input id="check_password" name="check_password" th:field="*{check_password}" th:errorclass="fieldError" type="password"
required="required"/><br/>
<p th:if="${#fields.hasErrors('check_password')}" th:errors="*{check_password}">Das Passwort darf
nicht leer sein.</p>
</div>
This is my Registration From class
class RegistrationForm {
#NotEmpty(message = "{RegistrationForm.name.NotEmpty}") //
private final String name;
#Size(min = 2, max = 14, message = "{RegistrationForm.password.Size}")
#NotEmpty(message = "{RegistrationForm.password.NotEmpty}") //
private final String password;
#NotEmpty(message = "{RegistrationForm.check_password.NotEmpty}") //
private String check_password;
private boolean check_password_condition;
#NotEmpty(message = "{RegistrationForm.address.NotEmpty}") // s
private final String address;
public RegistrationForm(String name, String password,String check_password, String address) {
this.name = name;
this.password = password;
this.check_password=check_password;
this.address = address;
}
#AssertTrue(message = "{RegistrationForm.check_password.AssertTrue}")
public boolean isCheckpassword(){
if(this.password.equals(this.check_password)){
return this.check_password_condition=true;
}
else return this.check_password_condition=false;
}
//return this.password != null && this.password.equals(this.check_password) : this.setCheck_password(); }
public String getName() {
return name;
}
public String getPassword() { return password; }
public String getCheck_password(){return check_password;}
public String getAddress() {
return address;
}
}
Please help to solve this problem when
error info from Whitelabel errorpage is:
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#fields.hasErrors('*')" (template: "register" - line 29, col 42)
at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290)
at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166)
at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138)
at org.thymeleaf.standard.expression.Expression.execute(Expression.java:125)
It may not fully solve your issue, but looks like your String comparison is incorrect, as you shouldn't use ==.
Instead, use the String#equals() method or even Objects.equals(). This answer provider a great explanation on this.
Here's what your code can be like:
#AssertTrue
public boolean checkPasswod() {
return Objects.equals(check_password, password);
}

Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

I have a error when I try to insert a user in the database.
I made i custom annotation which verify if the password match with the confirmation password it works when the field not matches , but when the passowrd matches i have this error :
This is my code This is my field match #Annotation :
package mereuta.marian.tennis01.annotations;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Constraint(validatedBy = FieldsValueMatchValidator.class)
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface FieldsValueMatch {
String message() default "Fields values don't match!";
String field();
String fieldMatch();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#interface List {
FieldsValueMatch[] value();
}
}
This is the Field Validator :
package mereuta.marian.tennis01.annotations;
import mereuta.marian.tennis01.model.Utilisateur;
import org.springframework.beans.BeanWrapperImpl;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldsValueMatchValidator implements ConstraintValidator<FieldsValueMatch , Object> {
private String field;
private String fieldMatch;
#Override
public void initialize(FieldsValueMatch fieldsValueMatch) {
this.field=fieldsValueMatch.field();
this.fieldMatch=fieldsValueMatch.fieldMatch();
}
#Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
Object fieldValue = new BeanWrapperImpl(value)
.getPropertyValue(field);
Object fieldMatchValue = new BeanWrapperImpl(value)
.getPropertyValue(fieldMatch);
if (fieldValue != null) {
return fieldValue.equals(fieldMatchValue);
} else {
return fieldMatchValue == null;
}
}
}
This is my Entity :
#FieldsValueMatch(field = "password", fieldMatch = "confirmPassword",
message = "Password do not match!")
#Entity(name = "utilisateurs")
public class Utilisateur {
#Id #GeneratedValue
#Column(name = "id_utilisateur")
private Integer id;
#NotNull
#Size(min = 4, max = 255)
#Column(name = "password")
private String password;
#Transient
#NotNull
private String confirmPassword;
This is the Controller :
#PostMapping("/addUtilisateur")
public String addUtilisateur(#Valid #ModelAttribute("utilisateur") Utilisateur utilisateur, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors() ) {
model.addAttribute("message", "le mot de passe ne correspond pas");
return "utilisateur/formRegister";
}
utilisateurMetier.creerUtilisateur(utilisateur);
return "utilisateur/utilisateurAjoute";
}
And finally the View :
<div class="container">
<form id="contact" th:action="#{addUtilisateur}" method="post" th:object="${utilisateur}">
<h3>Créer compte</h3>
<input placeholder="password" type="password" th:field="*{password}" tabindex="2" required/>
<span class="text text-danger" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span>
</fieldset>
<fieldset>
<input placeholder="password" type="password" th:field="*{confirmPassword}" tabindex="2" required/>
<span class="text text-danger" th:if="${#fields.hasErrors('confirmPassword')}"
th:errors="*{confirmPassword}" th:text="${message}"></span>
</fieldset>
For the custom annotations I find a example on : https://www.baeldung.com/spring-mvc-custom-validator
#Override
public void creerUtilisateur(Utilisateur utilisateur) {
Role role;
float credit = 0;
boolean actif = true;
role = roleRepository.getOne(3);
System.out.println(role);
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
utilisateur.setPassword(encoder.encode(utilisateur.getPassword()));
utilisateur.setRole(role);
utilisateur.setCredit(credit);
utilisateur.setActif(actif);
utilisateurRepository.save(utilisateur);
}
Thank you in advance for your help
As already mentioned the ContraintViolationException is thrown inside the 'creerUtilisateur' method. So the validation of your Utilisateur bean at the time it's passed to your Spring MVC controller method (addUtilisateur(#Valid #ModelAttribute("utilisateur")...) works correctly when both fields (password, confirmPassword) have the same value. Later, you encode the password and change the value of your Utilitsateur's 'password' instance variable:
utilisateur.setPassword(encoder.encode(utilisateur.getPassword()));
Now, 'password' and 'passwordConfirm' are not equal anymore! When persisting this entity in utilisateurRepository.save(utilisateur); JPA will again bean-validate your entity before saving it to database (pre-persist). The validation gets automatically executed when JPA/Hibernate triggers a pre-persist, pre-update or pre-remove lifecycle event. And then the ContraintViolationException is thrown!
In your creerUtilisateur method simply set the encoded password for both, 'password' and 'passwordConfirm', instance variables and hereby ensure that they still pass your equality check in FieldsValueMatchValidator.isValid(Object value, ConstraintValidatorContext context):
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
final String encodedPassword = encoder.encode(utilisateur.getPassword());
utilisateur.setPassword(encodedPassword);
utilisateur.setPasswordConfirm(encodedPassword);
//...
utilisateurRepository.save(utilisateur);
You could also try to customize JPA's bean validation behaviour:
https://www.thoughts-on-java.org/automatically-validate-entities-with-hibernate-validator/
Disable Hibernate validation for Merge/Update

Failed to convert property value of type 'java.lang.String'

What am I doing wrong here?
<select th:field="*{role}">
<option value="#" disabled="disabled" selected="selected">Role...</option>
<option th:each="r : ${roles}" th:value="${r}" th:text="${r.name}">Developer</option>
</select>
I am getting this error:
Field error in object 'collaborator' on field 'role': rejected value
[33]; codes
[typeMismatch.collaborator.role,typeMismatch.role,typeMismatch.com.imprender.instateam.model.Role,typeMismatch];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable:
codes [collaborator.role,role]; arguments []; default message [role]];
default message [*Failed to convert property value of type
'java.lang.String' to required type
'com.imprender.instateam.model.Role' for property 'role'*; nested
exception is java.lang.IllegalStateException: Cannot convert value of
type 'java.lang.String' to required type
'com.imprender.instateam.model.Role' for property 'role': no matching
editors or conversion strategy found]
It says:
**Failed to convert property value of type 'java.lang.String' to required type 'com.imprender.instateam.model.Role' for property
'role'**
but I don't understand where I am doing that.
I think I am not properly transmiting the value selected in the . I thought the object sent would be the one declared in the valueoption that gets selected, but obviously I got it wrong and can't find the way to do it properly.
The model:
package com.imprender.instateam.model;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
#Entity
public class Collaborator {
#Id
//Todo: check strategy
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Pattern(regexp = "([A-Z][a-zA-Z]*\\s*)+")
private String name;
//Todo: check, do we want to create a new table to associate values?
#NotNull
#ManyToOne
private Role role;
public Collaborator() {
}
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 Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
Your problem is that in your select says the field is a role, entity type Role, but in your options the value is an ID, some primitive value, then doesnt match. You can change to this
<select th:field="*{role.id}">
<option value="#" disabled = "disabled" selected="selected">Role...</option>
<option th:each="r : ${roles}" th:value="${r.id}" th:text="${r.name}">Developer</option>
</select>

Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableCollection in Spring Boot, JSP

I have this problem in my code, where I cannot submit a signup form in jsp. Here are the code intervening in the signup operation.
User.java
#Entity
#Table(name = "user", catalog = "spring_abc", uniqueConstraints = {#UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "username")})
public class User implements java.io.Serializable {
public static final String ROLE_ADMIN = "admin";
public static final String ROLE_MEMBER = "member";
private static final long serialVersionUID = 7376961072110620611L;
private Integer id;
private Long commentCount;
private Date createAt;
private String description;
#Email(message = "Entrez le format de l'email correct")
private String email;
private long number;
private String password;
public void setDepartement(String departement) {
this.departement = departement;
}
private long points;
private String role;
#Size(max = 60, message = "Pas plus de soixante caractères")
private String signature;
private Long topicCount;
#Size(max = 60, message = "Pas plus de soixante caractères")
private String twitter;
private Date updateAt;
#Pattern(regexp = "^(?!_)(?!.*?_$)[A-Za-z0-9|_]{3,9}", message = "Nom d'utilisateur, ne peut pas commencer ou se terminer par un trait de soulignement")
private String username;
private Set<Follow> followsForFollowerId = new HashSet<Follow>(0);
private Set<Notification> notifications = new HashSet<Notification>(0);
private Set<Topic> topics = new HashSet<Topic>(0);
private Set<Comment> comments = new HashSet<Comment>(0);
private Set<Focus> focuses = new HashSet<Focus>(0);
private Set<Collection> collections = new HashSet<Collection>(0);
private Set<Follow> followsForFollowingId = new HashSet<Follow>(0);
private Set<Comment> likeComments = new HashSet<Comment>();
The methode signup the service Part.
#Transactional
public User signup(User user, String password1, Errors errors) {
if (errors.hasErrors()) {
return null;
}
String username = user.getUsername();
String password = user.getPassword();
String email = user.getEmail();
if (userRepo.findOneByUsername(username) != null) {
errors.rejectValue("username", "username", "Nom d'utilisateur déjà enregistré");
} else if (userRepo.findOneByEmail(email) != null) {
errors.rejectValue("email", "email", "E-mail est déjà enregistré");
} else if (!password.equals(password1)) {
errors.rejectValue("password", "password", "Les mots de passe ne se correspondent pas");
}
if (errors.hasErrors()) {
return null;
}
user.setPassword(EncryptUtil.encryptUsernameAndPassword(username, password));
user.setCreateAt(new Date());
return userRepo.save(user);
}
Controller Account.java
#RequestMapping(value = "/signup", method = RequestMethod.POST)
public String singupAction(#Validated User user,
Errors erros,
String password1,
RedirectAttributes attributese,
HttpServletRequest request) {
User signinUser = userServ.signup(user, password1, erros);
if (erros.hasErrors()) {
attributese.addFlashAttribute("user", user);
attributese.addFlashAttribute("error", erros.getAllErrors());
return "redirect:/account/signup";
}
request.getSession().setAttribute("user", signinUser);
attributese.addFlashAttribute("msg", "Vous êtes inscrit avec succès");
return "redirect:/";
}
Signup.jsp, The problem appears when i try to validate information.
<form action="${x}/account/signup" data-toggle="validator" role="form" method="POST">
<input class="form-control" data-error="S'il vous plaît entrer une adresse email valide" placeholder="E-mail" type="email" id="email" name="email" value="${user.email}" />
<input class="form-control" id="username" data-error="Entre 6 et 18 caractères" pattern="^[_A-z0-9]{6,18}$" placeholder="Votre username" type="text" name="username" value="${user.username}" />
<input class="form-control" data-minlength="6" type="password" name="password" id="password" placeholder="Mot de passe" data-error="Entre 6 et 18 caractères" />
<input type="submit" class="btn btn-info btn-block" value="S'inscrire">
The stack I'm getting doesn't make any sense to me. It doesn't point out the problem
org.apache.jasper.JasperException: javax.el.ELException: java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:492)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:378)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
Caused by: javax.el.ELException: java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"
at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:742)
at javax.el.BeanELResolver.invoke(BeanELResolver.java:470)
at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:257)
You need to add getters and setters in your entity for each field.
e.g. private long number;
Should have defined following in your entity.
public long getNumber(){ return this.number;}
public void setNumber(long number){ this.number = number; }
from your stacktrace it is clear that it is trying to access fields with public getter method but it couldn't find it so thrown exception.

Spring MVC Pre Populate Checkboxes

First little background info. Got a fairly standard User Role relationship where the User can have many roles. I have roles defined as a set within the user class. Now I know that html forms have all the values as strings and trying to get values as my custom Role object does not work. I implemented an initbinder to convert the id's back into object so that I can retrieve the selected values off of my checkboxes, that part works.
But I can't seem to go back the other way. I retrieve a User from the database that already has roles and want to pre populate role checkboxes with all the roles that a user has. Based on this example :
Checkboxes example
They say that:
form:checkboxes items="${dynamic-list}" path="property-to-store"
For multiple checkboxes, as long as the “path” or “property” value is
equal to any of the “checkbox values – ${dynamic-list}“, the matched
checkbox will be checked automatically.
My interpretation of that is I should be able to feed it a Set of all the roles and define the path to be the roles from the User object and it should match them thus causing the check box to pre populate.
Every example out there seems to have the value of dynamic-list as a String[]. Well thats great and dandy but how does this work for custom objects that our defined as a Set? Can I still use this one line definition for checkboxes or do I need to do some kind of data binding heading into the view also?
Here is my user dto, user controller, custom form binder, and user edit page.
User DTO
#Entity
#Table
public class User extends BaseDto
{
#Column(updatable = false) #NotBlank
private String username;
#Column(name = "encrypted_password") #Size(min = 6, message = "password must be at least 6 characters") #Pattern(regexp = "^\\S*$", message = "invalid character detected")
private String password;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column #NotNull
private boolean enabled;
#Column #Email #NotBlank
private String email;
#Transient
private String confirmPassword;
#ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER, cascade = CascadeType.REFRESH) #JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
public User()
{
}
public User(final String usernameIn, final String passwordIn, final String firstNameIn, final String lastNameIn, final String emailIn, final boolean enabledIn)
{
username = usernameIn;
password = passwordIn;
firstName = firstNameIn;
lastName = lastNameIn;
email = emailIn;
enabled = enabledIn;
}
public String getUsername()
{
return username;
}
public void setUsername(final String usernameIn)
{
username = usernameIn;
}
public String getPassword()
{
return password;
}
public void setPassword(final String passwordIn)
{
password = passwordIn;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(final String firstNameIn)
{
firstName = firstNameIn;
}
public String getLastName()
{
return lastName;
}
public void setLastName(final String lastNameIn)
{
lastName = lastNameIn;
}
public String getEmail()
{
return email;
}
public void setEmail(final String emailIn)
{
email = emailIn;
}
public String getConfirmPassword()
{
return confirmPassword;
}
public void setConfirmPassword(final String confirmPasswordIn)
{
confirmPassword = confirmPasswordIn;
}
public boolean isEnabled()
{
return enabled;
}
public void setEnabled(final boolean enabledIn)
{
enabled = enabledIn;
}
public Set<Role> getRoles()
{
return roles;
}
public void setRoles(final Set<Role> rolesIn)
{
roles = rolesIn;
}
}
User Controller
#Controller #RequestMapping("/user")
public class UserController
{
#Autowired private UserService userService;
#Autowired private UserDao userDao;
#Autowired private RoleDao roleDao;
#InitBinder
public void bindForm(final WebDataBinder binder)
{
binder.registerCustomEditor(Set.class, "roles", new CustomFormBinder<RoleDao>(roleDao, Set.class));
}
#RequestMapping(method = RequestMethod.GET)
public String index(final ModelMap modelMap)
{
return "/user/index";
}
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String create(final ModelMap modelMap)
{
modelMap.addAttribute("userInstance", new User());
modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll()));
return "/user/create";
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(final ModelMap modelMap, #Valid #ModelAttribute("userInstance") final User user, final BindingResult bindingResult)
{
// TODO move to service validation
if (user.getPassword() == null || !user.getPassword().equals(user.getConfirmPassword()) )
{
bindingResult.addError(new FieldError("userInstance", "password", "password fields must match"));
bindingResult.addError(new FieldError("userInstance", "confirmPassword", "password fields must match"));
}
if (user.getRoles() == null || user.getRoles().isEmpty())
{
bindingResult.addError(new FieldError("userInstance", "roles", "Must select at least one role for a User"));
}
if (bindingResult.hasErrors())
{
modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll()));
return "/user/create";
}
userService.save(user);
return "redirect:/user/list";
}
#RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public String edit(#PathVariable final Integer id, final ModelMap modelMap)
{
final User user = userDao.find(id);
if (user != null)
{
modelMap.addAttribute("userInstance", user);
modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll()));
return "/user/edit";
}
return "redirect:/user/list";
}
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String editCurrent(final ModelMap modelMap)
{
return edit(userService.getLoggedInUser().getId(), modelMap);
}
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String update(#Valid #ModelAttribute("userInstance") final User user, final BindingResult bindingResult)
{
if (bindingResult.hasErrors())
{
return "/user/edit";
}
userService.save(user);
return "redirect:/user/list";
}
#ModelAttribute("userInstances")
#RequestMapping(value = "/list", method = RequestMethod.GET)
public List<User> list()
{
return userDao.findAll();
}
}
Custom Form Binder
public class CustomFormBinder<T extends GenericDao> extends CustomCollectionEditor
{
private final T dao;
private static final Logger LOG = LoggerFactory.getLogger(CustomFormBinder.class);
public CustomFormBinder(final T daoIn, final Class collectionType)
{
super(collectionType, true);
dao = daoIn;
}
#Override
protected Object convertElement(final Object element)
{
try
{
// forms should return the id as the itemValue
return dao.find(Integer.valueOf(element.toString()));
}
catch (NumberFormatException e)
{
LOG.warn("Unable to convert " + element + " to an integer");
return null;
}
}
}
User Edit View
<html>
<head>
<title>Create User</title>
</head>
<body>
<c:url value="/user/update" var="actionUrl"/>
<form:form method="post" commandName="userInstance" action="${actionUrl}">
<h1>Edit User ${userInstance.username}</h1>
<div>
<form:label path="username">Username:</form:label>
<form:input path="username" id="username" readonly="true"/>
</div>
<div>
<form:label path="password">Password:</form:label>
<form:input path="password" id="password" type="password" readonly="true"/>
<tag:errorlist path="userInstance.password" cssClass="formError"/>
</div>
<div>
<form:label path="firstName">First Name:</form:label>
<form:input path="firstName" id="firstName"/>
<tag:errorlist path="userInstance.firstName" cssClass="formError"/>
</div>
<div>
<form:label path="lastName">Last Name:</form:label>
<form:input path="lastName" id="lastName"/>
<tag:errorlist path="userInstance.lastName" cssClass="formError"/>
</div>
<div>
<form:label path="email">Email:</form:label>
<form:input path="email" id="email" size="30"/>
<tag:errorlist path="userInstance.email" cssClass="formError"/>
</div>
<div>
**<%--Want to Pre Populate these checkboxed--%>
<form:checkboxes title="Assigned Roles:" path="roles" id="roles" items="${validRoles}" itemLabel="displayName" itemValue="id" element="div"/>**
<tag:errorlist path="userInstance.roles" cssClass="formError"/>
</div>
<form:hidden path="enabled"/>
<form:hidden path="id"/>
<form:hidden path="version"/>
<div class="submit">
<input type="submit" value="Update"/>
Cancel
</div>
</form:form>
</body>
</html>
You need a correct implemented equals method for Role!
If this is not enough have a look at class oorg.springframework.web.servlet.tags.form.AbstractCheckedElementTag. The method void renderFromValue(Object item, Object value, TagWriter tagWriter) is where the the checked flag is set.

Resources