How to bind subclass object in spring form submit as modelAttribute
Asked Answered
K

3

6

I Have

Class Shape {
      //Implementation
}
Class Round extends Shape{
      //Implementation
}

Controller I Have

@Requestmapping(value="/view/form")
public ModelAndView getForm(){
ModelAndView mav=new ModelAndView();
mav.addObject("shape",new Round());
}


@RequestMapping(value="/submit", method = RequestMethod.POST)    
public ModelAndView submitForm(@ModelAttribute("shape") Shape shape){
         if(shape instanceof Round){ //**Not giving positive result**

         }
    }

in Jsp

<form:form action="/submit" commandName="shape" method="post">

//form tags

</form:form>

when I submit the form with Round object. At controller side ModelAttribute is not giving instance of Round . its giving instance of shape only. How to do this

Kef answered 2/6, 2016 at 11:21 Comment(3)
The static type is Shape no matter what you do. This has nothing to do with Spring; this is an issue with static/dynamic typing. You can either cast or create a factory/virtual constructor.Gallous
why cant you submit a Round from the formMug
@Mug there are more shape and same form for each shape.Kef
U
0

You cannot do this. Because those are two different request lifecycles.

@Requestmapping(value="/view/form")
public ModelAndView getForm(){
ModelAndView mav=new ModelAndView();
mav.addObject("shape",new Round());
}

When above request executes, even if you added Round object in mav, it has been converted into html response and sent back to client.

So when below request comes next when you submit the form, it's a totally separate request and spring has no way to identify which object type was added for previous request.

@RequestMapping(value="/submit", method = RequestMethod.POST)    
public ModelAndView submitForm(@ModelAttribute("shape") Shape shape){
         if(shape instanceof Round){ //**Not giving positive result**

         }
    }

But you can try exploring @SessionAttributes, using this you might be able to maintain the same object across different requests

Ultramicrochemistry answered 2/6, 2016 at 20:50 Comment(0)
M
3

this will never work

<form:form action="/submit" commandName="shape" method="post">

you are submitting a shape from the form and expecting a shape in the controller method

public ModelAndView submitForm(@ModelAttribute("shape") Shape shape)

which will never give you an Round object.

simply submit a Round object from the form and use that.

 <form:form action="/submit" commandName="round" method="post">
 public ModelAndView submitForm(@ModelAttribute("round") Round round)

edited :-

have a hiddenInput type in the form which will tell controller the type of Shape it is passing, you can change the value of hidden tag dynamically upon user request.

<input type="hidden" name="type" value="round">

get the value of the type inside contoller and use it to cast the Shape object

     public ModelAndView submitForm(
     @ModelAttribute("shape") Shape shape,
     @RequestParam("type") String type)
     {
     if(type.equals("round")){
      //if type is a round you can cast the shape to a round
      Round round = (Round)shape; 
       }
    }
Mug answered 3/6, 2016 at 3:17 Comment(0)
U
0

You cannot do this. Because those are two different request lifecycles.

@Requestmapping(value="/view/form")
public ModelAndView getForm(){
ModelAndView mav=new ModelAndView();
mav.addObject("shape",new Round());
}

When above request executes, even if you added Round object in mav, it has been converted into html response and sent back to client.

So when below request comes next when you submit the form, it's a totally separate request and spring has no way to identify which object type was added for previous request.

@RequestMapping(value="/submit", method = RequestMethod.POST)    
public ModelAndView submitForm(@ModelAttribute("shape") Shape shape){
         if(shape instanceof Round){ //**Not giving positive result**

         }
    }

But you can try exploring @SessionAttributes, using this you might be able to maintain the same object across different requests

Ultramicrochemistry answered 2/6, 2016 at 20:50 Comment(0)
D
0

Its possible to specify the subclass that you need to bind to. You have to add an additional parameter (hidden input) in your form which specify the type that needs to be bound to. This field must have the same name as the model attribute in this case shape. You then need to implement a converter that converts this string parameter value to the actual instance that you need to bind to

The following are the changes that you need to implement

1)In your jsp add the hidden input inside your

<form:form action="/submit" commandName="shape" method="post">
   <input type="hidden" name="shape" value="round"/>
//other form tags
</form:form>

2)Implement a Converter to convert from String to a Shape

public class StringToShapeConverter implements Converter<String,Shape>{

   public Shape convert(String source){
      if("round".equalsIgnoreCase(source)){
          return new Round();
      }
      //other shapes
   }
}

3) Then register your converter so that Spring MVC knows about it. If you are using Java config you need to extends WebMvcConfigurerAdapter and override the addFormatters method

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter{

   @Override
   public void addFormatters(FormatterRegistry registry){
      registry.addConverter(new StringToShapeConverter());
   }
}

If you are using xml configuration you can use the mvc:annotation-driven element to specify the conversion-service to use. Then register your converter using the FormattingConversionSErviceFactoryBean

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven conversion-service="conversionService"/>

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
       <property name="converters">
           <set>
              <bean class="some.package.StringToShapeConverter"/>
           </set>
       </property>
    </bean>
</beans>
Dang answered 3/6, 2016 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.