I'm having a problem regarding the validation error lost in render phase, but not sure whether this is bug in spring portlet mvc.
When The validation is done in action phase, the error will be store in the model attribute. However, if the model attribute was replaced in render phase, the errors that result from action phase was reset. Hence the error message cannot be display on jsp. In the example following, I have a jsp with one form input which is 'secondaryEmail' and the modelAttribute is "emailForm".
when the secondaryEmail was left blank and submit, the output log is as following. the log output:Code:public class PersonalDetailsController { private static final Log LOGGER = LogFactory.getLog(PersonalDetailsController.class); @ModelAttribute("emailForm") public EmailForm getEmailForm() { return new EmailForm(); } // --maps the incoming portlet request to this method @RenderMapping public String showDefaultPage(RenderRequest request, Model model) { Map<String, Object> modelMap = model.asMap(); Set<String> keys = modelMap.keySet(); for(String key: keys){ LOGGER.info("Render phase 1 ===> Model attribute: Map key = ["+key+"]; value = ["+modelMap.get(key)+"]"); } model.addAttribute("emailForm", new EmailForm()); Map<String, Object> newModelMap = model.asMap(); keys = newModelMap.keySet(); for(String key: keys){ LOGGER.info("Render model ===========> Map key: "+key+"; value: "+newModelMap.get(key)); } return "personalDetails"; } @ActionMapping(params = "myaction=editEmail") public void editEmail(ActionRequest request, ActionResponse response, Model model, @ModelAttribute("emailForm") EmailForm emailForm, BindingResult result) { LOGGER.info("+++ Updating email now. +++ ====> email: "+ emailForm.getSecondaryEmail()); ValidationUtils.rejectIfEmptyOrWhitespace(result, "secondaryEmail", "email.required", "Email cannot be empty!!!"); if (result.hasErrors()) { LOGGER.error("+++ Error Validate +++"); Map<String, Object> modelMap = model.asMap(); Set<String> keys = modelMap.keySet(); for(String key: keys){ LOGGER.info("Action: ======> Map key: "+key+"; value: "+modelMap.get(key)); } return; } }
So what I assume is that:17:34:43,735 INFO [STDOUT] 17:34:43,735 INFO [PersonalDetailsController] +++ Updating email now. +++ ====> email: null
17:34:43,737 INFO [STDOUT] 17:34:43,737 ERROR [PersonalDetailsController] +++ Error Validate +++
17:34:43,737 INFO [STDOUT] 17:34:43,737 INFO [PersonalDetailsController] Action: ======> Map key: emailForm; value: secondaryEmail:[null]
17:34:43,737 INFO [STDOUT] 17:34:43,737 INFO [PersonalDetailsController] Action: ======> Map key: org.springframework.validation.BindingResult.email Form; value: org.springframework.validation.BeanPropertyBinding Result: 1 errors
Field error in object 'emailForm' on field 'secondaryEmail': rejected value [null]; codes [email.required.emailForm.secondaryEmail,email.requ ired.secondaryEmail,email.required.java.lang.Strin g,email.required]; arguments []; default message [Email cannot be empty!!!]
17:34:43,765 INFO [STDOUT] 17:34:43,765 INFO [PersonalDetailsController] Render phase 1 ===> Model attribute: Map key = [emailForm]; value = [secondaryEmail:[null]]
17:34:43,765 INFO [STDOUT] 17:34:43,765 INFO [PersonalDetailsController] Render phase 1 ===> Model attribute: Map key = [org.springframework.validation.BindingResult.email Form]; value = [org.springframework.validation.BeanPropertyBinding Result: 1 errors
Field error in object 'emailForm' on field 'secondaryEmail': rejected value [null]; codes [email.required.emailForm.secondaryEmail,email.requ ired.secondaryEmail,email.required.java.lang.Strin g,email.required]; arguments []; default message [Email cannot be empty!!!]]
17:34:43,765 INFO [STDOUT] 17:34:43,765 INFO [PersonalDetailsController] Render model ===========> Map key: emailForm; value: secondaryEmail:[null]
----- end of log -----
whenwas run, the validation error that bind to model attribute "emailForm" was lost.model.addAttribute("emailForm", new EmailForm());
But the main problem is that if I want to get the "emailForm" attribute in render phase by adding one more argument to the render method
the validation result will be reset also and thisCode:public String showDefaultPage(RenderRequest request, Model model, @ModelAttribute("emailForm") EmailForm emailForm) { Map<String, Object> modelMap = model.asMap(); Set<String> keys = modelMap.keySet(); for(String key: keys){ LOGGER.info("Render phase 1 ===> Model attribute: Map key = ["+key+"]; value = ["+modelMap.get(key)+"]"); } model.addAttribute("emailForm", new EmailForm()); Map<String, Object> newModelMap = model.asMap(); keys = newModelMap.keySet(); for(String key: keys){ LOGGER.info("Render model ===========> Map key: "+key+"; value: "+newModelMap.get(key)); } return "personalDetails"; }will show the bindingResult has no error.LOGGER.info("Render phase 1 ===> Model attribute: Map key = ["+key+"]; value = ["+modelMap.get(key)+"]");
What is the proper solution if I would like to use the model attribute in render phase?
For temporary solution, what I do is make the model attribute "emailForm" session attribute
and get the model attribute through PortletUtils asCode:@SessionAttributes({"emailForm"}) public class PersonalDetailsController{ ... public String showDefaultPage(RenderRequest request, Model model) { ... EmailForm form = (EmailForm)PortletUtils.getSessionAttribute(request, "emailForm", PortletSession.PORTLET_SCOPE); ... } ...
in render phase.Code:PortletUtils.getSessionAttribute(request, "emailForm", PortletSession.PORTLET_SCOPE);
What is the proper way to do this?
Should I log this as bug in jira?
I'm using spring-webmvc-portlet-3.0.4.RELEASE
Thanks


Reply With Quote
