Spring Mvc ModelAttribute with referencing name is not working? - spring

I want to to create different #Entity entities within the same Controller.
#RequestMapping(value="create", method=RequestMethod.GET)
public String GET(Model model) throws InstantiationException, IllegalAccessException
{
Class<?> clazz = ????; // a Random POJO is chosen, i want to use POJOs!!
Object object = clazz.newInstance();
model.addAttribute("object", object);
return "create";
}
#RequestMapping(value="create", method=RequestMethod.POST)
public #ResponseBody Object POST(#ModelAttribute(value="object") Object object)
{
System.out.println("POST! got type: " + object.getClass().getName());
return object;
}
In the Post Method I get NULL for #ModelAttribute(value="object") Object object
If I change it to #ModelAttribute(value="object") realType object it is working perfectly fine. But I don't know the type yet.
I thought the #ModelAttribute can achieve this anyway with the name "object" but apparently not. What am I missing?

There is no actual model object named object when you submit, spring constructs it based on the parameter type and will bind the properties accordingly.
You have 2 choices to make it work
Store the object in the session
Use a #ModelAttribute annotated method
If neither of these are there spring will simply look at the method argument and use reflection to construct an instance of that class. So in your case it will only be Object and after that binding will fail.
Store object in the session
#Controller
#SessionAttributes("object")
public class MyController { ... }
Make sure that when you are finished that you call the setComplete() method on a SessionStatus object.
Use a #ModelAttribute annotated method
Instead of creating and adding the object in a request handling method create a speficic method for it.
#ModelAttribute("object")
public Object formBackingObject() {
Class<?> clazz = ????; // a Random POJO is chosen, i want to use POJOs!!
Object object = clazz.newInstance();
return object;
}
This method will be called before each request handling method, so that a newly fresh object is constructed which will be used for binding.

Related

#ModelAttribute always maps Boolean to false

when I try to map Boolean value from url to spring controller, it always map to false.
This is my url
http://localhost:8080/myurl?isFirstTime=true
here is my controller
#RequestMapping(value = "/myurl", method = RequestMethod.GET)
public ResponseEntity<?> getMyUrl(#Valid #ModelAttribute MyObject ap,BindingResult bindingResult ) {
//here isFirstTime is always set to false
}
MyObj is POJO and has several other attributes which are mapping perfectly
public class Myobj{
private boolean isFirstTime
//there are other members as well
//getter setter
i tried putting #JsonProperty but that also didn't work
#JsonProperty
private boolean isFirstTime
any idea what am I doing wrong here ?
With #ModelAttribute, the object will be initialized:
From the model if already added via Model.
From the HTTP session via #SessionAttributes.
From a URI path variable passed through a Converter.
From the invocation of a default constructor.
From the invocation of a "primary constructor" with arguments matching to Servlet request parameters; argument names are determined via JavaBeans
In your case, it might relative to the last statement.
You can try 2 way to solve it:
- Provide the constructor with the boolean argument in Myobj.java
- Add more method to initialize the #ModelAttribute Myobj firstly
#ModelAttribute
public Myobj initObj(#RequestMapping boolean isFirstTime){
Myobj obj = new MyObj();
obj.setIsFirstTime(isFirstTime);
return obj;
}
The most easiest method could be
#RequestMapping(value = "/myurl", method = RequestMethod.GET)
public ResponseEntity<?> getMyUrl(#Valid #ModelAttribute MyObject ap,#RequestParam boolean isFirstTime, BindingResult bindingResult ) {
//here isFirstTime is always initialized from incoming request parameters
// you can set it ap.isFirstTime(isFirstTime); // or whatever your setter method is
}
I stuck at this problem, but I've found that we must use Boolean object instead of boolean primitive type to map boolean value correctly in ModelAttribute

Why we add #ModelAttribute("r") Reg reg in controller class?

#RequestMapping(value="/addpost",method=RequestMethod.POST)
public ModelAndView addpost(HttpServletRequest request,HttpServletResponse response,#ModelAttribute("r") Reg reg)
{
int id=r.id;
System.out.println(id);
return mv;
}
In this code,there is given #ModelAttribute("r") Reg reg.Wether this modelattribute is taking values from jsp page?Can anyone explains the working of this ModelAttribute?
There are two usage of #ModelAttribute
At the Method Level
When the annotation is used at the method level it indicates the purpose of that method is to add one or more model attributes. Such methods support the same argument types as #RequestMapping methods but that cannot be mapped directly to requests.
#ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("msg", "Welcome to the Netherlands!");
}
In the example, method adds an attribute named msg to all models defined in the controller class.
As a Method Argument
When used as a method argument, it indicates the argument should be retrieved from the model. When not present, it should be first instantiated and then added to the model and once present in the model, the arguments fields should be populated from all request parameters that have matching names.
In the code snippet that follows the employee model attribute is populated with data from a form submitted to the addEmployee endpoint.
#RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
public String submit(#ModelAttribute("employee") Employee employee) {
// Code that uses the employee object
return "employeeView";
}
Refer : What is #ModelAttribute in Spring MVC?

How model annotated methods should interact?

I would like to know how controller methods should interact with ModelAttribute annotated methods.
For example handlePage method would like to filter the list created by createList method?
Or set the id for the object created by createAnObject method?
Is it possible or ModelAttribute annotated methods are designed to attach static data to the model?
#ModelAttribute("someList")
public ArrayList<SomeList> createList() {
return new ArrayList<SomeList>(100);
}
#ModelAttribute("anObject")
public AnObject createAnObject() {
return new MyObject();
}
#RequestMapping(method=RequestMethod.GET)
public void handlePage(Model model) {
//Do some stuff to populate the model....
}
The two shouldn't really interact. #ModelAttribute, in this context, is intended for exposure of reference data, i.e. data that doesn't depend on the details of the request.
If your handler method needs to modify that data, then #ModelAttribute isn't appropriate. Instead, the handler method should explicitly add the data to the model after modifying it.

Spring MVC 3.0: How do I bind to a persistent object

I'm working with Spring MVC and I'd like it to bind a a persistent object from the database, but I cannot figure out how I can set my code to make a call to the DB before binding. For example, I'm trying to update a "BenefitType" object to the database, however, I want it to get the object fromthe database, not create a new one so I do not have to update all the fields.
#RequestMapping("/save")
public String save(#ModelAttribute("item") BenefitType benefitType, BindingResult result)
{
...check for errors
...save, etc.
}
There are several options:
In the simpliest case when your object has only simple properties you can bind all its properties to the form fields (hidden if necessary), and get a fully bound object after submit. Complex properties also can be bound to the form fields using PropertyEditors.
You may also use session to store your object between GET and POST requests. Spring 3 faciliates this approach with #SessionAttributes annotation (from the Petclinic sample):
#Controller
#RequestMapping("/owners/*/pets/{petId}/edit")
#SessionAttributes("pet") // Specify attributes to be stored in the session
public class EditPetForm {
...
#InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
// Disallow binding of sensitive fields - user can't override
// values from the session
dataBinder.setDisallowedFields("id");
}
#RequestMapping(method = RequestMethod.GET)
public String setupForm(#PathVariable("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet); // Put attribute into session
return "pets/form";
}
#RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
public String processSubmit(#ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "pets/form";
} else {
this.clinic.storePet(pet);
// Clean the session attribute after successful submit
status.setComplete();
return "redirect:/owners/" + pet.getOwner().getId();
}
}
}
However this approach may cause problems if several instances of the form are open simultaneously in the same session.
So, the most reliable approach for the complex cases is to create a separate object for storing form fields and merge changes from that object into persistent object manually.
So I ended up resolving this by annotating a method with a #ModelAttribute of the same name in the class. Spring builds the model first before executing the request mapping:
#ModelAttribute("item")
BenefitType getBenefitType(#RequestParam("id") String id) {
// return benefit type
}
While it is possible that your domain model is so simple that you can bind UI objects directly to data model objects, it is more likely that this is not so, in which case I would highly recommend you design a class specifically for form binding, then translate between it and domain objects in your controller.
I'm a little confused. I think you're actually talking about an update workflow?
You need two #RequestMappings, one for GET and one for POST:
#RequestMapping(value="/update/{id}", method=RequestMethod.GET)
public String getSave(ModelMap model, #PathVariable Long id)
{
model.putAttribute("item", benefitDao.findById(id));
return "view";
}
then on the POST actually update the field.
In you example above, your #ModelAttribute should already be populated with a method like the above method, and the properties be bound using something like JSTL or Spring tabglibs in conjunction with the form backing object.
You may also want to look at InitBinder depending on your use case.

Custom bean instantiation logic in Spring MVC

I have a Spring MVC application trying to use a rich domain model, with the following mapping in the Controller class:
#RequestMapping(value = "/entity", method = RequestMethod.POST)
public String create(#Valid Entity entity, BindingResult result, ModelMap modelMap) {
if (entity== null) throw new IllegalArgumentException("An entity is required");
if (result.hasErrors()) {
modelMap.addAttribute("entity", entity);
return "entity/create";
}
entity.persist();
return "redirect:/entity/" + entity.getId();
}
Before this method gets executed, Spring uses BeanUtils to instantiate a new Entity and populate its fields. It uses this:
...
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
Here's the problem:
My entities are Spring managed beans. The reason for this is to inject DAOs on them. Instead of calling new, I use EntityFactory.createEntity(). When they're retrieved from the database, I have an interceptor that overrides the
public Object instantiate(String entityName, EntityMode entityMode, Serializable id)
method and hooks the factories into that.
So the last piece of the puzzle missing here is how to force Spring to use the factory rather than its own BeanUtils reflective approach? Any suggestions for a clean solution?
Thanks very much in advance.
You can use #ModelAttribute-annotated method to pre-populate the model with your bean. Then data binder will use that bean instead of instantiating the new one. However, this will affect all method of the controller.
#ModelAttribute
public Entity createEntity() { ... }

Resources