Results 1 to 9 of 9

Thread: @SessionAttributes not working when used with @ResponseBody

  1. #1

    Default @SessionAttributes not working when used with @ResponseBody

    Hi,
    I am in a fix working with @SessionAttributes annotation when used with @ResponseBody annotation.
    Basically I am writing a controller to edit some tabular data row in a popup window using jquery and AJAX. There are two such methods

    Code:
        
    @Controller
    @SessionAttributes("publisher")
    public class PublisherController {
    
        //Called only once at session start up because once it is added to session attribute map, it is only updated not created at subsequent calls of CRUD methods.
        @ModelAttribute("publisher")
        public Publisher getPublisher() {
            return new Publisher();
        }
    
    @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.GET)
        @ResponseBody
        public ModelMap setupUpdateForm(@RequestParam(value = "id", required = true) Integer publisherId) {
            LOGGER.info("Inside PublisherController.setupUpdateForm");
            ModelMap modelMap = new ModelMap();
            Publisher publisher = publisherService.getPublisher(publisherId);
            //Always pass the copy of publisher to avoid changes in actual hibernate bean. Sometimes if you don't do it, hibernate will complain about duplicate keys
            //because you would have actually modified the bean to make it equal to another already existing bean.
            Publisher publisherCopy = new Publisher();
            publisherCopy = publisherCopy.fill(publisher);
            modelMap.addAttribute(PUBLISHER_KEY, publisherCopy);
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return modelMap;
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.POST)
        @ResponseBody
        public ModelMap updatePublisher(Publisher publisherCopy, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.update");
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            //If user has changed no key field in publisher. Only non key fields need to be updated.
            if (publisherCopy.getName().equalsIgnoreCase(publisher.getName()) && publisherCopy.getVertical().equals(publisher.getVertical())) {
                return updatePublisher(publisher, publisherCopy, status);
            }
            //If code is here, means some key field has changed, hence need to validate for constraints and duplicity of publisher.
            publisherValidator.validate(publisherCopy, result);
            // Some validation has failed, hence take it back to update popup window again.
            if (result.hasErrors()) {
                ModelMap modelMap = setupUpdateForm(publisherCopy.getId());
                modelMap.addAttribute("status", "failure");
                modelMap.addAttribute("errors", result.getAllErrors());
                return modelMap;
            } else {
                //Every validation passes. Just update the publisher.
                return updatePublisher(publisher, publisherCopy, status);
            }
        }
    }
    setupEditForm() takes the id of the tabular row data and using jquery I am able to populate the Publisher object in my popup window, but when I make some changes to the popup window and want to save these changes using
    updatePublisher() method it fails.

    The reason for failure is that publisherCopy parameter of updatePublisher() method contains all its states reset to default instead of expected changed values from the popup window. This object does not have any field set however it was expected that it should contain the bounded value from setupEditForm() method. I have made publisher as a sessionAttribute hence it should persist between these two requests but I always get a new Publisher object instead of object saved in session.

    Can any body please help me out to understand what actually is happening?

    I have just gone through the code of spring 3.0.2 and I feel like that when @ResponseBody is being used, spring does not worry about the session attributes and simply returns null(AnnotationMethodHandlerAdapter.java line 842)
    Code:
    			if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
    				handleResponseBody(returnValue, webRequest);
    				return null;
    			}
    But in other cases it creates a new ModelAndView object from session attributes and model attributes stored in implicitModel object.

    Please comment if I am correct.

    Thanks a ton.
    Ahsan

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,624

    Default

    You made 'publisher' a session attribute NOT 'publisherCopy', by default the names of the method attributes are used. So you will get a fresh instance of Publisher. Either put a @ModelAttribute annotation before the attribute and tell it to use the 'publisher' or rename your attribute.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3

    Default

    Hi Marten,
    Thanks for quick reply. As suggested by you I changed my method definition to following, but still no luck.

    Code:
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.POST)
        @ResponseBody
        public ModelMap updatePublisher(@ModelAttribute("publisher") Publisher publisher, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.update");
            Publisher publisherOrig = publisherService.getPublisher(publisher.getId());
            //If user has changed no key field in publisher. Only non key fields need to be updated.
            if (publisher.getName().equalsIgnoreCase(publisherOrig.getName()) && publisher.getVertical().equals(publisherOrig.getVertical())) {
                return updatePublisher(publisherOrig, publisher, status);
            }
            //If code is here, means some key field has changed, hence need to validate for constraints and duplicity of publisher.
            publisherValidator.validate(publisher, result);
            // Some validation has failed, hence take it back to update screen again.
            if (result.hasErrors()) {
                ModelMap modelMap = setupUpdateForm(publisher.getId());
                modelMap.addAttribute("status", "failure");
                modelMap.addAttribute("errors", result.getAllErrors());
                return modelMap;
            } else {
                //Every validation passes. Just update the publisher.
                return updatePublisher(publisherOrig, publisher, status);
            }
        }
    I still get modelAttribute parameter as a new instance. Also I think by default the attribute name is derived from the class name not from the variable name.

    Please correct me if I am wrong.

    Thanks
    Ahsan

  4. #4

    Default

    The value property for both @SessionAttributes and @ModelAttribute is the name you will store the attribute as. I've had issues not specifying ModelAttribute before the parameter so I think of it more as insurance that I'm getting what I expect.

    I notice you also have an annotated method that returns an empty Publisher object. In this usage, it acts much like the referenceData() method on the old AbstractFormController. Both uses can be used in the same controller but I've never mixed these two for the same attribute name. I'm wondering if perhaps your annotated getPublsher() method is interacting somehow. Can you maybe test to see if that method gets called in the process somehow?

  5. #5

    Default

    @msecrist
    As I mentioned in the comment itself, annotated getPublisher() method is called only once at the startup of session only. I have verified it from debugging as well. If I remove this annotated getPublisher() method, I am getting Session attribute 'publisher' required - not found in session. I am posting my full code for all my CRUD operations.
    Code:
    @Controller
    @SessionAttributes("publisher")
    public class PublisherController {
        public static final Logger LOGGER = Logger.getLogger(PublisherController.class);
        private static final String PUBLISHER_CREATE_URL_KEY = "/secure/publisher/create.htm";
        private static final String PUBLISHER_UPDATE_URL_KEY = "/secure/publisher/update.htm";
        private static final String PUBLISHER_LIST_URL_KEY = "/secure/publisher/list.htm";
    
        private static final String PUBLISHER_CREATE_VIEW_KEY = "secure/publisher/create";
    
        private static final String PUBLISHER_UPDATE_VIEW_KEY = "secure/publisher/update";
        private static final String PUBLISHER_LIST_VIEW_KEY = "secure/publisher/list";
        private static final String PUBLISHER_LIST_REDIRECT_VIEW_KEY = "list.htm";
    
        private static final String PUBLISHER_KEY = "publisher";
        private static final String PUBLISHERS_KEY = "publishers";
        private static final String VERTICALS_KEY = "verticals";
    
        @Autowired
        private PublisherService publisherService;
        @Autowired
        private VerticalService verticalService;
        @Autowired
        private PublisherValidator publisherValidator;
        @Autowired
        private VerticalEditor verticalEditor;
    
        @InitBinder
        public void initBinder(WebDataBinder dataBinder) {
            dataBinder.setDisallowedFields("id");
            dataBinder.registerCustomEditor(Vertical.class, verticalEditor);
        }
    
        //Called only once at session start up because once it is added to session attribute map, it is only updated not created at subsequent calls of CRUD methods.
        @ModelAttribute("publisher")
        public Publisher getPublisher() {
            return new Publisher();
        }
    
        @RequestMapping(value = PUBLISHER_CREATE_URL_KEY, method = RequestMethod.GET)
        public ModelAndView setupCreateForm() {
            LOGGER.info("Inside PublisherController.setupCreateForm");
            ModelMap modelMap = new ModelMap();
            //Always return a new publisher to clear old modelAttribute from previous method executions.
            modelMap.addAttribute(PUBLISHER_KEY, new Publisher());
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return new ModelAndView(PUBLISHER_CREATE_VIEW_KEY, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_CREATE_URL_KEY, method = RequestMethod.POST)
        public ModelAndView createPublisher(Publisher publisher, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.create");
            publisherValidator.validate(publisher, result);
            if (result.hasErrors()) {
                return setupCreateForm();
            } else {
                return createPublisher(publisher, status);
            }
        }
    
        private ModelAndView createPublisher(Publisher publisher, SessionStatus status) {
            publisher.setCreationTime(new Date());
            publisherService.savePublisher(publisher);
            status.setComplete();
            return new ModelAndView(new RedirectView(PUBLISHER_LIST_REDIRECT_VIEW_KEY));
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.GET)
        @ResponseBody
        public ModelMap setupUpdateForm(@RequestParam(value = "id", required = true) Integer publisherId) {
            LOGGER.info("Inside PublisherController.setupUpdateForm");
            ModelMap modelMap = new ModelMap();
            Publisher publisher = publisherService.getPublisher(publisherId);
            //Always pass the copy of publisher to avoid changes in actual hibernate bean. Sometimes if you don't do it, hibernate will complain about duplicate keys
            //because you would have actually modified the bean to make it equal to another already existing bean.
            Publisher publisherCopy = new Publisher();
            publisherCopy = publisherCopy.fill(publisher);
            modelMap.addAttribute(PUBLISHER_KEY, publisherCopy);
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return modelMap;
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.POST)
        @ResponseBody
        public ModelMap updatePublisher(Publisher publisherCopy, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.update");
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            //If user has changed no key field in publisher. Only non key fields need to be updated.
            if (publisherCopy.getName().equalsIgnoreCase(publisher.getName()) && publisherCopy.getVertical().equals(publisher.getVertical())) {
                return updatePublisher(publisher, publisherCopy, status);
            }
            //If code is here, means some key field has changed, hence need to validate for constraints and duplicity of publisher.
            publisherValidator.validate(publisherCopy, result);
            // Some validation has failed, hence take it back to update screen again.
            if (result.hasErrors()) {
                ModelMap modelMap = setupUpdateForm(publisherCopy.getId());
                modelMap.addAttribute("status", "failure");
                modelMap.addAttribute("errors", result.getAllErrors());
                return modelMap;
            } else {
                //Every validation passes. Just update the publisher.
                return updatePublisher(publisher, publisherCopy, status);
            }
        }
    
        private ModelMap updatePublisher(Publisher publisher, Publisher publisherCopy, SessionStatus status) {
            publisher = publisher.fill(publisherCopy);
            publisher.setUpdateTime(new Date());
            publisherService.updatePublisher(publisher);
            status.setComplete();
            ModelMap modelMap = new ModelMap();
            modelMap.addAttribute("status", "success");
            return modelMap;
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, params = "delete", method = RequestMethod.POST)
        public ModelAndView deletePublisher(Publisher publisherCopy, SessionStatus status) {
            LOGGER.info("Inside PublisherController.delete");
            //Take original publisher to delete it from the hibernate managed entities. If you delete publisherCopy instead, hibernate will throw exception
            //because it still contains another bean with same identifier.
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            publisherService.deletePublisher(publisher);
            status.setComplete();
            return new ModelAndView(new RedirectView(PUBLISHER_LIST_REDIRECT_VIEW_KEY));
        }
    
        @RequestMapping(value = PUBLISHER_LIST_URL_KEY, method = RequestMethod.GET)
        public ModelAndView getAllPublishers() {
            LOGGER.info("Inside PublisherController.getAllPublishers");
            return new ModelAndView(PUBLISHER_LIST_VIEW_KEY, PUBLISHERS_KEY, publisherService.getAllPublishers());
        }
    }
    All my create, delete and list methods are working fine except annotated updatePublisher() method because it does not contain the session stored publisher data but it generates a new publisher object.

    However I can access the session stored publisher object in annotated createPublisher() method which is stored via setupCreateForm() method.

    Thanks
    Ahsan

  6. #6

    Default

    One another interesting thing that I found was if I remove @ResponseBody from both my setupUpdateForm() and updatePublisher(), it works fine somehow. Here is slightly modified code that works perfectly. Only significant change that it contains is that now all my update methods are normal requests rather than AJAX requests.
    Code:
    package com.webshrub.cpagenie.app.mvc.controller;
    
    import com.webshrub.cpagenie.app.mvc.propertyeditor.VerticalEditor;
    import com.webshrub.cpagenie.app.mvc.service.PublisherService;
    import com.webshrub.cpagenie.app.mvc.service.VerticalService;
    import com.webshrub.cpagenie.app.mvc.validator.PublisherValidator;
    import com.webshrub.cpagenie.core.publisher.Publisher;
    import com.webshrub.cpagenie.core.vertical.Vertical;
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.WebDataBinder;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.bind.support.SessionStatus;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.view.RedirectView;
    
    import java.util.Date;
    
    @Controller
    @SessionAttributes("publisher")
    public class PublisherController {
        public static final Logger LOGGER = Logger.getLogger(PublisherController.class);
        private static final String PUBLISHER_CREATE_URL_KEY = "/secure/publisher/create.htm";
        private static final String PUBLISHER_UPDATE_URL_KEY = "/secure/publisher/update.htm";
        private static final String PUBLISHER_LIST_URL_KEY = "/secure/publisher/list.htm";
    
        private static final String PUBLISHER_CREATE_VIEW_KEY = "secure/publisher/create";
    
        private static final String PUBLISHER_UPDATE_VIEW_KEY = "secure/publisher/update";
        private static final String PUBLISHER_LIST_VIEW_KEY = "secure/publisher/list";
        private static final String PUBLISHER_LIST_REDIRECT_VIEW_KEY = "list.htm";
    
        private static final String PUBLISHER_KEY = "publisher";
        private static final String PUBLISHERS_KEY = "publishers";
        private static final String VERTICALS_KEY = "verticals";
    
        @Autowired
        private PublisherService publisherService;
        @Autowired
        private VerticalService verticalService;
        @Autowired
        private PublisherValidator publisherValidator;
        @Autowired
        private VerticalEditor verticalEditor;
    
        @InitBinder
        public void initBinder(WebDataBinder dataBinder) {
            dataBinder.setDisallowedFields("id");
            dataBinder.registerCustomEditor(Vertical.class, verticalEditor);
        }
    
        //Called only once at session start up because once it is added to session attribute map, it is only updated not created at subsequent calls of CRUD methods.
        @ModelAttribute("publisher")
        public Publisher getPublisher() {
            return new Publisher();
        }
    
        @RequestMapping(value = PUBLISHER_CREATE_URL_KEY, method = RequestMethod.GET)
        public ModelAndView setupCreateForm() {
            LOGGER.info("Inside PublisherController.setupCreateForm");
            ModelMap modelMap = new ModelMap();
            //Always return a new publisher to clear old modelAttribute from previous method executions.
            modelMap.addAttribute(PUBLISHER_KEY, new Publisher());
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return new ModelAndView(PUBLISHER_CREATE_VIEW_KEY, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_CREATE_URL_KEY, method = RequestMethod.POST)
        public ModelAndView createPublisher(Publisher publisher, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.create");
            publisherValidator.validate(publisher, result);
            if (result.hasErrors()) {
                return setupCreateForm();
            } else {
                return createPublisher(publisher, status);
            }
        }
    
        private ModelAndView createPublisher(Publisher publisher, SessionStatus status) {
            publisher.setCreationTime(new Date());
            publisherService.savePublisher(publisher);
            status.setComplete();
            return new ModelAndView(new RedirectView(PUBLISHER_LIST_REDIRECT_VIEW_KEY));
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.GET)
        public ModelAndView setupUpdateForm(@RequestParam(value = "id", required = true) Integer publisherId) {
            LOGGER.info("Inside PublisherController.setupUpdateForm");
            ModelMap modelMap = new ModelMap();
            Publisher publisher = publisherService.getPublisher(publisherId);
            //Always pass the copy of publisher to avoid changes in actual hibernate bean. Sometimes if you don't do it, hibernate will complain about duplicate keys
            //because you would have actually modified the bean to make it equal to another already existing bean.
            Publisher publisherCopy = new Publisher();
            publisherCopy = publisherCopy.fill(publisher);
            modelMap.addAttribute(PUBLISHER_KEY, publisherCopy);
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return new ModelAndView(PUBLISHER_UPDATE_VIEW_KEY, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, params = "update", method = RequestMethod.POST)
        public ModelAndView updatePublisher(Publisher publisherCopy, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.update");
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            //If user has changed no key field in publisher. Only non key fields need to be updated.
            if (publisherCopy.getName().equalsIgnoreCase(publisher.getName()) && publisherCopy.getVertical().equals(publisher.getVertical())) {
                return updatePublisher(publisher, publisherCopy, status);
            }
            //If code is here, means some key field has changed, hence need to validate for constraints and duplicity of publisher.
            publisherValidator.validate(publisherCopy, result);
            // Some validation has failed, hence take it back to update screen again.
            if (result.hasErrors()) {
                return setupUpdateForm(publisherCopy.getId());
            } else {
                //Every validation passes. Just update the publisher.
                return updatePublisher(publisher, publisherCopy, status);
            }
        }
    
        private ModelAndView updatePublisher(Publisher publisher, Publisher publisherCopy, SessionStatus status) {
            publisher = publisher.fill(publisherCopy);
            publisher.setUpdateTime(new Date());
            publisherService.updatePublisher(publisher);
            status.setComplete();
            return new ModelAndView(new RedirectView(PUBLISHER_LIST_REDIRECT_VIEW_KEY));
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, params = "delete", method = RequestMethod.POST)
        public ModelAndView deletePublisher(Publisher publisherCopy, SessionStatus status) {
            LOGGER.info("Inside PublisherController.delete");
            //Take original publisher to delete it from the hibernate managed entities. If you delete publisherCopy instead, hibernate will throw exception
            //because it still contains another bean with same identifier.
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            publisherService.deletePublisher(publisher);
            status.setComplete();
            return new ModelAndView(new RedirectView(PUBLISHER_LIST_REDIRECT_VIEW_KEY));
        }
    
        @RequestMapping(value = PUBLISHER_LIST_URL_KEY, method = RequestMethod.GET)
        public ModelAndView getAllPublishers() {
            LOGGER.info("Inside PublisherController.getAllPublishers");
            return new ModelAndView(PUBLISHER_LIST_VIEW_KEY, PUBLISHERS_KEY, publisherService.getAllPublishers());
        }
    }

    But I dont want it to be normal page refresh. I want it to be updated via AJAX.
    I think it is pretty simple requirement to edit a table row data in a popup and save it in database. I did it in JSF successfully but I am having hardtime to do it in spring 3.0.2.

    Thanks
    Ahsan

  7. #7

    Default

    You're getting the session attribute not found in session error because one of the methods that depends on it is called before it has been initialized. It sounds like using the getPublisher method isn't causing you problems anyway I just hadn't seen that used in combination before so it made me wonder. Sorry I missed the comment. I looked it over too quickly I guess.

    It does seem odd that this doesn't work when using the @ResponseBody annotation. I've not done much with @ResponseBody but it seems like that shouldn't affect the treatment of a session object.

  8. #8

    Default

    Yeah.
    Can you please help me to file an issue with spring Jira. I searched that on net but could not find how to do that. They don't seem to have any register link on their Jira website.

    Thanks
    Ahsan

  9. #9

    Thumbs up

    I got this resolved.
    The problem, as stated in first post, was with @ResponseBody.
    When you use @ResponseBody annotation spring just returns null as ModelAndView (see Line 844 AnnotationMethodHandlerAdapter.java). This null modelAndView is used to store the session attributes later on(see Line no 206 HandlerMethodInvoker.java). This method updateModelAttributes uses the session attribute values from the model which will be null if we use @ResponseBody and hence implicitModel will be used which contains only initializer for session attributes not the update values.

    Here is the my modified code to return ModelAndView instead of @ResponseBody
    Code:
    @Controller
    @SessionAttributes("publisher")
    public class PublisherController {
        public static final Logger LOGGER = Logger.getLogger(PublisherController.class);
    
        private static final View JSON_VIEW = new MappingJacksonJsonView();
    
        private static final String PUBLISHER_CREATE_URL_KEY = "/secure/publisher/create.htm";
        private static final String PUBLISHER_UPDATE_URL_KEY = "/secure/publisher/update.htm";
        private static final String PUBLISHER_LIST_URL_KEY = "/secure/publisher/list.htm";
    
        private static final String PUBLISHER_CREATE_VIEW_KEY = "secure/publisher/create";
        private static final String PUBLISHER_LIST_VIEW_KEY = "secure/publisher/list";
    
        private static final String PUBLISHER_LIST_REDIRECT_VIEW_KEY = "list.htm";
    
        private static final String PUBLISHER_KEY = "publisher";
        private static final String PUBLISHERS_KEY = "publishers";
        private static final String VERTICALS_KEY = "verticals";
        private static final String ERRORS_KEY = "errors";
        private static final String STATUS_KEY = "status";
        private static final String SUCCESS_KEY = "success";
        private static final String FAILURE_KEY = "failure";
        private static final String UPDATE_KEY = "update";
        private static final String DELETE_KEY = "delete";
        private static final String ID_KEY = "id";
    
        @Autowired
        private PublisherService publisherService;
        @Autowired
        private VerticalService verticalService;
        @Autowired
        private PublisherValidator publisherValidator;
        @Autowired
        private VerticalEditor verticalEditor;
    
        @InitBinder
        public void initBinder(WebDataBinder dataBinder) {
            dataBinder.setDisallowedFields(ID_KEY);
            dataBinder.registerCustomEditor(Vertical.class, verticalEditor);
        }
    
        //Called only once at session start up because once it is added to session attribute map, it is only updated not created at subsequent calls of CRUD methods.
        @ModelAttribute(PUBLISHER_KEY)
        public Publisher getPublisher() {
            return new Publisher();
        }
    
        @RequestMapping(value = PUBLISHER_CREATE_URL_KEY, method = RequestMethod.GET)
        public ModelAndView setupCreateForm() {
            LOGGER.info("Inside PublisherController.setupCreateForm");
            ModelMap modelMap = new ModelMap();
            //Always return a new publisher to clear old modelAttribute from previous method executions.
            modelMap.addAttribute(PUBLISHER_KEY, new Publisher());
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return new ModelAndView(PUBLISHER_CREATE_VIEW_KEY, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_CREATE_URL_KEY, method = RequestMethod.POST)
        public ModelAndView createPublisher(Publisher publisher, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.create");
            publisherValidator.validate(publisher, result);
            if (result.hasErrors()) {
                return setupCreateForm();
            } else {
                return createPublisher(publisher, status);
            }
        }
    
        private ModelAndView createPublisher(Publisher publisher, SessionStatus status) {
            publisher.setCreationTime(new Date());
            publisherService.savePublisher(publisher);
            status.setComplete();
            return new ModelAndView(new RedirectView(PUBLISHER_LIST_REDIRECT_VIEW_KEY));
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, method = RequestMethod.GET)
        public ModelAndView setupUpdateForm(@RequestParam(value = ID_KEY, required = true) Integer publisherId) {
            LOGGER.info("Inside PublisherController.setupUpdateForm");
            ModelMap modelMap = new ModelMap();
            Publisher publisher = publisherService.getPublisher(publisherId);
            //Always pass the copy of publisher to avoid changes in actual hibernate bean. Sometimes if you don't do it, hibernate will complain about duplicate keys
            //because you would have actually modified the bean to make it equal to another already existing bean.
            Publisher publisherCopy = new Publisher();
            publisherCopy = publisherCopy.fill(publisher);
            modelMap.addAttribute(PUBLISHER_KEY, publisherCopy);
            modelMap.addAttribute(VERTICALS_KEY, verticalService.getAllVerticals());
            return new ModelAndView(JSON_VIEW, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, params = UPDATE_KEY, method = RequestMethod.POST)
        public ModelAndView updatePublisher(Publisher publisherCopy, BindingResult result, SessionStatus status) {
            LOGGER.info("Inside PublisherController.update");
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            //If user has changed no key field in publisher. Only non key fields need to be updated.
            if (publisherCopy.getName().equalsIgnoreCase(publisher.getName()) && publisherCopy.getVertical().equals(publisher.getVertical())) {
                return updatePublisher(publisher, publisherCopy, status);
            }
            //If code is here, means some key field has changed, hence need to validate for constraints and duplicity of publisher.
            publisherValidator.validate(publisherCopy, result);
            // Some validation has failed, hence take it back to update screen again.
            if (result.hasErrors()) {
                ModelAndView modelAndView = setupUpdateForm(publisherCopy.getId());
                ModelMap modelMap = modelAndView.getModelMap();
                modelMap.addAttribute(STATUS_KEY, FAILURE_KEY);
                modelMap.addAttribute(ERRORS_KEY, result.getAllErrors());
                return modelAndView;
            } else {
                //Every validation passes. Just update the publisher.
                return updatePublisher(publisher, publisherCopy, status);
            }
        }
    
        private ModelAndView updatePublisher(Publisher publisher, Publisher publisherCopy, SessionStatus status) {
            publisher = publisher.fill(publisherCopy);
            publisher.setUpdateTime(new Date());
            publisherService.updatePublisher(publisher);
            status.setComplete();
            ModelMap modelMap = new ModelMap();
            modelMap.addAttribute(STATUS_KEY, SUCCESS_KEY);
            return new ModelAndView(JSON_VIEW, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_UPDATE_URL_KEY, params = DELETE_KEY, method = RequestMethod.POST)
        public ModelAndView deletePublisher(Publisher publisherCopy, SessionStatus status) {
            LOGGER.info("Inside PublisherController.delete");
            //Take original publisher to delete it from the hibernate managed entities. If you delete publisherCopy instead, hibernate will throw exception
            //because it still contains another bean with same identifier.
            Publisher publisher = publisherService.getPublisher(publisherCopy.getId());
            publisherService.deletePublisher(publisher);
            status.setComplete();
            ModelMap modelMap = new ModelMap();
            modelMap.addAttribute(STATUS_KEY, SUCCESS_KEY);
            return new ModelAndView(JSON_VIEW, modelMap);
        }
    
        @RequestMapping(value = PUBLISHER_LIST_URL_KEY, method = RequestMethod.GET)
        public ModelAndView getAllPublishers() {
            LOGGER.info("Inside PublisherController.getAllPublishers");
            return new ModelAndView(PUBLISHER_LIST_VIEW_KEY, PUBLISHERS_KEY, publisherService.getAllPublishers());
        }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •