5

I have UsersController with method:

@RequestMapping(value={"/new"}, method=RequestMethod.GET)
public String showCreationForm(@ModelAttribute User user){
    return "user_registration_form";
}

which displays registration form. I want to keep modularity (would be nice to use this controller in some other project) in my project so User is an interface and there is its implementation - UserImpl. The problem is that Spring cannot instatiate User interface. Is there a way to configure spring to use some default implementation of User?

Bladositto
  • 293
  • 3
  • 14
  • 1
    Why do you want Spring to instantiate your class? Spring brings AOP and DI, if you want to use them then you should create a session-scoped or a request-scoped bean. – Boris Treukhov Aug 30 '12 at 12:47
  • @Modelattribute does the instatiation for me. – Bladositto Aug 30 '12 at 22:00
  • Does this answer your question? [Spring MVC ModelAttribute as Interface](https://stackoverflow.com/questions/35164774/spring-mvc-modelattribute-as-interface) – Jacob van Lingen Nov 23 '20 at 13:15

2 Answers2

4

You can provide an object to be populated with request data using @ModelAttribute-annotated method:

@ModelAttribute
public User createUser() {
    return new UserImpl();
}
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • Not quite what I was looking for. I'm trying to avoid direct invocations of UserImpl. One idea is to use interface EmptyUserFactory in controller. Its implementation would be injected and use to retrive UserImpl object. But maybe some better idea? – Bladositto Aug 30 '12 at 14:44
  • 2
    I've just realized that solution from my previous comment is crappy. I would loose ability to validate user by means of @Valid annotation. – Bladositto Aug 30 '12 at 18:04
0

Create a simple class that implements the interface minimally. It is the same idea as an interface, but it is a class. It does not contain any of your logic or validation or anything else. It is just the simplest implementation of the interface, call it UserSimple, and it implements your interface. It is called a Data Transfer Object.

public class UserSimple implements User {
    String name;
    String address;
    //getters and setters only
}

Add a converter that copies the real properties of the UserImpl into the UserSimple.

@Component
public class ImplToSimpleConverter 
        implements Converter<UserImpl, UserSimple> {

    @Override
    public UserSimple convert(UserImpl source) {
        UserSimple target = new UserSimple();
        BeanUtils.copyProperties(source, target);
        return target;
    }
    
}

Use UserSimple in the handler.

@RequestMapping(value={"/new"}, method=RequestMethod.GET)
public String showCreationForm(@ModelAttribute UserSimple user){
    return "user_registration_form";
}

This allows you to keep the code generic. Adding a different converter is all you would have to do to use the same class in a different application.

downeyt
  • 1,206
  • 2
  • 12
  • 23