How can the javax validator return a not null, but still empty, list of constraints? - hibernate-validator

I can see the javax validator returning a non null list of constraints. But that list contains 0 elements.
How can that be ?
It flies in the face of my test coverage.

Assuming you mean any of the various validate(), validateValue() etc. methods on Validator, returning an empty set of ConstraintViolation is the indicator that the requested validation was successful, i.e. no constraints were violated.
Returning an empty collection instead of null is a common best practice to avoid NullPointerExceptions on the caller's side. Check isEmpty() on the returned set to find out whether the validation was successful or not.

Related

the way to determine a request parameter is null

the way to determine a request parameter is null in spring
If you're talking about query or form parameters, then these cannot take value null. They are sent as strings; any conversion (e.g. to int) is done by the framework or your own application. So if a query parameter is sent in as ?var=null, then your applications gets 'null' - a string of length 4 containing the word null. So, if your application receives a null, then the query / form parameter was not sent.
It's a different story when you're talking about properties in JSON. If the type is simply String, Integer, etc., then you cannot see the difference between not-present and present as null. You can try using Optional<String> etc., but I haven't tried that myself. For Jackson you can find more information at https://www.baeldung.com/jackson-optional.
to make sure request parameter is not null and is always present you can use
#RequestParam(required = true)
This will make sure parameter is always passed

Model Binding and Validation Errors

I am using asp.net MVC3 and I am very new to this technology.
My models are designed in such a way that the properties will throw validation errors if the data is invalid. In this case, the properties are not set with invalid data.
When I redisplay my editing-view, validation error messages are shown; however the values that the user previously entered are gone because the model that it is bound to only contains the old-valid data.
For example, say I had a Person class and the Name property cannot be a null or empty string otherwise it throws a validation exception and prevents the property from being set. Now say the user removes the value from the Name property and tries to save the Person from the web. A validation exception will be thrown and handled properly to add the error to the ModelState so that it is displayed on the screen; however the old value for the Name is redisplayed since the invalid, empty string never made it into the property.
I do not know how to solve this problem and any advice on the issue would be greatly appreciated.
My advise is allow invalid data but use validation attributes. You wont save invalid entities so there is no problem and this is the standard approach these days. If you don't want do that, there is no easy solution. Most simple solution would be using the info from Request.Form
You should implement IValidatableObject to performe this kind of validation at server side.
From MSDN IValidatableObject Interface:
Provides a way for an object to be invalidated.
Theres an exemple here Using IValidatableObject Custom Validation, also from MSDN.
The solution to this problem was to create a ViewModel that allowed invalid data to be entered into this. This solution also simplified my ModelBinder classes because it took on most of the work.

Optional Invalid Query String Variables

This is a somewhat philosophical issue. I have a .net (but could be any platform) based helper library that parses query string values. Take for example a variable that returns an Int32: my framework has an option that specifies whether this value is required or optional. If it is required but not provided, the framework throws an exception. If it is optional and not specified, it returns a null.
Now an edge case has come up based on users hacking (in a good way) our urls. If they specify a variable with either an invalidly formatted Int32 ("&ID=abc") or provide the variable but not specify a value ("&id="), should the framework throw an exception or should it return a null?
Part of me feels that invalid variables or formats should return a null. It might be valid to argue that even if the parameter is optional, an invalidly formatted query string or value should still throw an exception.
Thoughts?
Since this is philophical ...
On something like an ID, I would agree with Shawn that it is a 404, especially if you are thinking in terms of state. There is no object, so not found. But, ID may not tie directly to a resource in all cases.
If the item is truly optional, a null is okay. But optional should mean "if present it makes the call more specific" in this case and there should always be a fallback. I don't see this in ID, unless the ID is keyed to an optional part of the page.
In the long run, I think you should look at the business reason for the page and what each variable means.
I believe that if a variable is optionaly, providing the variable but not specifying the value is equivalent to ommitting the variable itself. In this case, returning null seems OK.
However, providing an invalidly formatted value ought to cause an Exception, since the intent was to provide a value. In this case the user ought to be notified through some sort of validation mechanism.
A HttpException of 404 (Not Found). Your web application framework should know how to catch these errors and redirect to the proper page.
This is actually a not found error because the resources that the ID is pointing to does not exist.
I suspect there's no "right" answer to your question. If I were a developer using your library, I would expect/hope that the public API would include in its code comments, a description of how the function behaves when the URL param includes bad (wrong type) data.
You might also be able to craft your public API to get the best of both worlds: .NET seems to have adopted the "Parse" / "TryParse" approach in many places. If I'm the caller and I want the function to throw if given invalid data, I call Parse(). If I don't want it to throw, I call TryParse(). In my opinion, that is a nice pattern to follow with your API as well.

ASP.NET MVC3 TryValidateModel validates entire model collection, not just single instance

I have an action that takes a list of models. I'd like to validate each one individually vs. the entire model collection at once. I'm trying to use TryValidateModel, but it appears that if any one of my models is invalid, all of them are invalid. My form displays 5 SurveyResponseModels (a class with two Required strings and two ints). If I fill out all five models completely, I get validCount = 5 below. However, if any of the five models are incomplete (thus failing validation), I get a validCount of 0. Is the expected behavior of TryValidateModel? If so, any ideas on how I can validate these one at a time?
[HttpPost]
public ActionResult Create(IList<SurveyResponseModel> respondents)
{
int validCount = 0;
foreach (SurveyResponseModel respondent in respondents)
{
if (TryValidateModel(respondent))
{
validCount++;
}
}
ModelState.AddModelError("", validCount.ToString() + " respondents passed validation");
}
Looking at the code, it appears to me that TryValidateModel will validate all models of the type given by the object provided, not just that particular object itself. Moreover, it returns the current value of the ModelState.IsValid property so that once there is an invalid model, all invocations of TryValidateModel will return false. If you want to do something like this, I think that you'll need to get and run the validators for each model instance yourself on that particular model instance.
I also think that the model validators have already been run by the time you are invoking them manually. You can check this (for an invalid model) by looking at the value of ModelState.IsValid before your loop. If it's false, then it means that the validators were run by the model binder, which is what I think happens.
You can find the source code for MVC at http://aspnet.codeplex.com/.
TryValidateModel() adds to the list of validation errors. Use ModelState.Clear() to remove previous errors. Validation occurs as part of the model binding process, automatically, unless the [ValidateInput(false)] attribute is used. See https://stackoverflow.com/a/8581918/1238406 for more info.
I've seen this behaviour in another post.
To continue tvanfosson's suggestion, I suggest you put a breakpoint before your foreach, and check the ModelState to see if the errors are already there. They probably are: the DefaultModelBinder has put them. Then I can think of 2 possibilities:
Errors are correctly passed, in some way that identifies each Respondent (I don't think it's the case). In this case a simple linq expression can get you the distinct count of problematic respondents.
Errors are mixed, for example if 2 respondents have an invalid Name, you have only one error for Name, or you cannot distinguish which respondent is concerned. In this case you need to create custom validation logic. You can create an object like RespondentListViewModel and create a RespondentListViewModelBinder. You can see the source code above to see how the DefautlModelBinder validates lists and adds model errors.
Yes, it's this part of ASP.NET MVC where the binding logic doesn't do what we want it to do...
the source code:
protected internal bool TryValidateModel(object model, string prefix) {
if (model == null) {
throw new ArgumentNullException("model");
}
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, ControllerContext).Validate(null)) {
ModelState.AddModelError(DefaultModelBinder.CreateSubPropertyName(prefix, validationResult.MemberName), validationResult.Message);
}
return ModelState.IsValid;
}
It will always return false, in case one is wrong.

Why input elements don't render the value passed in ASP.Net MVC?

This post asks this question but doesn't really give an answer, so I thought I would ask the question differently.
I have a page that renders a hidden value from the model:
<%=Html.Hidden("myName", model.myValue) %>
Since I am passing a value in the value parameter, you would think it would output that value, but it doesn't.
The code for rendering input fields has the following:
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter), isExplicitValue);
Basically, if the ModelState (which contains posted values) contains a value for the "name" passed, it will use that value instead of your passed value to the helper method. In my case, I updated the model and my updated value wasn't outputted.
If I pass a value to a method, I expect that value to be rendered.
Am I missing something in this design or is it just wrong?
This is by design. Here is the intended flow:
The user requests a certain URI.
Your controller builds out a model.
The view is rendered. The ModelState dictionary should be empty at this point, so the value you pass to Html.Hidden will be rendered. However, the feature in question is more directly related to user input, so consider the case of Html.TextBox("someName", Model.SomeValue)
Now imagine the user enters some invalid data. If you have a client-side validation, this would be caught before the POST, but let's pretend you don't, or that the user has somehow circumvented it.
In this case, the action which handles the POST will return a ViewResult, causing the view from step 3 to be re-rendered. However, the user will see the value they input (so they can fix it) instead of the value from your model object. The idea here is that the data the user entered possibly cannot be represented as a value in Model.SomeValue, due to type safety. If Model.SomeValuewas of type integer, for example, and the user entered "ABC", the only way to re-render the user's data is to put it somewhere else. And that "somewhere else" is ModelState.
Re-displaying the user's invalid data allows the user to fix the data they entered and re-post the form.

Resources