【问题标题】:Lein fails to add jars to uberjarLein 无法将罐子添加到 uberjar
【发布时间】:2018-06-23 08:13:16
【问题描述】:

我正在构建一个简单的 Web 应用程序,它依赖于几个预编译的 jars,并且我想部署在 Heroku 上。我将罐子放入resources 文件夹,并将以下几行添加到我的project.clj

:resource-paths ["resources/jsesh-6.5.5.jar"
                 "resources/jseshGlyphs-6.5.5.jar"
                 "resources/java-cup-11b-runtime.jar"
                 "resources/java-cup-11b.jar"
                 "resources/qenherkhopeshefUtils-6.5.5.jar"]

现在我可以使用lein run -m hieroglyphs.web 运行项目;但是,当我使用 lein uberjar 编译所有内容并尝试时

java -cp ./target/hieroglyphs-standalone.jar clojure.main -m hieroglyphs.web

程序启动,但在尝试访问这些 jar 中定义的类之一时崩溃并出现 java.lang.NoClassDefFoundError

java.lang.NoClassDefFoundError: jsesh/mdcDisplayer/preferences/DrawingSpecification

我是否应该做一些额外的事情,以便在编译后可以访问 jar 中定义的类?

所有代码都可以在这里找到:https://github.com/macleginn/jsesh-web

【问题讨论】:

    标签: java jar clojure leiningen uberjar


    【解决方案1】:

    您应该更改您的 java 调用以使用 -jar 选项,如下所示:

    ~/expr/rundir > java -jar ./calc-0.1.0-SNAPSHOT-standalone.jar 
    main - enter
      (ac/add2 3 5) => 8
    main - leave
    

    对于看起来像这样的代码:

    calc
    ├── project.clj
    ├── resources
    │   └── adder.jar
    └── src
        ├── calc
        │   └── core.clj
    
    ~/expr/calc > cat src/calc/core.clj 
    (ns calc.core
      "Contains the core functions for namespace `calc.core`."
      (:require [adder.core :as ac] )
      (:gen-class))
    
    (defn -main []
      (println "main - enter")
      (println (ac/add2 3 5))
      (println "main - leave"))
    

    文件adder.jar 是使用来自另一个具有单一功能的项目的lein jar 创建的:

    (ns adder.core)
    (defn add2 [x y]
      (+ x y))
    

    生成的文件重命名为“adder.jar”并放入calc 项目的resources 目录中。看着project.clj

    (defproject calc  "0.1.0-SNAPSHOT"
      :description    "FIXME: write description"
      :url            "http://example.com/FIXME"
      :license {:name "Eclipse Public License"
                :url  "http://www.eclipse.org/legal/epl-v10.html"}
      :dependencies [
        [org.clojure/clojure "1.9.0"]
        [org.clojure/test.check "0.9.0"]
        [prismatic/schema "1.1.7"]
        [tupelo "0.9.71"]
      ]
      :profiles {:dev {:dependencies []
                       :plugins [
                         [com.jakemccrary/lein-test-refresh "0.22.0"] ] }
                 :uberjar {:aot :all}}
      :global-vars {*warn-on-reflection* false}
      :main ^:skip-aot calc.core
    
      :source-paths       ["src"]
      :test-paths         ["src"]
      :resource-paths     ["resources/adder.jar"]
      :target-path        "target/%s"
      :jvm-opts           ["-Xms500m" "-Xmx2g"]
    )
    

    诀窍在于:resource-paths,如下所示:

    :resource-paths     [ "resources/adder.jar" ]
    

    您需要在向量中单独列出每个*.jar 文件作为字符串。请注意,以下将不起作用

    :resource-paths     [ "resources" ]            ; does not find *.jar files
    :resource-paths     [ "resources/*.jar" ]      ; wildcards do not work
    :resource-paths     [  resources/adder.jar ]   ; without quotes fails
    

    然后我们可以为 calc 项目创建一个 uberjar,其中将包含来自 adder.jar 的内容:

    ~/expr/calc > lein uberjar
    Compiling _bootstrap
    Compiling calc.core
    Compiling tst.calc.core
    Created /home/alan/expr/calc/target/uberjar/calc-0.1.0-SNAPSHOT.jar
    Created /home/alan/expr/calc/target/uberjar/calc-0.1.0-SNAPSHOT-standalone.jar
    

    您想为您的 uberjar 使用 *-standalone.jar 版本。我们将其复制到一个空目录以验证它是否有效:

    ~/expr/calc > mkdir -p ../rundir
    ~/expr/calc > cp target/uberjar/calc-0.1.0-SNAPSHOT-standalone.jar ../rundir
    
    ~/expr/calc > cd ../rundir
    ~/expr/rundir > ls -al
    total 11744
    drwxrwxr-x 2 alan alan     4096 Jan 14 19:22 .
    drwxrwxr-x 5 alan alan     4096 Jan 14 19:22 ..
    -rw-rw-r-- 1 alan alan 12016027 Jan 14 19:30 calc-0.1.0-SNAPSHOT-standalone.jar
    
    ~/expr/rundir > java -jar calc-0.1.0-SNAPSHOT-standalone.jar 
    main - enter
      (ac/add2 3 5) => 8
    main - leave
    

    【讨论】:

      【解决方案2】:

      仅仅拥有一个资源目录并没有帮助。您将需要一个适当的本地 Maven 存储库。幸运的是,制作一个并不难。

      步骤:

      1. Install Maven 如果需要
      2. 在您的源代码库中创建一个lib 文件夹
      3. :repositories {"local" "file:lib"} 添加到您的project.clj
      4. 为每个依赖项运行类似mvn deploy:deploy-file -Dfile=resources/jsesh-6.5.5.jar -DartifactId=jsesh -Dversion=6.5.5 -DgroupId=jsesh -Dpackaging=jar -Durl=file:lib 的内容(适用于 jsesh jar)。请特别注意 artifactIdgroupIdversion
      5. 为每个罐子添加适当的:dependencies 项目。例如对于我在第 4 步中所做的那个,[jsesh/jsesh "6.5.5"]
      6. 对每个依赖项重复第 4 步和第 5 步

      您需要将lib 文件夹提交到源代码管理,但现在可以从project.clj 中删除resources 文件夹和:resource-paths

      (主要基于 https://gist.github.com/stuartsierra/3062743 的笔记)

      【讨论】:

      • 事实上,事实证明你可以在没有 Maven 的情况下做到这一点。将:respositories 位替换为:repositories {"local" {:url "file:lib" :username "" :password ""}} 并为步骤4 运行lein deploy local jshesh 6.5.5 resources/jsesh-6.5.5.jar(根据需要更改)
      • 您不需要 maven 或本地 maven repo。只需正确使用:resource-paths,然后使用java -jar xyz-standalone.jar运行即可
      猜你喜欢
      • 2012-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 1970-01-01
      • 2016-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多