Project structure

In devonfw we want to give clear structure and guidance for building applications. This also allows tools such as CobiGen or sonar-devon4j-plugin to "understand" the code. Also this helps developers going from one devonfw project to the next one to quickly understand the code-base. If every developer knows where to find what, the project gets more efficient. A long time ago maven standardized the project structure with src/main/java, etc. and turned chaos into structure. With devonfw we experienced the same for the codebase (what is inside src/main/java).

We initially started devon4j based on spring and spring-boot and proposed a classic project structure. With modern cloud-native trends we added a modern project structure, that is more lean and up-to-date with the latest market trends.

Modern project structure

With trends such as cloud, microservices, lean, and agile we decided for a more modern project structure that fits better to recent market trends. When starting new projects with devonfw and escpecially in the context of cloud-native development we strongly recommend this modern approach over the classic structure.

Modules

Due to trends such as microservices we are building smaller apps compared to moduliths. For simplicity we therefore do not split our app into different modules and keep everything top-level and easy.

In addition to java and resources we also add helm for helm templates and docker for docker scripts (e.g. Dockerfile) in src/main:

├──/src
|  ├──/main
|  |  ├──/docker
|  |  ├──/helm
|  |  ├──/java
|  |  └──/resources
|  └──/test
|     ├──/java
|     └──/resources
└──/pom.xml
Deployment

For modern projects we strongly recommend that your build process is generating the final deliverable as an OCI compliant container. Further, to go fully cloud-native you should build your app as a native image via GraalVM AOT compiler. Therefore we recommed to use quarkus as your main framework. In case you want to go with spring you may consider using spring-native.

Layers

The package structure of your code inside src/main/java (and src/test/java) of your app is described in our coding conventions in the sections packages. For the modern project structure the layers are defined by the following table:

Layer «layer» Description

service

service

The service layer exposing functionality via its remote API. Typical protocol is REST. May also be any other protocol you are using such as gRPC.

domain

domain

The domain with the data-model and DB access. Use sub-package (in «detail») repository for repository and dao for DAOs. Also we recommend to put entities in model sub-package.

logic

logic

The logic layer with the functionallity providing the business value.

common

common

cross-cutting code not assigned to a technical layer.

Architecture Mapping

In order to help you to map the architecture, packaging, layering, etc. to the code and see where different code elements should be placed, we provide this architecture mapping:

«root»
└──.«component»
   ├──.domain
   |  ├──.repo
   |  |  ├──.«BusinessObject»Repository
   |  |  ├──.«BusinessObject»Fragment
   |  |  └──.«BusinessObject»FragmentImpl
   |  ├──.dao [alternative to repo]
   |  |  ├──.«BusinessObject»Dao
   |  |  └──.«BusinessObject»DaoImpl
   |  └──.model
   |     └──.«BusinessObject»Entity
   ├──.logic
   |  ├──«BusinessObject»Validator
   |  └──«BusinessObject»EventsEmitter
   └──.service
      ├──.«Component»RestService
      ├──.mapper
      |  └──.«BusinessObject»Mapper
      └──.model
         └──.«BusinessObject»Dto

Classic project structure

In this section we describe the classic project structure as initially proposed for Java in devonfw. It is still valid and fully supported. However, if you want to start a new project, please consider using the modern structure.

Modules

The structure of a devon4j application is divided into the following modules:

  • api: module containing the API of your application. The API contains the required artifacts to interact with your application via remote services. This can be REST service interfaces, transfer-objects with their interfaces and datatypes but also OpenAPI or gRPC contracts.

  • core: maven module containing the core of the application with service implementation, as well as entire logic layer and dataaccess layer.

  • batch: optional module for batch layer

  • server: module that bundles the entire app (core with optional batch) typically as a bootified WAR file.

Deployment

Make jar not war

— Josh Long

First of all it is important to understand that the above defined modules aim to make api, core, and batch reusable artifacts, that can be used as a regular maven dependency. On the other hand to build and deploy your application you want a final artifact that is containing all required 3rd party libraries. This artifact is not reusable as a maven dependency. That is exactly the purpose of the server module to build and package this final deployment artifact. By default we first build a regular WAR file with maven in your server/target directory (*-server-«version».war) and in a second step create a bootified WAR out of this (*-server-bootified.war). The bootified WAR file can then be started standalone (java -jar «filename».war). However, it is also possible to deploy the same WAR file to a servlet container like tomcat or jetty. As application servers and externally provided servlet containers are not recommendet anymore for various reasons (see JEE), you may also want to create a bootified JAR file instead. All you need to do in that case is to change the packaging in your server/pom.xml from war to jar.

Package Structure

The package structure of your code inside src/main/java (and src/test/java) of your modules is described in our coding conventions in the sections packages. A full mapping of the architecture and the different code elements to the packaging is described in the following section.

Layers

The package structure of your code inside src/main/java (and src/test/java) of your app is described in our coding conventions in the sections packages. The following table describes our classic approach for packaging and layering:

Table 29. Traditional generic devon4j layers
Layer «layer»

service

service

logic

logic

data-access

dataaccess

batch (optional)

batch

client (optional)

client

common

common

Architecture Mapping

In order to help you to map the architecture, packaging, layering, etc. to the code and see where different code elements should be placed, we provide this architecture mapping:

«root»
├──.«component»
|  ├──.common
|  |  ├──.api[.«detail»]
|  |  |  ├──.datatype
|  |  |  |  └──.«Datatype» (api)
|  |  |  └──.«BusinessObject» (api)
|  |  └──.impl[.«detail»]
|  |     ├──.«Aspect»ConfigProperties (core)
|  |     ├──.«Datatype»JsonSerializer (core)
|  |     └──.«Datatype»JsonDeserializer (core)
|  ├──.dataaccess
|  |  ├──.api[.«detail»]
|  |  |  ├──.repo
|  |  |  |  └──.«BusinessObject»Repository (core)
|  |  |  ├──.dao (core) [alternative to repo]
|  |  |  |  └──.«BusinessObject»Dao (core) [alternative to Repository]
|  |  |  └──.«BusinessObject»Entity (core)
|  |  └──.impl[.«detail»]
|  |     ├──.dao (core) [alternative to repo]
|  |     |  └──.«BusinessObject»DaoImpl (core) [alternative to Repository]
|  |     └──.«Datatype»AttributeConverter (core)
|  ├──.logic
|  |  ├──.api
|  |  |  ├──.[«detail».]to
|  |  |  |   ├──.«MyCustom»«To (api)
|  |  |  |   ├──.«DataStructure»Embeddable (api)
|  |  |  |   ├──.«BusinessObject»Eto (api)
|  |  |  |   └──.«BusinessObject»«Subset»Cto (api)
|  |  |  ├──.[«detail».]usecase
|  |  |  |   ├──.UcFind«BusinessObject» (core)
|  |  |  |   ├──.UcManage«BusinessObject» (core)
|  |  |  |   └──.Uc«Operation»«BusinessObject» (core)
|  |  |  └──.«Component» (core)
|  |  ├──.base
|  |  |  └──.[«detail».]usecase
|  |  |     └──.Abstract«BusinessObject»Uc (core)
|  |  └──.impl
|  |     ├──.[«detail».]usecase
|  |     |   ├──.UcFind«BusinessObject»Impl (core)
|  |     |   ├──.UcManage«BusinessObject»Impl (core)
|  |     |   └──.Uc«Operation»«BusinessObject»Impl (core)
|  |     └──.«Component»Impl (core)
|  └──.service
|     ├──.api[.«detail»]
|     |  ├──.rest
|     |  |  └──.«Component»RestService (api)
|     |  └──.ws
|     |     └──.«Component»WebService (api)
|     └──.impl[.«detail»]
|        ├──.jms
|        |  └──.«BusinessObject»JmsListener (core)
|        ├──.rest
|        |  └──.«Component»RestServiceImpl (core)
|        └──.ws
|           └──.«Component»WebServiceImpl (core)
├──.general
│  ├──.common
│  |  ├──.api
|  |  |  ├──.to
|  |  |  |  ├──.AbstractSearchCriteriaTo (api)
|  |  |  └──.ApplicationEntity
│  |  ├──.base
|  |  |  └──.AbstractBeanMapperSupport (core)
│  |  └──.impl
│  |     ├──.config
│  |     |  └──.ApplicationObjectMapperFactory (core)
│  |     └──.security
│  |        └──.ApplicationWebSecurityConfig (core)
│  ├──.dataaccess
│  |  └──.api
|  |     └──.ApplicationPersistenceEntity (core)
│  ├──.logic
│  |  └──.base
|  |     ├──.AbstractComponentFacade (core)
|  |     ├──.AbstractLogic (core)
|  |     └──.AbstractUc (core)
|  └──.service
|     └──...
└──.SpringBootApp (core)
Last updated 2021-07-26 17:24:22 UTC