Commit 2f973ebc authored by Phillip Webb's avatar Phillip Webb

Fix default Launcher.isExploded() result

Fix the default implementation of `Launcher.isExploded` which should
have returned `true`.

Fixes gh-21575
parent 9b95ab26
...@@ -172,7 +172,7 @@ public abstract class Launcher { ...@@ -172,7 +172,7 @@ public abstract class Launcher {
* @since 2.3.0 * @since 2.3.0
*/ */
protected boolean isExploded() { protected boolean isExploded() {
return true; return false;
} }
/** /**
......
...@@ -19,12 +19,14 @@ package org.springframework.boot.loader; ...@@ -19,12 +19,14 @@ package org.springframework.boot.loader;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.jar.Attributes; import java.util.jar.Attributes;
import java.util.jar.Manifest; import java.util.jar.Manifest;
...@@ -39,10 +41,13 @@ import org.junit.jupiter.api.io.TempDir; ...@@ -39,10 +41,13 @@ import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.loader.archive.Archive; import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.archive.ExplodedArchive; import org.springframework.boot.loader.archive.ExplodedArchive;
import org.springframework.boot.loader.archive.JarFileArchive; import org.springframework.boot.loader.archive.JarFileArchive;
import org.springframework.boot.loader.jar.Handler;
import org.springframework.boot.loader.jar.JarFile;
import org.springframework.boot.testsupport.system.CapturedOutput; import org.springframework.boot.testsupport.system.CapturedOutput;
import org.springframework.boot.testsupport.system.OutputCaptureExtension; import org.springframework.boot.testsupport.system.OutputCaptureExtension;
import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.FileSystemResource;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
...@@ -65,14 +70,15 @@ class PropertiesLauncherTests { ...@@ -65,14 +70,15 @@ class PropertiesLauncherTests {
private CapturedOutput output; private CapturedOutput output;
@BeforeEach @BeforeEach
void setup(CapturedOutput capturedOutput) { void setup(CapturedOutput capturedOutput) throws Exception {
this.contextClassLoader = Thread.currentThread().getContextClassLoader(); this.contextClassLoader = Thread.currentThread().getContextClassLoader();
clearHandlerCache();
System.setProperty("loader.home", new File("src/test/resources").getAbsolutePath()); System.setProperty("loader.home", new File("src/test/resources").getAbsolutePath());
this.output = capturedOutput; this.output = capturedOutput;
} }
@AfterEach @AfterEach
void close() { void close() throws Exception {
Thread.currentThread().setContextClassLoader(this.contextClassLoader); Thread.currentThread().setContextClassLoader(this.contextClassLoader);
System.clearProperty("loader.home"); System.clearProperty("loader.home");
System.clearProperty("loader.path"); System.clearProperty("loader.path");
...@@ -81,6 +87,19 @@ class PropertiesLauncherTests { ...@@ -81,6 +87,19 @@ class PropertiesLauncherTests {
System.clearProperty("loader.config.location"); System.clearProperty("loader.config.location");
System.clearProperty("loader.system"); System.clearProperty("loader.system");
System.clearProperty("loader.classLoader"); System.clearProperty("loader.classLoader");
clearHandlerCache();
}
@SuppressWarnings("unchecked")
private void clearHandlerCache() throws Exception {
Map<File, JarFile> rootFileCache = ((SoftReference<Map<File, JarFile>>) ReflectionTestUtils
.getField(Handler.class, "rootFileCache")).get();
if (rootFileCache != null) {
for (JarFile rootJarFile : rootFileCache.values()) {
rootJarFile.close();
}
rootFileCache.clear();
}
} }
@Test @Test
...@@ -290,7 +309,6 @@ class PropertiesLauncherTests { ...@@ -290,7 +309,6 @@ class PropertiesLauncherTests {
@Test @Test
void testUserSpecifiedConfigPathWins() throws Exception { void testUserSpecifiedConfigPathWins() throws Exception {
System.setProperty("loader.config.name", "foo"); System.setProperty("loader.config.name", "foo");
System.setProperty("loader.config.location", "classpath:bar.properties"); System.setProperty("loader.config.location", "classpath:bar.properties");
PropertiesLauncher launcher = new PropertiesLauncher(); PropertiesLauncher launcher = new PropertiesLauncher();
...@@ -354,6 +372,23 @@ class PropertiesLauncherTests { ...@@ -354,6 +372,23 @@ class PropertiesLauncherTests {
assertThat(archiveRoot).isEqualTo(loaderPath); assertThat(archiveRoot).isEqualTo(loaderPath);
} }
@Test // gh-21575
void loadResourceFromJarFile() throws Exception {
File jarFile = new File(this.tempDir, "app.jar");
TestJarCreator.createTestJar(jarFile);
System.setProperty("loader.home", this.tempDir.getAbsolutePath());
System.setProperty("loader.path", "app.jar");
PropertiesLauncher launcher = new PropertiesLauncher();
try {
launcher.launch(new String[0]);
}
catch (Exception ex) {
}
URL resource = new URL("jar:" + jarFile.toURI() + "!/nested.jar!/3.dat");
byte[] bytes = FileCopyUtils.copyToByteArray(resource.openStream());
assertThat(bytes).isNotEmpty();
}
private void waitFor(String value) throws Exception { private void waitFor(String value) throws Exception {
Awaitility.waitAtMost(Duration.ofSeconds(5)).until(this.output::toString, containsString(value)); Awaitility.waitAtMost(Duration.ofSeconds(5)).until(this.output::toString, containsString(value));
} }
......
...@@ -49,7 +49,6 @@ public abstract class TestJarCreator { ...@@ -49,7 +49,6 @@ public abstract class TestJarCreator {
writeEntry(jarOutputStream, "d/9.dat", 9); writeEntry(jarOutputStream, "d/9.dat", 9);
writeDirEntry(jarOutputStream, "special/"); writeDirEntry(jarOutputStream, "special/");
writeEntry(jarOutputStream, "special/\u00EB.dat", '\u00EB'); writeEntry(jarOutputStream, "special/\u00EB.dat", '\u00EB');
writeNestedEntry("nested.jar", unpackNested, jarOutputStream); writeNestedEntry("nested.jar", unpackNested, jarOutputStream);
writeNestedEntry("another-nested.jar", unpackNested, jarOutputStream); writeNestedEntry("another-nested.jar", unpackNested, jarOutputStream);
writeNestedEntry("space nested.jar", unpackNested, jarOutputStream); writeNestedEntry("space nested.jar", unpackNested, jarOutputStream);
...@@ -79,7 +78,6 @@ public abstract class TestJarCreator { ...@@ -79,7 +78,6 @@ public abstract class TestJarCreator {
CRC32 crc32 = new CRC32(); CRC32 crc32 = new CRC32();
crc32.update(nestedJarData); crc32.update(nestedJarData);
nestedEntry.setCrc(crc32.getValue()); nestedEntry.setCrc(crc32.getValue());
nestedEntry.setMethod(ZipEntry.STORED); nestedEntry.setMethod(ZipEntry.STORED);
jarOutputStream.putNextEntry(nestedEntry); jarOutputStream.putNextEntry(nestedEntry);
jarOutputStream.write(nestedJarData); jarOutputStream.write(nestedJarData);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment