After upgrading 1.4.0.M1, Guava ClassPath
doesn't work with repackage
d jar file:
./gradlew clean bootRepackage; java -jar build/libs/spring-boot-throwaway-branches-1.0.jar
classes: []
With 1.3.3.RELEASE, it works:
classes: [com.izeye.throwaway.Application, com.izeye.throwaway.Person]
The following branch is a sample project reproducing the problem:
https://github.com/izeye/spring-boot-throwaway-branches/commits/guava
I guess it's affected by the same cause with #5323
Do I report to a wrong place again?
This could be due to the BOOT-INF/lib
and BOOT-INF/classes
changes. I'll take a look.
Prior to 1.4.0, Boot packages an application's classes in the root of the jar file. It then used an unconventional delegation model in LaunchedURLClassLoader
to prevent those classes from being loaded by the app class loader. This broke a few things, including a number of Java agents. 1.4 fixes the problem by moving application classes into BOOT-INF/classes
. This hides the classes from the app class loader, allowing LaunchedURLClassLoader
to use a conventional delegation model.
Guava's ClassPath
only supports URLClassLoader
and file
protocol URLs. It was previously able to find application classes in an executable jar as the jar itself was on the classpath with a file
URL and the classes were in the jar's root. It's never been able to find classes in a nested jar, or application classes or nested jars in an executable war. The move to using BOOT-INF/classes
has added an executable jar's application classes to the list of things affected by ClassPath
's limitations.
I'd recommend using something that's less limited if you need to scan the classpath. Spring Framework's PathMatchingResourcePatternResolver
supports much more than just file
URLs and works nicely in your example:
Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:com/izeye/throwaway/**/*");
System.out.println("classes: " + Arrays.toString(resources));
Produces:
classes: [URL [jar:file:/Users/awilkinson/dev/temp/spring-boot-throwaway-branches/build/libs/spring-boot-throwaway-branches-1.0.jar!/BOOT-INF/classes!/com/izeye/throwaway/Application.class], URL [jar:file:/Users/awilkinson/dev/temp/spring-boot-throwaway-branches/build/libs/spring-boot-throwaway-branches-1.0.jar!/BOOT-INF/classes!/com/izeye/throwaway/Person.class]]
It'll also find classes in nested jar files.
@wilkinsona Thanks for the detail and the tip!
Most helpful comment
Prior to 1.4.0, Boot packages an application's classes in the root of the jar file. It then used an unconventional delegation model in
LaunchedURLClassLoader
to prevent those classes from being loaded by the app class loader. This broke a few things, including a number of Java agents. 1.4 fixes the problem by moving application classes intoBOOT-INF/classes
. This hides the classes from the app class loader, allowingLaunchedURLClassLoader
to use a conventional delegation model.Guava's
ClassPath
only supportsURLClassLoader
andfile
protocol URLs. It was previously able to find application classes in an executable jar as the jar itself was on the classpath with afile
URL and the classes were in the jar's root. It's never been able to find classes in a nested jar, or application classes or nested jars in an executable war. The move to usingBOOT-INF/classes
has added an executable jar's application classes to the list of things affected byClassPath
's limitations.I'd recommend using something that's less limited if you need to scan the classpath. Spring Framework's
PathMatchingResourcePatternResolver
supports much more than justfile
URLs and works nicely in your example:Produces:
It'll also find classes in nested jar files.