diff --git a/gh-8822/build.gradle b/gh-8822/build.gradle new file mode 100644 index 0000000..63f9921 --- /dev/null +++ b/gh-8822/build.gradle @@ -0,0 +1,42 @@ +apply plugin: 'org.springframework.boot' + +buildscript { + ext { + springBootVersion = '1.5.2.RELEASE' + } + repositories { + jcenter() + } + dependencies { + // http://mvnrepository.com/artifact/org.springframework.boot/spring-boot-gradle-plugin + classpath group: 'org.springframework.boot', name: 'spring-boot-gradle-plugin', version: springBootVersion + } +} + +wrapper { + gradleVersion = '3.4.1' + distributionType = Wrapper.DistributionType.ALL +} + +repositories.addAll rootProject.buildscript.repositories + +subprojects { + repositories.addAll rootProject.buildscript.repositories + buildscript.repositories.addAll rootProject.buildscript.repositories +} + +dependencies { + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-loader + // should be runtime but JavaDoc @see requires compile for validation + compile group: 'org.springframework.boot', name: 'spring-boot-loader', version: springBootVersion +} + +bootRepackage { + // https://github.com/spring-projects/spring-boot/issues/1113 + // https://github.com/spring-projects/spring-boot/issues/8167 + classifier = 'repack' +} + +jar { + manifest.attributes 'Main-Class': 'Main' +} diff --git a/gh-8822/src/main/java/Main.java b/gh-8822/src/main/java/Main.java new file mode 100644 index 0000000..f272f56 --- /dev/null +++ b/gh-8822/src/main/java/Main.java @@ -0,0 +1,94 @@ +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; + +/** + * @see org.springframework.boot.loader.JarLauncher#main(java.lang.String[]) + * @see org.springframework.boot.loader.Launcher#launch(java.lang.String[]) + * @see org.springframework.boot.loader.ExecutableArchiveLauncher#getClassPathArchives() + * @see org.springframework.boot.loader.archive.JarFileArchive#getNestedArchives(org.springframework.boot.loader.archive.Archive.EntryFilter) + * @see org.springframework.boot.loader.archive.JarFileArchive#getNestedArchive(org.springframework.boot.loader.archive.Archive.Entry) + * @see org.springframework.boot.loader.jar.JarFile#getNestedJarFile(java.util.zip.ZipEntry) + * @see org.springframework.boot.loader.jar.JarFile#getNestedJarFile(org.springframework.boot.loader.jar.JarEntry) + * @see org.springframework.boot.loader.jar.JarFile#createJarFileFromEntry(org.springframework.boot.loader.jar.JarEntry) + * @see Jar launcer adds ! after BOOT-INF/classes url for resource + * @see org.springframework.boot.loader.LaunchedURLClassLoader unable to load 3rd party FileSystemProvider implementation from spring boot executable JAR + */ +public class Main { + public static void main(String[] args) throws URISyntaxException, IOException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + printClassLoaderTree(classLoader); + + // get resourceUri + URL resourceUrl = classLoader.getResource("test.txt"); + assert resourceUrl != null; + URI resourceUri = resourceUrl.toURI(); + + // open jar if necessary + if (resourceUri.toString().startsWith("jar:")) { + System.out.println("\nOpening jar…"); + FileSystems.newFileSystem(resourceUri, Collections.emptyMap()); + } + + System.out.println(""); + + // test files exists + { + Path resourcePath = Paths.get(resourceUri); + boolean exists = Files.exists(resourcePath); + System.out.println( + "Files.exists(resourcePath): " + exists + + "\n resourcePath: " + resourcePath + + "\n resourceUri: " + resourceUri + ); + } + + // apply workaround + { + System.out.println("\nApplying workaround. Replacing '!/BOOT-INF/classes!/' with '!/BOOT-INF/classes/'.\n"); + String brokenUri = resourceUri.toString(); + String fixedUri = brokenUri.replace("!/BOOT-INF/classes!/", "!/BOOT-INF/classes/"); + resourceUri = new URI(fixedUri); + } + + // test files exists + { + Path resourcePath = Paths.get(resourceUri); + boolean exists = Files.exists(resourcePath); + System.out.println( + "Files.exists(resourcePath): " + exists + + "\n resourcePath: " + resourcePath + + "\n resourceUri: " + resourceUri + ); + } + } + + private static void printClassLoaderTree(ClassLoader loader) { + StringBuilder message = new StringBuilder(); + + message.append("Using current thread context ClassLoader:\n"); + message.append(" \u25b8"); + message.append(loader.getClass().getCanonicalName()); + message.append('\n'); + + ClassLoader curClassLoader = loader; + int lvl = 0; + while ((curClassLoader = curClassLoader.getParent()) != null) { + int curLvl = ++lvl; + message.append(" "); + while (curLvl-- > 1) { + message.append(" "); + } + message.append(" \u2514\u2500\u2574"); + message.append(curClassLoader.getClass().getCanonicalName()); + message.append('\n'); + } + System.out.print(message); + } +} diff --git a/gh-8822/src/main/resources/test.txt b/gh-8822/src/main/resources/test.txt new file mode 100644 index 0000000..e69de29