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
Related
This question already has answers here:
Map a dto to an entity retrieved from database if Dto has Id using MapStruct
(2 answers)
Closed 2 years ago.
I'm creating some Spring app with REST Controller for communication with frontend
I have some complex objects containing reference to other objects. I want to make a Mockup class for those objects to send those mockups instead of real objects. Object -> Mockup conversion is easy, but I can't seem to find good solution for conversion of JSON objects into proper objects (I'm not receiving full data for the nested object, just some Id that let's me extract it from DB).
I think I need to #Autowire object I receive from REST POST, but I neither know if it's possible nor if it's good practice.
What's the proper solution for extracting nested dependancies for objects created from deserialized JSON?
Relevant code snippets:
public class Object {
NestedObject nestedObject;
...
}
//That's the part I'm not sure is proper solution
public class ObjectMockup {
#Autowired
private NestedObjectService nestedObjectService;
...
}
#PostMapping("/new-object")
public ObjectMockup postNewObject(#RequestBody ObjectMockup objectMockup) {
Object object = objectMockup.mockToObject();
...
return new ObjectMockup(object);
}
When I do it like that, NestedObjectService is not initialized and throws Exception as soon as I try to extract nested object from database, Probably because REST Controller did not Autowire Mockup's attribute.
Instead of having a method objectMockup.mockToObject() that fetches the data from the DB, you could:
Inject the service to the method
objectMockup.mockToObject(nestedObjectService)
Have a static factory method that takes the service and the mock:
NestedObject.mockToObject(objectMockup, nestedObjectService)
Have a separate MappingService:
#Service
public class MockToObjectMapperService {
#Autowired NestedObjectService nestedObjectService;
public Object mockToObject(objectMockup) {...}
}
// in Controller
Object object = mockToObjectMapperService.mockToObject(objectMockup);
Though your NestedObjectService could also contain this mapping method.
I have a DTO class and some REST services that sometimes return (among other things) a List of those DTOs.
I cannot alter that DTO, as it's used in several places of the project.
However, only for one specific REST service, I need to exclude some of the fields of that DTO object.
Basically I need to be able to apply this solution only at a certain point.
I tried applying #JsonFilter("restrictionFilter") to my DTO class, but then I get an error if I don't use that filter with a mapper every time I marshall the object into a JSON, like this:
final String writeValueAsString = mapper.writer(
new SimpleFilterProvider()
.addFilter("restrictionFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name", "sizeInByte"))
).writeValueAsString(objectsList);
The error is Cannot resolve PropertyFilter with id 'restrictionFilter'; no FilterProvider configured...
This issue sounds like a perfect Decorator design pattern use.
Create a new DTO with a constructor that gets the original DTO and create which get methods you want or ignore whatever get methods you like.
For example:
public class NewDto {
OldDto oldDto;
public NewDto(OldDto oldDto){
this.oldDto = oldDto;
}
public String getName(){
return oldDto.getName();
}
}
Now you will only need to return the NewDto object, like so:
return new NewDto(oldDto)
I have done a few MVC controllers now and used the spring form tags to pass data back and forth but I realise now my actual understanding is a little thin. In my current case I could actually just send the response as url parameters but there are about 15 and I would prefer to send it as a pojo if possible.
My actual question... is ... is it possible to set up a spring style model attribute in a jsp without the attribute having been passed in and without using the form tags ?
So for example something along the lines of
//Pojo
Class personclass
{
private String name + getters and setters
private String address + getters and setters
private String phone + getters and setters
...
}
////first mvc call
#RequestMapping ("/")
Public ModelAndView LandingPage()
{
// no mention of Person pbject
Return mandvobject;
}
//jsp page
//This is the question!
SET ModelAttribute that wasn't passed in to the page
personclass = X
//New MVC call without a submit
window.open ("/NewMVCCall")
//New mvc call
#RequestMapping ("/NewMVCCall")
Public void newMVCPage(#ModelAttribute ("pc") personclass pc, Model model)
{
//process pc object
}
Or am I missing the point and I would have to send it as a json string parameter? Sorry my grasp of this is pretty rudimentary and I'm not sure whether I could quite easily set my own http form content or whether it is because I have used Spring form objects so far that I haven't grasped the complexity of what is going on behind the scenes (i.e form tags converting pojos to json and so on) ?
Many thanks if anyone has the time to set me on the right path...
I am not sure if I am understood your question correctly but you can link a Model to your controller without having to manually pass it to a the view every time you need it, spring will take care of that:
in your Controller :
public class MyController{
#ModelAttribute("pc")
public PersonneClass getPersonnelClass(){
return new PersonneClass();
}
#RequestMapping ("/NewMVCCall")
Public void newMVCPage(#ModelAttribute ("pc") personclass pc, Model model)
{
//process pc object
}
//other methods
}
It is a good practice to stick to java conventions when naming classes so
(personneClass ) must start with an uppercase (PersonneClass) .
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.
I'm working on converting a legacy project to Spring (trying to adjust little as possible for now) and I'm running into a small issue with mapping/translating legacy parameters to a model attribute object. I may be completely wrong in thinking about this problem but it appears to me that to translate a parameter to a specific model attribute setter is to pass in the request parameter through a method for creating a model attribute and manually call the correct setter:
#ModelAttribute("form")
public MyForm createMyForm(#RequestParameter("legacy-param") legacy) {
MyForm myForm = new MyForm();
myForm.setNewParam(legacy);
return myForm;
}
I don't necessarily want to change the request parameter name yet since some javascript and JSPs are depending on it being named that way but is there any way to do something like this? Or is there a different way to map/translate request parameters to model attributes?
public class MyForm {
#ParameterName("legacy-param")
private String newParam;
public void setNewParam(String value) { ... }
public String getNewParam() { ... }
}
#Controller
public class MyController {
#RequestMapping("/a/url")
public String myMethod(#ModelAttribute("form") MyForm myForm, BindingResult result) { ... }
}
The way you've written that model attribute method is indeed odd. I'm not entirely clear what you're actually trying to do.Assuming there are many parameters, you're going to end up with an awful lot of instances of MyForm in your ModelMap. A more 'normal' way to create model attribute would be like this:
#ModelAttribute("legacyParamNotCamel")
public MyForm createMyForm(#RequestParameter("legacy-param-not-camel") String legacy) {
return legacy;
}
Then in the JSP you can refer to it directly in expression language. e.g.,
<c:out value="${legacyParamNotCamel}"/>
If you want to put them onto a form backing object, you need to do it all in a single method that creates the object, not make new copies of it in each method. (assuming your form has more than a single parameter associated with it.)
--
It seems like what you're really trying to do though is translate the parameter names in the request before the web data binder gets ahold of it, so that you can bind oddly named parameters onto a java bean? For that you'll need to use an interceptor that translates the names before the binding process begins, or make your own subclass of the databinder than can take a property name translation map.
You placed the #ModelAttribute at the Method Level but the intention seems to be more of a formBackingObject hence we should be dealing at the Method Parameter Level
There's a difference.
I put up an explanation here on my blog along examples at Spring 3 MVC: Using #ModelAttribute in Your JSPs at http://krams915.blogspot.com/2010/12/spring-3-mvc-using-modelattribute-in.html