I'm trying to simplify my code by binding request parameters directly to User Entity instead of copying value field by field, but I can't seem to get validation working that way.
Controller:
@Autowired
private UserValidator validator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
@PreAuthorize("isAnonymous()")
@RequestMapping("/register")
public List<String> register(@Valid @ModelAttribute RegisterRequest request, BindingResult result){
return result.getAllErrors().stream().map(error -> error.getCodes()[1]).collect(Collectors.toList());
}
Validator:
@Component
public class UserValidator implements Validator {
@Autowired
private UserRepository repo;
@Override
public boolean supports(Class<?> clazz) {
return clazz.equals(RegisterRequest.class)||clazz.equals(User.class);
}
@Override
public void validate(Object target, Errors errors) {
if(target instanceof RegisterRequest){
RegisterRequest request = (RegisterRequest)target;
if(isRegistered(request))
errors.rejectValue("User.Email", "InUse");
if(!isRepassCorrect(request))
errors.rejectValue("Repassword", "NoMatch");
}
}
private boolean isRegistered(RegisterRequest request){
return repo.findByEmail(request.getUser().getEmail())!=null;
}
private boolean isRepassCorrect(RegisterRequest request){
return request.getPassword().equals(request.getRepassword());
}
}
Models (note that nested object is annotaded with @Valid):
public class RegisterRequest {
@Valid
private User user = new User();
@NotEmpty
private String password;
@NotEmpty
private String repassword;
//Generated getters and setters for all fields
}
@Entity
@Table(name = "users")
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 3726459440738726042L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@NotEmpty
@Email
@Column(name = "email", nullable = false)
private String email;
@NotEmpty
@Column(name = "hash", nullable = false)
private String hash;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(referencedColumnName = "id")
private UserRole role;
@Column(name = "enabled", nullable = false)
private boolean enabled;
@NotEmpty
@Column(name = "name", nullable = false)
private String name;
@Column(name = "company")
private String company;
//Getters, setters, equals and hashCode
}
Problem is that only password and repassword fields are properly validated, validation annotations in User class are ignored and any request with just matching passwords passes while it should rise errors. Empty passwords or different ones rise errors as expected.
setValidatoruseaddValidator.