【发布时间】:2015-11-05 01:01:21
【问题描述】:
我的目标是在从 JAR 中加载资源并在 SBT 中从 JAR 运行应用程序时避免 FileNotFound 异常。
我有以下任务:
val generateSource = TaskKey[Unit]("generateSource")
val generateSourceImpl : Def.Initialize[Task[Unit]] = {
Def.task {
val localGeneratorJar = file(s"${baseDirectory.value.getParentFile.toString}/generator/repo/.sbt/generator.jar")
if (!localGeneratorJar.exists()) {
sys.error(s"Generator not found, please execute 'sbt publishLocal' in 'generator' project first.")
}
val r = (runner in Compile).value
val opts = Seq( /* options here */ )
toError(r.run(“com.example.AllMightyCompiler", Seq(localGeneratorJar), opts, streams.value.log))
}
}
问题发生在 AllMightyCompiler 加载时,例如来自‘localGeneratorJar’本身和 JAR 的 XSD 模式在 sbt 任务的运行之间被修改。 典型的工作流程是:
$ sbt
> generateSource
# all good, but
# when in meantime ‘generator.jar is modified’ task invocation will be
> generateSource
root > generateSource
[info] Running AllMightyCompiler —opts=dummy
com.example.GeneratorException: org.xml.sax.SAXParseException; schema_reference.4: Failed to read schema document 'jar:file:/Users/Me/Development/Work/generator/repo/.sbt/generator.jar!/module.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
at com.example.ModuleLoader.<init>(ModuleLoader.java:127)
at com.example.AllMightyCompiler.loadModel(Compiler.java:394)
at com.example.AllMightyCompiler.generateImpl(Compiler.java:264)
at com.example.AllMightyCompiler.generate(Compiler.java:144)
at com.example.AllMightyCompiler.main(Compiler.java:134)
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:483)
at sbt.Run.invokeMain(Run.scala:72)
at sbt.Run.run0(Run.scala:65)
at sbt.Run.sbt$Run$$execute$1(Run.scala:54)
at sbt.Run$$anonfun$run$1.apply$mcV$sp(Run.scala:58)
at sbt.Run$$anonfun$run$1.apply(Run.scala:58)
at sbt.Run$$anonfun$run$1.apply(Run.scala:58)
at sbt.Logger$$anon$4.apply(Logger.scala:90)
at sbt.TrapExit$App.run(TrapExit.scala:244)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.xml.sax.SAXParseException; schema_reference.4: Failed to read schema document 'jar:file:/Users/Me/Development/Work/generator/repo/.sbt/generator.jar!/module.xsd', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:347)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4166)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4149)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getSchemaDocument1(XSDHandler.java:2479)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getSchemaDocument(XSDHandler.java:2187)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:573)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:616)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:574)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:540)
at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:255)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:638)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:670)
at n4.generator.util.ModuleLoader.<init>(ModuleLoader.java:121)
... 17 more
据我所知,有两种可能的解决方案:
- 直接在 com.example.ModuleLoader 中禁用 JAR URL 缓存
- 不知何故,我的 sbt 任务“generateSources”中的 fork runner
选项 1 可以通过以下方式完成:
new URLConnection(schemaURL) {
@Override
public void connect() throws IOException {
// Do nothing
}
}.setDefaultUseCaches(false);
但是,选项 1 不是我想要的,因为它需要修改“generator.jar”,我现在可以这样做,但将来可能不会。 因此,唯一剩下的选项是在任务中使用分叉的 JVM,但是当我在 build.sbt 中设置时:
fork in Compile := true
获得的 runner 仍然使用与 sbt 本身相同的 JVM。
有人知道如何强制运行器在单独的 JVM 中启动吗?
附:我只认为分叉将有助于基于http://www.scala-sbt.org/0.13/docs/Running-Project-Code.html,因为当我第一次运行我的任务时,我看到:
异常:线程“run-main-0”中的 UncaughtExceptionHandler 抛出 sbt.TrapExitSecurityException
这是因为 AllMightyCompiler 当前以以下行结尾:
public static void main(String... args) {
… lot of code ...
System.exit(exit);
}
【问题讨论】: