Why is Spring not running my Validator? - spring

I am using Spring MVC and I am making a Validator but it looks like Spring is never running it.
Here is my Validator is a easy one right now just checking for two fields
public class MemberRequestValidator implements Validator {
public boolean supports(Class aClass) {
return MemberRequest.class.equals(aClass);
}
public void validate(Object obj, Errors errors) {
MemberRequest mr = (MemberRequest) obj;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "content", "Content field is Required");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "areacode", "Area code field is Required");
}
}
Now my controller looks like the following:
#InitBinder("memberrequest")
public void initMemberRequestBinder(WebDataBinder binder) {
binder.setValidator(new MemberRequestValidator());
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveRequest(#ModelAttribute #Valid MemberRequest mr, BindingResult result)
{
if (result.hasErrors())
{
LOGGER.debug("Pages had errors on it... returning to input page");
return new ModelAndView("question");
}
else
{
String Ticket = mService.sentWebRequest(mr);
Map<String, Object> model = new HashMap<String, Object>();
Ticket t = new Ticket();
t.setTicketDetails(Ticket);
model.put("ticket", t);
return new ModelAndView("thanks", model);
}
}
and in my JSP page I have the following:
<c:url var="saveUrl" value="/mrequest/save.html" />
<form:form modelAttribute="memberrequest" action="${saveUrl}" name="memberrequest" id="memberrequest">
so if I dont enter any data in on the form I should hit the errors but I dont?

Try with #ModelAttribute("memberrequest") in handler or modelAttribute="memberRequest" in form and #initBinder("memberRequest")

Related

Tomcat Show HTTP Status 400 Error Page During Validation

I'm learning to make Bean Validation works in Spring MVC with Thymeleaf as default view. Every valid data can be saved properly. But when I tried an invalid data passed, Tomcat just showed HTTP Status 400 Error page. In Tomcat console showed something like validation but just became logging text in Tomcat console. Here is the controller that saves data (item).
#Controller
#RequestMapping("/item")
#SessionAttributes("item")
public class ItemController {
#Autowired
private ItemService itemService;
#Autowired
private ColorService colorService;
#ModelAttribute("allColors")
public List<Color> populateColors() {
return colorService.findAll();
}
#ModelAttribute("allItems")
public List<Item> populateItems() {
return itemService.findAll();
}
#RequestMapping(value = {"/image/{id}", "image/{id}"})
#ResponseBody
public byte[] showImage(#PathVariable("id") String id) {
return itemService.getItem(id).getImage();
}
#RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
public String showAllItems() {
return "itemList";
}
#RequestMapping(value = {"add", "/add"}, method = RequestMethod.GET)
public String showItemAddForm(Model model) {
model.addAttribute("item", new Item());
return "itemAddForm";
}
#RequestMapping(value = {"add", "/add"}, method = RequestMethod.POST)
public String processAddItem(
#ModelAttribute("item") #Valid Item item,
RedirectAttributes model,
BindingResult errors,
SessionStatus session) {
if (errors.hasErrors()) {
return "itemAddForm";
}
itemService.saveItem(item);
session.setComplete();
model.addFlashAttribute("message", "Item has been added");
return "redirect:/item";
}
}
Is any wrong with the controller? How should I to make Bean Validation works with Spring and Thymeleaf?

How to use ValidationUtils in spring

I want to use ValidationUtils as follows. But I cannot instantiate errors object since Errors is an Interface. Can you tell me how I can make this working without using a validator?
if(visitorDetails==null)
{
Errors errors;
visitorDetails=new Visitor();
ValidationUtils.rejectIfEmpty(errors, "VisitorInfo", "Selected Visitor Details Not Found");
}
Read this : Validation...
However you must implement the Validation interface in a class, and than use it to validate your object, and to do that you autowire validator in your controller..
This is an example:
public class PersonValidator implements Validator {
/**
* This Validator validates *just* Person instances
*/
public boolean supports(Class clazz) {
return Person.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) {
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) {
e.rejectValue("age", "too.darn.old");
}
}
}
and in your controller:
....
#Autowired
private PersonValidator personValidator;
#InitBinder
protected void initBinder(final HttpServletRequest request, final ServletRequestDataBinder binder) {
binder.addValidators(personValidator);
}
...
Assuming you are using Spring Boot.
If using application.properties (under project/src/resources) put the following in it:
spring.messages.basename=validation
Now put a validation.properties (under project/src/resources) and put the following (for example) in it:
NotEmpty=This field is required.
Your model (AppUser in this case) should have:
private String useremail;
getters/setters;
Create a component (Class) like this (example):
#Component
public class UserAddValidator implements Validator {
#Autowired
private UserService userService;
#Override
public boolean supports(Class<?> aClass) {
return AppUser.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
AppUser user = (AppUser) o;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "useremail", "NotEmpty");
}
}
The following goes to your controller:
#RequestMapping(value = "registration", method = RequestMethod.POST)
public String registration(#ModelAttribute("userForm") AppUser userForm, BindingResult bindingResult, Model model) {
useraddValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "userregistration";
}
userService.save(userForm);
model.addAttribute("success", "User " + userForm.getUsername() + " created successfully");
return "success";
}
Last but not the least, in your view put similar to this:
<div class="row">
<label class="col-md-3" for="useremail">Email-ID</label>
<div class="col-md-8">
<spring:bind path="useremail">
<div class="form-group ${status.error ? 'has-error' : ''}">
<form:input type="text" path="useremail" class="form-control"
placeholder="Email-id" autofocus="true"></form:input>
<form:errors path="useremail">${emailerror}</form:errors>
</div>
</spring:bind>
</div>
</div>
The result should look (something) like below:
You can look HERE for more validations.
If I understand your question correctly you want to get the errors object.
In your case I would suggest below approach.
if(visitorDetails==null)
{
visitorDetails=new Visitor();
Errors errors = new BeanPropertyBindingResult(visitorDetails, visitorDetails.getClass().getName());
ValidationUtils.rejectIfEmpty(errors, "VisitorInfo", "Selected Visitor Details Not Found");
}
Let me know if you need more help.
you can use it to make some constraint on some of your field like show error when the field is empty or emptywithspace , this class already contain some static method that can do that
below an exemple for using ValidationUtils class
public class UserValidator implements Validator {
public boolean supports(Class clazz) {
// TODO Auto-generated method stub
return Employee.class.equals(clazz);
}
public void validate(Object target, Errors errors) {
// TODO Auto-generated method stub
ValidationUtils.rejectIfEmpty(errors, "email", "email");
ValidationUtils.rejectIfEmpty(errors, "password", "password");
Employee emplo = (Employee) target;
if(emplo.getEmail() != null && emplo.getEmail()=="aa") {
errors.rejectValue("email", "email invalide ");
}

Spring MVC ExceptionHandling: action annotated as #ExceptionHandling can't pass variable to error view

I know a lot of people have had issues similar to this.Sorry posting it again, but i believe there is something i might not be doing well.
I'm using Spring 3.0.5 with freemarker 2.3.14. Basically i wanted to show a friendly error message to the user.
#Controller("exceptioncontroller")
public class ExceptionController {
private static Logger logger = Logger.getLogger(ExceptionController.class);
#RequestMapping(value = "/site/contentnofoundexception")
public String throwContentFileNotFound(){
boolean exception = true;
if(exception){
throw new ContentFileNotFoundException("content ZZZ123 not found");
}
return "errortest";
}
#ExceptionHandler(value = ContentFileNotFoundException.class)
public String handleFileNotFoundException(ContentFileNotFoundException ex, Model model) {
model.addAttribute("msg",ex.getErrorMessage());//this message is never passed to the error view. msg is always null
return "error";
}
}
//same issue for handleException action which uses ModelAndView
#ExceptionHandler(value = Exception.class)
public ModelAndView handleException(Exception ex){
logger.error(ex);
ModelAndView mv = new ModelAndView();
mv.setViewName("error");
String message = "Something Broke. Please try again later";
mv.addObject("msg", message);
return mv;
}
// Custom Exception class
public class ContentFileNotFoundException extends RuntimeException {
private String errorMessage;
public ContentFileNotFoundException(String message) {
this.setErrorMessage(message);
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
So each case either handleFileNotFoundException or handleException actions are called alright but they can't send any message to the error.ftl view to display to the user. Is there anything i need to configure?
Thanks for helping in advance

Server side Validation not working properly

I am configuring server side validation for my form.My problem is that when the control comes in the Areavalidator class
#Override
public boolean supports(Class<?> clazz) {
return Area.class.isAssignableFrom(clazz);
}
from the above method the control again back to the controller class and in the error set it shows zero error.My question is that why it is not entering in the method where I am doing my validation stuff.
#Override
public void validate(Object target, Errors errors) {
Area object = (Area)target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "areaName",
"label.areaNameRequired");
if(object.getAreaCode().length()==0)
{
{
errors.rejectValue("areaCode", "label.areaCode", null);
}
}
}
The code in my controller class for validation
#Autowired
private AreaValidator areaValidator;
#InitBinder("area")
protected void initBinder(WebDataBinder binder) {
binder.setValidator(areaValidator);
}
#RequestMapping(value = "/saveGridArea", method = RequestMethod.POST)
public String saveCountry(#ModelAttribute #Valid Area area,ModelMap map,BindingResult error) {
if (error.hasErrors()) {
return "area";
}
It's because when you do #Valid, it is expected to have the corresponding BindingResult right next to the modelAttribute:
Here, your ModelMap is in between, making it impossible for the framework to associate the linked/associated errors to the modelAttribute .
You just need to change the order of your variable of the method.
Try this and it should work:
#RequestMapping(value = "/saveGridArea", method = RequestMethod.POST)
public String saveCountry(#ModelAttribute #Valid Area area,BindingResult error, ModelMap map){
...
}

Spring 3 Custom Editor field replacement

Having my ValueObject
UserVO {
long id;
String username;
}
I created custom editor for parsing this object from string id#username
public class UserVOEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) throws IllegalArgumentException {
Preconditions.checkArgument(text != null,"Null argument supplied when parsing UserVO");
String[] txtArray = text.split("\\#");
Preconditions.checkArgument(txtArray.length == 2, "Error parsing UserVO. Expected: id#username");
long parsedId = Long.valueOf(txtArray[0]);
String username = txtArray[1];
UserVO uvo = new UserVO();
uvo.setUsername(username);
uvo.setId(parsedId);
this.setValue(uvo);
}
#Override
public String getAsText() {
UserVO uvo = (UserVO) getValue();
return uvo.getId()+'#'+uvo.getUsername();
}
in my controller i register
#InitBinder
public void initBinder(ServletRequestDataBinder binder) {
binder.registerCustomEditor(UserVO.class, new UserVOEditor());
}
having in my model object ModelVO
ModelVO {
Set<UserVO> users = new HashSet<UserVO>();
}
after custom editor is invoked all you can see after form submission is
ModelVO {
Set<String> users (linkedHashSet)
}
so when trying to iterate
for(UserVO uvo : myModel.getUser()){ .. }
Im having classCastException .. cannot cast 1234#username (String) to UserVO ..
HOW THIS MAGIC IS POSSIBLE ?
It is not magic, it is because of Generics will be only proved at compile time. So you can put every thing in a Set at runtime, no one will check if you put the correct type in the Set.
What you can try, to make spring a bit more clever, is to put the ModelVO in your command object.
<form:form action="whatEver" method="GET" modelAttribute="modelVO">
#RequestMapping(method = RequestMethod.GET)
public ModelAndView whatEver(#Valid ModelVO modelVO){
...
}

Resources