NOTE A complete reproducible example is attached.
classgraph_resources_issue.zip Please run with mvn clean package && java -jar target/classgraph_resources_issue-0.0.1-SNAPSHOT.jar
A Spring Boot application packaged can be packaged as executable jar. The format is described here: https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/reference/html/appendix-executable-jar-format.html#executable-jar-restrictions
Given the following structure:
-> classgraph_resources_issue tree src/main
src/main
├── java
│ └── com
│ └── example
│ └── classgraph_resources_issue
│ └── ClassgraphResourcesIssueApplication.java
└── resources
├── application.properties
└── foo
└── a.cypher
6 directories, 3 files
A scan for resources inside the class path under the prefix "foo" like this:
@Override
public void run(String... args) {
try (ScanResult scanResult = new ClassGraph()
// .overrideClassLoaders(ClassLoader.getSystemClassLoader())
.whitelistPaths("foo").scan()) {
List<Resource> resources = scanResult.getResourcesWithExtension("cypher")
.stream()
.collect(Collectors.toList());
resources.forEach(System.err::println);
if (resources.size() > 1) {
throw new RuntimeException(":(");
}
}
}
Gives me the expected resources (a.cypher) when run unpackaged.
If I package the application as an executable jar, I get:
jar:file:/Users/msimons/Projects/Issues/classgraph_resources_issue/target/classgraph_resources_issue-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes/foo/a.cypher
jar:file:/Users/msimons/Projects/Issues/classgraph_resources_issue/target/classgraph_resources_issue-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/BOOT-INF/classes/foo/a.cypher
I can "fix" this by using the System class loader only (see commented line above), but this is against Spring Boots recommendation (see link about the format):
System classLoader: Launched applications should use Thread.getContextClassLoader() when loading classes (most libraries and frameworks do so by default). Trying to load nested jar classes with ClassLoader.getSystemClassLoader() fails.
When I use current context class loader, I only get this entry: jar:file:/Users/msimons/Projects/Issues/classgraph_resources_issue/target/classgraph_resources_issue-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/BOOT-INF/classes/foo/a.cypher, which I think is wrong. I can read it through the Resource class, but the getURL()gives me the wrong URL (Note the two times "BOOT-INF/classes" )
The jar looks like this:
x
├── BOOT-INF
│ ├── classes
│ │ ├── application.properties
│ │ ├── com
│ │ │ └── example
│ │ │ └── classgraph_resources_issue
│ │ │ └── ClassgraphResourcesIssueApplication.class
│ │ └── foo
│ │ └── a.cypher
│ ├── classpath.idx
│ └── lib
│ ├── classgraph-4.8.83.jar
│ ├── jakarta.annotation-api-1.3.5.jar
│ ├── jul-to-slf4j-1.7.30.jar
│ ├── log4j-api-2.13.2.jar
│ ├── log4j-to-slf4j-2.13.2.jar
│ ├── logback-classic-1.2.3.jar
│ ├── logback-core-1.2.3.jar
│ ├── slf4j-api-1.7.30.jar
│ ├── snakeyaml-1.26.jar
│ ├── spring-aop-5.2.6.RELEASE.jar
│ ├── spring-beans-5.2.6.RELEASE.jar
│ ├── spring-boot-2.3.0.RELEASE.jar
│ ├── spring-boot-autoconfigure-2.3.0.RELEASE.jar
│ ├── spring-boot-starter-2.3.0.RELEASE.jar
│ ├── spring-boot-starter-logging-2.3.0.RELEASE.jar
│ ├── spring-context-5.2.6.RELEASE.jar
│ ├── spring-core-5.2.6.RELEASE.jar
│ ├── spring-expression-5.2.6.RELEASE.jar
│ └── spring-jcl-5.2.6.RELEASE.jar
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
│ └── com.example
│ └── classgraph_resources_issue
│ ├── pom.properties
│ └── pom.xml
└── org
└── springframework
└── boot
└── loader
├── ClassPathIndexFile.class
├── ExecutableArchiveLauncher.class
├── JarLauncher.class
├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
├── LaunchedURLClassLoader.class
├── Launcher.class
├── MainMethodRunner.class
├── PropertiesLauncher$1.class
├── PropertiesLauncher$ArchiveEntryFilter.class
├── PropertiesLauncher$PrefixMatchingArchiveFilter.class
├── PropertiesLauncher.class
├── WarLauncher.class
├── archive
│ ├── Archive$Entry.class
│ ├── Archive$EntryFilter.class
│ ├── Archive.class
│ ├── ExplodedArchive$AbstractIterator.class
│ ├── ExplodedArchive$ArchiveIterator.class
│ ├── ExplodedArchive$EntryIterator.class
│ ├── ExplodedArchive$FileEntry.class
│ ├── ExplodedArchive$SimpleJarFileArchive.class
│ ├── ExplodedArchive.class
│ ├── JarFileArchive$AbstractIterator.class
│ ├── JarFileArchive$EntryIterator.class
│ ├── JarFileArchive$JarFileEntry.class
│ ├── JarFileArchive$NestedArchiveIterator.class
│ └── JarFileArchive.class
├── data
│ ├── RandomAccessData.class
│ ├── RandomAccessDataFile$1.class
│ ├── RandomAccessDataFile$DataInputStream.class
│ ├── RandomAccessDataFile$FileAccess.class
│ └── RandomAccessDataFile.class
├── jar
│ ├── AsciiBytes.class
│ ├── Bytes.class
│ ├── CentralDirectoryEndRecord$1.class
│ ├── CentralDirectoryEndRecord$Zip64End.class
│ ├── CentralDirectoryEndRecord$Zip64Locator.class
│ ├── CentralDirectoryEndRecord.class
│ ├── CentralDirectoryFileHeader.class
│ ├── CentralDirectoryParser.class
│ ├── CentralDirectoryVisitor.class
│ ├── FileHeader.class
│ ├── Handler.class
│ ├── JarEntry.class
│ ├── JarEntryFilter.class
│ ├── JarFile$1.class
│ ├── JarFile$JarEntryEnumeration.class
│ ├── JarFile$JarFileType.class
│ ├── JarFile.class
│ ├── JarFileEntries$1.class
│ ├── JarFileEntries$EntryIterator.class
│ ├── JarFileEntries.class
│ ├── JarURLConnection$1.class
│ ├── JarURLConnection$JarEntryName.class
│ ├── JarURLConnection.class
│ ├── StringSequence.class
│ └── ZipInflaterInputStream.class
├── jarmode
│ ├── JarMode.class
│ ├── JarModeLauncher.class
│ └── TestJarMode.class
└── util
└── SystemPropertyUtils.class
20 directories, 86 files
NOTE A complete reproducible example is attached.
classgraph_resources_issue.zip Please run with
mvn clean package && java -jar target/classgraph_resources_issue-0.0.1-SNAPSHOT.jarA Spring Boot application packaged can be packaged as executable jar. The format is described here: https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/reference/html/appendix-executable-jar-format.html#executable-jar-restrictions
Given the following structure:
A scan for resources inside the class path under the prefix "foo" like this:
Gives me the expected resources (a.cypher) when run unpackaged.
If I package the application as an executable jar, I get:
I can "fix" this by using the System class loader only (see commented line above), but this is against Spring Boots recommendation (see link about the format):
When I use current context class loader, I only get this entry:
jar:file:/Users/msimons/Projects/Issues/classgraph_resources_issue/target/classgraph_resources_issue-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/BOOT-INF/classes/foo/a.cypher, which I think is wrong. I can read it through theResourceclass, but thegetURL()gives me the wrong URL (Note the two times "BOOT-INF/classes" )The jar looks like this: