Announcement Announcement Module
Collapse
No announcement yet.
Bind abstract domain object to concrete class in controller Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Bind abstract domain object to concrete class in controller

    Hi!

    I have an abstract domain class called Item extended by many class.

    I wanto to have only one Dao / Service / Controller that handle all classes that extend Item.

    My dao and my service work ok.

    My problem is on controller:

    I can create FORM for create update and show returning the correct view based on the instance type returned from service given Item id.

    But i cannot save or modify Item object, because when I call for instance the create method:

    Code:
    @RequestMapping(method = RequestMethod.POST)
    public String create(final Item item, final BindingResult bindingResult, final Model uiModel, final HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
        	...
        }
        	
        uiModel.asMap().clear();
        itemService.saveItem(item);
        return "redirect:/item/" + UrlUtil.encodeUrlPathSegment(attrezzatura.getId().toString(), httpServletRequest);
    }
    I got the following exception:

    Could not instantiate bean class [...Item]: Is it an abstract class?; nested exception is java.lang.InstantiationException

    How can I bind Abstract class to correct Concrete class?

    I think I can do it in init binder.. but I have no idea on how to do it!

    Thank you!!
    Marco

  • #2
    The error is quite clear and it is obvious that you cannot instantiate an abstract class. Spring by default will try to instantiate the given type by using the default constructor. You can create a method annotated with @ModelAttribute and also annotate the method parameter with @ModelAttribute the method will then be used to construct the object, you can put whatever you want inside the method.

    Comment


    • #3
      You can use the following code to customize your bean creation logic:

      @ModelAttribute("item")
      public Item getItemInstance() {
      return ItemFactory.getItem(); //logic to create actual Item instance
      }
      @RequestMapping(method = RequestMethod.POST)
      public String create(final Item item, final BindingResult bindingResult, final Model uiModel, final HttpServletRequest httpServletRequest) {
      }

      The above controller method declaration should be replaced as follows:
      @RequestMapping(method = RequestMethod.POST)
      public String create(@ModelAttribute("item") Item item, final BindingResult bindingResult, final Model uiModel, final HttpServletRequest httpServletRequest) {
      }
      Hope this will help.

      Comment


      • #4
        Thank you very much! The explanation is very clear.

        But I have not understand how can I get the correct type of the object returned by the view in public Item getItemInstance().

        Do I need to set a request parameter "type" in createForm() and then get from it, or there's some way to get Item returned from view, detect the correct concrete class and then return the correct instance?

        Comment


        • #5
          There is no item returned from the view only strings (that is why the whole type conversion thing is needed). So you need a way to determine the type of object.

          Comment


          • #6
            Ok thank you.

            I solved using an input type hidden in view where I put the SimpleClassName of the object in createForm/updateForm.

            Then I've implemented:

            Code:
            @ModelAttribute("item")
            public Item getItem(final HttpServletRequest request){
            	String type = request.getParameter("type");
            	if (type!=null){
            		if (type.equals(Idroestrattore.class.getSimpleName())){
            			return new Idroestrattore();
            		}
            		if (type.equals(CarrelloSemovente.class.getSimpleName())){
            			return new CarrelloSemovente();
            		}
            		if (type.equals(SollevamentoMateriale.class.getSimpleName())){
            			return new SollevamentoMateriale();
            		}
            	}
            	return null; /////
            }

            Comment


            • #7
              Sorry for being late.
              Yes. your approach is fine as per my understanding.

              Comment


              • #8
                Thank you!!!

                Byeee

                Comment

                Working...
                X