From 9d23ecb95bdeefca4fc01afe3b6ef667fd70d6fa Mon Sep 17 00:00:00 2001 From: Eugene Kovko <37694937+eukovko@users.noreply.github.com> Date: Fri, 2 Feb 2024 20:26:16 +0100 Subject: [PATCH] Bael 7201 (#15792) * BAEL-7201: Maven compilation example * BAEL-7201: Disable the tests * BAEL-7201: Created MavenAdapter and moved repeated code * BAEL-7201: Project creation and tests * BAEL-7201: A couple of renames and refactors * BAEL-7201: Extract constants * BAEL-7201: Cleaned the POM * BAEL-7201: Remove unnecessary access modifiers --- maven-modules/maven-exec-plugin/pom.xml | 33 ++++++ .../learningplatform/JavaVersion.java | 17 +++ .../com/baeldung/learningplatform/Maven.java | 13 +++ .../MavenCompilationException.java | 12 +++ .../learningplatform/MavenEmbedder.java | 16 +++ .../MavenExecutorAdapter.java | 26 +++++ .../learningplatform/MavenInvoker.java | 30 ++++++ .../learningplatform/MavenProcessBuilder.java | 15 +++ .../learningplatform/MavenRuntimeExec.java | 13 +++ .../learningplatform/ProjectBuilder.java | 100 ++++++++++++++++++ .../baeldung/learningplatform/FileUtil.java | 32 ++++++ .../MavenRuntimeExecUnitTest.java | 41 +++++++ .../learningplatform/ProjectsPaths.java | 11 ++ 13 files changed, 359 insertions(+) create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/JavaVersion.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/Maven.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenCompilationException.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenEmbedder.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenExecutorAdapter.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenInvoker.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenProcessBuilder.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/MavenRuntimeExec.java create mode 100644 maven-modules/maven-exec-plugin/src/main/java/com/baeldung/learningplatform/ProjectBuilder.java create mode 100644 maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/FileUtil.java create mode 100644 maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/MavenRuntimeExecUnitTest.java create mode 100644 maven-modules/maven-exec-plugin/src/test/java/com/baeldung/learningplatform/ProjectsPaths.java 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"); +}