Repository: jhipster/jhipster-lite
Pull request #11669 (2025-01-01 22:44:47)

feat(code-quality): new module for modernizer maven/gradle plugin
These plugins detect uses of legacy APIs which modern Java versions supersede. These modern APIs are often more performant, safer, and idiomatic than the legacy equivalents


Patch:
diff --git a/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/application/ModernizerApplicationService.java b/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/application/ModernizerApplicationService.java
new file mode 100644
index 000000000..fa4996bb8
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/application/ModernizerApplicationService.java
@@ -0,0 +1,20 @@
+package tech.jhipster.lite.generator.server.javatool.modernizer.application;
+
+import org.springframework.stereotype.Service;
+import tech.jhipster.lite.generator.server.javatool.modernizer.domain.ModernizerModuleFactory;
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+
+@Service
+public class ModernizerApplicationService {
+
+  private final ModernizerModuleFactory modernizer;
+
+  public ModernizerApplicationService() {
+    modernizer = new ModernizerModuleFactory();
+  }
+
+  public JHipsterModule build(JHipsterModuleProperties properties) {
+    return modernizer.build(properties);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/domain/ModernizerModuleFactory.java b/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/domain/ModernizerModuleFactory.java
new file mode 100644
index 000000000..ad66ae431
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/domain/ModernizerModuleFactory.java
@@ -0,0 +1,67 @@
+package tech.jhipster.lite.generator.server.javatool.modernizer.domain;
+
+import static tech.jhipster.lite.module.domain.JHipsterModule.gradleCommunityPlugin;
+import static tech.jhipster.lite.module.domain.JHipsterModule.mavenPlugin;
+import static tech.jhipster.lite.module.domain.JHipsterModule.moduleBuilder;
+import static tech.jhipster.lite.module.domain.JHipsterModule.pluginExecution;
+import static tech.jhipster.lite.module.domain.mavenplugin.MavenBuildPhase.VERIFY;
+
+import tech.jhipster.lite.module.domain.JHipsterModule;
+import tech.jhipster.lite.module.domain.gradleplugin.GradleMainBuildPlugin;
+import tech.jhipster.lite.module.domain.mavenplugin.MavenPlugin;
+import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
+import tech.jhipster.lite.shared.error.domain.Assert;
+
+public class ModernizerModuleFactory {
+
+  private static final String MODERNIZER = "modernizer";
+
+  public JHipsterModule build(JHipsterModuleProperties properties) {
+    Assert.notNull("properties", properties);
+
+    //@formatter:off
+    return moduleBuilder(properties)
+      .mavenPlugins()
+        .pluginManagement(modernizerMavenPluginManagement())
+        .plugin(modernizerMavenPlugin().build())
+        .and()
+      .gradlePlugins()
+        .plugin(modernizerGradlePlugin())
+        .and()
+      .build();
+    //@formatter:on
+  }
+
+  private MavenPlugin.MavenPluginOptionalBuilder modernizerMavenPlugin() {
+    return mavenPlugin().groupId("org.gaul").artifactId("modernizer-maven-plugin");
+  }
+
+  private MavenPlugin modernizerMavenPluginManagement() {
+    return modernizerMavenPlugin()
+      .versionSlug("modernizer-maven-plugin")
+      .configuration(
+        """
+        <javaVersion>${java.version}</javaVersion>
+        <failOnViolations>true</failOnViolations>
+        """
+      )
+      .addExecution(pluginExecution().goals(MODERNIZER).id(MODERNIZER).phase(VERIFY))
+      .build();
+  }
+
+  private GradleMainBuildPlugin modernizerGradlePlugin() {
+    return gradleCommunityPlugin()
+      .id("com.github.andygoossens.modernizer")
+      .pluginSlug(MODERNIZER)
+      .versionSlug(MODERNIZER)
+      .configuration(
+        """
+        modernizer {
+          failOnViolations = true
+          includeTestClasses = true
+        }
+        """
+      )
+      .build();
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/primary/ModernizerModuleConfiguration.java b/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/primary/ModernizerModuleConfiguration.java
new file mode 100644
index 000000000..9fd9dad2f
--- /dev/null
+++ b/src/main/java/tech/jhipster/lite/generator/server/javatool/modernizer/primary/ModernizerModuleConfiguration.java
@@ -0,0 +1,28 @@
+package tech.jhipster.lite.generator.server.javatool.modernizer.primary;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import tech.jhipster.lite.generator.server.javatool.modernizer.application.ModernizerApplicationService;
+import tech.jhipster.lite.module.domain.resource.JHipsterModuleOrganization;
+import tech.jhipster.lite.module.domain.resource.JHipsterModulePropertiesDefinition;
+import tech.jhipster.lite.module.domain.resource.JHipsterModuleResource;
+import tech.jhipster.lite.shared.slug.domain.JHLiteFeatureSlug;
+import tech.jhipster.lite.shared.slug.domain.JHLiteModuleSlug;
+
+@Configuration
+class ModernizerModuleConfiguration {
+
+  @Bean
+  JHipsterModuleResource modernizerModule(ModernizerApplicationService modernizer) {
+    return JHipsterModuleResource.builder()
+      .slug(JHLiteModuleSlug.MODERNIZER)
+      .propertiesDefinition(JHipsterModulePropertiesDefinition.builder().build())
+      .apiDoc(
+        "Java",
+        "Add Modernizer build plugin for detecting uses of legacy APIs which modern Java versions supersede. These modern APIs are often more performant, safer, and idiomatic than the legacy equivalents."
+      )
+      .organization(JHipsterModuleOrganization.builder().addDependency(JHLiteFeatureSlug.JAVA_BUILD_TOOL).build())
+      .tags("server", "quality")
+      .factory(modernizer::build);
+  }
+}
diff --git a/src/main/java/tech/jhipster/lite/shared/slug/domain/JHLiteModuleSlug.java b/src/main/java/tech/jhipster/lite/shared/slug/domain/JHLiteModuleSlug.java
index c2a49bfa4..be0da5ffd 100644
--- a/src/main/java/tech/jhipster/lite/shared/slug/domain/JHLiteModuleSlug.java
+++ b/src/main/java/tech/jhipster/lite/shared/slug/domain/JHLiteModuleSlug.java
@@ -83,6 +83,7 @@ public enum JHLiteModuleSlug implements JHipsterModuleSlugFactory {
   LOGS_SPY("logs-spy"),
   MAVEN_JAVA("maven-java"),
   MAVEN_WRAPPER("maven-wrapper"),
+  MODERNIZER("modernizer"),
   MONGOCK("mongock"),
   MONGODB("mongodb"),
   NEO4J("neo4j"),
diff --git a/src/main/resources/generator/dependencies/build.gradle.kts b/src/main/resources/generator/dependencies/build.gradle.kts
index 4d7329a78..1c02a3211 100644
--- a/src/main/resources/generator/dependencies/build.gradle.kts
+++ b/src/main/resources/generator/dependencies/build.gradle.kts
@@ -2,6 +2,7 @@ plugins {
   java
   alias(libs.plugins.jib)
   alias(libs.plugins.protobuf)
+  alias(libs.plugins.modernizer)
   // jhipster-needle-gradle-plugin
 }
 
diff --git a/src/main/resources/generator/dependencies/gradle/libs.versions.toml b/src/main/resources/generator/dependencies/gradle/libs.versions.toml
index a0a45c239..035d514c8 100644
--- a/src/main/resources/generator/dependencies/gradle/libs.versions.toml
+++ b/src/main/resources/generator/dependencies/gradle/libs.versions.toml
@@ -6,6 +6,7 @@ protobuf-plugin = "0.9.4"
 jacoco = "0.8.11"
 sonarqube = "4.4.1.3373"
 node-gradle = "7.0.2"
+modernizer = "1.10.0"
 
 [plugins]
 [plugins.jib]
@@ -19,3 +20,7 @@ version.ref = "git-properties"
 [plugins.protobuf]
 id = "com.google.protobuf"
 version.ref = "protobuf-plugin"
+
+[plugins.modernizer]
+id = "com.github.andygoossens.modernizer"
+version.ref = "modernizer"
diff --git a/src/main/resources/generator/dependencies/pom.xml b/src/main/resources/generator/dependencies/pom.xml
index 9d44e07e6..d326d3eee 100644
--- a/src/main/resources/generator/dependencies/pom.xml
+++ b/src/main/resources/generator/dependencies/pom.xml
@@ -73,6 +73,7 @@
     <openapi-maven-plugin.version>0.0.21</openapi-maven-plugin.version>
     <openapi-backwards-compat-maven-plugin.version>1.0.3</openapi-backwards-compat-maven-plugin.version>
     <liquibase-linter-maven-plugin.version>0.9.0</liquibase-linter-maven-plugin.version>
+    <modernizer-maven-plugin.version>3.0.0</modernizer-maven-plugin.version>
   </properties>
 
   <dependencyManagement>
@@ -428,6 +429,11 @@
         <artifactId>checkstyle</artifactId>
         <version>${checkstyle.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.gaul</groupId>
+        <artifactId>modernizer-maven-plugin</artifactId>
+        <version>${modernizer-maven-plugin.version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 </project>
diff --git a/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestAssertions.java.mustache b/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestAssertions.java.mustache
index 0b754474a..105b737b7 100644
--- a/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestAssertions.java.mustache
+++ b/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestAssertions.java.mustache
@@ -54,7 +54,7 @@ public final class CucumberRestAssertions {
   }
 
   static String responseBody() {
-    return CucumberRestTestContext.getResponse().get();
+    return CucumberRestTestContext.getResponse().orElseThrow();
   }
 
   private static final class CallDescription extends Description {


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 b39acf7b2..35a9eec76 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
@@ -10,7 +10,6 @@ import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Collection;
 import java.util.function.Function;
 import java.util.stream.Stream;
@@ -63,7 +62,7 @@ class HexagonalArchTest {
   }
 
   private static Path rootPackagePath() {
-    return Stream.of(ROOT_PACKAGE.split("\\.")).map(Paths::get).reduce(Paths.get("src", "main", "java"), Path::resolve);
+    return Stream.of(ROOT_PACKAGE.split("\\.")).map(Path::of).reduce(Path.of("src", "main", "java"), Path::resolve);
   }
 
   private static Function<Path, String> toPackageName() {
diff --git a/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestTestContext.java.mustache b/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestTestContext.java.mustache
index 5e28d43b5..90c961a8f 100644
--- a/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestTestContext.java.mustache
+++ b/src/main/resources/generator/server/springboot/cucumber/rest/CucumberRestTestContext.java.mustache
@@ -40,10 +40,13 @@ public final class CucumberRestTestContext {
   public static Object getElement(String uri, String jsonPath) {
     return queries
       .stream()
-      .filter(query -> query.response.isPresent() && StringUtils.isNotBlank(query.response.get()))
       .filter(query -> query.forUri(uri))
+      .map(RestQuery::response)
+      .filter(Optional::isPresent)
+      .map(Optional::orElseThrow)
+      .filter(StringUtils::isNotBlank)
+      .map(toElement(jsonPath))
       .findFirst()
-      .flatMap(response -> response.response.map(toElement(jsonPath)))
       .orElse(null);
   }
 
@@ -129,7 +132,7 @@ public final class CucumberRestTestContext {
     public RestQuery(HttpRequest request, ClientHttpResponse response, ClientHttpRequestExecution execution, byte[] body) {
       this.request = request;
       try {
-        uri = URLDecoder.decode(request.getURI().toString(), StandardCharsets.UTF_8.displayName());
+        uri = URLDecoder.decode(request.getURI().toString(), StandardCharsets.UTF_8);
         responseHeaders = response.getHeaders();
         status = (HttpStatus) response.getStatusCode();
       } catch (IOException e) {
diff --git a/src/main/resources/generator/server/springboot/dbmigration/cassandra/TestCassandraMigrationLoader.java.mustache b/src/main/resources/generator/server/springboot/dbmigration/cassandra/TestCassandraMigrationLoader.java.mustache
index 033f58078..1cd015f1d 100644
--- a/src/main/resources/generator/server/springboot/dbmigration/cassandra/TestCassandraMigrationLoader.java.mustache
+++ b/src/main/resources/generator/server/springboot/dbmigration/cassandra/TestCassandraMigrationLoader.java.mustache
@@ -15,7 +15,6 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.stream.Stream;
 
 class TestCassandraMigrationLoader implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
@@ -48,7 +47,7 @@ class TestCassandraMigrationLoader implements ApplicationListener<ApplicationEnv
       return;
     }
 
-    try (Stream<Path> stream = Files.list(Paths.get(dirUrl.toURI()))){
+    try (Stream<Path> stream = Files.list(Path.of(dirUrl.toURI()))){
       stream
         .map(Path::toString)
         .filter(file -> file.endsWith(PATTERN))
diff --git a/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/ApplicationErrorsMessagesTest.java.mustache b/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/ApplicationErrorsMessagesTest.java.mustache
index 9543a4d06..f0f0f6a1b 100644
--- a/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/ApplicationErrorsMessagesTest.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/ApplicationErrorsMessagesTest.java.mustache
@@ -5,7 +5,6 @@ import static org.assertj.core.api.Assertions.*;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -38,7 +37,7 @@ class {{ baseName }}ErrorsMessagesTest {
 
   private static Map<String, Properties> loadMessages() {
     try {
-      return Files.list(Paths.get("src/main/resources/messages/errors")).collect(
+      return Files.list(Path.of("src/main/resources/messages/errors")).collect(
         Collectors.toUnmodifiableMap(Path::toString, toProperties())
       );
     } catch (IOException e) {
diff --git a/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/AssertionErrorMessagesTest.java.mustache b/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/AssertionErrorMessagesTest.java.mustache
index 1b4744381..674167689 100644
--- a/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/AssertionErrorMessagesTest.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/internationalized-errors/test/AssertionErrorMessagesTest.java.mustache
@@ -5,7 +5,6 @@ import static org.assertj.core.api.Assertions.*;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Map;
 import java.util.Properties;
 import java.util.function.Consumer;
@@ -23,7 +22,7 @@ class AssertionErrorMessagesTest {
 
   private static Map<String, Properties> loadMessages() {
     try {
-      return Files.list(Paths.get("src/main/resources/messages/assertions-errors")).collect(
+      return Files.list(Path.of("src/main/resources/messages/assertions-errors")).collect(
         Collectors.toUnmodifiableMap(Path::toString, toProperties())
       );
     } catch (IOException e) {
diff --git a/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerCatalogRepositoryIT.java.mustache b/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerCatalogRepositoryIT.java.mustache
index 3e2086dfd..57b8828e1 100644
--- a/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerCatalogRepositoryIT.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerCatalogRepositoryIT.java.mustache
@@ -18,6 +18,6 @@ class CassandraBeerCatalogRepositoryIT {
   void shouldSaveAndGetBeer() {
     beerCatalog.save(BeerCatalogTable.from(beer()));
 
-    assertThat(beerCatalog.findById(cloackOfFeathersId().get()).get().toDomain()).usingRecursiveComparison().isEqualTo(beer());
+    assertThat(beerCatalog.findById(cloackOfFeathersId().get()).orElseThrow().toDomain()).usingRecursiveComparison().isEqualTo(beer());
   }
 }
diff --git a/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerRepositoryIT.java.mustache b/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerRepositoryIT.java.mustache
index aa8a096d1..a3385b837 100644
--- a/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerRepositoryIT.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/sample/cassandrapersistence/test/infrastructure/secondary/CassandraBeerRepositoryIT.java.mustache
@@ -18,6 +18,6 @@ class CassandraBeerRepositoryIT {
   void shouldSaveAndGetBeer() {
     beers.save(BeerTable.from(beer()));
 
-    assertThat(beers.findById(cloackOfFeathersId().get()).get().toDomain()).usingRecursiveComparison().isEqualTo(beer());
+    assertThat(beers.findById(cloackOfFeathersId().get()).orElseThrow().toDomain()).usingRecursiveComparison().isEqualTo(beer());
   }
 }
diff --git a/src/main/resources/generator/server/springboot/mvc/sample/jpapersistence/test/infrastructure/secondary/JpaBeersRepositoryIT.java.mustache b/src/main/resources/generator/server/springboot/mvc/sample/jpapersistence/test/infrastructure/secondary/JpaBeersRepositoryIT.java.mustache
index 6ca7af2fa..4bd8c0537 100644
--- a/src/main/resources/generator/server/springboot/mvc/sample/jpapersistence/test/infrastructure/secondary/JpaBeersRepositoryIT.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/sample/jpapersistence/test/infrastructure/secondary/JpaBeersRepositoryIT.java.mustache
@@ -20,6 +20,6 @@ class JpaBeersRepositoryIT {
   void shouldSaveAndGetBeer() {
     beers.saveAndFlush(BeerEntity.from(beer()));
 
-    assertThat(beers.findById(cloackOfFeathersId().get()).get().toDomain()).usingRecursiveComparison().isEqualTo(beer());
+    assertThat(beers.findById(cloackOfFeathersId().get()).orElseThrow().toDomain()).usingRecursiveComparison().isEqualTo(beer());
   }
 }
diff --git a/src/main/resources/generator/server/springboot/mvc/sample/mongodbpersistence/test/infrastructure/secondary/MongoDBBeersRepositoryIT.java.mustache b/src/main/resources/generator/server/springboot/mvc/sample/mongodbpersistence/test/infrastructure/secondary/MongoDBBeersRepositoryIT.java.mustache
index 5818b5628..44740db5d 100644
--- a/src/main/resources/generator/server/springboot/mvc/sample/mongodbpersistence/test/infrastructure/secondary/MongoDBBeersRepositoryIT.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/sample/mongodbpersistence/test/infrastructure/secondary/MongoDBBeersRepositoryIT.java.mustache
@@ -18,6 +18,6 @@ class MongoDBBeersRepositoryIT {
   void shouldSaveAndGetBeer() {
     beers.save(BeerDocument.from(beer()));
 
-    assertThat(beers.findById(cloackOfFeathersId().get()).get().toDomain()).usingRecursiveComparison().isEqualTo(beer());
+    assertThat(beers.findById(cloackOfFeathersId().get()).orElseThrow().toDomain()).usingRecursiveComparison().isEqualTo(beer());
   }
 }
diff --git a/src/main/resources/generator/server/springboot/mvc/security/jwt/authentication/test/infrastructure/primary/JwtReaderTest.java.mustache b/src/main/resources/generator/server/springboot/mvc/security/jwt/authentication/test/infrastructure/primary/JwtReaderTest.java.mustache
index db551514e..61c20da8f 100644
--- a/src/main/resources/generator/server/springboot/mvc/security/jwt/authentication/test/infrastructure/primary/JwtReaderTest.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/security/jwt/authentication/test/infrastructure/primary/JwtReaderTest.java.mustache
@@ -58,7 +58,7 @@ class JwtReaderTest {
 
   @Test
   void shouldGetAuthenticationFromValidToken() {
-    Authentication authentication = reader.read(userToken()).get();
+    Authentication authentication = reader.read(userToken()).orElseThrow();
 
     assertThat(((User) authentication.getPrincipal()).getUsername()).isEqualTo("test");
     assertThat(authentication.getAuthorities().stream().map(SimpleGrantedAuthority.class::cast)).containsExactly(
@@ -78,7 +78,7 @@ class JwtReaderTest {
 
   @Test
   void shouldGetAuthenticationFromValidTokenWithoutRoles() {
-    Authentication authentication = reader.read(userTokenWithoutRoles()).get();
+    Authentication authentication = reader.read(userTokenWithoutRoles()).orElseThrow();
 
     assertThat(((User) authentication.getPrincipal()).getUsername()).isEqualTo("test");
     assertThat(authentication.getAuthorities()).isEmpty();
diff --git a/src/main/resources/generator/server/springboot/mvc/security/oauth2/account/test/infrastructure/secondary/OAuth2AuthenticationReaderTest.java.mustache b/src/main/resources/generator/server/springboot/mvc/security/oauth2/account/test/infrastructure/secondary/OAuth2AuthenticationReaderTest.java.mustache
index e0070abbb..561528e01 100644
--- a/src/main/resources/generator/server/springboot/mvc/security/oauth2/account/test/infrastructure/secondary/OAuth2AuthenticationReaderTest.java.mustache
+++ b/src/main/resources/generator/server/springboot/mvc/security/oauth2/account/test/infrastructure/secondary/OAuth2AuthenticationReaderTest.java.mustache
@@ -39,7 +39,7 @@ class OAuth2AuthenticationReaderTest {
   void shouldReadOAuth2Authentication() {
     context.setAuthentication(testAuthenticationToken());
 
-    assertThat(tokens.authenticatedUserAccount().get()).usingRecursiveComparison().isEqualTo(account());
+    assertThat(tokens.authenticatedUserAccount().orElseThrow()).usingRecursiveComparison().isEqualTo(account());
   }
 
   @Test
@@ -50,13 +50,13 @@ class OAuth2AuthenticationReaderTest {
 
     context.setAuthentication(buildToken(claims));
 
-    assertThat(tokens.authenticatedUserAccount().get()).usingRecursiveComparison().isEqualTo(account());
+    assertThat(tokens.authenticatedUserAccount().orElseThrow()).usingRecursiveComparison().isEqualTo(account());
   }
 
   @Test
   void shouldReadJwtAuthentication() {
     context.setAuthentication(testJwtAuthenticationToken());
 
-    assertThat(tokens.authenticatedUserAccount().get()).usingRecursiveComparison().isEqualTo(account());
+    assertThat(tokens.authenticatedUserAccount().orElseThrow()).usingRecursiveComparison().isEqualTo(account());
   }
 }
diff --git a/src/test/features/server/javatool/modernizer.feature b/src/test/features/server/javatool/modernizer.feature
new file mode 100644
index 000000000..775d19ec0
--- /dev/null
+++ b/src/test/features/server/javatool/modernizer.feature
@@ -0,0 +1,11 @@
+Feature: Modernizer module
+
+  Scenario: Should apply modernizer module for maven
+    When I apply "modernizer" module to default project with maven file without parameters
+    Then I should have "<artifactId>modernizer-maven-plugin</artifactId>" in "pom.xml"
+
+  Scenario: Should apply modernizer module for gradle
+    When I apply "modernizer" module to default project with gradle build
+      | packageName | tech.jhipster.chips |
+      | baseName    | jhipster            |
+    Then I should have "id = \"com.github.andygoossens.modernizer\"" in "gradle/libs.versions.toml"
diff --git a/src/test/java/tech/jhipster/lite/generator/server/javatool/modernizer/domain/ModernizerModuleFactoryTest.java b/src/test/java/tech/jhipster/lite/generator/server/javatool/modernizer/domain/ModernizerModuleFactoryTest.java
new file mode 100644
index 000000000..1abb9d4f6
--- /dev/null
+++ b/src/test/java/tech/jhipster/lite/generator/server/javatool/modernizer/domain/ModernizerModuleFactoryTest.java
@@ -0,0 +1,94 @@
+package tech.jhipster.lite.generator.server.javatool.modernizer.domain;
+
+import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.assertThatModuleWithFiles;
+import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.gradleBuildFile;
+import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.gradleLibsVersionFile;
+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 ModernizerModuleFactoryTest {
+
+  private final ModernizerModuleFactory factory = new ModernizerModuleFactory();
+
+  @Test
+  void shouldBuildModuleForMaven() {
+    JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest()).build();
+
+    JHipsterModule module = factory.build(properties);
+
+    assertThatModuleWithFiles(module, pomFile())
+      .hasFile("pom.xml")
+      .containing(
+        """
+                <plugin>
+                  <groupId>org.gaul</groupId>
+                  <artifactId>modernizer-maven-plugin</artifactId>
+                  <version>${modernizer-maven-plugin.version}</version>
+                  <executions>
+                    <execution>
+                      <id>modernizer</id>
+                      <phase>verify</phase>
+                      <goals>
+                        <goal>modernizer</goal>
+                      </goals>
+                    </execution>
+                  </executions>
+                  <configuration>
+                    <javaVersion>${java.version}</javaVersion>
+                    <failOnViolations>true</failOnViolations>
+                  </configuration>
+                </plugin>\
+        """
+      )
+      .containing(
+        """
+              <plugin>
+                <groupId>org.gaul</groupId>
+                <artifactId>modernizer-maven-plugin</artifactId>
+              </plugin>\
+        """
+      );
+  }
+
+  @Test
+  void shouldBuildModuleForGradle() {
+    JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest()).build();
+
+    JHipsterModule module = factory.build(properties);
+
+    assertThatModuleWithFiles(module, gradleBuildFile(), gradleLibsVersionFile())
+      .hasFile("gradle/libs.versions.toml")
+      .containing(
+        """
+        \t[plugins.modernizer]
+        \t\tid = "com.github.andygoossens.modernizer"
+
+        \t\t[plugins.modernizer.version]
+        \t\t\tref = "modernizer"
+        """
+      )
+      .and()
+      .hasFile("build.gradle.kts")
+      .containing(
+        """
+          alias(libs.plugins.modernizer)
+          // jhipster-needle-gradle-plugins
+        """
+      )
+      .containing(
+        """
+        modernizer {
+          failOnViolations = true
+          includeTestClasses = true
+        }
+        """
+      );
+  }
+}
diff --git a/tests-ci/generate.sh b/tests-ci/generate.sh
index bd0e20e07..7b96735df 100755
--- a/tests-ci/generate.sh
+++ b/tests-ci/generate.sh
@@ -44,7 +44,8 @@ init_server() {
   apply_modules \
     "init" \
     "${java_build_tool}-wrapper" \
-    "${java_build_tool}-java"
+    "${java_build_tool}-java" \
+    "modernizer"
 }
 
 spring_boot() {