spring-projects / spring-projects/spring-boot
Add support for loading META-INF/resources from jars referenced via a Class-Path manifest entry
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 81.5k
- Forks
- 42.7k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 65
Description
Spring Boot 1.4.7
Background:
Due to path length restrictions on Windows, IntelliJ has a "dynamic classloading" feature. When enabled, it creates a file called "classpath.jar" and puts the classpath of the application into the MANIFEST.MF file,
Problem description:
Spring Boot normally adds "resource jars", i.e. those containing a "META-INF/resources" folder to the Tomcat context, making static resources available to the Tomcat servlet engine. This is done here:
TomcatEmbeddedServletContainerFactory:
context.addLifecycleListener(new LifecycleListener() {
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
TomcatResources.get(context)
.addResourceJars(getUrlsOfJarsWithMetaInfResources());
}
}
});
In AbstractEmbeddedServletContainerFactory.getUrlsOfJarsWithMetaInfResources(), we find this code:
ClassLoader classLoader = getClass().getClassLoader();
List<URL> staticResourceUrls = new ArrayList<URL>();
if (classLoader instanceof URLClassLoader) {
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
[...]
This works as long as the ClassLoader used was initialized with a specific classpath. If the classpath refers to a jar that has a Class-Path entry in its manifest, Spring Boot does not find those jars.
Workaround:
I solved this issue locally by extending the TomcatEmbeddedServletContainerFactory, overriding the getUrlsOfJarsWithMetaInfResources() so that it also considers the entries in the Class-Path attribute of the jar file's manifest (if it exists).
So - in addition to the URLs returned by URLClassLoader.getURLs(), we add these to the set:
private URL[] getJarUrlsFromManifests(ClassLoader cl) {
try {
Set<URL> urlSet = new LinkedHashSet<>();
URL url = cl.getResource("META-INF/MANIFEST.MF");
if (url != null) {
Manifest manifest = new Manifest(url.openStream());
String classPath = manifest.getMainAttributes().getValue("Class-Path");
if (classPath != null) {
for (String urlStr : classPath.split(" ")) {
try {
urlSet.add(new URL(urlStr));
} catch (MalformedURLException ex) {
throw new AssertionError();
}
}
}
}
return urlSet.toArray(new URL[urlSet.size()]);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
I think Spring Boot should support this too.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with AbstractEmbeddedServletContainerFactory.getUrlsOfJarsWithMetaInfResources() and the resource-jar setup in TomcatEmbeddedServletContainerFactory. Read how URLClassLoader.getURLs() is currently used, then verify that jars named by a Class-Path manifest entry are also considered when they contain META-INF/resources and are exposed to the embedded Tomcat servlet engine.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring-boot
- Domain
- backend, web-dev
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100