【问题标题】:Using resource in kotlin func - does not work with fat jar (one jar)在 kotlin func 中使用资源 - 不适用于 fat jar(一个 jar)
【发布时间】:2017-09-20 04:44:53
【问题描述】:

我有以下代码:

fun main(args: Array<String>) {
    val urlForCSR: URL = ClassLoader.getSystemClassLoader().getResource("merchant.id")
    // also tried ClassLoader.getSystemResource("merchant.id")
    ...

从 intelliJ 运行时,以下内容可以正常工作并找到资源。但是当使用捆绑的 jar 运行时,它会给出 NullPointerException

  • 资源路径:/src/main/resources/merchant.id
  • 代码路径:/src/main/java/Route.kt

以下是 Maven 配置 sn-p:

    ...
    <!-- Make this jar executable -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>RouteKt</mainClass> <!-- Class generated (for above main func - named Route.kt) -->
                    </manifest>
                </archive>
            </configuration>
        </plugin>

        <!-- Includes the runtime dependencies -->
        <plugin>
            <groupId>org.dstovall</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
            <executions>
                <execution>
                    <goals>
                        <goal>one-jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>

是否有任何其他战争来获取上述资源的 URL,它可以使用一个 jar 或其他制作胖 jar 的方式。

Jar 内容:

jar tf target/Route-1.0-SNAPSHOT.jar
META-INF/
META-INF/MANIFEST.MF
merchant.id
RouteKt$main$1.class
RouteKt.class
META-INF/maven/
META-INF/maven/groupId/
META-INF/maven/groupId/TokenGenerator/
META-INF/maven/groupId/TokenGenerator/pom.xml
META-INF/maven/groupId/TokenGenerator/pom.properties

单罐内容:

META-INF/MANIFEST.MF
main/Route-1.0-SNAPSHOT.jar
lib/kotlin-stdlib-0.1-SNAPSHOT.jar
lib/kotlin-runtime-0.1-SNAPSHOT.jar
lib/spark-core-2.3.jar
lib/slf4j-api-1.7.12.jar
lib/slf4j-simple-1.7.12.jar
lib/jetty-server-9.3.2.v20150730.jar
...

【问题讨论】:

  • 您的问题中缺少重要信息。 merchant.id 位于源中的什么位置?您是否查看了胖罐子的内部并在那里也看到了这个文件?如果不存在,您是否查看过如何确保将资源复制到 fat jar 中?您是否阅读过其他 SO 文章,例如 stackoverflow.com/questions/5688329/…?还是stackoverflow.com/questions/23276836/…?
  • @JaysonMinard 是的,文件在那里——正如问题中所说——这从 intelliJ 执行得非常好。资源路径:/src/main/resources/ 代码路径:/src/main/java/Route.kt
  • 资源 merchant.id 是否在 onejar lib/ 目录中的 JAR 中? IE。您的 onejar 胖 JAR 是 myApp.jar,其中还有许多其他 JAR 文件在 lib/dependency1.jar lib/dependency2.jar 中,其中是您的 merchant.id 而不是顶级 jar?
  • (注意,与从平面文件系统运行的 intellij 相比,OneJar 完全改变了类和资源的打包内容和方式)
  • 当资源在胖 JAR 中的 JAR 中时,您会遇到以下问题:stackoverflow.com/questions/21361931/…stackoverflow.com/questions/941754/… 和...并且 onejar 使用自己的类加载器,而不是系统加载器您正在使用:stackoverflow.com/a/20636830/3679676

标签: kotlin onejar


【解决方案1】:

OneJar 将您的所有代码打包到一个 JAR 文件中,该文件还包含 lib/ 目录中的其他 JAR 文件,或者作为 JAR 外部其他目录中对它们的引用(取决于您使用的 onejar 系统)。它使用自定义类加载器来完成这项工作。因此,它使您无法使用系统类加载器。

解决此问题的一种方法是使用与您要加载的资源相同的 JAR 中的类,因此其类加载器可能已正确设置到 JAR 或嵌套 JAR 或魔术位置在你的资源的纳尼亚:

val stream = MyClass::class.java.getResourceAsStream("/merchant.id")

其中MyClass 是与merchant.id 来自同一个JAR 的类,资源的路径必须是绝对路径,前导/

确保获取 而不是资源 URL,因为它不是系统可以理解的 URL。它可以为 JAR 中的 JAR 生成一个其他 Java 无法理解的 URL,例如 file:/path/to/jarfile/bot.jar!/config/file.txt(或更糟!)。它可以工作,但我不确定它何时是 JAR 中的 JAR,其中包含文件。

次要选项:

val stream = Thread.currentThread().contextClassLoader.getResourceAsStream("/merchant.id")

检查您的资源名称:

在您的问题中,您说要读取资源 merchant.id,然后显示具有 merchant.id.soft.applepaydev-v1.csr 的 JAR 内容...如果您尝试加载此确切资源,请确保这些名称匹配。


必须自定义onejar中的资源加载,这很难看。 In a link to one resource that talks about resource loading with onejar

Java 支持查找和打开资源的方式有多种:

  • URL findResource(String resource):返回一个资源,如果没有找到则返回null。
  • 枚举 findResources(String resource):返回与给定字符串匹配的资源 URL 的枚举
  • URL.openConnection():通过 URL 打开到资源的连接。

One-Jar 在 One-Jar 文件的上下文中支持所有这些机制,其中可能包含具有重复资源的 Jar 文件。

这个问题是从这些其他 Stack Overflow 帖子中引用的,因此这几乎是一个重复的问题:

谷歌搜索会发现更多资源。

【讨论】:

  • 我所做的是添加另一个具有访问资源功能的类。然后使用MyClass::class.java.getResource
  • getResourcegetResourceAsStream ...有趣的是,如果 getResource 有效,那么我应该编辑我的答案。
  • 确实如此——我只是不想创建一个新类。但是 cotillon 中的 fun 不允许我这样做。
  • 您可以将main() 放在类的companion object 中,而不是让它进入默认创建的类,添加@JvmStatic 注释,它可以直接从您的新类运行.那么你两个都有。
猜你喜欢
  • 2019-08-29
  • 1970-01-01
  • 2017-04-06
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
  • 2020-03-02
  • 2012-12-04
  • 2013-02-18
相关资源
最近更新 更多