diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/FileWatcher.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/FileWatcher.java index eecad97b3b4e..9c4331dea493 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/FileWatcher.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/FileWatcher.java @@ -86,7 +86,7 @@ void watch(Set paths, Runnable action) { this.thread = new WatcherThread(); this.thread.start(); } - this.thread.register(new Registration(paths, action)); + this.thread.register(new Registration(resolveSymlinks(paths), action)); } catch (IOException ex) { throw new UncheckedIOException("Failed to register paths for watching: " + paths, ex); @@ -94,6 +94,14 @@ void watch(Set paths, Runnable action) { } } + private Set resolveSymlinks(Set paths) throws IOException { + Set result = new HashSet<>(); + for (Path path : paths) { + result.add(Files.isSymbolicLink(path) ? Files.readSymbolicLink(path) : path); + } + return result; + } + @Override public void close() throws IOException { synchronized (this.lock) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/FileWatcherTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/FileWatcherTests.java index 5b3e18e3f79e..f0a2cc8b1674 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/FileWatcherTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/FileWatcherTests.java @@ -94,6 +94,18 @@ void shouldWatchFile(@TempDir Path tempDir) throws Exception { callback.expectChanges(); } + @Test + void shouldFollowSymlink(@TempDir Path tempDir) throws Exception { + Path realFile = tempDir.resolve("realFile.txt"); + Path symLink = tempDir.resolve("symlink.txt"); + Files.createFile(realFile); + Files.createSymbolicLink(symLink, realFile); + WaitingCallback callback = new WaitingCallback(); + this.fileWatcher.watch(Set.of(symLink), callback); + Files.writeString(realFile, "Some content"); + callback.expectChanges(); + } + @Test void shouldIgnoreNotWatchedFiles(@TempDir Path tempDir) throws Exception { Path watchedFile = tempDir.resolve("watched.txt");