Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cleanly (physically) seperate the domain layer from spring data code?

In my DDD-by-the-book application, I have a repository definition like this in my domain layer:

public interface CustomerRepository {
    Customer findById(long id);
    ...
}

The database integration layer contains the implementation of this interface, like this:

public class CustomerDao implements CustomerRepository {
    public Customer findById(long id) {
        // access EntityManager or JDBCTemplates or ...
    }
}

There is a module for each layer, and the database module depends on domain and all integration libraries (e.g. hibernate), while the domain module depends on anything. So we have clean seperation of concerns and no "technical" dependencies of the domain, as DDD proposes. As a consequence, I can switch from database to in-memory persistency by creating an appropriate repository implementation. The implementation that is used is configured in my application layer.

Implementing repositories for database access is awful, and is not necessary any more as we have Spring Data around. To use spring data, I have to define a repository like this.

public interface CustomerRepository implements Repository<Customer, Long> {
    ....

That means, as the repository interface definition is in my domain layer, I now have a dependency of my domain layer to a "technical" library. When switching to the in-memory implementation, I will also have the spring-data classes in my application. I think, this smells a bit.

How do you think about it? How do you handle this? Is it possible to use spring data and NOT have a dependency from my domain layer?

thx

(BTW: My business object are JPA annotated, therefore my domain module has a dependency to javax.persistence. But I can live with this, mainly because javax.persistence only contains annotations and no implementations. So this is rather a "logical" than a "technical" dependency. I suppose a dependency to a spring-data-annotation module would smell less.)

like image 481
tchick Avatar asked Mar 14 '23 22:03

tchick


1 Answers

Recently I have faced the same challange when working on a project using Spring Data and following the Onion architecture. Below is my recipe:

  1. define CustomerRepository (in your domain layer) without references to Spring Data:

    public interface CustomerRepository {
      Customer findById(long id);
      // ..
    }
    
  2. define CustomerDao in your data access layer, which has a dependency to Spring Data:

    public CustomerDao implements Repository<Customer, Long> { }
    
  3. define an implementation of domain CustomerRepository which will delegate all its calls to CustomerSpringDataRepository and which will have a CustomerDao instance injected by Spring:

    public class CustomerRepositoryImpl implements CustomerRepository {
       @Autowired private CustomerDao dao;
    
       public Customer findById(long id) { return doa.findById(id); }
    }
    
  4. inject CustomerRepository in your domain layer

With such approach:

  • your domain layer does not have a dependency to Spring Data, only the data access layer has a dependency to Spring Data
  • your domain does not depend on the data access layer, which means no infrastructure (such as Spring Data) classes show up in the domain

I have created a sample project using Spring Data and the Onion architecture following the above approach.

like image 95
Adam Siemion Avatar answered Apr 07 '23 15:04

Adam Siemion