Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decoupling backing store with Spring Web MVC

This is a design pattern question, so I'll illustrate it with a simple example of an address book app.

Firstly a few assumptions. 1. It appears to be acceptable to directly use DB domain objects as the backing store for Spring MVC forms.

Iteration 1 of my app I created a JPA mapped Person object with various attributes attached. Using the DAO pattern I created a persistence object which can getAll, store and delete people from the database. In addition I have a factory method, create, so I can get a person object. Using this DAO object I create a simple web front end. All is good.

In iteration 2 I need to support multiple storage types, so I create an interface for person, which has multiple implementations, and an interface for the DAO persistence, again with multiple implementations. Also, person was extended to be able to have multiple addresses.

interface IPerson {
    public String getName();
    public List<IAddress> getAddresses();
}

But, when it comes to updating the web interface to be able to deal with these multiple implementations I have an issue. The persistence implementation is injected by Spring. And, because that persistence object has a factory method I am all good for creating the IPerson implementation. But, if I want to do something fancy like allow multiple addresses be submitted as part of the one request then I have an issue. To allow this to work with Spring you seem to need to use an AutoPopulatingList, so spring can just .get(#) the record an copy the attributes in.

So, one solution to making this work is to require all persistence implementations use an autopopulating list, and create the correct implementation for all child classes. Is this appropriate, given that we'd need to apply this @PostLoad with JPA as the base lists get replaced by Hibernate.

The alternative is to not make any assumptions about the implementation passed into the persistence implementation and convert/copy the objects across to the appropriate type. This looks better, as then the Domain object are kept simple, and all the storage complexity is in the DAO. In this case we'd use a Default* implementation of the IPerson and IAddress interfaces.

Even though I like the second option better, I am not necessarily comfortable with this situation. Can anyone offer any insights or advice?

like image 238
Nigel Avatar asked Jan 23 '23 22:01

Nigel


1 Answers

The alternative is to not make any assumptions about the implementation passed into the persistence implementation and convert/copy the objects across to the appropriate type. This looks better, as then the Domain object are kept simple, and all the storage complexity is in the DAO.he alternative is to not make any assumptions about the implementation passed into the persistence implementation and convert/copy the objects across to the appropriate type.

This is the pattern I've followed with Spring MVC

  • A package of domain objects, which have no references to services/DAO code (think of this as your model)
  • The controller layer, services layer, and DAO layer operate on Domain objects
  • To handle form controllers, use a separate layer of "command" or "form" objects which model the data that the user is filling out in the form, not your domain objects. Users submit to a controller which binds the request to a "command"/"form" object, and your controller maps or converts these beans to your domain beans.

For example, you might have a pretty rich User object, but when new Users sign up, they only need to supply 2 or 3 fields. I would model this as a UserSignupCommand and the UserSignupController uses this as it's command class (not the User domain object). The controller is then responsible for taking the UserSignupCommand bean and either converting the data to a User bean or whatever other type of input your services layer requires.

I would not recommend using domain objects as the form backing objects because in most cases there is not a true matchup between "the object in my domain I am modeling" and "the data supplied by the user in a form".

like image 79
matt b Avatar answered Jan 31 '23 22:01

matt b