【问题标题】:Problem setting up H2 init runscript. File is not found when script is not in classpath root folder while using java modular system设置 H2 初始化运行脚本时出现问题。使用 java 模块化系统时脚本不在类路径根文件夹中时找不到文件
【发布时间】:2022-02-17 00:28:05
【问题描述】:

以下关于如何从资源文件夹中初始化 runscript 的问题的公认答案:problem with INIT=RUNSCRIPT and relative paths

连接字符串:

jdbc:h2:mem:;INIT=RUNSCRIPT FROM 'classpath:desktop/core/database/databaseCreation.sql'

但是我得到一个异常,即使文件存在也找不到文件。

例外:

org.h2.jdbc.JdbcSQLNonTransientException: IO Exception: "java.io.FileNotFoundException: resource /desktop/core/database/databaseCreation.sql"; "classpath:desktop/core/database/databaseCreation.sql"; SQL statement:
RUNSCRIPT FROM 'classpath:desktop/core/database/databaseCreation.sql' [90031-210]
    at com.h2database@2.1.210/org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
    at com.h2database@2.1.210/org.h2.message.DbException.getJdbcSQLException(DbException.java:496)
    at com.h2database@2.1.210/org.h2.message.DbException.get(DbException.java:216)
    at com.h2database@2.1.210/org.h2.message.DbException.convertIOException(DbException.java:461)
    at com.h2database@2.1.210/org.h2.command.dml.ScriptBase.openInput(ScriptBase.java:168)
    at com.h2database@2.1.210/org.h2.command.dml.RunScriptCommand.update(RunScriptCommand.java:52)
    at com.h2database@2.1.210/org.h2.command.CommandContainer.update(CommandContainer.java:174)
    at com.h2database@2.1.210/org.h2.command.Command.executeUpdate(Command.java:252)
    at com.h2database@2.1.210/org.h2.engine.Engine.openSession(Engine.java:279)
    at com.h2database@2.1.210/org.h2.engine.Engine.createSession(Engine.java:201)
    at com.h2database@2.1.210/org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:338)
    at com.h2database@2.1.210/org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:122)
    at com.h2database@2.1.210/org.h2.Driver.connect(Driver.java:59)
    at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:681)
    at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:252)
    at ispfdesktop/desktop.core.database.DatabaseManager.connectToInMemoryDatabase(DatabaseManager.java:184)
    at ispfdesktop/desktop.core.database.CRUDTests.setUpBeforeClass(CRUDTests.java:21)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptLifecycleMethod(TimeoutExtension.java:126)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptBeforeAllMethod(TimeoutExtension.java:68)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllMethods$9(ClassBasedTestDescriptor.java:384)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllMethods(ClassBasedTestDescriptor.java:382)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:196)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:78)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:136)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:84)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.io.FileNotFoundException: resource /desktop/core/database/databaseCreation.sql
    at com.h2database@2.1.210/org.h2.store.fs.disk.FilePathDisk.newInputStream(FilePathDisk.java:386)
    at com.h2database@2.1.210/org.h2.store.fs.FileUtils.newInputStream(FileUtils.java:267)
    at com.h2database@2.1.210/org.h2.command.dml.ScriptBase.openInput(ScriptBase.java:166)
    ... 69 more

尝试使用 getResource 访问文件(DatabaseManager 类在 desktop.core.database 包中)告诉文件存在:

String file = DatabaseManager.class.getResource("databaseCreation.sql").getFile();
boolean yes = new File(file).exists(); // yes is true

在 Windows(10) 和 Linux (Kubuntu) 平台上都试过,并使用 2.1.210 版的 h2。

更新 #1

文件在根类路径文件夹classpath:databaseCreation.sql 中时找到,但在桌面/核心/数据库等子文件夹下仍然找不到。

在第一个子文件夹之前附加“/”不起作用。

试图将sql文件放到所有文件夹中。

'classpath:desktop/core/database/databaseCreation.sql' 不起作用

'classpath:desktop/core/databaseCreation.sql' 不起作用

'classpath:desktop/databaseCreation.sql' 不起作用

只有这个有效

'classpath:databaseCreation.sql'

不使用类路径:

不使用类路径,文件可以在任何子文件夹中,但是这样,我需要使用文件的绝对路径:

jdbc:h2:mem:;INIT=RUNSCRIPT FROM '<absolute path here>'

由于引用的问题的答案已过时,该问题在当前的 H2 版本上不起作用,并且想知道如何使用 classpath 使其工作,因此将问题保持打开状态。

更新 #2

为了复制,需要在项目中使用java模块化系统(module-info.java)。

【问题讨论】:

  • 出于调试目的,如果您将该文件直接放在 src/main/resources 下并执行RUNSCRIPT FROM 'classpath:databaseCreation.sql 会发生什么情况@ 只是好奇它是否是路径问题?也许它需要/desktop 而不是desktop
  • 将文件移动到src/main/resourceclasspath:databaseCreation.sql 有效!!!但是在 desktop/co... 之前附加 / 不会。我很好奇为什么当接受的答案显示子文件夹的使用(名为:脚本)时它在链接问题上起作用。由于我想从该子文件夹桌面/核心/数据库运行它,因此仍然存在问题。
  • 你提出了一个有趣的问题。我想这可能取决于您的包装方式?例如,您的目标在文件夹结构方面看起来如何?你的桌面是这样存在于/target/desktop 下的吗?
  • @SMA 是的。所有文件夹、资源和 .class 文件都按预期存在。 (target/classes/desktop/core/database/中的databaseCreation.sql)。如果它不存在,我使用 .getResource 方法检查该文件的示例代码将返回 null(抛出 NullPointerException,因为我调用了 .getFile() )。
  • 我做了一个最小的、可重现的例子:github.com/lookslikeitsnot/stackoverflow-70862699 具有描述的布局,但无法复制错误。你能检查一下 repo 看它是否与你的代码匹配吗?

标签: java h2


【解决方案1】:

更新: (module-info.java)

根据您的评论,您的原始设置使用 JDK 9+ 模块。这是一个复杂而令人困惑的话题。简单地删除 module-info.java 而不使用模块是最简单的。如果您打算使用模块并将资源保存在单独的目录(模块)中,则有多种选择,没有一个明确的选择。也许最简单的选择是打开包含资源的“包”。这样的事情在我的本地测试中起作用:

module myAppModule {
    exports desktop.core.database;

    opens desktop.core.database;

    requires java.sql;
    requires org.junit.jupiter.api;
}

更多信息:

原创

我无法使用非常简单的 maven 设置复制您的问题,仅使用 H2 运行时作为依赖项(相同版本,2.1.210)以及 JUnit 5。它按预期工作。

堆栈跟踪显示这是在 Eclipse 中作为测试运行的。如果我手动添加 src/main/resources 作为 Java 构建路径源文件夹,我可以在 Eclipse 中完全复制您的问题,但是排除 **/,这将排除资源的子目录。

如果您使用的是 maven,或许可以尝试使用 mvn test 在命令行上运行以验证它不是您的 Eclipse 设置。

否则,您将需要发布更多信息以获得帮助。

【讨论】:

  • 我使用 JUnit 5、H2 创建了新的 Maven 项目,其版本与您相同,将源代码复制到相同的包并且它工作(我连接到数据库的测试)......所以我不知道为什么它可以工作,因为我没有对 java 构建路径做任何事情或在第一个项目中添加任何排除项......然后我发现没有 module-info.java 并且当我将它添加到新创建的项目时,它不起作用。 ..同样的错误。所以 module-info.java 导致了这个问题。在使用 java 模块化系统时如何在不使用绝对路径的情况下使其工作?
  • 我更新了关于将模块与资源一起使用的一种方法的答案,以及更多信息。
  • 谢谢!打开 desktop.core.database; module-info.java 中缺少。添加它导致我可以在 init=runscript from. 中使用 classpath:/
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-19
  • 2020-08-07
  • 2015-12-05
  • 2021-08-03
  • 1970-01-01
相关资源
最近更新 更多