diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java
index aba2ec97f4..e985308028 100644
--- a/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java
+++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/CommandletManagerImpl.java
@@ -108,6 +108,7 @@ public CommandletManagerImpl(IdeContext context) {
add(new Node(context));
add(new Npm(context));
add(new Mvn(context));
+ add(new RefactorCommandlet(context));
add(new GcViewer(context));
add(new Gradle(context));
add(new Eclipse(context));
diff --git a/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java
new file mode 100644
index 0000000000..77e1d14355
--- /dev/null
+++ b/cli/src/main/java/com/devonfw/tools/ide/commandlet/RefactorCommandlet.java
@@ -0,0 +1,109 @@
+package com.devonfw.tools.ide.commandlet;
+
+import com.devonfw.tools.ide.context.IdeContext;
+import com.devonfw.tools.ide.property.EnumProperty;
+import com.devonfw.tools.ide.property.StringProperty;
+import com.devonfw.tools.ide.tool.ToolCommandlet;
+import com.devonfw.tools.ide.tool.mvn.Mvn;
+import com.devonfw.tools.ide.tool.openrewrite.RecipeManager;
+import com.devonfw.tools.ide.tool.openrewrite.RecipeWrapper;
+import com.devonfw.tools.ide.tool.openrewrite.RefactorRecipeEnum;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * {@link ToolCommandlet} for Refactor.
+ */
+public class RefactorCommandlet extends Commandlet {
+
+ public final EnumProperty command;
+ public final StringProperty arguments;
+ private RecipeManager recipeManager;
+ /**
+ * The constructor.
+ *
+ * @param context the {@link IdeContext}.
+ */
+ public RefactorCommandlet(IdeContext context) {
+
+ super(context);
+ addKeyword(getName());
+ this.command = add(new EnumProperty<>("", true, "recipe_name", RefactorRecipeEnum.class));
+ this.arguments = new StringProperty("", false, true, "recipe-extra-arguments");
+ recipeManager = new RecipeManager();
+ add(this.arguments);
+ //this.recipe = context.
+ }
+
+ @Override
+ public String getName() {
+ //this indicates the command name
+ return "refactor";
+ }
+
+ private String[] adaptMVNCommand(String recipeRawCommands) {
+ if(recipeRawCommands.startsWith("mvn")) {
+ return recipeRawCommands.replaceFirst("\\Qmvn\\E", "").split("\\s+");
+ } else {
+ return recipeRawCommands.split("\\s+");
+ }
+ }
+
+ private String changeToDryRunCommand(String recipeRawCommands) {
+ return recipeRawCommands.replaceAll(":run\\b", ":dryrun");
+ }
+
+ private void showInfo(RecipeWrapper wrapper) {
+ context.info("Recipe [{}], {} ", wrapper.ideasy_command.name(), wrapper.description);
+ context.info("Reference {}", wrapper.url);
+ context.info("Raw command: {}", wrapper.raw_cmd);
+ }
+
+ private boolean confirmApplyChange() {
+ context.info("***Before making actual changes to the code, please confirm it seriously. It is strongly recommended to perform a DRY-RUN first***");
+ context.info("Type yes to apply changes, or press other keys to perform DRY-RUN: ");
+
+ Scanner scanner = new Scanner(System.in);
+ String input = scanner.nextLine();
+
+ return (input.equalsIgnoreCase("yes"));
+ }
+
+ @Override
+ public void run() {
+
+ context.info("{} called", getClass().getSimpleName());
+
+ RefactorRecipeEnum command = this.command.getValue();
+ String option = this.arguments.getValue();
+
+ if(!recipeManager.isValidRecipeEnum(command)) {
+ context.error("INVALID recipe name: {}", command);
+ return;
+ }
+
+ RecipeWrapper wrapper = recipeManager.getRecipeWrapper(command);
+
+ showInfo(wrapper);
+
+ String commandLine = wrapper.raw_cmd;
+
+ if(!confirmApplyChange()) {
+ commandLine = changeToDryRunCommand(commandLine);
+ }
+
+ context.info("Actual command line: {}", commandLine);
+
+ getCommandlet(Mvn.class).runTool(adaptMVNCommand(commandLine));
+
+ }
+
+ @Override
+ public boolean isIdeHomeRequired() {
+
+ return false;
+ }
+}
diff --git a/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java b/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java
new file mode 100644
index 0000000000..04a1321aa8
--- /dev/null
+++ b/cli/src/main/java/com/devonfw/tools/ide/property/RefactorRecipeProperty.java
@@ -0,0 +1,50 @@
+package com.devonfw.tools.ide.property;
+
+import com.devonfw.tools.ide.commandlet.Commandlet;
+import com.devonfw.tools.ide.completion.CompletionCandidateCollector;
+import com.devonfw.tools.ide.context.IdeContext;
+import com.devonfw.tools.ide.tool.ToolCommandlet;
+import com.devonfw.tools.ide.tool.plugin.PluginBasedCommandlet;
+import com.devonfw.tools.ide.tool.plugin.ToolPluginDescriptor;
+import com.devonfw.tools.ide.tool.plugin.ToolPlugins;
+import com.devonfw.tools.ide.validation.PropertyValidator;
+
+public class RefactorRecipeProperty extends Property {
+
+ public RefactorRecipeProperty(String name) {
+
+ this(name, null);
+ }
+
+ public RefactorRecipeProperty(String name, PropertyValidator validator) {
+
+ super(name, true, null, true, validator);
+ }
+
+ @Override
+ public Class getValueType() {
+
+ return String.class;
+ }
+
+ @Override
+ public String parse(String valueAsString, IdeContext context) {
+
+ return valueAsString;
+ }
+
+ @Override
+ protected void completeValue(String arg, IdeContext context, Commandlet commandlet, CompletionCandidateCollector collector) {
+
+ ToolCommandlet cmd = commandlet.getToolForCompletion();
+ if (cmd instanceof PluginBasedCommandlet pbc) {
+ ToolPlugins plugins = pbc.getPlugins();
+ for (ToolPluginDescriptor pluginDescriptor : plugins.getPlugins()) {
+ if (pluginDescriptor.name().toLowerCase().startsWith(arg.toLowerCase())) {
+ collector.add(pluginDescriptor.name(), null, null, commandlet);
+ }
+ }
+ }
+ }
+
+}
diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java
new file mode 100644
index 0000000000..530606dcde
--- /dev/null
+++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManager.java
@@ -0,0 +1,62 @@
+package com.devonfw.tools.ide.tool.openrewrite;
+
+import com.devonfw.tools.ide.json.JsonMapping;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+
+public class RecipeManager {
+
+ private static final String OPEN_REWRITE_CONFIG_JSON_PATH = "refactor/openrewrite.json";
+ private final Map recipes = new HashMap<>();
+
+
+ public RecipeManager() {
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ Objects.requireNonNull(RecipeManager.class.getClassLoader().getResourceAsStream(OPEN_REWRITE_CONFIG_JSON_PATH)), StandardCharsets.UTF_8));
+ ObjectMapper objectMapper = JsonMapping.create();
+
+ List wrapperList = objectMapper.readValue(reader, objectMapper.getTypeFactory().constructCollectionType(List.class, RecipeWrapper.class));
+
+ for(RecipeWrapper one: wrapperList) {
+ recipes.put(one.ideasy_command, one);
+ }
+
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List listAvailableRecipes() {
+ return Collections.unmodifiableList(recipes.values().stream().toList());
+ }
+
+ private Optional findRecipeByName(String rawName) {
+ return recipes.values().stream().filter(x -> x.origin_name.equals(rawName)).findAny();
+ }
+
+ public boolean isValidRecipeNameRawName(String rawName) {
+ return findRecipeByName(rawName).isPresent();
+ }
+
+ public boolean isValidRecipeEnum(RefactorRecipeEnum recipeEnum) {
+ return recipes.containsKey(recipeEnum);
+ }
+
+ public RecipeWrapper getRecipeWrapper(RefactorRecipeEnum recipeEnum) {
+ return recipes.get(recipeEnum);
+ }
+
+}
diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java
new file mode 100644
index 0000000000..c13de47c0b
--- /dev/null
+++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RecipeWrapper.java
@@ -0,0 +1,17 @@
+package com.devonfw.tools.ide.tool.openrewrite;
+
+import java.util.Locale;
+
+public class RecipeWrapper {
+ public String description;
+ public String origin_name;
+ public String url;
+ public RefactorRecipeEnum ideasy_command;
+ public String raw_cmd;
+
+ //in case of future need
+ public String getName() {
+ return this.origin_name;
+ }
+
+}
diff --git a/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java
new file mode 100644
index 0000000000..c72c299526
--- /dev/null
+++ b/cli/src/main/java/com/devonfw/tools/ide/tool/openrewrite/RefactorRecipeEnum.java
@@ -0,0 +1,5 @@
+package com.devonfw.tools.ide.tool.openrewrite;
+
+public enum RefactorRecipeEnum {
+ FORMAT_JAVA_CODE, REMOVE_BLANK_LINES, UNRECOGNIZED_RECIPE
+}
diff --git a/cli/src/main/resources/nls/Help.properties b/cli/src/main/resources/nls/Help.properties
index be1c8cc704..22c97039ee 100644
--- a/cli/src/main/resources/nls/Help.properties
+++ b/cli/src/main/resources/nls/Help.properties
@@ -88,6 +88,9 @@ cmd.python=Tool commandlet for Python.
cmd.python.detail=Python is an object-oriented programming language, comparable to Perl, Ruby, Scheme, or Java. Detailed documentation can be found at https://www.python.org/doc/
cmd.quarkus=Tool commandlet for Quarkus (framework for cloud-native apps).
cmd.quarkus.detail=Quarkus is a Kubernetes-native Java framework for building cloud-native applications. Detailed documentation can be found at https://quarkus.io/
+cmd.refactor=Refactor existing code base with specific recipes provided by OpenRewrite
+cmd.refactor.detail=OpenRewrite is a popular tool for refactoring (meta-programming). Detailed documentation can be found at https://docs.openrewrite.org/
+cmd.refactor.val.recipe_name=Refactor recipe names (RECIPE_1|RECIPE_2|RECIPE_3)
cmd.repository=Set up pre-configured git repositories using 'ide repository setup '
cmd.repository.detail=Without further arguments this will set up all pre-configured git repositories.\nAlso, you can provide an explicit git repo as `` argument and IDEasy will automatically clone, build and set up your project based on the existing property file.\nRepositories are configured in 'settings/repository/.properties' and can therefore be shared with your project team for automatic or optional setup.
cmd.repository.val.repository=The name of the properties file of the pre-configured git repository to set up, omit to set up all active repositories.
@@ -155,6 +158,7 @@ val.cfg=Selection of the configuration file (settings | home | conf | workspace)
val.commandlet=The selected commandlet (use 'ide help' to list all commandlets).
val.edition=The tool edition.
val.plugin=The plugin to select
+val.recipe-extra-arguments=possible additional arguments for the recipe
val.settingsRepository=The settings git repository with the IDEasy configuration for the project.
val.tool=The tool commandlet to select.
val.version=The tool version.
diff --git a/cli/src/main/resources/nls/Help_de.properties b/cli/src/main/resources/nls/Help_de.properties
index 7944c5f23d..8abaa54cac 100644
--- a/cli/src/main/resources/nls/Help_de.properties
+++ b/cli/src/main/resources/nls/Help_de.properties
@@ -88,6 +88,9 @@ cmd.python=Werkzeug Kommando für Python.
cmd.python.detail=Python ist eine objektorientierte Programmiersprache, vergleichbar mit Perl, Ruby, Scheme oder Java. Detaillierte Dokumentation ist zu finden unter https://www.python.org/doc/
cmd.quarkus=Werkzeug Kommando für Quarkus (Framework für Cloud-native Anwendungen).
cmd.quarkus.detail=Quarkus ist ein Kubernetes-native Java-Framework zur Entwicklung von Cloud-native Anwendungen. Detaillierte Dokumentation ist zu finden unter https://quarkus.io/
+cmd.refactor=Refaktorieren Sie die vorhandene Codebasis mit spezifischen Rezepten von OpenRewrite
+cmd.refactor.detail=OpenRewrite ist ein beliebtes Tool für Refactoring (Metaprogrammierung). Eine ausführliche Dokumentation finden Sie unter https://docs.openrewrite.org/
+cmd.refactor.val.recipe_name=Rezeptnamen umgestalten (RECIPE_1|RECIPE_2|RECIPE_3)
cmd.repository=Richtet das vorkonfigurierte Git Repository ein mittels 'ide repository setup '.
cmd.repository.detail=Dies wird alle vorkonfigurierten Repositories einrichten. Rufen Sie einfach 'ide repository setup ' auf, ersetzen Sie durch den Namen Ihrer Projektkonfigurationsdatei, die sich in 'settings/repository/your_project_name' befindet und IDEasy wird Ihr Projekt basierend auf der vorhandenen Eigenschaftsdatei automatisch klonen, bauen und einrichten.\nWenn Sie den Projektnamen weglassen, werden alle im Repository-Verzeichnis gefundenen Projekte vorkonfiguriert.
cmd.repository.val.repository=Der Name der Properties-Datei des vorkonfigurierten Git Repositories zum Einrichten. Falls nicht angegeben, werden alle aktiven Projekte eingerichtet.
@@ -155,6 +158,7 @@ val.cfg=Auswahl der Konfigurationsdatei (settings | home | conf | workspace).
val.commandlet=Das ausgewählte Commandlet ("ide help" verwenden, um alle Commandlets aufzulisten).
val.edition=Die Werkzeug Edition.
val.plugin=Die zu selektierende Erweiterung.
+val.recipe-extra-arguments=Mögliche zusätzliche Argumente für das Rezept.
val.settingsRepository=Das settings git Repository mit den IDEasy Einstellungen für das Projekt.
val.tool=Das zu selektierende Werkzeug Kommando.
val.version=Die Werkzeug Version.
diff --git a/cli/src/main/resources/refactor/openrewrite.json b/cli/src/main/resources/refactor/openrewrite.json
new file mode 100644
index 0000000000..4ed6375340
--- /dev/null
+++ b/cli/src/main/resources/refactor/openrewrite.json
@@ -0,0 +1,16 @@
+[
+ {
+ "origin_name": "java.format_java_code",
+ "ideasy_command": "FORMAT_JAVA_CODE",
+ "description": "Format Java code using a standard comprehensive set of Java formatting recipes.",
+ "url": "https://docs.openrewrite.org/recipes/java/format/autoformat",
+ "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.AutoFormat -Drewrite.exportDatatables=true"
+ },
+ {
+ "origin_name": "java.remove_blank_lines",
+ "ideasy_command": "REMOVE_BLANK_LINES",
+ "description": "Add and/or remove blank lines.",
+ "url": "https://docs.openrewrite.org/recipes/java/format/blanklines",
+ "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.BlankLines -Drewrite.exportDatatables=true"
+ }
+]
diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java
new file mode 100644
index 0000000000..6710f0b767
--- /dev/null
+++ b/cli/src/test/java/com/devonfw/tools/ide/tool/openrewrite/RecipeManagerTest.java
@@ -0,0 +1,37 @@
+package com.devonfw.tools.ide.tool.openrewrite;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class RecipeManagerTest {
+
+ static RecipeManager manager;
+
+ @BeforeAll
+ static void init() {
+ manager = new RecipeManager();
+ }
+
+ @Test
+ public void testCreation() {
+ assertFalse(manager.listAvailableRecipes().isEmpty());
+ }
+
+ @Test
+ public void testStringValidation() {
+ assertFalse(manager.isValidRecipeNameRawName("NONSENSE"));
+ assertTrue(manager.isValidRecipeNameRawName(manager.listAvailableRecipes().stream().findAny().get().origin_name));
+ }
+
+ @Test
+ public void testEnumValidation() {
+ assertFalse(manager.isValidRecipeEnum(RefactorRecipeEnum.UNRECOGNIZED_RECIPE));
+ assertTrue(manager.isValidRecipeEnum(
+ Arrays.stream(RefactorRecipeEnum.values())
+ .filter(x -> !x.equals(RefactorRecipeEnum.UNRECOGNIZED_RECIPE)).findAny().get()));
+ }
+}
diff --git a/cli/src/test/resources/refactor/openrewrite.json b/cli/src/test/resources/refactor/openrewrite.json
new file mode 100644
index 0000000000..4ed6375340
--- /dev/null
+++ b/cli/src/test/resources/refactor/openrewrite.json
@@ -0,0 +1,16 @@
+[
+ {
+ "origin_name": "java.format_java_code",
+ "ideasy_command": "FORMAT_JAVA_CODE",
+ "description": "Format Java code using a standard comprehensive set of Java formatting recipes.",
+ "url": "https://docs.openrewrite.org/recipes/java/format/autoformat",
+ "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.AutoFormat -Drewrite.exportDatatables=true"
+ },
+ {
+ "origin_name": "java.remove_blank_lines",
+ "ideasy_command": "REMOVE_BLANK_LINES",
+ "description": "Add and/or remove blank lines.",
+ "url": "https://docs.openrewrite.org/recipes/java/format/blanklines",
+ "raw_cmd": "mvn -U org.openrewrite.maven:rewrite-maven-plugin:run -Drewrite.activeRecipes=org.openrewrite.java.format.BlankLines -Drewrite.exportDatatables=true"
+ }
+]