13

I'm going to start a new project to learn spring boot, spring data, and the hexagonal architecture. From my understanding the hexagonal architecture aims to separate the core or domain layer from the database operations (Infrastructure Layer). I have seen the following project structure for this architecture.

The Core Layer has:

Services-> Where the logic goes (interfaces and their implementations).

Entities -> These are going to be used in the entire application.

Repository-> Interfaces that the infrastructure layer has to implement.

The Infrastructure Layer has the implementation of the Repository interfaces, the JPA entities, calls made to the database (hibernate) and some sort of functions to transform the JPA entities to the Core Entities (mappers?).

Spring data has a very useful way to implement CRUD operations:

public interface UserRepository extends JpaRepository<User, Integer> {
}

However, I think if I use spring data, the JPA entities won't be part of the Infrastructure Layer if UserRepository is part of the Core Layer. This means that the Core entities would be useless. Should I create another UserRepository interface that belong to the Core Layer or Is there something I am missing?

UPDATE:

My concern using spring data comes from that I have to include the JPA entities inside the domain, which In theory would violate the hexagonal architecture.

So I was thinking to separate the domain Entities from the JPA entities. but If I do this I don't know where the repository of Spring Data should go and also find a way to transform the JPA entities into the Domain entities.

To ilustrate a little bit better I'm going to assume that I need to connect to a database from my application to read a users table.

This could be Domain Entity:

public class UserDomain{
  private String name;
  ....//More fields, getters, and setters.

From my understanding, the services should include the logic and operates the Domain entities.

public interface UserService{
  public void create(UserDomain user);
  ...

The implementation:

public class UserServiceImpl implements UserService{
  public void create(UserDomain user) {
     ... //Calling the repository(Spring Data Repository?)

The above along with the repository interface is what I consider the Domain (If I'm wrong please correct me). Next, the infrastructure is composed by the JPA entities

@Entity
@Table(name="users")
public class User{
  @Column(name="name")
  private String name;
  ... // More Fields, getters, and setters

I think the interface in which I call Spring Data should be in the infrastructure part because later I need to map the JPA entities into the Domain entities and maybe I need to use yet another class (and adapter?) to do that mapping. Is this approach correct or Is there any other way? Sorry for the long post,I hope I have made myself clear.

Rafael
  • 513
  • 4
  • 17

3 Answers3

19

Here is a good article on how to connect your database to your application: http://www.dossier-andreas.net/software_architecture/ports_and_adapters.html

What you are trying to do is creating a 'secondary port' and 'secondary adapter'.

The 'secondary port' (= interface) describes what to do, but has no framework dependencies. The 'secondary adapter' (= implementation) uses the jpa-repositories.

A jpa-entity cannot be your domain. It describes how the data is stored in the database. So a jpa-entity cannot be used in the 'secondary port', only your domain.

The 'secondary adapter' will need to convert your domain to jpa-entities.

Be careful, though, if you really want to use the proper hexagonal architecture. The power of Hibernate, and later JPA, was that the jpa-entity is your domain. It makes things a lot simpler (and harder). By splitting your domain from your entities, you'll loose lazy-loading opportunities, clear transaction boundaries, orphan deletion, ... Maybe you should make a trade-of and putting jpa within the core-layer.

I hope you've found this helpfull

Tom Van Rossom
  • 1,325
  • 9
  • 18
  • So there is no solution to keep lazy-loading opportunities **AND** use proper hexagonal architecture ? I feel desperate about this ! – Anddo Dec 16 '19 at 19:04
  • 1
    In my opinion, those are the problem with frameworks. They provide you the skeleton, all you have to do is wrap yourself to it, you are bond with their decisions. No doubt hibernate is a powerful tool. – mubeen Nov 07 '20 at 15:22
5

I'm a little confused about your question. You talk a lot about layers, while what I consider "the article" about hexagonal architecture uses that term (almost ?) exclusively for describing what not to do.

Spring Data fits nicely with the hexagonal approach: Entities form your core domain, repository interfaces form the database facing API. Note that the implementation (outside the core domain, mostly provided by Spring Data itself) depends on the interface, not the other way round). Services and/or Controler form one or more user-facing APIs.

There are some violations of the rules prescribed by the hexagonal architecture: The annotations on the entities and also on repositories. They are inside the core domain but depend on the usage/implementation of the database access by being part of JPA or Spring Data.

JPA itself violates the hexagonal architecture even further in that the behavior fo the persistence implementation might leak heavily into your domain because if you work with managed entities any change gets automatically tracked and eventually persisted without any call to the persistence API. Also, changes to the persistence layer like the configuration of the flush strategy might completely change the behavior of your API.

Jens Schauder
  • 65,795
  • 24
  • 148
  • 294
1

To add to Tom's answer, I found the following options:

  • Create an interface with the same construction that is done in spring data, the problem is that you have to do the cast in the service.
  • Create an abstract class that has undefined functions that give you the data, then in the spring service, inherit from that class and implement the functions with the jpa repository, the problem is that you would not have separated your repository from your service.
  • Do not create an interface for the repositories, create in the domain a class / interface that gives you the data (it would be your repository), that function is what you inherit in the service of spring that will have the figure of repository but not the annotation and there if you use the JPA repository, example.

Domain.Service uses Domain.Repository, Application.repository inherits from Domain.repository and uses a JPA Repository, Aplication.service inherits from Domain.service and uses Domain.repository

The problem with the previous one is the complexity and play with the injection of dependencies of spring for the service of the application

The other problem is the entities, in some projects I simply use the jpa, in another I made an interface only with the getters and setter, the latter is somewhat cumbersome

user3001
  • 3,171
  • 3
  • 25
  • 50
phipex
  • 681
  • 12
  • 13