My major intention is to do validation for an object in Spring Controller itself.
My code structure looks like
public #ResponseBody
String functionName(#RequestBody Employee employee){}
The idea is to validate the DTO the moment an http post request is hit
For same,I wrote an exception method to be called in constructor which adds the object to an error queue in case of error.
However the problem is, the values are set in spring by setter and not by constructor.
Is there any way/setting to change it so that values are set by constructor.
EDIT
The intention is to validate object employee the moment request is received without writing another method to validate.
My idea was to do validation in constructor of Employee and in case of failure, Pass the data to a error handler and stop object formation itself.
But it seems, In spring constructor is not used to set data, instead setter's are used.
So question is if constructor can be used.
Related
I have the following form model:
ReservationLockRequestForm:
public class ReservationLockRequestForm {
private Restaurant restaurant;
private ReservationInquiryResponse reservationData;
private Time reservationTime;
}
I left out the getters, setters and empty constructor for legibility.
Now, If i call this
formFactory.form(ReservationLockRequestForm.class).bindFromRequest().get()
I get
Invalid property 'restaurant[tables][1][numberOfChairs]' of bean class [models.helpers.forms.ReservationLockRequestForm]: Illegal attempt to get property 'restaurant' threw exception
The Restaurant Model contains a List<Tables> object, and the Tables model does contain a numberOfChairs property.
What am I doing wrong?
EDIT: Adding a Breakpoint in the ReservationLockRequestForm Restataurant Setter revels that the incoming Restaurant object is empty (all properties are null), but a quick check of the request revels that it contains all the data.
You need a custom property editor. You'll need to have a class which extends PropertyEditorSupport e.g. RestaurantPropertyEditor extends PropertyEditorSupport, which is responsible for converting restaurant, or whichever field to and from text representation. It will need to override setAsText and getAsText.
Then in your controller which returns the view, you will need to have
#InitBinder("reservationLockRequestForm ")
public void initBinder(WebDataBinder binder)
{
binder.registerCustomEditor(Restaurant .class, new RestaurantPropertyEditor());
// ... other ones too
}
Often your PropertyEditor will need your dao to convert from an id to an entity and vice versa, you'll need to do all this yourself.
Sometimes it is easier not to use Spring Binding directly with your entity and manually handling the request parameters from the post/get. Keep that in mind, I find this is the case for dealing with parameters which are collections.
Okay I fixed it. Turns out the Front-End was sending the request as Form-Data, not as JSON. I changed that, and without any modifications to the Back-End it worked flawlessly
I have the following code:
#RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Void> flagDevice (#RequestBody List<MobileDeviceData> devicedataList, #RequestHeader(value="special_code") String specialCode) {
// Implementation details
}
Each instance of MobileDeviceData that gets created needs to have a param field filled in with the RequestHeader special_code.
How would I go about doing this so that it is fully populated by the time the flagDevice method body gets called?
Thanks in advance.
This is non trivial.
An HttpMessageConverter is already provided that deserializes the JSON, that's the MappingJackson2HttpMessageConverter. It has access to request headers. You could extend that class to also use the headers for deserialization (this is extremely difficult to do generically, as opposed to only for MobileDeviceData).
You could use Spring AOP, intercept the method, retrieve the arguments, cast to the appropriate types, and assign the value yourself.
The solution I would go for is the simplest: do it yourself in the handler method. Loop the the List and use a corresponding setter to set the specialCode for each MobileDeviceData.
Another option is to define your own HandlerMethodArgumentResolver specifically for List<MobileDeviceData> parameters that need to be constructed from header vales.
I have a dto object which keeps an IP Range using first and last fields. Simple CRUD operations are made with this class using dropwizard (jersey-jackson-hibernate validator)
public class IpRangeDto {
#JsonCreator
public static IpRangeDto fromCidr(#JsonProperty("cidr") String cidr) {
//Resolve CIDR and assign first and last fields
}
#NotNull
#IpAddress // My custom validator
private String first;
#NotNull
#IpAddress
private String last;
}
For the sake of user-friendliness I had decided to add an alternative way to create this object, which is by using CIDR. So the client could send either first and last fields in JSON or only the cidr field. So the way to do it is as above, using #JsonCreator. And it works just fine.
"ipRange":{
"first": "15.0.0.1",
"last": "15.0.0.255",
}
"ipRange":{
"cidr": "15.0.0.0/24"
}
I want to validate this CIDR value that it's the right format so I can return 422 with proper error message. If I throw exception in the constructor/factory method then jersey-jackson returns 400 directly (even if I throw ConstraintViolationException, it's encapsulated by JsonProcessingException).
I could simply ignore the exceptions, and leave the fields empty which will return 422 because of #NotNull constraints but then the error message will not be as clear as it should be.
I tried adding my #Cidr validator next to the #JsonProperty parameter but that doesn't seem to be effective. My understanding is that validation occurs after Jackson is finished with creating Dtos, so with my #JsonCreator approach there might not be any solution to this problem. So I'm open to refactoring suggestions as well.
I am not an expert on the exact integration of Bean Validation into jackson, but I think it is just doing actual property validation. This means as you already pointed out, the entities are created first and then the properties are validated.
Bean Validation (as of version 1.1) also offers so called method validation, in which case you could place your Cidr constraint onto the string parameter of the method, but as said, I don't think that there is an integration in jackson for that.
And one more thing ;-) - static methods and properties are generally excluded from validation in Bean Validation (see also http://beanvalidation.org/1.1/spec/#d0e2815).
Regarding a workaround, one thing comes to mind (even though it feels a bit complicated). Write a custom class level IpRange constraint. In a class constraint you would get passed a IpRangeDto instance and it is up to you to validate the whole object and select the right error message for any violations. Provided you would add a cidr property to the dto which gets set when fromCidr is called, you would have then all information you need for the validation and selection of a proper error message.
I need to implement a controller that has a command object that is backing a filtering form for a search across multiple entries.
The problem is that the i was asked to do that without using POST request, instead using GET request only, and there before loosing the functionality of the default data binding that springs makes happily for us.
So i tried to implement a method, inside my controller, that looks like this:
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (isSearchRequest(request)) {
MyCommandObject myCommandObject = (MyCommandObject) getCommand(request);
System.out.println(managePositionsForm);
}
return super.handleRequestInternal(request, response);
}
But the getCommand returns me a brand new CommandObject with no values, despite that the values are present in the request object (i could retrieve then using the getParameter method of HttpServletRequest). But there isn't any binding.
So the question :
1) Is there any way to archive this?
2) Also is very important, that all the values in the form, are lost and, eventually (if this problem is solved) i will need to "persist" the filters for the users in order to avoid re entering after the first search.
Auto Response : setSessionForm(true); looks like can do the work! (According to javadoc)
Thanks to all!
Greetings
Victor.
Okey, i found a way to archive what a was looking for.
I will explain for the sake of those have the same problem before, and hoping to find a experienced user to validate this method... some quiet common is there a multiple ways to do a same thing and as human beings is very difficult to know without proper acknowledge the right path.. so this i a found looking inside the AbstractFormController (that is excellently documented with javadoc).
So what i did was the following, on my controller constructor i add these lines at the end :
setSessionForm(true);
setBindOnNewForm(true);
That all the magic!
But is not enought with setSessionForm(true). According to javadoc the setBindOnNewForm(boolean) method does the following :
/**
* Set if request parameters should be bound to the form object
* in case of a non-submitting request, i.e. a new form.
*/
So my guess are that these two flags are necessary to be marked as true, because :
The setSessionForm makes posible to store as a session attribute the form object, so "is stored in the session to keep the form object instance between requests, instead of creating a new one on each request" (according to javadoc of the setSessionForm method).
The setBindOnNewForm allows the population of the form object with the initial request (despites what type of request method we have). According the javadoc found the AbstractFormController "Only if bindOnNewForm is set to true, then ServletRequestDataBinder gets applied to populate the new form object with initial request parameters..."
But still i noticed, following the controller flow with a debugger, that the population is happening inside the method "getErrorsForNewForm(HttpServletRequest request)".. that is where a concrete object of type ServletRequestDataBinder is used IF the setBindOnNewForm is true, and later (as the javadoc stated) the onBindOnNewForm method is invoked, allowing the programmer to overwrite it with custom behavior, the default behavior is just empty (again this was double checked against the code of AbstractFormController).
I have an strong felling to validate my thoughts here, so if anyone can help me, that would be alright, besides the problem is solved!
Thanks to all in advance!
Greetings.
I am new to extjs and am trying to implement the update operation. I tried to Google but could not find a solution.
I have form which is used for updating records in a store. For this, I am using the following code in the controller,
var formPanel = Ext.getCmp('displayForm');
var record = formPanel.getRecord();
var values = formPanel.getValues();
record.set(values);
companyStore.sync();
The record.set() method calls the method(i.e.rest service) pointed by the URL specified for update operation in the store’s proxy.
How can I read the values passed by the record.set() method in the rest service coded in java.
I tried with,
#POST
#Produces({"application/xml"})
#Path("/updateData")
public CompanyDataService updateData(#QueryParam("company") Company companyObj){
//code
}
but companyObj is unable to capture the parameter values
There is no "values" parameter being passed. Based on the configuration of your store proxy's Writer (http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.writer.Json), the parameters will either be a single root value (if encode configuration is true), or as individually named parameters, one per model field being persisted.
How is your Writer configured?
Also, just to clarify, record.set() doesn't trigger the proxy call unless autoSync is configured to true. In you example, I suspect the proxy call is happening because you explicitly call sync().