Commit bceed130 authored by Madhura Bhave's avatar Madhura Bhave

Jar files added after build time should be added to classpath

Fixes gh-19973
parent b281af0b
...@@ -72,6 +72,13 @@ final class ClassPathIndexFile { ...@@ -72,6 +72,13 @@ final class ClassPathIndexFile {
return this.folders.contains(name); return this.folders.contains(name);
} }
boolean containsEntry(String name) {
if (name == null || name.isEmpty()) {
return false;
}
return this.lines.contains(name);
}
List<URL> getUrls() { List<URL> getUrls() {
return Collections.unmodifiableList(this.lines.stream().map(this::asUrl).collect(Collectors.toList())); return Collections.unmodifiableList(this.lines.stream().map(this::asUrl).collect(Collectors.toList()));
} }
......
...@@ -101,17 +101,18 @@ public abstract class ExecutableArchiveLauncher extends Launcher { ...@@ -101,17 +101,18 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
@Override @Override
protected Iterator<Archive> getClassPathArchivesIterator() throws Exception { protected Iterator<Archive> getClassPathArchivesIterator() throws Exception {
Archive.EntryFilter searchFilter = (entry) -> isSearchCandidate(entry) && !isFolderIndexed(entry); Archive.EntryFilter searchFilter = this::isSearchCandidate;
Iterator<Archive> archives = this.archive.getNestedArchives(searchFilter, this::isNestedArchive); Iterator<Archive> archives = this.archive.getNestedArchives(searchFilter,
(entry) -> isNestedArchive(entry) && !isEntryIndexed(entry));
if (isPostProcessingClassPathArchives()) { if (isPostProcessingClassPathArchives()) {
archives = applyClassPathArchivePostProcessing(archives); archives = applyClassPathArchivePostProcessing(archives);
} }
return archives; return archives;
} }
private boolean isFolderIndexed(Archive.Entry entry) { private boolean isEntryIndexed(Archive.Entry entry) {
if (this.classPathIndex != null) { if (this.classPathIndex != null) {
return this.classPathIndex.containsFolder(entry.getName()); return this.classPathIndex.containsEntry(entry.getName());
} }
return false; return false;
} }
......
...@@ -25,6 +25,7 @@ import java.io.Writer; ...@@ -25,6 +25,7 @@ import java.io.Writer;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
...@@ -52,11 +53,12 @@ public abstract class AbstractExecutableArchiveLauncherTests { ...@@ -52,11 +53,12 @@ public abstract class AbstractExecutableArchiveLauncherTests {
File tempDir; File tempDir;
protected File createJarArchive(String name, String entryPrefix) throws IOException { protected File createJarArchive(String name, String entryPrefix) throws IOException {
return createJarArchive(name, entryPrefix, false); return createJarArchive(name, entryPrefix, false, Collections.emptyList());
} }
@SuppressWarnings("resource") @SuppressWarnings("resource")
protected File createJarArchive(String name, String entryPrefix, boolean indexed) throws IOException { protected File createJarArchive(String name, String entryPrefix, boolean indexed, List<String> extraLibs)
throws IOException {
File archive = new File(this.tempDir, name); File archive = new File(this.tempDir, name);
JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(archive)); JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(archive));
jarOutputStream.putNextEntry(new JarEntry(entryPrefix + "/")); jarOutputStream.putNextEntry(new JarEntry(entryPrefix + "/"));
...@@ -74,6 +76,9 @@ public abstract class AbstractExecutableArchiveLauncherTests { ...@@ -74,6 +76,9 @@ public abstract class AbstractExecutableArchiveLauncherTests {
addNestedJars(entryPrefix, "/lib/foo.jar", jarOutputStream); addNestedJars(entryPrefix, "/lib/foo.jar", jarOutputStream);
addNestedJars(entryPrefix, "/lib/bar.jar", jarOutputStream); addNestedJars(entryPrefix, "/lib/bar.jar", jarOutputStream);
addNestedJars(entryPrefix, "/lib/baz.jar", jarOutputStream); addNestedJars(entryPrefix, "/lib/baz.jar", jarOutputStream);
for (String lib : extraLibs) {
addNestedJars(entryPrefix, "/lib/" + lib, jarOutputStream);
}
jarOutputStream.close(); jarOutputStream.close();
return archive; return archive;
} }
......
...@@ -20,6 +20,8 @@ import java.io.File; ...@@ -20,6 +20,8 @@ import java.io.File;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -72,7 +74,7 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests { ...@@ -72,7 +74,7 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests {
@Test @Test
void explodedJarShouldPreserveClasspathOrderWhenIndexPresent() throws Exception { void explodedJarShouldPreserveClasspathOrderWhenIndexPresent() throws Exception {
File explodedRoot = explode(createJarArchive("archive.jar", "BOOT-INF", true)); File explodedRoot = explode(createJarArchive("archive.jar", "BOOT-INF", true, Collections.emptyList()));
JarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot, true)); JarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot, true));
Iterator<Archive> archives = launcher.getClassPathArchivesIterator(); Iterator<Archive> archives = launcher.getClassPathArchivesIterator();
URLClassLoader classLoader = (URLClassLoader) launcher.createClassLoader(archives); URLClassLoader classLoader = (URLClassLoader) launcher.createClassLoader(archives);
...@@ -80,6 +82,19 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests { ...@@ -80,6 +82,19 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests {
assertThat(urls).containsExactly(getExpectedFileUrls(explodedRoot)); assertThat(urls).containsExactly(getExpectedFileUrls(explodedRoot));
} }
@Test
void jarFilesPresentInBootInfLibsAndNotInClasspathIndexShouldBeAddedAfterBootInfClasses() throws Exception {
ArrayList<String> extraLibs = new ArrayList<>(Arrays.asList("extra-1.jar", "extra-2.jar"));
File explodedRoot = explode(createJarArchive("archive.jar", "BOOT-INF", true, extraLibs));
JarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot, true));
Iterator<Archive> archives = launcher.getClassPathArchivesIterator();
URLClassLoader classLoader = (URLClassLoader) launcher.createClassLoader(archives);
URL[] urls = classLoader.getURLs();
List<File> expectedFiles = getExpectedFilesWithExtraLibs(explodedRoot);
URL[] expectedFileUrls = expectedFiles.stream().map(this::toUrl).toArray(URL[]::new);
assertThat(urls).containsExactly(expectedFileUrls);
}
protected final URL[] getExpectedFileUrls(File explodedRoot) { protected final URL[] getExpectedFileUrls(File explodedRoot) {
return getExpectedFiles(explodedRoot).stream().map(this::toUrl).toArray(URL[]::new); return getExpectedFiles(explodedRoot).stream().map(this::toUrl).toArray(URL[]::new);
} }
...@@ -93,4 +108,15 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests { ...@@ -93,4 +108,15 @@ class JarLauncherTests extends AbstractExecutableArchiveLauncherTests {
return expected; return expected;
} }
protected final List<File> getExpectedFilesWithExtraLibs(File parent) {
List<File> expected = new ArrayList<>();
expected.add(new File(parent, "BOOT-INF/classes"));
expected.add(new File(parent, "BOOT-INF/lib/extra-1.jar"));
expected.add(new File(parent, "BOOT-INF/lib/extra-2.jar"));
expected.add(new File(parent, "BOOT-INF/lib/foo.jar"));
expected.add(new File(parent, "BOOT-INF/lib/bar.jar"));
expected.add(new File(parent, "BOOT-INF/lib/baz.jar"));
return expected;
}
} }
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