jars) {
+ return infLibs(jars.stream().map(File::new).toList());
+ }
+
/**
* Provides the Spring Boot loader launcher fully-qualified class name.
*
@@ -347,6 +393,7 @@ public abstract class AbstractBootOperation>
* @param jars a collection of Java archives
* @return this operation instance
* @throws IOException if a JAR could not be found
+ * @see #infLibs(File...)
*/
public T launcherLibs(Collection jars) throws IOException {
for (var j : jars) {
@@ -366,18 +413,10 @@ public abstract class AbstractBootOperation>
* @param jars one or more Java archives
* @return this operation instance
* @throws IOException if a JAR could not be found
+ * @see #infLibs(Collection)
*/
- @SuppressWarnings("UnusedReturnValue")
public T launcherLibs(File... jars) throws IOException {
- for (var j : jars) {
- if (j.exists()) {
- launcherLibs_.add(j);
- } else {
- throw new IOException("Spring Boot loader launcher library not found: " + j);
- }
- }
- //noinspection unchecked
- return (T) this;
+ return launcherLibs(List.of(jars));
}
/**
@@ -386,19 +425,46 @@ public abstract class AbstractBootOperation>
* @param jars one or more Java archives
* @return this operation instance
* @throws IOException if a JAR could not be found
+ * @see #launcherLibsStrings(Collection)
*/
- @SuppressWarnings("UnusedReturnValue")
public T launcherLibs(String... jars) throws IOException {
- for (var j : jars) {
- var p = Path.of(j);
- if (Files.exists(p)) {
- launcherLibs_.add(p.toFile());
- } else {
- throw new IOException("Spring Boot loader launcher library not found: " + j);
- }
- }
- //noinspection unchecked
- return (T) this;
+ return launcherLibsStrings(List.of(jars));
+ }
+
+ /**
+ * Provides the libraries for the Spring Boot loader launcher.
+ *
+ * @param jars one or more Java archives
+ * @return this operation instance
+ * @throws IOException if a JAR could not be found
+ * @see #launcherLibsPaths(Collection)
+ */
+ public T launcherLibs(Path... jars) throws IOException {
+ return launcherLibsPaths(List.of(jars));
+ }
+
+ /**
+ * Provides the libraries for the Spring Boot loader launcher.
+ *
+ * @param jars one or more Java archives
+ * @return this operation instance
+ * @throws IOException if a JAR could not be found
+ * @see #launcherLibs(Path...)
+ */
+ public T launcherLibsPaths(Collection jars) throws IOException {
+ return launcherLibs(jars.stream().map(Path::toFile).toList());
+ }
+
+ /**
+ * Provides the libraries for the Spring Boot loader launcher.
+ *
+ * @param jars one or more Java archives
+ * @return this operation instance
+ * @throws IOException if a JAR could not be found
+ * @see #launcherLibs(String...)
+ */
+ public T launcherLibsStrings(Collection jars) throws IOException {
+ return launcherLibs(jars.stream().map(File::new).toList());
}
/**
@@ -462,9 +528,10 @@ public abstract class AbstractBootOperation>
*
* @param directories one or more source directories
* @return this operation instance
+ * @see #sourceDirectories(File...)
*/
- public T sourceDirectories(File... directories) {
- sourceDirectories_.addAll(List.of(directories));
+ public T sourceDirectories(Collection directories) {
+ sourceDirectories_.addAll(directories);
//noinspection unchecked
return (T) this;
}
@@ -474,11 +541,32 @@ public abstract class AbstractBootOperation>
*
* @param directories one or more source directories
* @return this operation instance
+ * @see #sourceDirectories(Collection)
+ */
+ public T sourceDirectories(File... directories) {
+ return sourceDirectories(List.of(directories));
+ }
+
+ /**
+ * Provides source directories that will be used for the archive creation.
+ *
+ * @param directories one or more source directories
+ * @return this operation instance
+ * @see #sourceDirectoriesStrings(Collection)
*/
public T sourceDirectories(String... directories) {
- sourceDirectories_.addAll(Arrays.stream(directories).map(File::new).toList());
- //noinspection unchecked
- return (T) this;
+ return sourceDirectoriesStrings(List.of(directories));
+ }
+
+ /**
+ * Provides source directories that will be used for the archive creation.
+ *
+ * @param directories one or more source directories
+ * @return this operation instance
+ * @see #sourceDirectoriesPaths(Collection)
+ */
+ public T sourceDirectories(Path... directories) {
+ return sourceDirectoriesPaths(List.of(directories));
}
/**
@@ -490,6 +578,28 @@ public abstract class AbstractBootOperation>
return sourceDirectories_;
}
+ /**
+ * Provides source directories that will be used for the archive creation.
+ *
+ * @param directories one or more source directories
+ * @return this operation instance
+ * @see #sourceDirectories(Path...)
+ */
+ public T sourceDirectoriesPaths(Collection directories) {
+ return sourceDirectories(directories.stream().map(Path::toFile).toList());
+ }
+
+ /**
+ * Provides source directories that will be used for the archive creation.
+ *
+ * @param directories one or more source directories
+ * @return this operation instance
+ * @see #sourceDirectories(String...)
+ */
+ public T sourceDirectoriesStrings(Collection directories) {
+ return sourceDirectories(directories.stream().map(File::new).toList());
+ }
+
/**
* Verifies that all the elements ({@link #mainClass() mainClass}, {@link #launcherClass() launcherClass} and
* {@link #launcherLibs() launcherLibs}) required to create the archive have been provided, throws an
diff --git a/src/main/java/rife/bld/extension/BootJarOperation.java b/src/main/java/rife/bld/extension/BootJarOperation.java
index 22edfe9..d758857 100644
--- a/src/main/java/rife/bld/extension/BootJarOperation.java
+++ b/src/main/java/rife/bld/extension/BootJarOperation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/main/java/rife/bld/extension/BootUtils.java b/src/main/java/rife/bld/extension/BootUtils.java
index c45138c..42ae132 100644
--- a/src/main/java/rife/bld/extension/BootUtils.java
+++ b/src/main/java/rife/bld/extension/BootUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/main/java/rife/bld/extension/BootWarOperation.java b/src/main/java/rife/bld/extension/BootWarOperation.java
index da4bd53..51f7fdf 100644
--- a/src/main/java/rife/bld/extension/BootWarOperation.java
+++ b/src/main/java/rife/bld/extension/BootWarOperation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import rife.tools.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -145,6 +146,7 @@ public class BootWarOperation extends AbstractBootOperation {
*
* @param jars a collection of Java archive files
* @return this operation instance
+ * @see #providedLibs(File...)
*/
public BootWarOperation providedLibs(Collection jars) {
providedLibs_.addAll(jars);
@@ -156,9 +158,62 @@ public class BootWarOperation extends AbstractBootOperation {
*
* @param jars one or more Java archive files
* @return this operation instance
+ * @see #providedLibsStrings(Collection)
+ */
+ public BootWarOperation providedLibs(String... jars) {
+ return providedLibsStrings(List.of(jars));
+ }
+
+ /**
+ * Provides the libraries that will be used for the WAR creation in {@code /WEB-INF/lib-provided}.
+ *
+ * @param jars one or more Java archive files
+ * @return this operation instance
+ * @see #providedLibs(Collection)
*/
public BootWarOperation providedLibs(File... jars) {
- providedLibs_.addAll(List.of(jars));
- return this;
+ return providedLibs(List.of(jars));
+ }
+
+ /**
+ * Provides the libraries that will be used for the WAR creation in {@code /WEB-INF/lib-provided}.
+ *
+ * @param jars one or more Java archive files
+ * @return this operation instance
+ * @see #providedLibsPaths(Collection)
+ */
+ public BootWarOperation providedLibs(Path... jars) {
+ return providedLibsPaths(List.of(jars));
+ }
+
+ /**
+ * Retrieves the libraries that will be used for the WAR creation in {@code /WEB-INF/lib-provided}.
+ *
+ * @return the list of Java archive files.
+ */
+ public List providedLibs() {
+ return providedLibs_;
+ }
+
+ /**
+ * Provides the libraries that will be used for the WAR creation in {@code /WEB-INF/lib-provided}.
+ *
+ * @param jars one or more Java archive files
+ * @return this operation instance
+ * @see #providedLibs(Path...)
+ */
+ public BootWarOperation providedLibsPaths(Collection jars) {
+ return providedLibs(jars.stream().map(Path::toFile).toList());
+ }
+
+ /**
+ * Provides the libraries that will be used for the WAR creation in {@code /WEB-INF/lib-provided}.
+ *
+ * @param jars one or more Java archive files
+ * @return this operation instance
+ * @see #providedLibs(String...)
+ */
+ public BootWarOperation providedLibsStrings(Collection jars) {
+ return providedLibs(jars.stream().map(File::new).toList());
}
}
diff --git a/src/test/java/rife/bld/extension/BootJarOperationTest.java b/src/test/java/rife/bld/extension/BootJarOperationTest.java
index 5695287..5ee7341 100644
--- a/src/test/java/rife/bld/extension/BootJarOperationTest.java
+++ b/src/test/java/rife/bld/extension/BootJarOperationTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package rife.bld.extension;
+import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test;
import rife.bld.Project;
import rife.bld.dependencies.VersionNumber;
@@ -24,6 +25,7 @@ import rife.tools.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
@@ -33,8 +35,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
class BootJarOperationTest {
- private static final String BLD = "bld-2.0.1.jar";
- private static final String BOOT_VERSION = "3.3.2";
+ private static final String BLD = "bld-2.2.1.jar";
+ private static final String BOOT_VERSION = "3.4.5";
private static final String EXAMPLES_LIB_COMPILE = "examples/lib/compile/";
private static final String EXAMPLES_LIB_RUNTIME = "examples/lib/runtime/";
private static final String EXAMPLES_LIB_STANDALONE = "examples/lib/standalone/";
@@ -44,6 +46,8 @@ class BootJarOperationTest {
org/springframework/boot/
org/springframework/boot/loader/
org/springframework/boot/loader/jar/
+ org/springframework/boot/loader/jar/JarEntriesStream$InputStreamSupplier.class
+ org/springframework/boot/loader/jar/JarEntriesStream.class
org/springframework/boot/loader/jar/ManifestInfo.class
org/springframework/boot/loader/jar/MetaInfVersionsInfo.class
org/springframework/boot/loader/jar/NestedJarFile$JarEntriesEnumeration.class
@@ -58,6 +62,7 @@ class BootJarOperationTest {
org/springframework/boot/loader/jar/ZipInflaterInputStream.class
org/springframework/boot/loader/jarmode/
org/springframework/boot/loader/jarmode/JarMode.class
+ org/springframework/boot/loader/jarmode/JarModeErrorException.class
org/springframework/boot/loader/launch/
org/springframework/boot/loader/launch/Archive$Entry.class
org/springframework/boot/loader/launch/Archive.class
@@ -157,6 +162,8 @@ class BootJarOperationTest {
private static final String SPRING_BOOT = "spring-boot-" + BOOT_VERSION + ".jar";
private static final String SPRING_BOOT_ACTUATOR = "spring-boot-actuator-" + BOOT_VERSION + ".jar";
private static final String SPRING_BOOT_LOADER = "spring-boot-loader-" + BOOT_VERSION + ".jar";
+ private static final String SRC_MAIN_JAVA = "src/main/java";
+ private static final String SRC_TEST_JAVA = "src/test/java";
private StringBuilder readJarEntries(File jar) throws IOException {
var jarEntries = new StringBuilder();
@@ -198,6 +205,38 @@ class BootJarOperationTest {
assertThat(bootWar.verifyExecute()).isTrue();
}
+ @Test
+ void testInfLibs() {
+ var op = new BootWarOperation();
+
+ var foo = new File(EXAMPLES_LIB_COMPILE + SPRING_BOOT);
+ var bar = new File(EXAMPLES_LIB_COMPILE + SPRING_BOOT_ACTUATOR);
+
+ op.infLibs(EXAMPLES_LIB_COMPILE + SPRING_BOOT, EXAMPLES_LIB_COMPILE + SPRING_BOOT_ACTUATOR);
+ assertThat(op.infLibs()).as("String...").containsExactly(foo, bar);
+ op.infLibs().clear();
+
+ op.infLibs(foo, bar);
+ assertThat(op.infLibs()).as("File...").containsExactly(foo, bar);
+ op.infLibs().clear();
+
+ op.infLibs(foo.toPath(), bar.toPath());
+ assertThat(op.infLibs()).as("Path...").containsExactly(foo, bar);
+ op.infLibs().clear();
+
+ op.infLibsStrings(List.of(EXAMPLES_LIB_COMPILE + SPRING_BOOT, EXAMPLES_LIB_COMPILE + SPRING_BOOT_ACTUATOR));
+ assertThat(op.infLibs()).as("List(String...)").containsExactly(foo, bar);
+ op.infLibs().clear();
+
+ op.infLibs(List.of(foo, bar));
+ assertThat(op.infLibs()).as("List(File...)").containsExactly(foo, bar);
+ op.infLibs().clear();
+
+ op.infLibsPaths(List.of(foo.toPath(), bar.toPath()));
+ assertThat(op.infLibs()).as("List(Path...)").containsExactly(foo, bar);
+ op.infLibs().clear();
+ }
+
@Test
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
void testJarExecute() throws Exception {
@@ -272,31 +311,95 @@ class BootJarOperationTest {
FileUtils.deleteDirectory(tmp_dir);
}
+ @Test
+ void testLauncherLibs() throws IOException {
+ var op = new BootJarOperation();
+
+ var launcher = new File(EXAMPLES_LIB_STANDALONE + SPRING_BOOT_LOADER);
+ op = op.launcherLibs(EXAMPLES_LIB_STANDALONE + SPRING_BOOT_LOADER);
+ assertThat(op.launcherLibs()).as("String...").containsExactly(launcher);
+ op.launcherLibs().clear();
+
+ op = op.launcherLibs(launcher);
+ assertThat(op.launcherLibs()).as("File...").containsExactly(launcher);
+ op.launcherLibs().clear();
+
+ op = op.launcherLibs(launcher.toPath());
+ assertThat(op.launcherLibs()).as("Path...").containsExactly(launcher);
+ op.launcherLibs().clear();
+
+ op = op.launcherLibsStrings(List.of(EXAMPLES_LIB_STANDALONE + SPRING_BOOT_LOADER));
+ assertThat(op.launcherLibs()).as("List(String...)").containsExactly(launcher);
+ op.launcherLibs().clear();
+
+ op = op.launcherLibs(List.of(launcher));
+ assertThat(op.launcherLibs()).as("List(File...)").containsExactly(launcher);
+ op.launcherLibs().clear();
+
+ op = op.launcherLibsPaths(List.of(launcher.toPath()));
+ assertThat(op.launcherLibs()).as("List(Path...)").containsExactly(launcher);
+ op.launcherLibs().clear();
+ }
+
@Test
void testProject() throws IOException {
var tmp_dir = Files.createTempDirectory("bootprjtmp").toFile();
var project = new CustomProject(tmp_dir);
- var bootJar = new BootJarOperation().fromProject(project).sourceDirectories("src/main/java");
+ var bootJar = new BootJarOperation().fromProject(project).sourceDirectories(SRC_MAIN_JAVA);
- assertThat(bootJar.mainClass()).as("mainClass").isEqualTo(MAIN_CLASS);
- assertThat(bootJar.sourceDirectories()).as("sourceDirectories.size").hasSize(3)
- .containsExactly(project.buildMainDirectory(), project.srcMainResourcesDirectory(),
- new File("src/main/java"));
- assertThat(bootJar.manifestAttributes()).as("manifestAttributes.size").hasSize(3);
- assertThat(bootJar.manifestAttributes().get("Manifest-Version")).as("Manifest-Version").isEqualTo("1.0");
- assertThat(bootJar.manifestAttributes().get("Main-Class")).as("Main-Class").endsWith("JarLauncher");
- assertThat(bootJar.manifestAttributes().get("Start-Class")).as("Start-Class").isEqualTo(MAIN_CLASS);
- assertThat(bootJar.manifestAttribute("Manifest-Test", "tsst")
- .manifestAttributes().get("Manifest-Test")).as("Manifest-Test").isEqualTo("tsst");
- assertThat(bootJar.destinationDirectory()).as("destinationDirectory").isDirectory();
- assertThat(bootJar.destinationDirectory()).isEqualTo(project.buildDistDirectory());
- assertThat(bootJar.infLibs()).as("infoLibs").isEmpty();
- assertThat(bootJar.launcherLibs()).as("launcherJars").isEmpty();
- assertThat(bootJar.destinationFileName()).isEqualTo("test_project-0.0.1-boot.jar");
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(bootJar.mainClass()).as("mainClass").isEqualTo(MAIN_CLASS);
+ softly.assertThat(bootJar.sourceDirectories()).as("sourceDirectories.size").hasSize(3)
+ .containsExactly(project.buildMainDirectory(), project.srcMainResourcesDirectory(),
+ new File(SRC_MAIN_JAVA));
+ softly.assertThat(bootJar.manifestAttributes()).as("manifestAttributes.size").hasSize(3);
+ softly.assertThat(bootJar.manifestAttributes().get("Manifest-Version")).as("Manifest-Version")
+ .isEqualTo("1.0");
+ softly.assertThat(bootJar.manifestAttributes().get("Main-Class")).as("Main-Class").endsWith("JarLauncher");
+ softly.assertThat(bootJar.manifestAttributes().get("Start-Class")).as("Start-Class").isEqualTo(MAIN_CLASS);
+ softly.assertThat(bootJar.manifestAttribute("Manifest-Test", "tsst")
+ .manifestAttributes().get("Manifest-Test")).as("Manifest-Test").isEqualTo("tsst");
+ softly.assertThat(bootJar.destinationDirectory()).as("destinationDirectory").isDirectory();
+ softly.assertThat(bootJar.destinationDirectory()).isEqualTo(project.buildDistDirectory());
+ softly.assertThat(bootJar.infLibs()).as("infoLibs").isEmpty();
+ softly.assertThat(bootJar.launcherLibs()).as("launcherJars").isEmpty();
+ softly.assertThat(bootJar.destinationFileName()).isEqualTo("test_project-0.0.1-boot.jar");
+ }
FileUtils.deleteDirectory(tmp_dir);
}
+ @Test
+ void testSourceDirectories() {
+ var op = new BootJarOperation();
+
+ var src = new File(SRC_MAIN_JAVA);
+ var test = new File(SRC_TEST_JAVA);
+ op = op.sourceDirectories(SRC_MAIN_JAVA, SRC_TEST_JAVA);
+ assertThat(op.sourceDirectories()).as("String...").containsExactly(src, test);
+ op.sourceDirectories().clear();
+
+ op = op.sourceDirectories(src, test);
+ assertThat(op.sourceDirectories()).as("File...").containsExactly(src, test);
+ op.sourceDirectories().clear();
+
+ op = op.sourceDirectories(src.toPath(), test.toPath());
+ assertThat(op.sourceDirectories()).as("Path...").containsExactly(src, test);
+ op.sourceDirectories().clear();
+
+ op.sourceDirectoriesStrings(List.of(SRC_MAIN_JAVA, SRC_TEST_JAVA));
+ assertThat(op.sourceDirectories()).as("List(String...").containsExactly(src, test);
+ op.sourceDirectories().clear();
+
+ op.sourceDirectories(List.of(src, test));
+ assertThat(op.sourceDirectories()).as("List(File...)").containsExactly(src, test);
+ op.sourceDirectories().clear();
+
+ op.sourceDirectoriesPaths(List.of(src.toPath(), test.toPath()));
+ assertThat(op.sourceDirectories()).as("List(Path...)").containsExactly(src, test);
+ op.sourceDirectories().clear();
+ }
+
@Test
void testWarProjectExecute() throws Exception {
var tmp_dir = Files.createTempDirectory("bootjartmp").toFile();
@@ -304,9 +407,9 @@ class BootJarOperationTest {
new BootWarOperation()
.fromProject(project)
.launcherLibs(List.of(new File(EXAMPLES_LIB_STANDALONE + SPRING_BOOT_LOADER)))
- .destinationDirectory(tmp_dir)
- .infLibs(new File(EXAMPLES_LIB_COMPILE + SPRING_BOOT),
- new File(EXAMPLES_LIB_COMPILE + SPRING_BOOT_ACTUATOR))
+ .destinationDirectory(tmp_dir.toPath())
+ .infLibs(Path.of(EXAMPLES_LIB_COMPILE + SPRING_BOOT),
+ Path.of(EXAMPLES_LIB_COMPILE + SPRING_BOOT_ACTUATOR))
.providedLibs(new File(EXAMPLES_LIB_RUNTIME + PROVIDED_LIB))
.execute();
@@ -337,6 +440,24 @@ class BootJarOperationTest {
FileUtils.deleteDirectory(tmp_dir);
}
+ @Test
+ void testWarProvidedLibs() {
+ var op = new BootWarOperation();
+
+ var foo = new File(EXAMPLES_LIB_RUNTIME + PROVIDED_LIB);
+ op = op.providedLibs(EXAMPLES_LIB_RUNTIME + PROVIDED_LIB);
+ assertThat(op.providedLibs()).containsExactly(foo);
+ op.providedLibs().clear();
+
+ op = op.providedLibs(foo);
+ assertThat(op.providedLibs()).containsExactly(foo);
+ op.providedLibs().clear();
+
+ op = op.providedLibs(foo.toPath());
+ assertThat(op.providedLibs()).containsExactly(foo);
+ op.providedLibs().clear();
+ }
+
static class CustomProject extends Project {
CustomProject(File tmp) {
super();