你好。
我们使用 Spring Boot 1.5.8 作为开源身份管理软件 midPoint 的一部分。最近我们发现,在启动过程中,midPoint 无法正确解析如下所示的 URI(注意:schema-3.7.jar 是我们的组件之一):
jar:file:/C:/tmp/mp/lib/midpoint.war!/WEB-INF/lib/schema-3.7.jar!/prism/xml/ns/public/types-3.xsd
调用方法获取的是完全不相关的二进制数据(没有任何错误指示),而不是预期的 types-3.xsd 的 XML 内容!原来数据就是这个文件的内容:
C:\tmp\mp\lib\midpoint.war!/WEB-INF/lib/hibernate-commons-annotations-4.0.5.Final.jar
schema-3.7.jar 和 hibernate-commons-annotations-4.0.5.Final.jar 文件没有任何共同点,除了它们都位于类路径上(首先是 hibernate jar,其次是 schema - 这很重要)。
我们能够针对这种情况创建一个测试用例(受到 LaunchedURLClassLoaderTests 中类似测试的启发):
@Test
public void resolveFromNestedNestedJarAbsolutePath() throws Exception {
File file = this.temporaryFolder.newFile();
TestJarCreator.createTestJar(file, false, true); // creates a structure described below
JarFile jarFile = new JarFile(file);
JarFile nestedJarFile = jarFile.getNestedJarFile(jarFile.getEntry("nesting-nested.jar"));
JarFile nJarFile = jarFile.getNestedJarFile(jarFile.getEntry("n123456789012345678901234567890.jar"));
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(new URL[] { nJarFile.getUrl(), nestedJarFile.getUrl() }, null);
String absolutePath = nestedJarFile.getUrl() + "nested.jar!/3.dat";
URL resource = loader.getResource(absolutePath);
System.out.println("Looked for: " + absolutePath);
System.out.println("Found resource: " + resource);
assertThat(resource.toString()).isEqualTo(absolutePath);
assertThat(resource.openConnection().getInputStream().read()).isEqualTo(3);
}
测试 JAR 文件是 midpoint.war 的模拟,包含以下条目(除其他外):
- nesting-nested.jar(这类似于 midPoint 中的 schema-3.7.jar)
- nested.jar(在 midPoint 中不存在)
- 3.dat(包含值 3)(类似于 types-3.xsd)
- n123456789012345678901234567890.jar(类似于 hibernate-commons-annotations-4.0.5.Final.jar)
- (除清单外不包含任何条目)
如果类路径是:
- jar:文件:/ C:/用户/.../junit4507521104116618629.tmp!/n123456789012345678901234567890.jar!/
- jar:文件:/C:/Users/.../junit4507521104116618629.tmp!/nesting-nested.jar!/
然后方法调用:
loader.getResource("jar:file:/C:/Users/.../junit4507521104116618629.tmp!/nesting-nested.jar!/nested.jar!/3.dat")
返回 n123456789012345678901234567890.jar 的内容而不是 3.dat,没有任何警告。
为了完整起见,系统输出是
Looked for: jar:file:/C:/Users/.../junit4507521104116618629.tmp!/nesting-nested.jar!/nested.jar!/3.dat
Found resource: jar:file:/C:/Users/.../junit4507521104116618629.tmp!/nesting-nested.jar!/nested.jar!/3.dat
但例外是
org.junit.ComparisonFailure:
Expected: 3
Actual: 80
(请注意,80 是“P”字符,是 n1234...jar 文件的第一个)
问题出在同一类中与extractFullSpec(String, String)方法相关的JarURLConnection.get(URL, JarFile)方法中。该实现忽略了这样一个事实:要解析的 URL 可能指向与调用者提供的 JarFile 不同的 JAR 文件。在这种情况下,通常不会发生任何问题;但文件名长度有可能发生冲突,导致 extractFullSpec 返回一个空字符串,稍后在 get 方法中将其解释为“我们找到了匹配项”。如果需要,我可以提供更多详细信息。
请在即将提交的提交中找到几个测试用例(均在 LaunchedURLClassLoaderTests 和 JarURLConnectionTests 中)和建议的修复。
在阅读 JarURLConnection.get/extractFullSpec 的代码时,我们发现了另外两个错误,我们为此编写了单独的测试用例。第一个与 extractFullSpec 返回的路径中多个段的解析有关(这一行应该是“=”而不是“+=” )。第二个与 jar 条目名称中的空格和其他不符合 URI 的字符有关。再次,请查看创建的测试用例和建议的修复。
您能看一下问题和建议的修复吗?如果它们是正确的,我们可以提交 PR。如果不是,请您给我们一个提示,我们应该怎样做才能以正确的方式解决它们?
谢谢。