diff --git a/maven-modules/maven-exec-plugin/pom.xml b/maven-modules/maven-exec-plugin/pom.xml
index 7f017b415d..fc4d2d79f1 100644
--- a/maven-modules/maven-exec-plugin/pom.xml
+++ b/maven-modules/maven-exec-plugin/pom.xml
@@ -8,6 +8,36 @@
0.0.1-SNAPSHOT
maven-exec-plugin
+
+
+ org.apache.maven.shared
+ maven-invoker
+ ${apache.maven.invoker.version}
+
+
+ org.apache.maven
+ maven-embedder
+ ${apache.maven.version}
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit.jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit.jupiter.version}
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit.jupiter.version}
+ test
+
+
@@ -38,6 +68,9 @@
3.12.1
3.1.0
+ 5.10.0
+ 3.9.6
+ 3.2.0
\ No newline at end of file
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/JavaVersion.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/JavaVersion.java
new file mode 100644
index 0000000000..1dc57c5e18
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/JavaVersion.java
@@ -0,0 +1,17 @@
+package com.baeldung.learningplatform;
+
+public enum JavaVersion {
+
+ JAVA_8("1.8"), JAVA_9("9"), JAVA_17("17");
+
+ private final String version;
+
+
+ JavaVersion(String version) {
+ this.version = version;
+ }
+
+ public String getVersion() {
+ return this.version;
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/Maven.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/Maven.java
new file mode 100644
index 0000000000..4dbe6db6fa
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/Maven.java
@@ -0,0 +1,13 @@
+package com.baeldung.learningplatform;
+
+import java.nio.file.Path;
+
+public interface Maven {
+ String POM_XML = "pom.xml";
+ String COMPILE_GOAL = "compile";
+ String USE_CUSTOM_POM = "-f";
+ int OK = 0;
+ String MVN = "mvn";
+
+ void compile(Path projectFolder);
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenCompilationException.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenCompilationException.java
new file mode 100644
index 0000000000..572a7bc408
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenCompilationException.java
@@ -0,0 +1,12 @@
+package com.baeldung.learningplatform;
+
+public class MavenCompilationException extends RuntimeException {
+
+ public MavenCompilationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public MavenCompilationException(String message) {
+ super(message);
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenEmbedder.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenEmbedder.java
new file mode 100644
index 0000000000..0969ff504f
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenEmbedder.java
@@ -0,0 +1,16 @@
+package com.baeldung.learningplatform;
+
+import java.nio.file.Path;
+import org.apache.maven.cli.MavenCli;
+
+public class MavenEmbedder implements Maven {
+
+ public static final String MVN_HOME = "maven.multiModuleProjectDirectory";
+
+ @Override
+ public void compile(Path projectFolder) {
+ MavenCli cli = new MavenCli();
+ System.setProperty(MVN_HOME, projectFolder.toString());
+ cli.doMain(new String[]{COMPILE_GOAL}, projectFolder.toString(), null, null);
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenExecutorAdapter.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenExecutorAdapter.java
new file mode 100644
index 0000000000..1acee8404e
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenExecutorAdapter.java
@@ -0,0 +1,26 @@
+package com.baeldung.learningplatform;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public abstract class MavenExecutorAdapter implements Maven {
+
+ @Override
+ public void compile(Path projectFolder) {
+ int exitCode;
+ try {
+ exitCode = execute(projectFolder, COMPILE_GOAL);
+ } catch (InterruptedException e) {
+ throw new MavenCompilationException("Interrupted during compilation", e);
+ } catch (IOException e) {
+ throw new MavenCompilationException("Incorrect execution", e);
+ }
+ if (exitCode != OK) {
+ throw new MavenCompilationException("Failure during compilation: " + exitCode);
+ }
+ }
+
+ protected abstract int execute(Path projectFolder, String compileGoal)
+ throws InterruptedException, IOException;
+
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenInvoker.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenInvoker.java
new file mode 100644
index 0000000000..49fed4b6f9
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenInvoker.java
@@ -0,0 +1,30 @@
+package com.baeldung.learningplatform;
+
+import java.nio.file.Path;
+import java.util.Collections;
+import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.DefaultInvoker;
+import org.apache.maven.shared.invoker.InvocationRequest;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.MavenInvocationException;
+
+public class MavenInvoker implements Maven {
+
+ @Override
+ public void compile(Path projectFolder) {
+ InvocationRequest request = new DefaultInvocationRequest();
+ request.setPomFile(projectFolder.resolve(POM_XML).toFile());
+ request.setGoals(Collections.singletonList(Maven.COMPILE_GOAL));
+ Invoker invoker = new DefaultInvoker();
+ try {
+ InvocationResult result = invoker.execute(request);
+ if (result.getExitCode() != 0) {
+ throw new MavenCompilationException("Build failed", result.getExecutionException());
+ }
+ } catch (MavenInvocationException e) {
+ throw new MavenCompilationException("Exception during Maven invocation", e);
+ }
+
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenProcessBuilder.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenProcessBuilder.java
new file mode 100644
index 0000000000..7f4459f98a
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenProcessBuilder.java
@@ -0,0 +1,15 @@
+package com.baeldung.learningplatform;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public class MavenProcessBuilder extends MavenExecutorAdapter {
+ private static final ProcessBuilder PROCESS_BUILDER = new ProcessBuilder();
+
+ protected int execute(Path projectFolder, String compileGoal) throws IOException, InterruptedException {
+ Process process = PROCESS_BUILDER
+ .command(MVN, USE_CUSTOM_POM, projectFolder.resolve(POM_XML).toString(), compileGoal)
+ .start();
+ return process.waitFor();
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenRuntimeExec.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenRuntimeExec.java
new file mode 100644
index 0000000000..20ffa33607
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenRuntimeExec.java
@@ -0,0 +1,13 @@
+package com.baeldung.learningplatform;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public class MavenRuntimeExec extends MavenExecutorAdapter {
+ @Override
+ protected int execute(Path projectFolder, String compileGoal) throws InterruptedException, IOException {
+ String[] arguments = {MVN, USE_CUSTOM_POM, projectFolder.resolve(POM_XML).toString(), COMPILE_GOAL};
+ Process process = Runtime.getRuntime().exec(arguments);
+ return process.waitFor();
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/ProjectBuilder.java b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/ProjectBuilder.java
new file mode 100644
index 0000000000..5f9538e97d
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/ProjectBuilder.java
@@ -0,0 +1,100 @@
+package com.baeldung.learningplatform;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+public class ProjectBuilder {
+
+ private static final String PACKAGE = "package ";
+ private static final String POM_XML = "pom.xml";
+ private static final String SRC_TEST = "src/test/";
+ private static final String SRC_MAIN_JAVA = "src/main/java/";
+ private static final String PACKAGE_DELIMITER = ".";
+ private static final String MAIN_JAVA = "Main.java";
+ private final List dependencies = new ArrayList<>();
+ private JavaVersion javaVersion = JavaVersion.JAVA_8;
+
+ public ProjectBuilder addDependency(String groupId, String artifactId, String version) {
+ Dependency dependency = new Dependency();
+ dependency.setGroupId(groupId);
+ dependency.setArtifactId(artifactId);
+ dependency.setVersion(version);
+ dependencies.add(dependency);
+ return this;
+ }
+
+ public ProjectBuilder setJavaVersion(JavaVersion version) {
+ this.javaVersion = version;
+ return this;
+ }
+
+ public void build(String userName, Path projectPath, String packageName) throws IOException {
+ Model model = new Model();
+ configureModel(userName, model);
+ dependencies.forEach(model::addDependency);
+ Build build = configureJavaVersion();
+ model.setBuild(build);
+ MavenXpp3Writer writer = new MavenXpp3Writer();
+ writer.write(new FileWriter(projectPath.resolve(POM_XML).toFile()), model);
+ generateFolders(projectPath, SRC_TEST);
+
+ Path generatedPackage = generateFolders(projectPath,
+ SRC_MAIN_JAVA +
+ packageName.replace(PACKAGE_DELIMITER, FileSystems.getDefault().getSeparator()));
+ String generatedClass = generateMainClass(PACKAGE + packageName);
+ Files.writeString(generatedPackage.resolve(MAIN_JAVA), generatedClass);
+ }
+
+ private static void configureModel(String userName, Model model) {
+ model.setModelVersion("4.0.0");
+ model.setArtifactId("com." + userName.toLowerCase());
+ model.setGroupId("learning-project");
+ model.setVersion("0.0.1-SNAPSHOT");
+ }
+
+ private static String generateMainClass(String packageName) {
+ return packageName + ";\n" +
+ "\n" +
+ "public class Main {\n" +
+ " public static void main(String[] args){\n" +
+ " System.out.println(\"Hello World!\");\n" +
+ " }\n" +
+ "}\n";
+ }
+
+ private static Path generateFolders(Path sourceFolder, String packageName) throws IOException {
+ return Files.createDirectories(sourceFolder.resolve(packageName));
+ }
+
+ private Build configureJavaVersion() {
+ Plugin plugin = new Plugin();
+ plugin.setGroupId("org.apache.maven.plugins");
+ plugin.setArtifactId("maven-compiler-plugin");
+ plugin.setVersion("3.8.1");
+
+ Xpp3Dom configuration = new Xpp3Dom("configuration");
+ Xpp3Dom source = new Xpp3Dom("source");
+ source.setValue(javaVersion.getVersion());
+ Xpp3Dom target = new Xpp3Dom("target");
+ target.setValue(javaVersion.getVersion());
+ configuration.addChild(source);
+ configuration.addChild(target);
+
+ plugin.setConfiguration(configuration);
+
+ Build build = new Build();
+ build.addPlugin(plugin);
+ return build;
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/FileUtil.java b/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/FileUtil.java
new file mode 100644
index 0000000000..b781ab61f4
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/FileUtil.java
@@ -0,0 +1,32 @@
+package com.baeldung.learningplatform;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+public class FileUtil {
+
+ private FileUtil() {
+ }
+
+ public static void removeDirectoryRecursively(Path folder) throws IOException {
+ if (Files.exists(folder)) {
+ Files.walkFileTree(folder, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+ }
+}
diff --git a/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/MavenRuntimeExecUnitTest.java b/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/MavenRuntimeExecUnitTest.java
new file mode 100644
index 0000000000..4765cb299c
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/MavenRuntimeExecUnitTest.java
@@ -0,0 +1,41 @@
+package com.baeldung.learningplatform;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class MavenRuntimeExecUnitTest {
+
+ private static final String PACKAGE_NAME = "com.baeldung.generatedcode";
+ private static final String USER_NAME = "john_doe";
+ @TempDir
+ private Path tempDir;
+
+ @BeforeEach
+ public void setUp() throws IOException {
+ ProjectBuilder projectBuilder = new ProjectBuilder();
+ projectBuilder.build(USER_NAME, tempDir, PACKAGE_NAME);
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void givenMavenInterface_whenCompileMavenProject_thenCreateTargetDirectory(Maven maven) {
+ maven.compile(tempDir);
+ assertTrue(Files.exists(tempDir));
+ }
+
+ static Stream givenMavenInterface_whenCompileMavenProject_thenCreateTargetDirectory() {
+ return Stream.of(
+ new MavenRuntimeExec(),
+ new MavenProcessBuilder(),
+ new MavenEmbedder(),
+ new MavenInvoker());
+ }
+}
\ No newline at end of file
diff --git a/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/ProjectsPaths.java b/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/ProjectsPaths.java
new file mode 100644
index 0000000000..3967a83ca2
--- /dev/null
+++ b/maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/ProjectsPaths.java
@@ -0,0 +1,11 @@
+package com.baeldung.learningplatform;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public interface ProjectsPaths {
+
+ public static final Path PROJECT_DIR = Paths.get("src/test/resources/learning-project/");
+ public static final Path PROJECT_POM_XML = PROJECT_DIR.resolve("pom.xml");
+ public static final Path PROJECT_TARGET = PROJECT_DIR.resolve("target");
+}