Consistently return non-zero exit codes for jarmode failures

Update jar mode launchers to catch all exceptions and return a non-zero
exit code. This refinement also allows us to consolidate the existing
error reporting logic to a central locations. Modes that wish to report
a simple error rather than a full stacktrace can throw the newly
introduced `JarModeErrorException`.

Fixes gh-43435
This commit is contained in:
Phillip Webb
2024-12-06 17:15:10 -08:00
parent 589697a011
commit f21402d4c3
18 changed files with 230 additions and 80 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@@ -36,7 +36,8 @@ public interface JarMode {
* Run the jar in the given mode.
* @param mode the mode to use
* @param args any program arguments
* @throws JarModeErrorException on an error that should print a simple error message
*/
void run(String mode, String[] args);
void run(String mode, String[] args) throws JarModeErrorException;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2012-2024 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader.jarmode;
/**
* Simple {@link RuntimeException} used to fail the jar mode with a simple printed error
* message.
*
* @author Phillip Webb
* @since 3.3.7
*/
public class JarModeErrorException extends RuntimeException {
public JarModeErrorException(String message) {
super(message);
}
public JarModeErrorException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@@ -19,6 +19,7 @@ package org.springframework.boot.loader.launch;
import java.util.List;
import org.springframework.boot.loader.jarmode.JarMode;
import org.springframework.boot.loader.jarmode.JarModeErrorException;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.ClassUtils;
@@ -31,11 +32,31 @@ final class JarModeRunner {
static final String DISABLE_SYSTEM_EXIT = JarModeRunner.class.getName() + ".DISABLE_SYSTEM_EXIT";
static final String SUPPRESSED_SYSTEM_EXIT_CODE = JarModeRunner.class.getName() + ".SUPPRESSED_SYSTEM_EXIT_CODE";
private JarModeRunner() {
}
static void main(String[] args) {
String mode = System.getProperty("jarmode");
boolean disableSystemExit = Boolean.getBoolean(DISABLE_SYSTEM_EXIT);
try {
runJarMode(mode, args);
if (disableSystemExit) {
System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "0");
}
}
catch (Throwable ex) {
printError(ex);
if (disableSystemExit) {
System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "1");
return;
}
System.exit(1);
}
}
private static void runJarMode(String mode, String[] args) {
List<JarMode> candidates = SpringFactoriesLoader.loadFactories(JarMode.class,
ClassUtils.getDefaultClassLoader());
for (JarMode candidate : candidates) {
@@ -44,10 +65,17 @@ final class JarModeRunner {
return;
}
}
System.err.println("Unsupported jarmode '" + mode + "'");
if (!Boolean.getBoolean(DISABLE_SYSTEM_EXIT)) {
System.exit(1);
throw new JarModeErrorException("Unsupported jarmode '" + mode + "'");
}
private static void printError(Throwable ex) {
if (ex instanceof JarModeErrorException) {
String message = ex.getMessage();
System.err.println("Error: " + message);
System.err.println();
return;
}
ex.printStackTrace();
}
}