Skip to content

PathMatchingResourcePatternResolver cannot load resources with a '#' in their file name within JARs #23532

@tofdragon

Description

@tofdragon

Affects: spring version 5.1.5

Description

Given file /validation/api#test.json within a.jar which is in the classpath...

a project dependent a.jar, in project code

ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
Resource[] resources22 = resourceLoader.getResources("classpath*:/validation/**/api#test.json");
InputStream inputStream = resources[0].getInputStream();

error:

Exception in thread "main" java.io.FileNotFoundException: JAR entry validation/api not found in a.jar
	at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:142)
	at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:150)
	at java.net.URL.openStream(URL.java:1038)

Analysis

The URL created in org.springframework.core.io.UrlResource.createRelative(String) treats everything after # as the URL fragment, causing the file path to be incorrect when the file is last read.

URL object:

  • file: a.jar!/validation/api
  • path: a.jar!/validation/api
  • ref: test.json

Solutions

Solution 1

extends PathMatchingResourcePatternResolver

@Override
protected Set<Resource> doFindPathMatchingJarResources() {
  ....
    
      result.add(rootDirResource.createRelative(ParseUtil.encodePath(relativePath)))
  ...
}

Solution 2

 URL url = resources[0].getURL();
            if (ResourceUtils.isJarURL(url) || ResourceUtils.isJarFileURL(url)) {
                String parent = url.toExternalForm().substring(0, url.toExternalForm().indexOf("!/validation/") + 13);
                String encodeFileName = url.toExternalForm().substring(url.toExternalForm().indexOf("!/validation/") + 13);
                String encodeFile = ParseUtil.encodePath(encodeFileName);
                URL url21 = new URL(parent + encodeFile);
                inputStream = url21.openStream();
            } else {
                inputStream = resources[0].getInputStream();
            }

Question

Is there any other better solution, or is there a problem with my use?

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions