fix: support pre-3.2 Spring Boot JARs in runtime entrypoint
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m39s
CI / docker (push) Successful in 1m38s
CI / deploy (push) Successful in 47s
CI / deploy-feature (push) Has been skipped

RuntimeDetector now derives the correct PropertiesLauncher FQN from
the JAR manifest Main-Class package. Spring Boot 3.2+ uses
org.springframework.boot.loader.launch.PropertiesLauncher, pre-3.2
uses org.springframework.boot.loader.PropertiesLauncher.

DockerRuntimeOrchestrator uses the detected class instead of a
hardcoded 3.2+ reference, falling back to 3.2+ when not auto-detected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-15 23:21:01 +02:00
parent 7961c6e18c
commit 859cf7c10d
3 changed files with 13 additions and 7 deletions

View File

@@ -121,9 +121,12 @@ public class DockerRuntimeOrchestrator implements RuntimeOrchestrator {
case "plain-java" -> "exec java -javaagent:/app/agent.jar -cp " + appJarPath + case "plain-java" -> "exec java -javaagent:/app/agent.jar -cp " + appJarPath +
":/app/cameleer-log-appender.jar" + customArgs + " " + request.mainClass(); ":/app/cameleer-log-appender.jar" + customArgs + " " + request.mainClass();
case "native" -> "exec " + appJarPath + customArgs; case "native" -> "exec " + appJarPath + customArgs;
default -> // spring-boot (default) default -> { // spring-boot (default)
"exec java -javaagent:/app/agent.jar -Dloader.path=/app/cameleer-log-appender.jar" + String launcher = request.mainClass() != null ? request.mainClass()
customArgs + " -cp " + appJarPath + " org.springframework.boot.loader.launch.PropertiesLauncher"; : "org.springframework.boot.loader.launch.PropertiesLauncher";
yield "exec java -javaagent:/app/agent.jar -Dloader.path=/app/cameleer-log-appender.jar" +
customArgs + " -cp " + appJarPath + " " + launcher;
}
}; };
createCmd.withEntrypoint("sh", "-c", entrypoint); createCmd.withEntrypoint("sh", "-c", entrypoint);

View File

@@ -48,8 +48,11 @@ public final class RuntimeDetector {
} }
// Spring Boot: any launcher in org.springframework.boot.loader // Spring Boot: any launcher in org.springframework.boot.loader
// Derive PropertiesLauncher from the same package as the detected launcher
// (3.2+ uses org.springframework.boot.loader.launch.*, pre-3.2 uses org.springframework.boot.loader.*)
if (mainClass.startsWith("org.springframework.boot.loader")) { if (mainClass.startsWith("org.springframework.boot.loader")) {
return new DetectionResult(RuntimeType.SPRING_BOOT, null); String loaderPackage = mainClass.substring(0, mainClass.lastIndexOf('.'));
return new DetectionResult(RuntimeType.SPRING_BOOT, loaderPackage + ".PropertiesLauncher");
} }
// Quarkus // Quarkus

View File

@@ -44,7 +44,7 @@ class RuntimeDetectorTest {
Path jar = createJarWithMainClass("org.springframework.boot.loader.launch.JarLauncher"); Path jar = createJarWithMainClass("org.springframework.boot.loader.launch.JarLauncher");
RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar); RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType()); assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType());
assertNull(result.mainClass()); assertEquals("org.springframework.boot.loader.launch.PropertiesLauncher", result.mainClass());
} }
@Test @Test
@@ -52,7 +52,7 @@ class RuntimeDetectorTest {
Path jar = createJarWithMainClass("org.springframework.boot.loader.launch.PropertiesLauncher"); Path jar = createJarWithMainClass("org.springframework.boot.loader.launch.PropertiesLauncher");
RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar); RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType()); assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType());
assertNull(result.mainClass()); assertEquals("org.springframework.boot.loader.launch.PropertiesLauncher", result.mainClass());
} }
@Test @Test
@@ -60,7 +60,7 @@ class RuntimeDetectorTest {
Path jar = createJarWithMainClass("org.springframework.boot.loader.JarLauncher"); Path jar = createJarWithMainClass("org.springframework.boot.loader.JarLauncher");
RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar); RuntimeDetector.DetectionResult result = RuntimeDetector.detect(jar);
assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType()); assertEquals(RuntimeType.SPRING_BOOT, result.runtimeType());
assertNull(result.mainClass()); assertEquals("org.springframework.boot.loader.PropertiesLauncher", result.mainClass());
} }
@Test @Test