Spring是一个非常优秀的开源项目,然而,跟其它任何优秀的系统产品一样,也存在着这样那样的问题,我们喜欢称为Bug。Spring中的Bug确实不少,今天为了充实“中文问题没商量”主题,举一个不算很重要,也比较简单理解的一个Bug示例。
这里提前申明,这个话题不是针对Spring项目,因此请“
春迷”们自重、没事勿扰,文中不足之处欢迎大家批评指教。
我们知道,一个开源软件项目,给用户的单元测试最基本的要求是能全部通过测试,在Java中就是在运行单元测试的时候应该要看见一个绿条。Spring项目的单元测试写得非常好,也非常全面。然而,单元测试中却有一些问题,在中文路径上无法完全通过测试,必须放到英文路径下才能完全通过测试,因此,这属于一种“没商量”的中文问题。
单元测试: 包:org.springframework.beans.factory.xml
类:XmlBeanFactoryTests
方法:testFileSystemResourceWithImport
错误图示:
详细错误信息:
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [C:\Documents%20and%20Settings\Administrator\%e6%a1%8c%e9%9d%a2\spring\spring-framework-2.0-rc2\bin\org\springframework\beans\factory\xml\resource.xml]; nested exception is java.io.FileNotFoundException: C:\Documents%20and%20Settings\Administrator\%e6%a1%8c%e9%9d%a2\spring\spring-framework-2.0-rc2\bin\org\springframework\beans\factory\xml\resource.xml (系统找不到指定的路径。)
Caused by: java.io.FileNotFoundException: C:\Documents%20and%20Settings\Administrator\%e6%a1%8c%e9%9d%a2\spring\spring-framework-2.0-rc2\bin\org\springframework\beans\factory\xml\resource.xml (系统找不到指定的路径。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at org.springframework.core.io.FileSystemResource.getInputStream(FileSystemResource.java:85)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:315)
at org.springframework.beans.factory.xml.XmlBeanFactory.<init>(XmlBeanFactory.java:73)
at org.springframework.beans.factory.xml.XmlBeanFactory.<init>(XmlBeanFactory.java:61)
at org.springframework.beans.factory.xml.XmlBeanFactoryTests.testFileSystemResourceWithImport(XmlBeanFactoryTests.java:946)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
测试代码:
public void testFileSystemResourceWithImport() {
String file = getClass().getResource("resource.xml").getFile();
XmlBeanFactory xbf = new XmlBeanFactory(new FileSystemResource(file));
// comes from "resourceImport.xml"
ResourceTestBean resource1 = (ResourceTestBean) xbf.getBean("resource1");
// comes from "resource.xml"
ResourceTestBean resource2 = (ResourceTestBean) xbf.getBean("resource2");
}
出错原因:
这个问题是笔者在参与开发EasyJWeb及EasyDBO框架中遇到过的问题,因此很容易就找到了问题的所在。Java的Class.getResource(name)返回的是一个URL,而URL.getFile默认情况下返回的是经过URL编码后的字符,会把中文等特殊字符变成类似%e6的形式。而一般io构造路径是没有自动解码功能的,所以在中文路径下要出现错误。
解决办法:
在使用URL.getFile返回的路径时,使用前需要使用java.net.URLDecoder对路径进行一次解码操作。修改后的且能通过测试的方法如下:
public void testFileSystemResourceWithImport() {
String file = getClass().getResource("resource.xml").getFile();
try{
file=java.net.URLDecoder.decode(file,"UTF-8");
}
catch(Exception e)
{
e.printStackTrace();
}
XmlBeanFactory xbf = new XmlBeanFactory(new FileSystemResource(file));
// comes from "resourceImport.xml"
ResourceTestBean resource1 = (ResourceTestBean) xbf.getBean("resource1");
// comes from "resource.xml"
ResourceTestBean resource2 = (ResourceTestBean) xbf.getBean("resource2");
}
小结:
由于Spring开源项目的开发团队中,除了一些喜欢跟在Rod大叔的屁股后面唱中文版赞歌的“
春迷”以外,当前似乎还没有中国人参与到正式的Spring开发小组中。因此,也许没有在中文路径下运行过测试用例,导致我这样的Spring初学者一不小心就遇上这样的问题。
问题是解决了,但是却是一种比较罕见的方式,而且Spring开发小组事先也许没有预想到或是故意忽略掉的问题,因此,可以称得上是“没商量”的中文问题。