Search code examples
javapackageencapsulationhexagonal-architecturearchunit

Classes and packages encapsulation in an hexagonal architecture


I would like to know if in Java (JDK 17) there is a way to easily handle classes and packages encapsulation in an hexagonal architure. I would like to make unavailable classes present in an adapter to the domain. To illustrate my goal, say we have this package organisation:

com.company
           |-domain
                  |-model
                        |-Customer.java
                        |-Product.java
                  |-ports
                        |-DbPort.java
                        |-ServiceBusPort.java
                  |-services
                           |-CustomerService.java
                           |-ProductService.java
           |-adapters 
                   |-inbound
                           |-rest
                               |-CustomerRestAdapter.java
                               |-ProductRestAdapter.java
                           |-bus
                               |-ServiceBusAdapter.java
                               |-RabbitAdapter.java
                   |-outbound
                           |-db
                              |-entities
                                      |-Customer.java
                                      |-Product.java
                              |-repositories
                                      |-CustomerRepository.java
                                      |-ProductRepository.java
                              |-mappers
                           |-bus
                               |-dtos
                                   |-CutomerDto.java
                                   |-ProductDto.java
                               |-mappers

What I want to achieve is: all classes and packages under com.company.adapters should not be visible from the com.company.domain package. The goal is to prevent developers to use for example the class com.company.adapters.outbound.db.entities.Customer in com.company.domain.services.CustomerService. But classes inside com.company.domain should be accessible from everywhere.


Solution

  • To achieve strong encapsulation with Java, you could make use of maven modules per layer, left, right and domain. I have not tried but I guess Java 9 modules would also help here. Check this link.

    Another approach I use for the sake of simplicity and code readability, is to use a single module, without strong encapsulation, but different packages per layers, one for domain, another for infra..

    And, to enforce architecture rules within this module, like hexagonal ones, I usually define a unit test which fails in case of any violation, for example when some domain package code directly depends on a technical API client implem defined outside the domain. So far I have used Archunit framework for that.

    Also I prefer this approach because, as a developer or new joiner for example, IMO it is much easier to break some architecture rules / encapsulation patterns, not being aware till the code review, rather than breaking / ignoring a test which would fail the build, and which would also act as a spec for these rules.