Add classpath index support for exploded war archives
Update the Maven and Gradle packaging for war files so that a `classpath.idx` file is written into the archive that provides the original order of the classpath, as was previously done for jar files. The `WarLauncher` class will use this file when running as an exploded archive to ensure that the classpath order is the same as when running from the far war. Fixes gh-19875
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -21,9 +21,11 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
|
||||
/**
|
||||
* Base class for executable archive {@link Launcher}s.
|
||||
@@ -31,6 +33,7 @@ import org.springframework.boot.loader.archive.Archive;
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
* @author Scott Frederick
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class ExecutableArchiveLauncher extends Launcher {
|
||||
@@ -39,6 +42,8 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
|
||||
|
||||
protected static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = "Spring-Boot-Classpath-Index";
|
||||
|
||||
protected static final String DEFAULT_CLASSPATH_INDEX_FILE_NAME = "classpath.idx";
|
||||
|
||||
private final Archive archive;
|
||||
|
||||
private final ClassPathIndexFile classPathIndex;
|
||||
@@ -64,9 +69,21 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
|
||||
}
|
||||
|
||||
protected ClassPathIndexFile getClassPathIndex(Archive archive) throws IOException {
|
||||
// Only needed for exploded archives, regular ones already have a defined order
|
||||
if (archive instanceof ExplodedArchive) {
|
||||
String location = getClassPathIndexFileLocation(archive);
|
||||
return ClassPathIndexFile.loadIfPossible(archive.getUrl(), location);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getClassPathIndexFileLocation(Archive archive) throws IOException {
|
||||
Manifest manifest = archive.getManifest();
|
||||
Attributes attributes = (manifest != null) ? manifest.getMainAttributes() : null;
|
||||
String location = (attributes != null) ? attributes.getValue(BOOT_CLASSPATH_INDEX_ATTRIBUTE) : null;
|
||||
return (location != null) ? location : getArchiveEntryPathPrefix() + DEFAULT_CLASSPATH_INDEX_FILE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMainClass() throws Exception {
|
||||
Manifest manifest = this.archive.getManifest();
|
||||
@@ -133,7 +150,10 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
|
||||
* @since 2.3.0
|
||||
*/
|
||||
protected boolean isSearchCandidate(Archive.Entry entry) {
|
||||
return true;
|
||||
if (getArchiveEntryPathPrefix() == null) {
|
||||
return true;
|
||||
}
|
||||
return entry.getName().startsWith(getArchiveEntryPathPrefix());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,6 +186,14 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
|
||||
protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path prefix for entries in the archive.
|
||||
* @return the path prefix
|
||||
*/
|
||||
protected String getArchiveEntryPathPrefix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isExploded() {
|
||||
return this.archive.isExploded();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -16,13 +16,8 @@
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.Archive.EntryFilter;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
|
||||
/**
|
||||
* {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are
|
||||
@@ -32,12 +27,11 @@ import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
* @author Scott Frederick
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class JarLauncher extends ExecutableArchiveLauncher {
|
||||
|
||||
private static final String DEFAULT_CLASSPATH_INDEX_LOCATION = "BOOT-INF/classpath.idx";
|
||||
|
||||
static final EntryFilter NESTED_ARCHIVE_ENTRY_FILTER = (entry) -> {
|
||||
if (entry.isDirectory()) {
|
||||
return entry.getName().equals("BOOT-INF/classes/");
|
||||
@@ -52,38 +46,21 @@ public class JarLauncher extends ExecutableArchiveLauncher {
|
||||
super(archive);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassPathIndexFile getClassPathIndex(Archive archive) throws IOException {
|
||||
// Only needed for exploded archives, regular ones already have a defined order
|
||||
if (archive instanceof ExplodedArchive) {
|
||||
String location = getClassPathIndexFileLocation(archive);
|
||||
return ClassPathIndexFile.loadIfPossible(archive.getUrl(), location);
|
||||
}
|
||||
return super.getClassPathIndex(archive);
|
||||
}
|
||||
|
||||
private String getClassPathIndexFileLocation(Archive archive) throws IOException {
|
||||
Manifest manifest = archive.getManifest();
|
||||
Attributes attributes = (manifest != null) ? manifest.getMainAttributes() : null;
|
||||
String location = (attributes != null) ? attributes.getValue(BOOT_CLASSPATH_INDEX_ATTRIBUTE) : null;
|
||||
return (location != null) ? location : DEFAULT_CLASSPATH_INDEX_LOCATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPostProcessingClassPathArchives() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSearchCandidate(Archive.Entry entry) {
|
||||
return entry.getName().startsWith("BOOT-INF/");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isNestedArchive(Archive.Entry entry) {
|
||||
return NESTED_ARCHIVE_ENTRY_FILTER.matches(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArchiveEntryPathPrefix() {
|
||||
return "BOOT-INF/";
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new JarLauncher().launch(args);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
|
||||
/**
|
||||
* {@link Launcher} for WAR based archives. This launcher for standard WAR archives.
|
||||
@@ -26,6 +25,7 @@ import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class WarLauncher extends ExecutableArchiveLauncher {
|
||||
@@ -42,11 +42,6 @@ public class WarLauncher extends ExecutableArchiveLauncher {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSearchCandidate(Entry entry) {
|
||||
return entry.getName().startsWith("WEB-INF/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNestedArchive(Archive.Entry entry) {
|
||||
if (entry.isDirectory()) {
|
||||
@@ -55,6 +50,11 @@ public class WarLauncher extends ExecutableArchiveLauncher {
|
||||
return entry.getName().startsWith("WEB-INF/lib/") || entry.getName().startsWith("WEB-INF/lib-provided/");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArchiveEntryPathPrefix() {
|
||||
return "WEB-INF/";
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new WarLauncher().launch(args);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user