在我的测试中获得MalformedURLException但从未发生过

时间:2018-05-07 10:06:09

标签: java url exception

我将Windows从7升级到10,现在在我的项目中,我在运行测试时遇到了这些异常。

这是我的代码

    @BeforeClass
public static void createSchema() throws Exception {

    log.info("Creating H2 CA_MANAGER schema");

    URL schemaDDL = Thread.currentThread().getContextClassLoader().getResource("create_cam_test.sql");
    RunScript.execute(TestConfig.URL,
            TestConfig.USER, TestConfig.PASSWORD, schemaDDL.getFile(), null, false);

    log.info("Running H2 CA_MANAGER DDL");

    URL ddl = Thread.currentThread().getContextClassLoader().getResource("ca_manager3_ddl_h2.sql");
    RunScript.execute(TestConfig.URL,
            TestConfig.USER, TestConfig.PASSWORD, ddl.getFile(), null, false);
}

这是例外。

 org.h2.message.DbException: IO Exception: "java.net.MalformedURLException: no protocol: /C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql"; "/C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql" [90031-196]

    at org.h2.message.DbException.get(DbException.java:168)
    at org.h2.message.DbException.convertIOException(DbException.java:330)
    at org.h2.tools.RunScript.process(RunScript.java:334)
    at org.h2.tools.RunScript.execute(RunScript.java:304)
    at 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.h2.jdbc.JdbcSQLException: IO Exception: "java.net.MalformedURLException: no protocol: /C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql"; "/C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql" [90031-196]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
    ... 27 more
Caused by: java.net.MalformedURLException: no protocol: /C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql
    at java.net.URL.<init>(URL.java:593)
    at java.net.URL.<init>(URL.java:490)
    at java.net.URL.<init>(URL.java:439)
    at org.h2.store.fs.FilePathDisk.newInputStream(FilePathDisk.java:317)
    at org.h2.store.fs.FileUtils.newInputStream(FileUtils.java:218)
    at org.h2.tools.RunScript.process(RunScript.java:186)
    at org.h2.tools.RunScript.process(RunScript.java:329)
    ... 24 more

当我想执行脚本时发生异常。 变量schemaDDL.getFile()返回完全如异常中所示的路径:

/C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql

我也检查过,它肯定在那里。我还发现需要将file://附加到路径上的解决方案,我这样做了,仍然会发生相同的异常。文件路径如下所示

file://C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql

该例外情况如下

org.h2.jdbc.JdbcSQLException: IO Exception: "java.net.MalformedURLException: no protocol: //C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql"; "file://C:/Users/Documents/camanager-combined/camanager.persistence.hibernate/target/test-classes/create_cam_test.sql" [90031-196]

我使用的Java版本是Java 1.8.0_121。你有什么解决办法。

1 个答案:

答案 0 :(得分:1)

问题在于

/C:/Users/francois17/Documents/.../create_cam_test.sql

不是网址。这是一个路径名。

所以问题是为什么会引发这个问题?

现在看起来它来自这个电话:

RunScript.execute(TestConfig.URL,
        TestConfig.USER, TestConfig.PASSWORD, schemaDDL.getFile(), null, false);

或者这个

RunScript.execute(TestConfig.URL,
        TestConfig.USER, TestConfig.PASSWORD, ddl.getFile(), null, false);

看起来没问题,因为执行API要求第4个参数是路径名。

然后我查看了创建URL的网站。它位于org.h2.store.FileDiskPath::newInputStream。该方法的代码是:

public InputStream  newInputStream() throws IOException {
    if (name.indexOf(':') > 1) {
        // if the : is in position 1, a windows file access is assumed: C:.. or D:
        if (name.startsWith(CLASSPATH_PREFIX)) {
            String fileName = name.substring(CLASSPATH_PREFIX.length());
            if (!fileName.startsWith("/")) {
                fileName = "/" + fileName;
            }
            InputStream in = getClass().getResourceAsStream(fileName);
            if (in == null) {
                 Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
            }
            if (in == null) {
                throw new FileNotFoundException("resource " + fileName);
            }
            return in;
        }
        // otherwise an URL is assumed
        URL url = new URL(name);
        InputStream in = url.openStream();
        return in;
    }
    FileInputStream in = new FileInputStream(name);
    IOUtils.trace("openFileInputStream", name, in);
    return in;
}

总结它的作用:

  1. 在路径名
  2. 中查找冒号
  3. 如果冒号不是第二个字符:
    1. 它查找“classpath:”URL并对其进行处理。
    2. 否则,它会将URL作为普通URL打开
  4. 如果没有冒号,或者冒号是第二个字符(即Windows驱动器字符),它会将对象作为文件打开。
  5. 灯泡!

    仔细查看上面的路径名。它看起来像路径名一样,但实际上它是错误的。带驱动器的Windows路径名不应该以“/”开头。额外的“/”导致冒号成为第3个字符,这违反了newInputStream方法的逻辑。

    带驱动器的路径名的正确格式为:

    C:/Users/francois17/Documents/.../create_cam_test.sql
    

    查找虚假主导“/”的来源,您可能已经解决了问题。您也可以通过删除它或预先添加“file://”来解决伪造的“/”问题。 (注意:2斜线......因为已有一个!)