Issues

Select view

Select search mode

 
34 of 34

includeAll does not work with java 9+ and multi-module projects.

Description

As far as I can tell, IncludeAll relies on legacy java ClassLoader capabilities to compute the relative path of the files to include.
Specifically AbstractResourceAccessor.convertToPath() relies on rootStrings which was populated with the URLs of all jars present in the classpath before java 9.

if (classLoader instanceof URLClassLoader) { // only true before java 9 baseUrls = new Vector<>(Arrays.asList(((URLClassLoader) classLoader).getURLs())).elements(); while (baseUrls.hasMoreElements()) { addRootPath(baseUrls.nextElement()); // add jar URLs } } baseUrls = classLoader.getResources(""); while (baseUrls.hasMoreElements()) { addRootPath(baseUrls.nextElement()); // do not add jar URLs }

This approach does not work with java 9+.

As result changelog files from external jars are not included and the following warning is logged:
WARN Not a valid resource entry: jar:file:/.m2/repository/com/foo/1.0.0/foo-1.0.0.jar!/db/changelog/changelog-001.xml

Environment

SpringBoot 2.2.2 and 2.1.11
Maven
Windows

Details

Reporter

Affects versions

Priority

Created January 4, 2020 at 10:23 PM
Updated January 6, 2020 at 3:47 AM

Activity

Show:

mat January 6, 2020 at 3:47 AM

After further research, it seems like there is no clean equivalent in java 9 for the current approach.
See: https://stackoverflow.com/questions/49557431/how-to-safely-access-the-urls-of-all-resource-files-in-the-classpath-in-java-9-1

For now, my work around is to override SpringResourceOpener.list() with:

@Override public Set<String> list(String relativeTo, String path, boolean includeFiles, boolean includeDirectories, boolean recursive) throws IOException { if (path == null) { return null; } // // Possible Resources Types // // Standalone Jar // Root Path: jar:file:/Projects/my-project/second-module/target/second-module-1.0.0-SNAPSHOT-exec.jar!/BOOT-INF/lib/first-module-1.0.0-SNAPSHOT.jar!/ // +Resource: jar:file:/Projects/my-project/second-module/target/second-module-1.0.0-SNAPSHOT-exec.jar!/BOOT-INF/lib/first-module-1.0.0-SNAPSHOT.jar!/db/changelog/0-initial-schema.xml // Standalone War // Root Path: jar:file:/Projects/my-project/second-module/target/second-module-1.0.0-SNAPSHOT-exec.war!/WEB-INF/lib/first-module-1.0.0-SNAPSHOT.jar!/ // +Resource: jar:file:/Projects/my-project/second-module/target/second-module-1.0.0-SNAPSHOT-exec.war!/WEB-INF/lib/first-module-1.0.0-SNAPSHOT.jar!/-db/changelog/0-initial-schema.xml // Openned Jar Dependency // Root Path: file:/Projects/my-project/first-module/target/classes/ // +Resource: file:/Projects/my-project/first-module/target/classes/db/changelog/0-initial-schema.xml // War Wild-Fly Exploded // Root Path: vfs:/Projects/my-project/second-module/target/second-module-1.0.0-SNAPSHOT/WEB-INF/lib/first-module-1.0.0-SNAPSHOT.jar/ // +Resource: vfs:/Projects/my-project/second-module/target/second-module-1.0.0-SNAPSHOT/WEB-INF/lib/first-module-1.0.0-SNAPSHOT.jar/db/changelog/0-initial-schema.xml // War Wild-Fly Artifact // Root Path: vfs:/content/second-module-1.0.0-SNAPSHOT.war/WEB-INF/lib/first-module-1.0.0-SNAPSHOT.jar/ // +Resource: vfs:/content/second-module-1.0.0-SNAPSHOT.war/WEB-INF/lib/first-module-1.0.0-SNAPSHOT.jar/db/changelog/0-initial-schema.xml Set<String> returnSet = new HashSet<>(); path = path + (recursive ? "**" : '*'); // All files inside! String tempFile = FilenameUtils.concat(FilenameUtils.getFullPath(relativeTo), path); Resource[] resources = getResources(adjustClasspath(tempFile)); for (Resource resource : resources) { String resourceStr = resource.getURL().toExternalForm(); String resourcePath = convertToPath(resourceStr); if (resourceStr.endsWith(resourcePath) && !resourceStr.equals(resourcePath)) { returnSet.add(resourcePath); } else { // Closed Jar Dependency // Root Path: file:/.m2/repository/org/liquibase/test/first-module/1.0.0-SNAPSHOT/first-module-1.0.0-SNAPSHOT.jar/ // +Resource: jar:file:/.m2/repository/org/liquibase/test/first-module/1.0.0-SNAPSHOT/first-module-1.0.0-SNAPSHOT.jar!/db/changelog/0-initial-schema.xml String newResourceStr = resource.getURL().getFile(); // Remove "jar:" from begining. newResourceStr = newResourceStr.replaceAll("!", ""); String newResourcePath = convertToPath(newResourceStr); if (newResourceStr.endsWith(newResourcePath) && !newResourceStr.equals(newResourcePath)) { returnSet.add(newResourcePath); } else { // TODO https://liquibase.jira.com/browse/CORE-3550: Truncating URLs based on exclamation marks // as fallback. Jar root paths cannot be obtained from the classloader in java 9+. int exclamationMarkIndex; if (resource.getURL().toString().startsWith("jar:file:") && (exclamationMarkIndex = resource.getURL().getFile().lastIndexOf("!")) > 0) { returnSet.add(resource.getURL().getFile().substring(exclamationMarkIndex +1)); }else { LogService.getLog(getClass()).warning( LogType.LOG, "Not a valid resource entry: " + resourceStr); } } } } return returnSet; }

Please advice on what would possibly be a better fix.