Search code examples
javaspringspring-mvcinitializationfactory-pattern

Question about instance creation by using Spring framework?


Here goes a command object which needs to be populated from a Spring form

public class Person {

    private String name;
    private Integer age;    

    /**
      * on-demand initialized
      */
    private Address address;

    // getter's and setter's

}

And Address

public class Address {

    private String street;

    // getter's and setter's

}

Now suppose the following MultiActionController

@Component
public class PersonController extends MultiActionController {

    @Autowired
    @Qualifier("personRepository")
    private Repository<Person, Integer> personRepository;

    /**
      * mapped To /person/add
      */
    public ModelAndView add(HttpServletRequest request, HttpServletResponse response, Person person) throws Exception {
        personRepository.add(person);

        return new ModelAndView("redirect:/home.htm");
    }

}

Because Address attribute of Person needs to be initialized on-demand, i need to override newCommandObject to create an instance of Person to initiaze address property. Otherwise, i will get NullPointerException

@Component
public class PersonController extends MultiActionController {

    /**
      * code as shown above
      */

    @Override
    public Object newCommandObject(Class clazz) thorws Exception {
        if(clazz.isAssignableFrom(Person.class)) {
            Person person = new Person();
            person.setAddress(new Address());

            return person;
        }
    }

}

Ok, Expert Spring MVC and Web Flow says

Options for alternate object creation include pulling an instance from a BeanFactory or using method injection to transparently return a new instance.

First option

  • pulling an instance from a BeanFactory

can be written as

@Override
public Object newCommandObject(Class clazz) thorws Exception {
    /**
      * Will retrieve a prototype instance from ApplicationContext whose name matchs its clazz.getSimpleName()
      */
    getApplicationContext().getBean(clazz.getSimpleName());
}

But what does he want to say by using method injection to transparently return a new instance ??? Can you show how i implement what he said ???

ATT: I know this funcionality can be filled by a SimpleFormController instead of MultiActionController. But it is shown just as an example, nothing else


Solution

  • I'm pretty sure he means using the lookup-method system as documented in chapter 3 of the spring reference manual

    Only down side is that <lookup-method> requires a no arg method rather than the newCommandObject(Class) method of MultiActionController.

    this can be solved with something like:

    public abstract class PersonController extends MultiActionController {
    
        /**
          * code as shown above
          */
    
        @Override
        public Object newCommandObject(Class clazz) thorws Exception {
            if(clazz.isAssignableFrom(Person.class)) {
                return newPerson();
            }
        }                          
    
        public abstract Person newPerson();
    }
    

    in the context file:

    <bean id="personController" class="org.yourapp.PersonController">
      <lookup-method name="newPerson" bean="personPrototype"/>
    </bean>
    

    The down side is that using this sort of thing is you are kinda stuck with configuring the controller bean via xml it's not possible (certainly in < 3) to do this with annotations.