Java – Implementing MVC when using JPA


As I have understood MVC, the logic for the model should also go into model itself – making every object a selfcontained entity. This means that the methods of an class has to have triggers and chains of actions. For example, by using setZipCode(zip) in a Person class could trigger an action where it looks up the zip code from a zip to city table, and then sets setCity(city) at the same.

This all seems nice and all, but what happens when you take some JPA implementation into the picture? As I see it, the setters and getters of the class has to be clean of all extra logic, as the JPA implementation uses these to build up the objects. Therefore you cant call setCity inside setZipCode. We have gone around this is a project I work with by moving all model-specific logic to the controller layer. Instead of calling the Person directly in this case, we would call PersonController.setAddressInfo(zip) which handles both, or something like this. Maybe a nicer option would be to have transient functions inside the entity itself that does this.

So here's my question: Have I missed something fundamental in the prinicples of MVC or JPA, or can't MVC just not be fully implemented when using an ORM layer? Would it be better if the generic setters and getters be private for JPA and the classes would have a separate public, transient, API meant for the developers? (Hibernate doesn't seem to mind accessing private methods for some reason.)

Of the JPA implementations we use Hibernate in the project, my colleague has used EclipseLink in another project and i've been reading a little something about OpenJPA lately.

Best Solution

I made the experience, that you will probably have to add another layer between the actual JPA Domain Objects and your MVC Framework Controller. Literature about JPA calls them Data Access Objects (DAOs) Ideally, the JPA business Objects are just POJOs (Plain Old Java Objects) with getters and setters that don't have any logic and the DAOs implement operations like

List<Post> PostDao::searchPostsByDate(Date d);
void PostDao::save(Post p);

I worked with architectures that even had another service Layer above the DAO Layer where DAOs were specific to one domain model entity and the service class did Transaction Management and called the corresponding DAO methods. These services could interact with several DAOs so that the service could offer methods like

City MainService::getCityByZipCode(ZipCode zc);

Personally I think that the service layer isn't mandatory when you e.g. use Springs @Transactional annotation in your DAOs and offer proper methods like

City ZipCodeDAO::getCity(ZipCode z);