Repository: jhipster/jhipster-lite
Pull request #9172 (2024-03-08 21:52:33)

jMolecules and jQAssistant (living) documentation modules
https://github.com/xmolecules/jmolecules
https://github.com/jQAssistant

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/jhipster/jhipster-lite/pull/9172?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jhipster) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`abd00c0`)](https://app.codecov.io/gh/jhipster/jhipster-lite/commit/abd00c0090274f3953f569581359baa3f71261f0?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jhipster) to head [(`92abb28`)](https://app.codecov.io/gh/jhipster/jhipster-lite/pull/9172?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jhipster).
> Report is 2 commits behind head on main.


<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##                main     #9172    +/-   ##
============================================
  Coverage     100.00%   100.00%            
- Complexity      2918      2949    +31     
============================================
  Files            733       739     +6     
  Lines          12611     12762   +151     
  Branches         254       254            
============================================
+ Hits           12611     12762   +151     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/jhipster/jhipster-lite/pull/9172?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jhipster).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=jhipster).

DamnClin: So much waiting for this modules! (I'm lucky enough to have seen them in action). @pascalgrimaud  I really think this deserve a Bounty, this is clearly a game changer!

Patch:
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/application/JMoleculesApplicationService.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/application/JMoleculesApplicationService.java
new file mode 100644
index 000000000..e11dcd9b8
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/application/JMoleculesApplicationService.java
@@ -0,0 +1,20 @@
+package tech.jhipster.lite.generator.server.documentation.jmolecules.application;
+
+import org.springframework.stereotype.Service;
+import tech.jhipster.lite.generator.server.documentation.jmolecules.domain.JMoleculesModuleFactory;
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+
+@Service
+public class JMoleculesApplicationService {
+
+  private final JMoleculesModuleFactory factory;
+
+  public JMoleculesApplicationService() {
+    factory = new JMoleculesModuleFactory();
+  }
+
+  public JHipsterModule buildModule(JHipsterModuleProperties properties) {
+    return factory.buildModule(properties);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/domain/JMoleculesModuleFactory.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/domain/JMoleculesModuleFactory.java
new file mode 100644
index 000000000..6ed8eb3ec
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/domain/JMoleculesModuleFactory.java
@@ -0,0 +1,38 @@
+package tech.jhipster.lite.generator.server.documentation.jmolecules.domain;
+
+import static tech.jhipster.lite.module.domain.JHipsterModule.*;
+import static tech.jhipster.lite.module.domain.javadependency.JavaDependencyScope.IMPORT;
+import static tech.jhipster.lite.module.domain.javadependency.JavaDependencyType.POM;
+
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.javabuild.GroupId;
+import tech.jhipster.lite.module.domain.javadependency.JavaDependency;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+
+public class JMoleculesModuleFactory {
+
+  private static final GroupId JMOLECULES_GROUP_ID = groupId("org.jmolecules");
+
+  public JHipsterModule buildModule(JHipsterModuleProperties properties) {
+    //@formatter:off
+    return moduleBuilder(properties)
+      .javaDependencies()
+        .addDependencyManagement(jMoleculesBomDependency())
+        .addDependency(JMOLECULES_GROUP_ID, artifactId("jmolecules-ddd"))
+        .addDependency(JMOLECULES_GROUP_ID, artifactId("jmolecules-hexagonal-architecture"))
+        .addDependency(JMOLECULES_GROUP_ID, artifactId("jmolecules-events"))
+        .and()
+      .build();
+    //@formatter:on
+  }
+
+  private JavaDependency jMoleculesBomDependency() {
+    return javaDependency()
+      .groupId(JMOLECULES_GROUP_ID)
+      .artifactId("jmolecules-bom")
+      .versionSlug("jmolecules-bom")
+      .type(POM)
+      .scope(IMPORT)
+      .build();
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/infrastructure/primary/JMoleculesModuleConfiguration.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/infrastructure/primary/JMoleculesModuleConfiguration.java
new file mode 100644
index 000000000..aeaac7eac
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/infrastructure/primary/JMoleculesModuleConfiguration.java
@@ -0,0 +1,25 @@
+package tech.jhipster.lite.generator.server.documentation.jmolecules.infrastructure.primary;
+
+import static tech.jhipster.lite.generator.slug.domain.JHLiteModuleSlug.JMOLECULES;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import tech.jhipster.lite.generator.server.documentation.jmolecules.application.JMoleculesApplicationService;
+import tech.jhipster.lite.generator.slug.domain.JHLiteFeatureSlug;
+import tech.jhipster.lite.module.domain.resource.JHipsterModuleOrganization;
+import tech.jhipster.lite.module.domain.resource.JHipsterModuleResource;
+
+@Configuration
+class JMoleculesModuleConfiguration {
+
+  @Bean
+  JHipsterModuleResource jMoleculesModule(JMoleculesApplicationService jMolecules) {
+    return JHipsterModuleResource.builder()
+      .slug(JMOLECULES)
+      .withoutProperties()
+      .apiDoc("Documentation", "Add support for jMolecules documentation annotations")
+      .organization(JHipsterModuleOrganization.builder().addDependency(JHLiteFeatureSlug.JAVA_BUILD_TOOL).build())
+      .tags("server", "documentation")
+      .factory(jMolecules::buildModule);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/package-info.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/package-info.java
new file mode 100644
index 000000000..4b042256b
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jmolecules/package-info.java
@@ -0,0 +1,2 @@
+@tech.jhipster.lite.BusinessContext
+package tech.jhipster.lite.generator.server.documentation.jmolecules;
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/application/JQAssistantApplicationService.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/application/JQAssistantApplicationService.java
new file mode 100644
index 000000000..25223745c
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/application/JQAssistantApplicationService.java
@@ -0,0 +1,28 @@
+package tech.jhipster.lite.generator.server.documentation.jqassistant.application;
+
+import org.springframework.stereotype.Service;
+import tech.jhipster.lite.generator.server.documentation.jqassistant.domain.JQAssistantModuleFactory;
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+
+@Service
+public class JQAssistantApplicationService {
+
+  private final JQAssistantModuleFactory factory;
+
+  public JQAssistantApplicationService() {
+    factory = new JQAssistantModuleFactory();
+  }
+
+  public JHipsterModule buildModule(JHipsterModuleProperties properties) {
+    return factory.buildModule(properties);
+  }
+
+  public JHipsterModule buildJMoleculesModule(JHipsterModuleProperties properties) {
+    return factory.buildJMoleculesModule(properties);
+  }
+
+  public JHipsterModule buildSpringModule(JHipsterModuleProperties properties) {
+    return factory.buildSpringModule(properties);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/domain/JQAssistantModuleFactory.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/domain/JQAssistantModuleFactory.java
new file mode 100644
index 000000000..ff258b953
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/domain/JQAssistantModuleFactory.java
@@ -0,0 +1,174 @@
+package tech.jhipster.lite.generator.server.documentation.jqassistant.domain;
+
+import static tech.jhipster.lite.module.domain.JHipsterModule.*;
+import static tech.jhipster.lite.module.domain.mavenplugin.MavenBuildPhase.VERIFY;
+
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.javabuild.GroupId;
+import tech.jhipster.lite.module.domain.javadependency.JavaDependency;
+import tech.jhipster.lite.module.domain.mavenplugin.MavenPlugin;
+import tech.jhipster.lite.module.domain.mavenplugin.MavenPlugin.MavenPluginOptionalBuilder;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+import tech.jhipster.lite.shared.error.domain.Assert;
+
+public class JQAssistantModuleFactory {
+
+  private static final String JQASSISTANT_CONFIGURATION_FILE = ".jqassistant.yml";
+  private static final String SOURCE = "server/documentation/jqassistant";
+  private static final String JHIPSTER_NEEDLE_JQASSISTANT_PLUGIN = "# jhipster-needle-jqassistant-plugin";
+  private static final String JHIPSTER_NEEDLE_JQASSISTANT_ANALYZE_GROUP = "# jhipster-needle-jqassistant-analyze-group";
+  private static final GroupId JQASSISTANT_PLUGIN_GROUP_ID = groupId("org.jqassistant.plugin");
+  private static final String PROPERTIES = "properties";
+
+  public JHipsterModule buildModule(JHipsterModuleProperties properties) {
+    Assert.notNull(PROPERTIES, properties);
+
+    //@formatter:off
+    return moduleBuilder(properties)
+      .files()
+        .add(from(SOURCE).append(JQASSISTANT_CONFIGURATION_FILE), to(JQASSISTANT_CONFIGURATION_FILE))
+        .and()
+      .javaDependencies()
+        .addDependencyManagement(jQAssistantContextMapperDependency())
+        .and()
+      .mavenPlugins()
+        .pluginManagement(jQAssistantPluginManagement())
+        .plugin(jQAssistantPluginBuilder().build())
+        .pluginManagement(asciidoctorPluginManagement())
+        .plugin(asciidoctorPluginBuilder().build())
+        .and()
+      .build();
+    //@formatter:on
+  }
+
+  private static JavaDependency jQAssistantContextMapperDependency() {
+    return JavaDependency.builder()
+      .groupId(JQASSISTANT_PLUGIN_GROUP_ID)
+      .artifactId("jqassistant-context-mapper-plugin")
+      .versionSlug("jqassistant-context-mapper-plugin")
+      .build();
+  }
+
+  private static MavenPluginOptionalBuilder jQAssistantPluginBuilder() {
+    return mavenPlugin().groupId("com.buschmais.jqassistant").artifactId("jqassistant-maven-plugin");
+  }
+
+  private static MavenPlugin jQAssistantPluginManagement() {
+    return jQAssistantPluginBuilder()
+      .versionSlug("jqassistant")
+      .addExecution(pluginExecution().goals("scan", "analyze").id("default-cli"))
+      .build();
+  }
+
+  private static MavenPluginOptionalBuilder asciidoctorPluginBuilder() {
+    return mavenPlugin().groupId("org.asciidoctor").artifactId("asciidoctor-maven-plugin");
+  }
+
+  private static MavenPlugin asciidoctorPluginManagement() {
+    return asciidoctorPluginBuilder()
+      .versionSlug("asciidoctor-maven-plugin")
+      .configuration(
+        """
+        <backend>html5</backend>
+        <attributes>
+          <jqassistant-report-path>${project.build.directory}/jqassistant/jqassistant-report.xml</jqassistant-report-path>
+        </attributes>
+        """
+      )
+      .addExecution(pluginExecution().goals("process-asciidoc").id("html").phase(VERIFY))
+      .addDependency(jqassistantAsciidoctorjExtensions())
+      .build();
+  }
+
+  private static JavaDependency jqassistantAsciidoctorjExtensions() {
+    return javaDependency()
+      .groupId("org.jqassistant.tooling.asciidoctorj")
+      .artifactId("jqassistant-asciidoctorj-extensions")
+      .versionSlug("jqassistant-asciidoctorj-extensions")
+      .build();
+  }
+
+  public JHipsterModule buildJMoleculesModule(JHipsterModuleProperties properties) {
+    Assert.notNull(PROPERTIES, properties);
+
+    //@formatter:off
+    return moduleBuilder(properties)
+      .javaDependencies()
+        .addDependencyManagement(jQAssistantJMoleculesDependency())
+        .and()
+      .mandatoryReplacements()
+        .in(path(JQASSISTANT_CONFIGURATION_FILE))
+          .add(
+            lineBeforeText(JHIPSTER_NEEDLE_JQASSISTANT_PLUGIN),
+            jQAssistantPluginDeclaration(jQAssistantJMoleculesDependency())
+          )
+          .add(
+            lineBeforeText(JHIPSTER_NEEDLE_JQASSISTANT_ANALYZE_GROUP),
+            conceptOrGroupDeclaration("jmolecules-ddd:Default")
+          )
+          .add(
+            lineBeforeText(JHIPSTER_NEEDLE_JQASSISTANT_ANALYZE_GROUP),
+            conceptOrGroupDeclaration("jmolecules-hexagonal:Default")
+          )
+          .add(
+            lineBeforeText(JHIPSTER_NEEDLE_JQASSISTANT_ANALYZE_GROUP),
+            conceptOrGroupDeclaration("jmolecules-event:Default")
+          )
+          .and()
+        .and()
+      .build();
+    //@formatter:on
+  }
+
+  private static JavaDependency jQAssistantJMoleculesDependency() {
+    return JavaDependency.builder()
+      .groupId(JQASSISTANT_PLUGIN_GROUP_ID)
+      .artifactId("jqassistant-jmolecules-plugin")
+      .versionSlug("jqassistant-jmolecules-plugin")
+      .build();
+  }
+
+  public JHipsterModule buildSpringModule(JHipsterModuleProperties properties) {
+    Assert.notNull(PROPERTIES, properties);
+
+    //@formatter:off
+    return moduleBuilder(properties)
+      .javaDependencies()
+        .addDependencyManagement(jQAssistantSpringDependency())
+        .and()
+      .mandatoryReplacements()
+        .in(path(JQASSISTANT_CONFIGURATION_FILE))
+          .add(
+            lineBeforeText(JHIPSTER_NEEDLE_JQASSISTANT_PLUGIN),
+            jQAssistantPluginDeclaration(jQAssistantSpringDependency())
+          )
+          .add(
+            lineBeforeText(JHIPSTER_NEEDLE_JQASSISTANT_ANALYZE_GROUP),
+            conceptOrGroupDeclaration("spring-boot:Default")
+          )
+          .and()
+        .and()
+      .build();
+    //@formatter:on
+  }
+
+  private JavaDependency jQAssistantSpringDependency() {
+    return JavaDependency.builder()
+      .groupId(JQASSISTANT_PLUGIN_GROUP_ID)
+      .artifactId("jqassistant-spring-plugin")
+      .versionSlug("jqassistant-spring-plugin")
+      .build();
+  }
+
+  private static String jQAssistantPluginDeclaration(JavaDependency pluginDependency) {
+    return """
+        - group-id: %s
+          artifact-id: %s
+          version: ${%s.version}\
+    """.formatted(pluginDependency.id().groupId(), pluginDependency.id().artifactId(), pluginDependency.version().orElseThrow());
+  }
+
+  private static String conceptOrGroupDeclaration(String conceptOrGroup) {
+    return "      - " + conceptOrGroup;
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/infrastructure/primary/JQAssistantModuleConfiguration.java b/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/infrastructure/primary/JQAssistantModuleConfiguration.java
new file mode 100644
index 000000000..7738e4f2a
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/documentation/jqassistant/infrastructure/primary/JQAssistantModuleConfiguration.java
@@ -0,0 +1,51 @@
+package tech.jhipster.lite.generator.server.documentation.jqassistant.infrastructure.primary;
+
+import static tech.jhipster.lite.generator.slug.domain.JHLiteModuleSlug.*;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import tech.jhipster.lite.generator.server.documentation.jqassistant.application.JQAssistantApplicationService;
+import tech.jhipster.lite.generator.slug.domain.JHLiteFeatureSlug;
+import tech.jhipster.lite.module.domain.resource.JHipsterModuleOrganization;
+import tech.jhipster.lite.module.domain.resource.JHipsterModuleResource;
+
+@Configuration
+class JQAssistantModuleConfiguration {
+
+  private static final String DOCUMENTATION = "Documentation";
+  private static final String SERVER_TAG = "server";
+  private static final String DOCUMENTATION_TAG = "documentation";
+
+  @Bean
+  JHipsterModuleResource jQAssistantModule(JQAssistantApplicationService jqassistant) {
+    return JHipsterModuleResource.builder()
+      .slug(JQASSISTANT)
+      .withoutProperties()
+      .apiDoc(DOCUMENTATION, "Setup jQAssistant for documentation and analysis of the project")
+      .organization(JHipsterModuleOrganization.builder().addDependency(JHLiteFeatureSlug.JAVA_BUILD_TOOL).build())
+      .tags(SERVER_TAG, DOCUMENTATION_TAG)
+      .factory(jqassistant::buildModule);
+  }
+
+  @Bean
+  JHipsterModuleResource jQAssistantJMoleculesModule(JQAssistantApplicationService jqassistant) {
+    return JHipsterModuleResource.builder()
+      .slug(JQASSISTANT_JMOLECULES)
+      .withoutProperties()
+      .apiDoc(DOCUMENTATION, "Add jMolecules support for jQAssistant")
+      .organization(JHipsterModuleOrganization.builder().addDependency(JQASSISTANT).addDependency(JMOLECULES).build())
+      .tags(SERVER_TAG, DOCUMENTATION_TAG)
+      .factory(jqassistant::buildJMoleculesModule);
+  }
+
+  @Bean
+  JHipsterModuleResource jQAssistantSpringModule(JQAssistantApplicationService jqassistant) {
+    return JHipsterModuleResource.builder()
+      .slug(JQASSISTANT_SPRING)
+      .withoutProperties()
+      .apiDoc(DOCUMENTATION, "Add Spring support for jQAssistant")
+      .organization(JHipsterModuleOrganization.builder().addDependency(JQASSISTANT).addDependency(SPRING_BOOT).build())
+      .tags(SERVER_TAG, DOCUMENTATION_TAG)
+      .factory(jqassistant::buildSpringModule);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/slug/domain/JHLiteModuleSlug.java b/src/main/java/tech/jhipster/lite/generator/slug/domain/JHLiteModuleSlug.java
index 489acfad9..65469a17d 100644
--- a/src/main/java/tech/jhipster/lite/generator/slug/domain/JHLiteModuleSlug.java
+++ b/src/main/java/tech/jhipster/lite/generator/slug/domain/JHLiteModuleSlug.java
@@ -55,7 +55,11 @@ public enum JHLiteModuleSlug implements JHipsterModuleSlugFactory {
   JAVA_ENUMS("java-enums"),
   JAVA_MEMOIZERS("java-memoizers"),
   JIB("jib"),
+  JMOLECULES("jmolecules"),
   JPA_PAGINATION("jpa-pagination"),
+  JQASSISTANT("jqassistant"),
+  JQASSISTANT_JMOLECULES("jqassistant-jmolecules"),
+  JQASSISTANT_SPRING("jqassistant-spring"),
   JQWIK("jqwik"),
   KIPE_AUTHORIZATION("kipe-authorization"),
   KIPE_EXPRESSION("kipe-expression"),
diff --git a/src/main/resources/generator/dependencies/pom.xml b/src/main/resources/generator/dependencies/pom.xml
index 91d922f5c..3712fb734 100644
--- a/src/main/resources/generator/dependencies/pom.xml
+++ b/src/main/resources/generator/dependencies/pom.xml
@@ -36,6 +36,12 @@
     <alpinejs-webjars.version>3.14.0</alpinejs-webjars.version>
     <protobuf.version>4.27.1</protobuf.version>
     <proto-backwards-compatibility.version>1.0.7</proto-backwards-compatibility.version>
+    <jmolecules-bom.version>2023.1.2</jmolecules-bom.version>
+    <jqassistant.version>2.1.0-RC1</jqassistant.version>
+    <jqassistant-asciidoctorj-extensions.version>1.0.1</jqassistant-asciidoctorj-extensions.version>
+    <jqassistant-context-mapper-plugin.version>2.1.0-M1</jqassistant-context-mapper-plugin.version>
+    <jqassistant-jmolecules-plugin.version>2.1.0-M3</jqassistant-jmolecules-plugin.version>
+    <jqassistant-spring-plugin.version>2.1.0-M1</jqassistant-spring-plugin.version>
     <!-- Test dependencies -->
     <junit-jupiter.version>5.10.2</junit-jupiter.version>
     <assertj.version>3.26.0</assertj.version>
@@ -62,6 +68,7 @@
     <compiler-plugin.version>3.13.0</compiler-plugin.version>
     <surefire-plugin.version>3.2.5</surefire-plugin.version>
     <failsafe-plugin.version>3.2.5</failsafe-plugin.version>
+    <asciidoctor-maven-plugin.version>3.0.0</asciidoctor-maven-plugin.version>
   </properties>
 
   <dependencyManagement>
@@ -350,6 +357,43 @@
         <version>${jqwik.version}</version>
         <scope>test</scope>
       </dependency>
+      <dependency>
+        <groupId>org.jmolecules</groupId>
+        <artifactId>jmolecules-bom</artifactId>
+        <version>${jmolecules-bom.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>com.buschmais.jqassistant</groupId>
+        <artifactId>jqassistant-maven-plugin</artifactId>
+        <version>${jqassistant.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jqassistant.plugin</groupId>
+        <artifactId>jqassistant-context-mapper-plugin</artifactId>
+        <version>${jqassistant-context-mapper-plugin.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jqassistant.plugin</groupId>
+        <artifactId>jqassistant-jmolecules-plugin</artifactId>
+        <version>${jqassistant-jmolecules-plugin.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jqassistant.plugin</groupId>
+        <artifactId>jqassistant-spring-plugin</artifactId>
+        <version>${jqassistant-spring-plugin.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.jqassistant.tooling.asciidoctorj</groupId>
+        <artifactId>jqassistant-asciidoctorj-extensions</artifactId>
+        <version>${jqassistant-asciidoctorj-extensions.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.asciidoctor</groupId>
+        <artifactId>asciidoctor-maven-plugin</artifactId>
+        <version>${asciidoctor-maven-plugin.version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 </project>
diff --git a/src/main/resources/generator/server/documentation/jqassistant/.jqassistant.yml b/src/main/resources/generator/server/documentation/jqassistant/.jqassistant.yml
new file mode 100644
index 000000000..2dee4580a
--- /dev/null
+++ b/src/main/resources/generator/server/documentation/jqassistant/.jqassistant.yml
@@ -0,0 +1,15 @@
+jqassistant:
+  plugins:
+    - group-id: org.jqassistant.plugin
+      artifact-id: jqassistant-context-mapper-plugin
+      version: ${jqassistant-context-mapper-plugin.version}
+    # jhipster-needle-jqassistant-plugin
+
+  analyze:
+    concept:
+      # jhipster-needle-jqassistant-analyze-concept
+    groups:
+      # jhipster-needle-jqassistant-analyze-group
+    execute-applied-concepts: true
+    report:
+      continue-on-failure: true


Test patch:
diff --git a/src/main/resources/generator/server/javatool/archunit/test/HexagonalArchTest.java.mustache b/src/main/resources/generator/server/javatool/archunit/test/HexagonalArchTest.java.mustache
index cc1dc3a94..cb28d029e 100644
--- a/src/main/resources/generator/server/javatool/archunit/test/HexagonalArchTest.java.mustache
+++ b/src/main/resources/generator/server/javatool/archunit/test/HexagonalArchTest.java.mustache
@@ -41,9 +41,9 @@ class HexagonalArchTest {
   // the empty package is related to: https://github.com/TNG/ArchUnit/issues/191#issuecomment-507964792
   private static final Collection<String> vanillaPackages = List.of("java..", "");
   private static final Collection<String> commonToolsAndUtilsPackages = List.of(
-    "org.slf4j..",
     "org.apache.commons..",
-    "com.google.guava.."
+    "org.jmolecules..",
+    "org.slf4j.."
   );
 
   private static Collection<String> buildPackagesPatterns(Collection<String> packages) {
diff --git a/src/test/features/server/documentation/jmolecules.feature b/src/test/features/server/documentation/jmolecules.feature
new file mode 100644
index 000000000..c330a981c
--- /dev/null
+++ b/src/test/features/server/documentation/jmolecules.feature
@@ -0,0 +1,6 @@
+Feature: jMolecules
+
+  Scenario: Should apply jMolecules module
+    When I apply "jmolecules" module to default project with maven file
+      | packageName | tech.jhipster.chips |
+    Then I should have "<artifactId>jmolecules-bom</artifactId>" in "pom.xml"
diff --git a/src/test/features/server/documentation/jqassistant.feature b/src/test/features/server/documentation/jqassistant.feature
new file mode 100644
index 000000000..ba7d1b064
--- /dev/null
+++ b/src/test/features/server/documentation/jqassistant.feature
@@ -0,0 +1,26 @@
+Feature: jQAssistant module
+
+  Scenario: Should apply jQAssistant module
+    When I apply "jqassistant" module to default project with maven file
+      | packageName | tech.jhipster.chips |
+    Then I should have "<artifactId>jqassistant-maven-plugin</artifactId>" in "pom.xml"
+    And I should have files in "."
+      | .jqassistant.yml |
+
+  Scenario: Should apply jQAssistant-jMolecules module
+    When I apply modules to default project
+      | maven-java             |
+      | jmolecules             |
+      | jqassistant            |
+      | jqassistant-jmolecules |
+    Then I should have "<jqassistant-jmolecules-plugin.version>" in "pom.xml"
+    Then I should have "${jqassistant-jmolecules-plugin.version}" in ".jqassistant.yml"
+
+  Scenario: Should apply jQAssistant-Spring module
+    When I apply modules to default project
+      | maven-java         |
+      | spring-boot        |
+      | jqassistant        |
+      | jqassistant-spring |
+    Then I should have "<jqassistant-spring-plugin.version>" in "pom.xml"
+    Then I should have "${jqassistant-spring-plugin.version}" in ".jqassistant.yml"
diff --git a/src/test/java/tech/jhipster/lite/generator/server/documentation/jmolecules/domain/JMoleculesModuleFactoryTest.java b/src/test/java/tech/jhipster/lite/generator/server/documentation/jmolecules/domain/JMoleculesModuleFactoryTest.java
new file mode 100644
index 000000000..654cd3d3f
--- /dev/null
+++ b/src/test/java/tech/jhipster/lite/generator/server/documentation/jmolecules/domain/JMoleculesModuleFactoryTest.java
@@ -0,0 +1,65 @@
+package tech.jhipster.lite.generator.server.documentation.jmolecules.domain;
+
+import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.assertThatModuleWithFiles;
+import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.pomFile;
+
+import org.junit.jupiter.api.Test;
+import tech.jhipster.lite.TestFileUtils;
+import tech.jhipster.lite.UnitTest;
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.JHipsterModulesFixture;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+
+@UnitTest
+class JMoleculesModuleFactoryTest {
+
+  private static final JMoleculesModuleFactory factory = new JMoleculesModuleFactory();
+
+  @Test
+  void shouldBuildModule() {
+    JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest())
+      .basePackage("com.jhipster.test")
+      .build();
+
+    JHipsterModule module = factory.buildModule(properties);
+
+    assertThatModuleWithFiles(module, pomFile())
+      .hasFile("pom.xml")
+      .containing("<jmolecules-bom.version>")
+      .containing(
+        """
+              <dependency>
+                <groupId>org.jmolecules</groupId>
+                <artifactId>jmolecules-bom</artifactId>
+                <version>${jmolecules-bom.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+              </dependency>
+        """
+      )
+      .containing(
+        """
+            <dependency>
+              <groupId>org.jmolecules</groupId>
+              <artifactId>jmolecules-ddd</artifactId>
+            </dependency>
+        """
+      )
+      .containing(
+        """
+            <dependency>
+              <groupId>org.jmolecules</groupId>
+              <artifactId>jmolecules-hexagonal-architecture</artifactId>
+            </dependency>
+        """
+      )
+      .containing(
+        """
+            <dependency>
+              <groupId>org.jmolecules</groupId>
+              <artifactId>jmolecules-events</artifactId>
+            </dependency>
+        """
+      );
+  }
+}
diff --git a/src/test/java/tech/jhipster/lite/generator/server/documentation/jqassistant/domain/JQAssistantModuleFactoryTest.java b/src/test/java/tech/jhipster/lite/generator/server/documentation/jqassistant/domain/JQAssistantModuleFactoryTest.java
new file mode 100644
index 000000000..1236a8b92
--- /dev/null
+++ b/src/test/java/tech/jhipster/lite/generator/server/documentation/jqassistant/domain/JQAssistantModuleFactoryTest.java
@@ -0,0 +1,170 @@
+package tech.jhipster.lite.generator.server.documentation.jqassistant.domain;
+
+import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.*;
+
+import org.junit.jupiter.api.Test;
+import tech.jhipster.lite.TestFileUtils;
+import tech.jhipster.lite.UnitTest;
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.JHipsterModulesFixture;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+import tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions;
+
+@UnitTest
+class JQAssistantModuleFactoryTest {
+
+  private static final JQAssistantModuleFactory factory = new JQAssistantModuleFactory();
+
+  @Test
+  void shouldBuildModule() {
+    JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest())
+      .basePackage("com.jhipster.test")
+      .build();
+
+    JHipsterModule module = factory.buildModule(properties);
+
+    assertThatModuleWithFiles(module, pomFile())
+      .hasFile(".jqassistant.yml")
+      .containing("artifact-id: jqassistant-context-mapper-plugin")
+      .containing("# jhipster-needle-jqassistant-plugin")
+      .containing("# jhipster-needle-jqassistant-analyze-concept")
+      .containing("# jhipster-needle-jqassistant-analyze-group")
+      .and()
+      .hasFile("pom.xml")
+      // jQAssistant
+      .containing("<jqassistant-context-mapper-plugin.version>")
+      .containing(
+        """
+                <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>
+                </plugin>
+        """
+      )
+      .containing(
+        """
+              <plugin>
+                <groupId>com.buschmais.jqassistant</groupId>
+                <artifactId>jqassistant-maven-plugin</artifactId>
+              </plugin>
+        """
+      )
+      // Asciidoctor
+      .containing("<jqassistant-asciidoctorj-extensions.version>")
+      .containing(
+        """
+                <plugin>
+                  <groupId>org.asciidoctor</groupId>
+                  <artifactId>asciidoctor-maven-plugin</artifactId>
+                  <version>${asciidoctor-maven-plugin.version}</version>
+                  <executions>
+                    <execution>
+                      <id>html</id>
+                      <phase>verify</phase>
+                      <goals>
+                        <goal>process-asciidoc</goal>
+                      </goals>
+                    </execution>
+                  </executions>
+                  <dependencies>
+                    <dependency>
+                      <groupId>org.jqassistant.tooling.asciidoctorj</groupId>
+                      <artifactId>jqassistant-asciidoctorj-extensions</artifactId>
+                      <version>${jqassistant-asciidoctorj-extensions.version}</version>
+                    </dependency>
+                  </dependencies>
+                  <configuration>
+                    <backend>html5</backend>
+                    <attributes>
+                      <jqassistant-report-path>${project.build.directory}/jqassistant/jqassistant-report.xml</jqassistant-report-path>
+                    </attributes>
+                  </configuration>
+                </plugin>
+        """
+      )
+      .containing(
+        """
+              <plugin>
+                <groupId>org.asciidoctor</groupId>
+                <artifactId>asciidoctor-maven-plugin</artifactId>
+              </plugin>
+        """
+      );
+  }
+
+  @Test
+  void shouldBuildJqassistantJmoleculesModule() {
+    JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest())
+      .basePackage("com.jhipster.test")
+      .build();
+
+    JHipsterModule module = factory.buildJMoleculesModule(properties);
+
+    assertThatModuleWithFiles(module, pomFile(), jQAssistantYmlFile())
+      .hasFile(".jqassistant.yml")
+      .containing(
+        """
+            - group-id: org.jqassistant.plugin
+              artifact-id: jqassistant-jmolecules-plugin
+              version: ${jqassistant-jmolecules-plugin.version}
+            # jhipster-needle-jqassistant-plugin
+        """
+      )
+      .containing(
+        """
+              - jmolecules-ddd:Default
+              - jmolecules-hexagonal:Default
+              - jmolecules-event:Default
+              # jhipster-needle-jqassistant-analyze-group
+        """
+      )
+      .and()
+      .hasFile("pom.xml")
+      // jQAssistant
+      .containing("<jqassistant-jmolecules-plugin.version>");
+  }
+
+  @Test
+  void shouldBuildJqassistantSpringModule() {
+    JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest())
+      .basePackage("com.jhipster.test")
+      .build();
+
+    JHipsterModule module = factory.buildSpringModule(properties);
+
+    assertThatModuleWithFiles(module, pomFile(), jQAssistantYmlFile())
+      .hasFile(".jqassistant.yml")
+      .containing(
+        """
+            - group-id: org.jqassistant.plugin
+              artifact-id: jqassistant-spring-plugin
+              version: ${jqassistant-spring-plugin.version}
+            # jhipster-needle-jqassistant-plugin
+        """
+      )
+      .containing(
+        """
+              - spring-boot:Default
+              # jhipster-needle-jqassistant-analyze-group
+        """
+      )
+      .and()
+      .hasFile("pom.xml")
+      // jQAssistant
+      .containing("<jqassistant-spring-plugin.version>");
+  }
+
+  private JHipsterModulesAssertions.ModuleFile jQAssistantYmlFile() {
+    return file("src/main/resources/generator/server/documentation/jqassistant/.jqassistant.yml", ".jqassistant.yml");
+  }
+}
diff --git a/tests-ci/generate.sh b/tests-ci/generate.sh
index bcaedeae7..6c1f3973d 100755
--- a/tests-ci/generate.sh
+++ b/tests-ci/generate.sh
@@ -153,6 +153,10 @@ elif [[ $application == 'fullapp' ]]; then
   "internationalized-errors" \
   "spring-boot-cache" \
   "caffeine-cache" \
+  "jmolecules" \
+  "jqassistant" \
+  "jqassistant-jmolecules" \
+  "jqassistant-spring" \
   "license-apache" \
   "renovate"