Grails messages.properties typeMismatch error messages - validation

I have a User domain class that has an enum field in it called Gender. It has values for male and female in it. When I represent it on the GSP page it appears as a drop down. To test the security of the web app, I used firebug to alter the value of male which was 0 to abc to see if the validation catches it. I does but the message it showed wasn't human readable. I used the following in my messages.properties.
typeMismatch.User.gender=The value for {0} is {1} and it is not a valid value
But the problem is, when my GSP renders the Errors, It doesn't replace {1} with the rejected value of the drop down list. I tried {2} and {3} and etc, it only prints them as String and don't replace them. Is there a way to get the rejectedValue in the message ?
Updated: I have toString method in my enum Gender too. Here is some code from controller and gsp page.
Controller:
if (bioInstance.hasErrors() || currentUser.hasErrors()) {
render(view: 'editProfile', model: [user: currentUser, bioInstance: bioInstance])
return
}
GSP:
<g:hasErrors beans="[bioInstance:Bio,user:User]">
<ul class="alert alert-danger">
<g:renderErrors beans="[bioInstance:Bio,user:User]" as="list"/>
</ul>
</g:hasErrors>

It happens because grails renders error messages via message(error: someError) method. someError is an instance of org.springframework.validation.FieldError, which was created during validation phase, and it has only one argument to its message - the name of domain class itself. So, it's a binding error, not a validation error, which by default has 3 arguments: property name, domain class name and rejected value.
If you're using grails 2.3 and above - you can write a custom binder as described at http://grails.org/doc/latest/guide/theWebLayer.html#dataBinding. Or use an integer field inside the domain class, write some constraints for it, and expose it to the outside via getter as enum.

Related

HTML Form send an array of objects using thymeleaf and spring boot

I am trying to built an application where I need to send a list of objects, having a variable length.
[Form view]
(https://i.stack.imgur.com/ynE2T.png)
Is there any way I can capture such fields in the controller? I was trying something in the lines of:
public String setNewTratament(
#RequestParam("medicamente") MedicamentatieStartStop[] input,
Model model) {
// ...
}
and in the post request something like:
<input x-bind:name="`medicamente[${index}][medicament]\`" type="text" class="input input-bordered w-full"\>
(using alpineJS), where the last field will be the properties of the object "MedicamentatieStartStop". The names are copied from an th:inline script, pasting exactly one such array.
The problem was it throws the following error: 'required request parameter 'medicamente' for method parameter type MedicamentatieStartStop[] is not present.
Any ideas how I should approach this situation?
Solved it by adding a th:object on the form with a DTO and instead of [attribute] i changed it to .attribute, everything else stayed the same.

Grail validate data already saved to database

I have this really complicated form. All the fields must be filled, but the process of filling can be saved and leter continued. So what i need s that when finally confirm is pressed, all the data get validated. But because it is already saved to database calling validate() wont work. I save the data by douing save(validate:false), because i dont need validation when the work is still in progremm.
How can i validate data that has already been saved to database ? Do i have to do it manually?
What happens when you validate an already persisted object?
Is there a way to make it appear dirty after retrieving and before validating?
I have edited the answer to explain form encapsulation in more detail, typically maybe from a tier step process of form input or more complex iterated objects that needs to be elsewhere. To begin if all you need is a one step that captures a variety of information and you are happy to then process all that manually and store in different classes on mass params dump then look into jquery-ui tabs. If you choose to use the dynamic feature of tabs i.e. <li><a href="someurl">click</li> which then loads content dynamically to a given tab then that would also cover single forms that are outside or maybe if you prefer more complex within DOM.
Anyhow the reason for my edit wasn't above it is for something a little more complex that captures multi tier forms.
So you had step 1 that sent params through to a controller that then passed those params to a new gsp or maybe even an iteration of something that belongs to another totally different object within the form.
Typically you would end up with:
<g:form action=myDomain" action="doThis">
<!-- this is some iteration that belongs to some other class outside of what i am actually trying to do: -->
<g:each in="someObject" var="p">
<g:hiddenField name="form1.firstName" value="${p.firstName}"/>
<!-- in this case hidden -->
<g:hiddenField name="form1.surName" value="${p.surName}"/>
</g:each>
<!-- this is my actual form -->
<g:textField name="username" />
</g:form>
When form is submitted to a controller
Class MyDomainController {
def doThis(MyBean bean) {
save(bean)
}
}
//this be in src/main/groovy
import grails.validation.Validateable
//important for some reason it needs entire collections
// have had issues initialising it without .*
import org.apache.commons.collections.*
Class MyBean implements Validateable {
//this is capturing the current form fields
String username
//This is now collecting our form1 fields
List<MyDetailsBean> form1 = ListUtils.lazyList([], { new MyDetailsBean() } as Factory)
//if that had been 1 instance of it or like as mentioned passed from pervious form and called form2
MyDetailsBean form2
static constraints={
username(nullable:false) //, validator: checkSomething)
}
}
This is again in src/main/groovy and was used to originally collect each iteration of an object:
import grails.validation.Validateable
Class MyDetailsBean implements Validateable {
String firstName
String surName
}
I have updated the answer since i suggested encapsulating the object in a bean without any details of how one would go about doing such a thing. I hope above is clear. It is all on the fly but if tested hope it all works as explained above.
TO add after next update explained form2 example. to finally validate both sets you call
if (bean.validate() && bean.form2.validate()) {
//all good
}
Because you are binding it to another validation class the rules of that class can now be applied as part of validation process.
Old answer
Quite simply put it is on the db why on earth would you want to validate a validated input. Anyhow the work around is a validation bean in Grails 2 src/groovy/package which is #Validateable or
Grails 3 : src/main/groovy/package which implements Validateable
class MyDmainBean {
// must declare id
def id
// Then each object in your real domain class
static constraints = {
id (nullable:true,bindable:true)
importFrom MyDomainClass//, exclude: ['field1']
//field 1 is not included but if field 1 was integer
// in actual domain class and BigDecimal in bean
//then exlude it since it won't bind
}
def formatObject(MyDomainClass domain) {
id=domain.id
..
}
}
Now you can call
MyDomain record = MyDomain.get(0L)
MyDmainBean bean = new MyDmainBean().formatObject(record)
bean.validate()

How does Spring bind form values into class variables?

If I use a form:form object in Spring, I can use the commandName in order to let Spring inject the class variable values.
However, I wonder, how does the controller catch this value?
#RequestMapping(method = RequestMethod.POST, value = "/form")
public String postForm(#ModelAttribute("item") Item item, ModelMap model)
{
return "result";
}
In the above code, the Item is injected. However, even changing the name of this variable (or removing the modelattribute), doesn't affect that this variable is injected with the form values.
Will spring just inject the values in the first model class found, from the form? How does Spring know that it has to inject the form into the Item item parameter?
At first I thought the variable in the controller (POST) should have the name of commandName of the form, but it does work with other names as well, strangely enough.
There is a dedicated section in the Spring Documentation describing the usage of #ModelAttribute on method arguments.
This process is known as Data Binding on submit and is following some conventions:
If #ModelAttribute is explicitely declared with a name on an argument (your case). In this case the submitted data of the form are copied over automatically under this name. You can check yourself that it is already there in your ModelMap model by invoking/inspecting model.get("item").
If there is no #ModelAttribute argument annotation at all, then the attribute name is assumed from the type essentially in your case type Item converts to attribute name item (camelCase notation) that is created for you holding a new Item with the form data-bind'ed fields. That is also there in the ModelMap (same check as above: model.get("item"))
Key point to realise is in all these cases DataBinding occurs before hitting your Post form RequestMapping.

Spring form tags. Allow nulls in form:select (enum)

I'm using Spring form tags for filling form with values.
I have form backing object:
public class FormInfo {
public enum Status {ON, OFF}
private Satus status;
//getter setter
...
}
And in JSP Status enum presented like this:
<form:form commandObject="formInfo " ...>
<form:select path="status">
<form:option value="null" label="Please select"/>
<form:options/>
</form:select>
</form:form>
All works fine, i.e. default message and enum values are presented in <select>.
But the status field is not required, so I want allow user to leave Status field unselected. But if form submitted without selecting status field, then I get error:
error in object 'formInfo' on field 'status': rejected value [null];
How I can set enum to null when no values is selected?
Please note I'm using JSR 303 validation. And error described above is not happens automatically, I get this error message manually from following method BindingResult#getFieldErrors().
This is my controller code:
public void myMethod(#Valid #ModelAttribute("formInfo") FormInfo sourcingDetail, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
log.error("Error during validation is occurred." + bindingResult.getFieldErrors().toString()); // <-- this is error message
}
...
}
Also please note, I didn't set any JSR-303 annotation (like #NotNull) on status field.
UPDATE:
Almost full error message which I get from calling this method BindingResult#getFieldErrors() (explained above):
Error during validation is occurred.[Field error in object 'formInfo'
on field 'status': rejected value [null];
...
[Failed to convert property value of type 'java.lang.String' to
required type 'com.my.project.model.Status' for property 'status';
nested exception is java.lang.IllegalStateException: Cannot convert
value of type [java.lang.String] to required type
[com.my.project.model.Status] for property 'status': no matching
editors or conversion strategy found],
Looks like you have the same problem as i!.
There is a method in the controller that serves as a hook where you could specify how to transform the String values, that came from the HTTP request, to a concrete object!.
The method is called initBinder, and there you attach the right behavior to do the conversion properly. I am still researching, but so far, looks good.
Take a look at this :
Form Values to be Null instead of "" in Spring
http://kaushalyas.blogspot.com.ar/2011/02/data-binding-in-spring-mvc.html
Hope it helps to found the solution!
Greetings
Victor.

Play Framework: automatic validation of controller methods applied?

I have some issue with validation of parameters passed to a controller method.
Following the suggestion from the tutorial, I am using the same controller method for "save" and "create new" of an entity. See example in
http://www.playframework.org/documentation/1.2.4/guide9
So, my controller method looks like:
public static void saveEntity(long l, Long itemId,
#Required(message="error.shouldspecifyname") String name,
#Required(message="error.shouldspecifycategory") String category)
If 'itemId' is not part of the data sent via an HTTP request - it is supposed to be set to 'null'.
Unfortunately, it seems like "Play" is automatically adding a validation error on the "missing" parameter.
When looking into the validation errors' list, every time 'itemId' is 'null' - I am getting an error Incorrect value for field itemId
Is it a documented behavior? Any way to override it, or "get rid" of the error.
I am handling the errors simply using redirection, like:
if(validation.hasErrors() )
{
validation.keep();
showSomePage();
}
So the errors are displayed "out of the context" they get generated. This is the reason the "automatic" error bothers me.
Thanks for any hint.
Most likely it fails to validate itemId because it's declared as Long, are you sure you have "Long" there ant not just "long"? We are using validation with controllers every where and it works with #Required and passed "null" to "Long" values.
Worst case you can remove error from validation object based on "itemId" key, also if you're using controller to save model object, you might want to use:
public static void saveEntity(#Required #Valid MyEntity entity) {
if(validation.hasErrors() ) {
validation.keep();
showSomePage();
}
entity.save();
}
It will automaticly hook your changes inside existing entity if you pass ID from page with:
<input type="hidden" name="myEntity.id" value="${myEntity.id}">

Resources