Skip to content
This repository has been archived by the owner on May 11, 2023. It is now read-only.

@jmolecules integration for jQAssistant to identify architectural concepts in Java applications

License

Notifications You must be signed in to change notification settings

jqassistant-archive/jqassistant-jmolecules-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jqassistant-jmolecules-plugin

Note
This project has been archived and is no longer actively developed. It has been superseded by the jqassistant-jmolecules-plugin

The jMolecules Plugin provides concepts to map architectural language elements from the jMolecules project (https://github.com/xmolecules/jmolecules) to the graph representation build by jQAssistant in order to gain new insights, create additional concepts and constraints.

Usage of the jQAssistant jMolecules Plugin

Please check the documentation of the jMolecules project to see how architectural concepts can be marked in the source code.

Afterwards, 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>
        </execution>
    </executions>
    <dependencies>
        <dependency> // (1)
            <groupId>org.jqassistant.contrib.plugin</groupId>
            <artifactId>jqassistant-jmolecules-plugin</artifactId>
            <version>1.4.0</version>
        </dependency>
    </dependencies>
</plugin>
  1. Definition of the plugin dependency

Mapping between jMolecules and jQAssistant

jMolecules comes with a set of different sub-projects, each providing annotations and marker interfaces for different architectural aspects.

The jqassistant-jmolecules-plugin provides concepts to map the annotations and interfaces to the graph. For each sub-project, there is a jQAssistant rule group containing all relevant concepts and additional constraints. Following is the mapping between jMolecules and jQAssistant.

Table 1. Mapping between jMolecules and jQAssistant
jMolecules jQAssistant

jmolecules-cqrs-architecute

jmolecules-cqrs:Default

jmolecules-layered-architecture

jmolecules-layered:Default

jmolecules-layered:Strict

jmolecules-onion-architecture (Classical)

jmolecules-onion-classical:Default

jmolecules-onion-classical:Strict

jmolecules-onion-architecture (Simplified)

jmolecules-onion-simplified:Default

jmolecules-onion-simplified:Strict

jmolecules-ddd

jmolecules-ddd:Default

jmolecules-ddd:Strict

jmolecules-event

jmolecules-event:Default

In order to make use of the provided concepts, the respective groups need to be added to the plugin configuration as following:

<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> // (1)
                    <group>jmolecules-cqrs:Default</group>
                    <group>jmolecules-layered:Default</group>
                    <group>jmolecules-layered:Strict</group>
                    <group>jmolecules-onion-classical:Default</group>
                    <group>jmolecules-onion-classical:Strict</group>
                    <group>jmolecules-onion-simplified:Default</group>
                    <group>jmolecules-onion-simplified:Strict</group>
                    <group>jmolecules-ddd:Default</group>
                    <group>jmolecules-ddd:Strict</group>
                    <group>jmolecules-event:Default</group>
                </groups>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.jqassistant.contrib.plugin</groupId>
            <artifactId>jqassistant-jmolecules-plugin</artifactId>
            <version>1.4.0</version>
        </dependency>
    </dependencies>
</plugin>
  1. Definition of the rules to be used

Concepts and Constraints for the Layered Architecture

  • The concepts mentioned in this section are used for jmolecules-architecture-layered

  • The concepts mentioned in this section are part of jmolecules-layered:Default or jmolecules-layered:Strict

  • jmolecules-layered:Strict contains jmolecules-layered:Default

  • For each technical layer, a node will be created, to which all types will be associated via a :CONTAINS relationship

  • Dependencies between types will be aggregated to the level of technical layers using a :DEPENDS_ON relation

  • When using the strict-group, allowed dependencies between the layers will be added to the graph using a :DEFINES_DEPENDENCY relation

Supported Annotations and Types:

  • InterfaceLayer

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Layered:Layer(name: 'Interface')

  • ApplicationLayer

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Layered:Layer(name: 'Application')

  • DomainLayer

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Layered:Layer(name: 'Domain')

  • InfrastructureLayer

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Layered:Layer(name: 'Infrastructure')

Additionally, the dependencies between types will be aggregated to the level of Layers including a weight, giving how many dependencies between layers exist.

Constraint:

  • jmolecules-layered:TypeInMultipleLayers

    • Checks that each type is part of only one layer

  • jmolecules-layered:IllegalLayerDependency (strict-group)

    • Checks that dependencies between layers only exist where allowed

Concepts for Onion Architecture

Classical Onion Architecture

  • The concepts mentioned in this section are used for jmolecules-architecture-onion

  • The concepts mentioned in this section are part of jmolecules-onion-classical:Default or jmolecules-onion-classical:Strict

  • jmolecules-onion-classical:Strict contains jmolecules-onion-classical:Default

  • For each ring, a node will be created, to which all types will be associated via a :CONTAINS relationship

  • Dependencies between types will be aggregated to the level of technical rings using a :DEPENDS_ON relation

  • When using the strict-group, allowed dependencies between the rings will be added to the graph using a :DEFINES_DEPENDENCY relation

Supported Annotations and Types:

  • ApplicationServiceRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'ApplicationService')

  • DomainServiceRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'DomainService')

  • DomainModelRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'DomainModel')

  • InfrastructureRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'Infrastructure')

Additionally, the dependencies between types will be aggregated to the level of Rings including a weight, giving how many dependencies between rings exist.

Constraint:

  • jmolecules-onion-classical:TypeInMultipleRings

    • Checks that each type is part of only one ring

  • jmolecules-onion-classical:IllegalRingDependency (strict-group)

    • Checks that dependencies between rings only exist where allowed

Simplified Onion Architecture

  • The concepts mentioned in this section are used for jmolecules-architecture-onion

  • The concepts mentioned in this section are part of jmolecules-onion-simplified:Default

  • For each ring, a node will be created, to which all types will be associated via a :CONTAINS relationship

  • Dependencies between types will be aggregated to the level of technical rings using a :DEPENDS_ON relation

  • When using the strict-group, allowed dependencies between the rings will be added to the graph using a :DEFINES_DEPENDENCY relation

Supported Annotations and Types:

  • ApplicationRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'Application')

  • DomainRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'Domain')

  • InfrastructureRing

    • Supported as Package- and Type-Annotation

    • Applied Labels: :JMolecules:Architecture:Onion:Ring(name: 'Infrastructure')

Additionally, the dependencies between types will be aggregated to the level of Rings including a weight, giving how many dependencies between rings exist.

Constraint:

  • jmolecules-onion-simplified:TypeInMultipleRings

    • Checks that each type is part of only one ring

  • jmolecules-onion-simplified:IllegalRingDependency (strict-group)

    • Checks that dependencies between rings only exist where allowed

Concepts for Domain-Driven Design

  • The concepts mentioned in this section are used for jmolecules-ddd

  • The concepts mentioned in this section are part of jmolecules-ddd:Default or jmolecules-ddd:Strict

Supported Annotations and Types:

  • AggregateRoot

    • Supported as Type-Annotation and Interface

    • Applied Labels: :JMolecules:DDD:Identifiable:Entity:AggregateRoot

  • BoundedContext

    • Supported as Package-Annotation

    • Per BoundedContext (unique by id), a node will be created representing the bounded context. Types will be linked via a :CONTAINS relationship.

    • Applied Labels: :JMolecules:DDD:BoundedContext

    • The properties id, name, and description are supported

    • In case the id is missing, the package name will be used

  • Entity

    • Supported as Type-Annotation and Interface

    • Applied Labels: :JMolecules:DDD:Identifiable:Entity

  • Identifier

    • Supported as Interface

    • Applied Labels: `:JMolecules:DDD:Identifier

  • Identity

    • Supported as Field- and Method-Annotation and via Entity and AggregateRoot-Interfaces (via the getId method)

    • Created relations: :HAS_IDENTITY towards a :Field- or :Method-node (:Member)

    • The relation will be transferred from super- to implementing types in case they don’t override the getId method

  • Factory

    • Supported as Type-Annotation

    • Applied Labels: :JMolecules:DDD:Factory

  • Module

    • Supported as Package-Annotation

    • Per Module (unique by id), a node will be created representing the module. Types will be linked via a :CONTAINS relationship.

    • Applied Labels: :JMolecules:DDD:Modules

    • The properties id, name, and description are supported

    • In case the id is missing, the package name will be used

  • Repository

    • Supported as Type-Annotation and Interface

    • Applied Labels: :JMolecules:DDD:Repository

  • Service

    • Supported as Type-Annotation

    • Applied Labels: :JMolecules:DDD:Service

  • ValueObject

    • Supported as Type-Annotation and Interface

    • Applied Labels: :JMolecules:DDD:ValueObject

Additionally, the dependencies between types will be aggregated to the level of BoundedContexts and Modules including a weight, giving how many dependencies between BoundedContext or Modules, respectively, exist.

Constraint:

  • jmolecules-ddd:TypeInMultipleBoundedContexts

    • Checks that each type is part of only one bounded context

  • jmolecules-ddd:TypeInMultipleModules

    • Checks that each type is part of only one module

  • jmolecules-ddd:MutableValueObject

    • Checks that values in ValueObjects are only manipulated via a constructor in the declaring class

  • jmolecules-ddd:MutableEntityId

    • Checks that the :Field identified by :HAS_IDENTITY in :Identifiable nodes is only manipulated via a constructor in the declaring class

  • jmolecules-ddd:ValueObjectReferencingEntityOrAggregateRoot

    • Checks that a :ValueObject is not referencing a :Entity or :AggregateRoot (:Identifiable)

  • jmolecules-ddd:NonFinalFieldInValueObject (strict-group)

    • Checks that values in ValueObjects final

  • jmolecules-ddd:NonFinalEntityId (strict-group)

    • Checks that the :Field identified by :HAS_IDENTITY in :Identifiable nodes is final

  • jmolecules-ddd:IllegalDependenciesBetweenBoundedContexts (strict-group)

    • Checks that :DEPENDS_ON relations between :BoundedContext nodes only exist where also :DEFINES_DEPENDENCY exists

    • Note: Allowed dependencies need to be provided using a custom concept which specifies the provided concept: jmolecules-ddd:AllowedBoundedContextDependency

    • Note: This can also be accomplished by using the jqassistant-context-mapper-plugin

Concepts for CQRS

  • The concepts mentioned in this section are used for jmolecules-cqrs

  • The concepts mentioned in this section are part of jmolecules-cqrs:Default

  • QueryModel

    • Supported as Type-Annotation

    • Applied Labels: :JMolecules:CQRS:QueryModel

  • Command

    • Supported as Type-Annotation

    • Applied Labels: :JMolecules:CQRS:Command

    • The properties name and namespace are supported, they’ll be added to the type node as commandName and commandNamespace, respectively

      • Default values for commandName: Simple Type Name of the annotated class

      • Default values for commandNamespace: Fully-qualified name of the package containing the annotated class

  • CommandHandler

    • Supported as Method-Annotation

    • Applied Labels: JMolecules:CQRS:CommandHandler

    • The properties name and namespace are supported to match the handled commands, '*' is allowed as a placeholder to match all

    • The relationship (:CommandHandler)-[:HANDLES]→(:Command) is established via the specified properties, or, alternatively, via the method parameter

      • See the official jMolecules JavaDoc for further details

  • CommandDispatcher

    • Supported as Method-Annotation

    • Applied Labels: :JMolecules:CQRS:CommandDispatcher

    • The property dispatches is supported to match the published command via '<namespace>.<name>'

      • See the official jMolecules JavaDoc for further details

Concepts for Events

  • The concepts mentioned in this section are used for jmolecules-event

  • The concepts mentioned in this section are part of jmolecules-event:Default

  • DomainEvent

    • Supported as Type-Annotation and Interface

    • Applied Labels: :JMolecules:Event:DomainEvent

    • The properties name and namespace are supported, they’ll be added to the type node as eventName and eventNamespace, respectively

      • Default values for eventName: Simple Type Name of the annotated class

      • Default values for eventNamespace: Fully-qualified name of the package containing the annotated class

  • DomainEventHandler

    • Supported as Method-Annotation

    • Applied Labels: JMolecules:Event:DomainEventHandler

    • The properties name and namespace are supported to match the handled events, '*' is allowed as a placeholder to match all

    • The relationship (:DomainEventHandler)-[:HANDLES]→(:DomainEvent) is established via the specified properties, or, alternatively, via the method parameter

      • See the official jMolecules JavaDoc for further details

  • DomainEventPublisher

    • Supported as Method-Annotation

    • Applied Labels: :JMolecules:Event:DomainEventPublisher

    • The property publishes is supported to match the published event via '<namespace>.<name>'

      • See the official jMolecules JavaDoc for further details

    • The property type is supported and will be enriched on the :PUBLISHES relationship

Visual Reporting

PlantUML-Reporting

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

  • Bounded Context

  • Module

  • Ring (both for classical and simplified Onion Architecture)

  • Layer (Interface, Application, Domain, Infrastructure)

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

  • reportType="plantuml-component-diagram"

Context Mapper-Reporting

The jMolecules plug-in works well with the jqassistant-context-mapper-plugin to visualize Bounded Contexts identified via jMolecules as a context map.

For further details, see the project page.