After upgrading 1.4.0.M1, Guava ClassPath doesn't work with repackaged 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
LaunchedURLClassLoaderto 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, allowingLaunchedURLClassLoaderto use a conventional delegation model.Guava's
ClassPathonly supportsURLClassLoaderandfileprotocol URLs. It was previously able to find application classes in an executable jar as the jar itself was on the classpath with afileURL 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/classeshas 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
PathMatchingResourcePatternResolversupports much more than justfileURLs and works nicely in your example:Produces:
It'll also find classes in nested jar files.