From 3a40b0a623e96696fa90bc5eb6babf6aaabe98c7 Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Mon, 18 Aug 2025 14:44:22 +0200 Subject: [PATCH] Improve null-safety of loader/spring-boot-loader-tools See gh-46926 --- .../boot/loader/tools/AbstractJarWriter.java | 1 + .../boot/loader/tools/DefaultLaunchScript.java | 8 ++++++-- .../org/springframework/boot/loader/tools/FileUtils.java | 6 +++++- .../org/springframework/boot/loader/tools/Library.java | 1 + .../boot/loader/tools/MainClassFinder.java | 5 ++++- .../boot/loader/tools/SizeCalculatingEntryWriter.java | 7 ++++--- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java index 642183c975a..2e4704fb614 100644 --- a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java +++ b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java @@ -224,6 +224,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter { @Override public void writeLoaderClasses(String loaderJarResourceName) throws IOException { URL loaderJar = getClass().getClassLoader().getResource(loaderJarResourceName); + Assert.state(loaderJar != null, "Unable to load resource '%s'".formatted(loaderJarResourceName)); try (JarInputStream inputStream = new JarInputStream(new BufferedInputStream(loaderJar.openStream()))) { JarEntry entry; while ((entry = inputStream.getNextJarEntry()) != null) { diff --git a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLaunchScript.java b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLaunchScript.java index 960a5838e93..79c4198d556 100644 --- a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLaunchScript.java +++ b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLaunchScript.java @@ -31,6 +31,8 @@ import java.util.regex.Pattern; import org.jspecify.annotations.Nullable; +import org.springframework.util.Assert; + /** * Default implementation of {@link LaunchScript}. Provides the default Spring Boot launch * script or can load a specific script File. Also support mustache style template @@ -63,7 +65,9 @@ public class DefaultLaunchScript implements LaunchScript { private String loadContent(@Nullable File file) throws IOException { if (file == null) { - return loadContent(getClass().getResourceAsStream("launch.script")); + InputStream stream = getClass().getResourceAsStream("launch.script"); + Assert.state(stream != null, "Unable to load resource 'launch.script'"); + return loadContent(stream); } return loadContent(new FileInputStream(file)); } @@ -85,7 +89,7 @@ public class DefaultLaunchScript implements LaunchScript { outputStream.flush(); } - private String expandPlaceholders(@Nullable String content, Map properties) throws IOException { + private String expandPlaceholders(String content, @Nullable Map properties) throws IOException { StringBuilder expanded = new StringBuilder(); Matcher matcher = PLACEHOLDER_PATTERN.matcher(content); while (matcher.find()) { diff --git a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java index d8da46dac4b..90c0aacef42 100644 --- a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java +++ b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java @@ -25,6 +25,8 @@ import java.util.jar.Manifest; import org.jspecify.annotations.Nullable; +import org.springframework.util.Assert; + /** * Utilities for manipulating files and directories in Spring Boot tooling. * @@ -43,7 +45,9 @@ public abstract class FileUtils { */ public static void removeDuplicatesFromOutputDirectory(File outputDirectory, File originDirectory) { if (originDirectory.isDirectory()) { - for (String name : originDirectory.list()) { + String[] files = originDirectory.list(); + Assert.state(files != null, "'files' must not be null"); + for (String name : files) { File targetFile = new File(outputDirectory, name); if (targetFile.exists() && targetFile.canWrite()) { if (!targetFile.isDirectory()) { diff --git a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java index 7130b755059..767f7da6176 100644 --- a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java +++ b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java @@ -109,6 +109,7 @@ public class Library { * @throws IOException on error */ InputStream openStream() throws IOException { + Assert.state(this.file != null, "'file' must not be null"); return new FileInputStream(this.file); } diff --git a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/MainClassFinder.java b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/MainClassFinder.java index c9e6c7c3877..f3376505c46 100644 --- a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/MainClassFinder.java +++ b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/MainClassFinder.java @@ -154,7 +154,10 @@ public abstract class MainClassFinder { return null; } - private static void pushAllSorted(Deque stack, File[] files) { + private static void pushAllSorted(Deque stack, File @Nullable [] files) { + if (files == null) { + return; + } Arrays.sort(files, Comparator.comparing(File::getName)); for (File file : files) { stack.push(file); diff --git a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/SizeCalculatingEntryWriter.java b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/SizeCalculatingEntryWriter.java index 0062c6204f5..8606dd6071e 100644 --- a/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/SizeCalculatingEntryWriter.java +++ b/loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/SizeCalculatingEntryWriter.java @@ -115,17 +115,18 @@ final class SizeCalculatingEntryWriter implements EntryWriter { } private OutputStream convertToFileOutputStream(ByteArrayOutputStream byteArrayOutputStream) throws IOException { - initializeTempFile(); - FileOutputStream fileOutputStream = new FileOutputStream(this.tempFile); + File tempFile = initializeTempFile(); + FileOutputStream fileOutputStream = new FileOutputStream(tempFile); StreamUtils.copy(byteArrayOutputStream.toByteArray(), fileOutputStream); return fileOutputStream; } - private void initializeTempFile() throws IOException { + private File initializeTempFile() throws IOException { if (this.tempFile == null) { this.tempFile = File.createTempFile("springboot-", "-entrycontent"); this.tempFile.deleteOnExit(); } + return this.tempFile; } @Override