Skip to content
This repository has been archived by the owner on Oct 25, 2022. It is now read-only.

Annotations to explicitly mark concepts of DDD in Java including @jQAssistant constraints to enforce common concepts.

License

Notifications You must be signed in to change notification settings

jqassistant-archive/jqassistant-java-ddd-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NOTE: This project was superseded jMolecules and its integration. All information can be found here: jMolecules-jQAssistant-Plugin

jQAssistant DDD Plugin

The jQAssistant DDD Plugin provides means to map DDD language elements onto the code and to enrich this information in the graph in order to apply additional, DDD-general as well as project specific, concepts and constraints.

Usage of the jQAssistant DDD Plugin

To make use of the provided annotations (as will be shown in the next section), following dependency is needed to be defined:

<dependency>
    <groupId>org.jqassistant.contrib.plugin</groupId>
    <artifactId>jqassistant-java-ddd-annotations</artifactId>
    <version>${jqassistant.version}</version>
</dependency>

Additionally, to have jQAssistant consider the annotations and to allow the execution of constraints, following dependency in the jqassistant-maven-plugin needs to be defined:

<plugin>
    <groupId>com.buschmais.jqassistant</groupId>
    <artifactId>jqassistant-maven-plugin</artifactId>
    <version>${jqassistant.version}</version>
    <executions>
        <execution>
            <id>default-cli</id>
            <goals>
                <goal>scan</goal>
                <goal>analyze</goal>
            </goals>
            <configuration>
                <groups>
                    <group>java-ddd:Default</group> // (2)
                </groups>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency> // (1)
            <groupId>org.jqassistant.contrib.plugin</groupId>
            <artifactId>jqassistant-java-ddd-plugin</artifactId>
            <version>${jqassistant.version}</version>
        </dependency>
    </dependencies>
</plugin>
  1. Definition of the plugin dependency

  2. Definition of the java-ddd:Default group to be executed

DDD Concepts

The jQAssistant DDD plugin comes with jQA-concepts and Java-annotations for multiple DDD concepts. The supported DDD-concepts and how they are mapped in from source code to the graph is shown in the following list.

All supported DDD-concepts can be applied both on package level (by annotating the package definition in a package-info.java file) or class level (by annotating a Java class).

Bounded Context

A bounded context is a well-defined, functional consistent, and cohesive subset of the complete solution domain. It therewith represents the implementation of one functional slice of the problem space.

A bounded context is identified by its name. In case that multiple bounded contexts with the same name were declared, only one node will be created.

The bounded context nodes will be labeled by :DDD:BoundedContext.

Package Level

All classes in the annotated package and its sub packages will be assigned to the corresponding node.

Definition of a bounded context and its contained types at package level.
@BoundedContext(name = "catalog")
package com.buschmais.shop.catalog;
Type Level

The annotated class will be assigned to the corresponding node.

Definition of a bounded context and its contained type using at class level.
@BoundedContext(name = "catalog")
public class Product { }
Bounded Context Dependencies

Besides defining a bounded context with a name it’s also possible to define allowed dependencies between dependencies. The definition is done by specifying a list of bounded contexts by their name on which the defining bounded context may depend on.

Definition of allowed dependencies between bounded contexts.
@BoundedContext(name = "catalog", dependsOn = {"merchant"})

Domain Event

A domain event is a notice about the change of state in a functional sense, to which interested parties can listen.

Package Level

All classes in the annotated package will be labeled as :DDD:DomainEvent.

Definition of domain events at the package level.
@DomainEvent
package com.buschmais.shop.catalog.event;
Type Level

The annotated class will be labeled as :DDD:DomainEvent.

Definition of domain events at the type level.
@DomainEvent
public class ProductCreatedEvent { }

Aggregate

An aggregate is a logical, cohesive group of entities and value objects from the same bounded context. Manipulations to an aggregate or its contained entities and value objects may only be done through the aggregate root which itself represents some kind of an transaction boundary. Aggregates are used to group domain objects which need to stay absolutely consistent to each other and thus are rather small.

Package Level

All classes in the annotated package will be labeled as :DDD:AggregateRoot.

Definition of aggregates at the package level.
@AggregateRoot
package com.buschmais.shop.catalog.model.aggregateroot;
Type Level

The annotated class will be labeled as :DDD:Aggregate.

Definition of aggregates at the type level.
@AggregateRoot
public class Product { }

Entity

An entity is a domain object which is not defined by its properties but by its unique identifier which will not change throughout its existence.

Note: Both the @Entity-annotation provided by this plug-in as well as @javax.persistence.Entity will be treated as DDD entities.

Package Level

All classes in the annotated package will be labeled as :DDD:Entity.

Definition of entities at the package level.
@Entity
package com.buschmais.shop.catalog.model.entity;
Type Level

The annotated class will be labeled as :DDD:Entity.

Definition of entities at the type level.
@Entity
public class Product { }

Value Object

Value objects are immutable domain objects which have no unique identifies but are identified by their properties.

Package Level

All classes in the annotated package will be labeled as :DDD:ValueObject.

Definition of value objects at the package level.
@ValueObject
package com.buschmais.shop.catalog.model.valueobject;
Type Level

The annotated class will be labeled as :DDD:ValueObject.

Definition of value objects at the type level.
@ValueObject
public class Price { }

Service

A service is a stateless object providing access to domain objects and implementing business rules as methods (commands and queries). Services operate on aggregates.

Package Level

All classes in the annotated package will be labeled as :DDD:Service.

Definition of services at the package level.
@Service
package com.buschmais.shop.catalog.service;
Type Level

The annotated class will be labeled as :DDD:Service.

Definition of services at the type level.
@Service
public class ProductService { }

Repository

A repository represents an accessor to a persistent store by both providing functionality to create and modify domain objects. Repositories operate on an aggregate.

Package Level

All classes in the annotated package will be labeled as :DDD:Repository.

Definition of repositories at the package level.
@Repository
package com.buschmais.shop.catalog.repository;
Type Level

The annotated class will be labeled as :DDD:Repository.

Definition of repositories at the type level.
@Repository
public class ProductRepository { }

Factory

A factory takes care of creating a new entity or value object from given data or an already existing object and takes care of its invariants. A factory (method) can be present directly in the domain model class or as a separate class.

Package Level

All classes in the annotated package will be labeled as :DDD:Factory.

Definition of factories at the package level.
@Factory
package com.buschmais.shop.catalog.factory;
Type Level

The annotated class will be labeled as :DDD:Factory.

Definition of factories at the type level.
@Factory
public class ProdutFactory { }

Layer

Besides the definition of functional concepts in DDD there are also requirements to the technical layering of the application stated.

Per layer, a new node labeled as ':DDD:Layer' with a name property will be created. All classes annotated as being part of a specific layer will be associated to the respective layer node using a 'CONTAINS' relation.

Following nodes will be created:

  • (:DDD:Layer {name: 'Interface'})

  • (:DDD:Layer {name: 'Application'})

  • (:DDD:Layer {name: 'Domain'})

  • (:DDD:Layer {name: 'Infrastructure})

InterfaceLayer

The interface layer is the outermost layer in a DDD-architecture, providing access to the application to other services and the user. This layer is very thin and provides only rudimentary functionality for e.g. request handling. No domain logic shall be implemented by this layer.

Package Level

All classes in the annotated package will associated to the (:DDD:Layer {name: 'Interface'}) node.

Assignement to the interface layer at the package level.
@InterfaceLayer
package com.buschmais.shop.catalog.interfaces;
Type Level

The annotated class will be associated to the (:DDD:Layer {name: 'Interface'}) node.

Assignment to the interface layer at the type level.
@InterfaceLayer
public class ProductController { }

ApplicationLayer

The application layer is a thin layer orchestrating business use cases and spanning transactions. It implements no specific domain logic but coordinates the correct execution of scenarios and takes care of aspects like transaction handling.

Package Level

All classes in the annotated package will be associated to the (:DDD:Layer {name: 'Application'}) node.

Assignement to the application layer at the package level.
@ApplicationLayer
package com.buschmais.shop.catalog.application;
Type Level

The annotated class will be associated to the (:DDD:Layer {name: 'Application'}) node.

Assignment to the application layer at the type level.
@ApplicationLayer
public class ProductHandler { }

DomainLayer

The domain layer is the heart of a DDD-structured application and implements the business logic and objects of bounded contexts.

Package Level

All classes in the annotated package will be associated to the (:DDD:Layer {name: 'Domain'}) node.

Assignement to the domain layer at the package level.
@DomainLayer
package com.buschmais.shop.catalog.domain;
Type Level

The annotated class will be associated to the (:DDD:Layer {name: 'Domain'}) node.

Assignment to the domain layer at the type level.
@DomainLayer
public class ProductService { }

InfrastructureLayer

The infrastructure layer is the supporting layer for the other layers providing technical implementations like database access.

Infrastructure can both be present in the bounded context scope (like when providing access to the product table) or in global scope, e.g. for sending e-mails.

Package Level

All classes in the annotated package will be associated to the (:DDD:Layer {name: 'Infrastructure}) node.

Assignement to the infrastructure layer at the package level.
@InfrastructureLayer
package com.buschmais.shop.catalog.infrastructure;
Type Level

The annotated class will be associated to the (:DDD:Layer {name: 'Infrastructure}) node.

Assignment to the infrastructure layer at the type level.
@InfrastructureLayer
public class ProductRepositoryImpl { }

Default DDD Constraints

The jQAssistant DDD plug-in comes with several pre-defined constraints which check the implemented architecture against the basic DDD architectural principles.

The following constraints will be active by default and configured with a Major-severity.

java-ddd:TypeInMultipleLayers

The constraint checks that each type is only part of one layer.

java-ddd:TypeInMultipleBoundedContexts

The constraint checks that each type is only part of one bounded context.

java-ddd:IllegalDependenciesBetweenBoundedContexts

The constraints checks that there are no dependencies between bounded contexts present when they are not defined.

java-ddd:UnneededDependenciesBetweenBoundedContexts

The constraint checks that there are no dependencies between bounded contexts defined which are not required by the implementation.

Strict DDD Constraints

Additionally to the default DDD constraints which are quite relaxed and thus easy to integrate into legacy projects, there is a more strict set of constraints provided by the DDD plug-in.

The constraints can be activated by declaring the name of it in the executed groups section of the plug-in configuration:

<groups>
    <group>java-ddd:Default</group> // (1)
    <group>java-ddd:Strict</group> // (2)
</groups>
  1. Activation of the default rule set.

  2. Activation of the strict rule set.

java-ddd:IllegalDependenciesBetweenTechnicalLayers

As defined by DDD, only dependencies between specific layers are allowed. These dependencies are visualized in the following diagram:

skinparam componentStyle uml2

component {
component InterfaceLayer
component ApplicationLayer
component DomainLayer
}

component InfrastructureLayer

InterfaceLayer --> ApplicationLayer
InterfaceLayer --> DomainLayer
ApplicationLayer --> DomainLayer

InfrastructureLayer --> InterfaceLayer
InfrastructureLayer -left-> ApplicationLayer
InfrastructureLayer --> DomainLayer

The constraint checks for the correct implementation of the relations.

Visual Reporting

The DDD plug-in supports visualization of concepts using PlantUML in jQAssistant reports for the following concepts:

  • Bounded Context

  • Layer (Interface, Application, Domain, Infrastructure)

To use this functionality, define the jQAssistant concept with the following property set:

  • reportType="plantuml-component-diagram"

Licensing

The jqassistant-java-ddd-annotations module is licensed under the Apache License, Version 2.0. Therefore, it can be added as a direct dependency to the project without the need to disclose the source code.

The jqassistant-java-ddd-plugin module is licensed under the GNU GENERAL PUBLIC LICENSE, Version 3 due to the dependency to Neo4j. However, as this will be declared as a dependency of the jqassistant-maven-plugin (which is a build plugin), it will not end up in the delivery.

About

Annotations to explicitly mark concepts of DDD in Java including @jQAssistant constraints to enforce common concepts.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages