Is BindingResult useful to bind just exceptions with view, or something else?
what is the exact use of BindingResult?
Or is it useful in binding model attribute with view.
Particular example: use a BindingResult object as an argument for a validate method of a Validator inside a Controller.
Then, you can check this object looking for validation errors:
validator.validate(modelObject, bindingResult);
if (bindingResult.hasErrors()) {
// do something
}
Basically BindingResult is an interface which dictates how the object that stores the result of validation should store and retrieve the result of the validation(errors, attempt to bind to disallowed fields etc)
From Spring MVC Form Validation with Annotations Tutorial:
[BindingResult] is Spring’s object that holds the result of the
validation and binding and contains errors that may have occurred. The
BindingResult must come right after the model object that is validated
or else Spring will fail to validate the object and throw an
exception.
When Spring sees #Valid, it tries to find the validator for the
object being validated. Spring automatically picks up validation
annotations if you have “annotation-driven” enabled. Spring then
invokes the validator and puts any errors in the BindingResult and
adds the BindingResult to the view model.
It's important to note that the order of parameters is actually important to spring. The BindingResult needs to come right after the Form that is being validated. Likewise, the [optional] Model parameter needs to come after the BindingResult.
Example:
Valid:
#RequestMapping(value = "/entry/updateQuantity", method = RequestMethod.POST)
public String updateEntryQuantity(#Valid final UpdateQuantityForm form,
final BindingResult bindingResult,
#RequestParam("pk") final long pk,
final Model model) {
}
Not Valid:
RequestMapping(value = "/entry/updateQuantity", method = RequestMethod.POST)
public String updateEntryQuantity(#Valid final UpdateQuantityForm form,
#RequestParam("pk") final long pk,
final BindingResult bindingResult,
final Model model) {
}
Well its a sequential process.
The Request first treat by FrontController and then moves towards our own customize controller with #Controller annotation.
but our controller method is binding bean using modelattribute and we are also performing few validations on bean values.
so instead of moving the request to our controller class, FrontController moves it towards one interceptor which creates the temp object of our bean and the validate the values.
if validation successful then bind the temp obj values with our actual bean which is stored in #ModelAttribute otherwise if validation fails it does not bind and moves the resp towards error page or wherever u want.
From the official Spring documentation:
General interface that represents binding results. Extends the
interface for error registration capabilities, allowing for a
Validator to be applied, and adds binding-specific analysis and model
building.
Serves as result holder for a DataBinder, obtained via the
DataBinder.getBindingResult() method. BindingResult implementations
can also be used directly, for example to invoke a Validator on it
(e.g. as part of a unit test).
BindingResult is used for validation..
Example:-
public #ResponseBody String nutzer(#ModelAttribute(value="nutzer") Nutzer nutzer, BindingResult ergebnis){
String ergebnisText;
if(!ergebnis.hasErrors()){
nutzerList.add(nutzer);
ergebnisText = "Anzahl: " + nutzerList.size();
}else{
ergebnisText = "Error!!!!!!!!!!!";
}
return ergebnisText;
}
Related
I am creating a small validation application using Spring MVC. I am very new to Spring MVC and would like to ensure that what I want is possible.
I have simplified my problem.
I have setup a controller that will be called when a URL is executed. localhost/validate/{SOME TEXT}
The {SOME TEXT} value with be sent to all my validation classes I created.
I currently have 4 classes which does the validation and returns another Object data about what happened during the validation
The 4 validation classes are:
CreditCardValidator
AddressValidator
ZipcodeValidator
AccountNumberValidator
I have a main controller bean that when called I want the string to be passed to each class and the object returned from each to be stored and then finally all results are sent back in a response.
Normally, I would do this without Spring by creating an interface that each validation class implements. Then iteration through the list of classes and execute a method.
The problem doing it that way is that whenever I need to add a new validation class I'll need to register it so the request can use it. This involved modifying existing classes.
Since I am using Spring quick heavily in this application I am wondering if this is possible to do via Spring and annotated classes.
I was thinking of creating a custom annotation that each validation class has and then using spring component-scan to get the classes. This would allow me to create new validations without modifying existing code.
Below is the what I am trying to do.
#Controller
public class StringValidationController {
#RequestMapping(value = "/validate/{text:.+}", method = RequestMethod.GET)
public ModelAndView index(#PathVariable("text") String text) {
ModelAndView model = new ModelAndView();
model.setViewName("index");
model.addObject("result", getListOfValidatedData());
return model;
}
public List getListOfValidatedData(){
//Scan for IValidator annotation
//call each concrete class and pass in text
// get object with has validation information in it
}
}
I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable
Is it possible to use Bean Validation annotations like #Past or #Length on Request Parameters in spring mvc?
I would like to do something like:
#RequestMapping(method = RequestMethod.POST)
public RedirectView initiateSignup(#RequestParam #Valid #Past Date birthdate, BindingResult birthdateResult,
HttpServletResponse httpServletResponse) throws HttpMediaTypeNotAcceptableException {
I made it work with the help of a blog post:
http://blog.codeleak.pl/2012/03/how-to-method-level-validation-in.html
an additional annotation and a bean post processor were nessecary, but now it works.
I don't think that's possible. You can apply #Valid but not e.g. #Past. You can instead create a model class with fields that correspond to your request parameters, and put the JSR-303 annotations on the class's fields. You can then use that class as the controller method argument type, with #Valid on it, and Spring should validate it appropriately.
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/validation.html#validation-mvc-jsr303
MODEL
[Remote("ValidateDuplicateUsername", "Account", ErrorMessage = "Username is already taken")]
public string Username { get; set; }
CONTROLLER
ModelState.IsValid
The RequiredAttribute automatically adds entry to ModelState if the field is invalid.
And then it displays the error message in the view.
How can I also do that using the RemoteAttribute? so that when I call the ModelState.IsValid, it also validates the Remote Validation?
The RequiredAttribute automatically adds entry to ModelState if the field is invalid
No, you must have misunderstood something. The Required attribute doesn't add anything to the ModelState. Validation attributes do not have access to ModelState neither to HttpContext. They override the IsValid method and return true or false to indicate whether the model is valid or not. It is the default model binder that executes validation when trying to bind the model from the request that adds errors to ModelState. Data Annotations are designed to be MVC independent. They are in a separate assembly (System.ComponentModel.DataAnnotations) with the idea of using them for example in WPF, Silverlight, ... applications. So you understand that the notion of ModelState doesn't make sense.
So if you look at the IsValid implementation of the RemoteAttribute you will notice the following:
public override bool IsValid(object value)
{
return true;
}
That's the reason why the RemoteAttribute considers your model as valid when you post the form. You could write your custom remote validation attribute and override this method.
I have a Spring MVC controller with an action that's called using AJAX.
#SessionAttributes({"userContext"})
public class Controller
{
...
#RequestMapping(value = "/my-url", method= { RequestMethods.POST })
public ModelAndView doSomething(#ModelAttribute("userContext") UserContext context,
SessionStatus sessionStatus)
{
BusinessObject obj = doSomeBusinessLogic(context.getUserName());
sessionStatus.setComplete();
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("someInt", obj.getId());
return mav;
}
}
When I run this action, I get the following exception:
net.sf.json.JSONException: There is a cycle in the hierarchy!
at t.sf.json.util.CycleDetectionStrategy$StrictCycleDetectionStrategy.handleRepeatedReferenceAsObject(CycleDetectionStrategy.java:97)
at net.sf.json.JSONObject._fromBean(JSONObject.java:833)
at net.sf.json.JSONObject.fromObject(JSONObject.java:168)
at org.springframework.web.servlet.view.json.writer.jsonlib.PropertyEditorRegistryValueProcessor.processObjectValue(PropertyEditorRegistryValueProcessor.java:127)
at net.sf.json.JSONObject._fromMap(JSONObject.java:1334)
Truncated. see log file for complete stacktrace
After doing some debugging I found out that Spring is placing the UserContext object onto the ModelAndView that I am returning. If I hard-code my user name and remove the context object from the method's parameters, the action runs successfully. Is there a way to configure Spring to omit the ModelAttribute-annotated parameters from the returned ModelAndView? As you can see, sessionStatus.setComplete() has no effect.
I've had similar problems in the past with #SessionAttributes. By declaring #SessionAttributes({"userContext"}) you're telling Spring that you want "userContext" to always be available in the model, and so Spring has no choice but to send your UserContext object out to the model, just in case you're going to be redirecting or doing something else which might end up at another Controller.
The "solution" (and I didn't like it much, but it worked) was to omit the #SessionAttributes annotation on the controller, add an HttpSession parameter to the necessary methods and "manually" manage what's in it.
I'm interested to see if there's a better way, because it seems #SessionAttributes has tremendous potential to tidy up controller-level code.
I registered a WebArgumentResolver to get to my session variable. This allowed me to keep this session variable out of the response while keeping my action unit testable.
Along with #ModelAttribute, pass #ModelMap as a method argument.
Based on business logic, error conditions -- if you do not need the attribute for certain scenarios, then remove it from the map.
public ModelAndView foo(#ModelAttribute("userContext") UserContext, #ModelMap map){
if(success){
return success.jsp
}
else{
map.remove("userContext");
return "error.jsp"
}
}
Not totally satisfied with having to pass the ModelMap as well, but I did not find any other easier way of doing it.
Cheers!!