in src/main/java/software/amazon/smithy/gradle/SmithyUtils.java [253:335]
private static void executeCliThread(Project project, List<String> arguments, FileCollection classpath) {
// URL caching must be disabled when running the Smithy CLI using a
// custom class loader. An "empty" resource was added to the Gradle
// plugin to provide access to the global URL-wide caching behavior
// provided by URLConnection#setDefaultUseCaches. Setting that to
// false on any URLConnection disables caching on all URLConnections.
// Not doing this will lead to consistent errors like
// java.util.zip.ZipException: ZipFile invalid LOC header (bad signature)
// The default caching setting is restored after invoking the CLI.
URLConnection cacheBuster;
boolean isCachingEnabled;
try {
cacheBuster = SmithyUtils.class.getResource("empty").openConnection();
isCachingEnabled = cacheBuster.getDefaultUseCaches();
cacheBuster.setDefaultUseCaches(false);
} catch (IOException e) {
throw new SmithyBuildException(e);
}
// Create a custom class loader to run within the context of.
Set<File> files = classpath.getFiles();
URL[] paths = new URL[files.size()];
int i = 0;
for (File file : files) {
try {
paths[i++] = file.toURI().toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
Logger logger = project.getLogger();
// Need to run this in a doPrivileged to pass SpotBugs.
try (URLClassLoader classLoader = AccessController.doPrivileged(
(PrivilegedExceptionAction<URLClassLoader>) () -> new URLClassLoader(paths))) {
// Reflection is used to make calls on the loaded SmithyCli object.
String smithyCliName = SmithyCli.class.getCanonicalName();
String cliName = Cli.class.getCanonicalName();
Thread thread = new Thread(() -> {
try {
Class cliClass = classLoader.loadClass(cliName);
Class smithyCliClass = classLoader.loadClass(smithyCliName);
Object cli = smithyCliClass.getDeclaredMethod("create").invoke(null);
smithyCliClass.getDeclaredMethod("classLoader", ClassLoader.class).invoke(cli, classLoader);
overrideCliStdout(cliClass, logger);
smithyCliClass.getDeclaredMethod("run", List.class).invoke(cli, arguments);
} catch (ReflectiveOperationException e) {
logger.info("Error executing Smithy CLI (ReflectiveOperationException)", e);
throw new RuntimeException(e);
}
});
// Configure the thread to re-throw exception and use our custom class loader.
thread.setContextClassLoader(classLoader);
ExceptionHandler handler = new ExceptionHandler();
thread.setUncaughtExceptionHandler(handler);
thread.start();
thread.join();
if (handler.e != null) {
logger.info("Error executing Smithy CLI (thread handler)", handler.e);
throw handler.e;
}
} catch (Throwable e) {
// Find the originating exception message.
String message;
Throwable current = e;
do {
message = current.getMessage();
current = current.getCause();
} while (current != null);
logger.error(message);
throw new GradleException(message, e);
} finally {
// Restore URL caching to the previous value.
cacheBuster.setDefaultUseCaches(isCachingEnabled);
}
}