Validate architecture with Java Jigsaw
In July 2017 the version 9 of Java will be relased. A new feature of this version is Jigsaw.
Jigsaw is designed to make Java applications more modular. It introduces the concept of modules and their dependencies to each other. One benefit of a modularized application is, that modules can be optional and therfore be ommitted when linking the application. This results in much smaller size of applications which contain only the necessary modules can now be deployed to embedded plattforms with limited resources in sense of CPU, RAM and storage.
Here we don’t speak about how Jigsaw works, but about one sideeffect of Jigsaw which allows an out-of-the-box validation of software architecture.
Choose an architecture style
Every software has some kind of software architecture.
One example of an architecture style is the following simple onion architecure, which will be used as an example in this post.
The main charateristics of the onion architecture are:
- An outer layer can not be accessed by an inner layer.
- An outer layer can itself access several inner layers (but not necessarily each inner layer).
In our example the layer “Use Case” can access the layers “Repository Contract” and “Domain Entities” but not the layer “Controller”.
On this architecture style we will realize a car rent station application.
The implementation can look like the Java code below. The code snippets are ordered inside out, beginning with the central layer.
Domain Entities layer
1 2 3 4 5 6 7 8 9 10 11 |
package de.novatec.domainentities; public class Car { private String vin; private int kilometers; private boolean rented; // constructor, getter and setter ... } |
Repository Contract layer
1 2 3 4 5 6 7 |
package de.novatec.repositorycontract; import de.novatec.domainentities.Car; public interface CarRepository { Car rentCar(); } |
Use Case layer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package de.novatec.usecase; import de.novatec.repositorycontract.CarRepository; import de.novatec.domainentities.Car; public class RentCar { CarRepository carRepository; public Car rentCar(){ Car car = carRepository.rentCar(); //do other business stuff like set, that selected car is now rented return car; } } |
Controller layer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package de.novatec.controller; import de.novatec.useCase.RentCar; import de.novatec.domainentities.Car; public class SimpleController { RentCar rentCar; public void onRentCar(){ Car car = rentCar.rentCar(); displayRentedCar(car); } private void displayRentedCar(Car car) { System.out.println(car); } } |
Violation of architecture rules
To be conform with an architectural style we need the discipline of the developer or we can use other processes like feedback based development. However, these processes are not automated. People are involved in these processes. And people make mistakes. If a developer has a bad day, he can violate this architecture like in the next example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class SimpleController { // Violation, because this is a Repository Contract. private CarRepository carRepository; public void onRentCar(){ carRepository.rentCar(); Car car = carRepository.rentCar(); displayRentedCar(car); } private void displayRentedCar(Car car) { System.out.println(car); } } |
Here we skip the “Use Case” Layer and access the repository contract directly. The violation of the architecture rules is possible, because Java doesn’t know, that these rules exist, because there is no direct concept of layers and access control verification in Java.
Compliance of architecture rules with Jigsaw
To prevent this problem we can use the modul concept of Jigsaw. All you have to do is the correct usage of the following two keywords in the module-info.
- export-keyword: export packages to this modules (if the is an arrow ends in this layer)
- requires-keyword: require a module (if the is an arrow starts in this layer)
Defining each layer as a module, ensures that the rules cannot be violated. See the following code snippets for the module-info.java of our example, again starting inside out.
For the “Domain Entities” layer we don’t need an access to other layers. Therefore we do not have any “requires” in the module-info. We only export our own package as a module, which is needed by other modules.
1 2 3 |
module de.novatec.domainentities { exports de.novatec.domainentities; } |
For the “Repository Contract” layer we need the module “de.novatec.repositorycontract” and export the repository contracts.
1 2 3 4 5 |
module de.novatec.repositorycontract { exports de.novatec.repositorycontract; requires de.novatec.domainentities; } |
The other modules-info.java files look simmilar to this.
1 2 3 4 5 6 |
module de.novatec.usecase { exports de.novatec.usecase; requires de.novatec.domainentities; requires de.novatec.repositorycontract; } |
1 2 3 4 |
module de.novatec.controller { requires de.novatec.domainentities; requires de.novatec.usecase; } |
Summary
Now we can’t violate our architecture rules. We can’t use any “Repository Contract” in a Controller layer. These classes are not visible in the module.
Summarized in Java 9 we can define our layers of an architecture. This has the advantage, that we can’t violate the access to another layer and we validate our architecture at compile time out-of-the-box.
What is missing in Jigsaw is a good IDE support. For example, the individual modules and thus the layers could be represented in a diagram. In this diagram you could then edit and view the modules.
Until July there is some time. Let us surprise, what Eclipse, IntelliJ etc. still make to the release of Java 9.
Recent posts






Comment article