【问题标题】:Package Clojure and Java source codes into a JAR file with Maven使用 Maven 将 Clojure 和 Java 源代码打包成 JAR 文件
【发布时间】:2021-04-01 12:23:06
【问题描述】:

我想在我的 Java 应用程序中使用 Clojure 代码:

; clj.clj
(ns utils
  (:gen-class
    :name clj.Clj
    :methods [#^{:static true} [clj [] String]])

(defn -clj []
  "Hello from Clojure!")
// Java.java
package main;

import clj.Clj;

public class Java {
    public static void main(String[] args) {
        System.out.println("Java main");
        System.out.println(Clj.clj());
    }
}

当我运行 JAR 文件时,我想要输出:

Java main
Hello from Clojure!

如何编译 Clojure 和 Java 文件并使用 Maven 将它们打包成可运行的 JAR 文件?


更新:
这是我拥有的当前代码:
<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <groupId>com.github.loadingbg</groupId>
  <artifactId>proj</artifactId>
  <version>1.0.0</version>
  
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  
  <build>
    <plugins>
      <!-- Clojure Compiler -->
      <plugin>
        <groupId>com.theoryinpractise</groupId>
        <artifactId>clojure-maven-plugin</artifactId>
        <version>1.8.4</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <namespaces>
            <namespace>utils</namespace>
          </namespaces>
          <compileDeclaredNamespaceOnly>true</compileDeclaredNamespaceOnly>
          <sourceDirectories>
            <sourceDirectory>src/main/clojure</sourceDirectory>
          </sourceDirectories>
        </configuration>
      </plugin>
      
      <!-- Maven Compiler -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>11</source>
          <target>11</target>
        </configuration>
      </plugin>
      
      <!-- Maven Assembly Plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.3.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>proj.Main</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
      
      <!-- Maven Shade Plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.4</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <minimizeJar>true</minimizeJar>
          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
              <mainClass>proj.Main</mainClass>
            </transformer>
          </transformers>
        </configuration>
      </plugin>
    </plugins>
  </build>
  
  <dependencies>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure</artifactId>
      <version>1.10.0</version>
    </dependency>
  </dependencies>
</project>
; /src/main/clojure/utils.clj
(ns utils
  (:gen-class
    :name utils.Utils
    :methods [#^{:static true} [clj [] String]]))

(defn -clj []
  "Hello from clojure")
// /src/main/java/pack/Main.java
package proj;

import utils.Utils;

public class Main {
    public static void main(String[] args) {
        System.out.println("Starting");
        System.out.println(Utils.clj());
    }
}

我在运行mvn clean install 时得到以下信息:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.google.inject.internal.cglib.core.$ReflectUtils$1 (file:/usr/share/maven/lib/guice.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.google.inject.internal.cglib.core.$ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< com.github.loadingbg:bot >----------------------
[INFO] Building bot 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ bot ---
[INFO] Deleting /home/loadingbg/proj/target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ bot ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/loadingbg/proj/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ bot ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/loadingbg/proj/target/classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /home/loadingbg/proj/src/main/java/proj/Main.java:[3,13] package utils does not exist
[ERROR] /home/loadingbg/proj/src/main/java/proj/Main.java:[8,28] cannot find symbol
  symbol:   variable Utils
  location: class proj.Main
[INFO] 2 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.136 s
[INFO] Finished at: 2020-12-22T22:36:42+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project
 bot: Compilation failure: Compilation failure:
[ERROR] /home/loadingbg/proj/src/main/java/proj/Main.java:[3,13] package utils does not exist
[ERROR] /home/loadingbg/proj/src/main/java/proj/Main.java:[8,28] cannot find symbol
[ERROR]   symbol:   variable Utils
[ERROR]   location: class proj.Main
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

它只是拒绝承认从 Clojure 文件生成的类。 utils.clj 应该生成具有静态方法 Utils#clj()utils.Utils 类,该方法返回一个字符串。
我看到将clojure-maven-plugin 移动到maven-compiler-plugin 上方会有所帮助,但没有。关键是让clojure-maven-pluginmaven-compiler-plugin 之前执行,但事实并非如此。如何重新排序插件执行顺序,这会有所帮助吗?


更新 2(回应 Alan Thompson):
我在新的 Leiningen 项目中复制了之前的代码,但出现此错误:
Compiling 1 source files to /home/loadingbg/proj/target/default/class-files
/home/loadingbg/proj/src/java/proj/Main.java:3: error: package utils does not exist
import utils.Utils;
            ^
/home/loadingbg/proj/src/java/proj/Main.java:8: error: cannot find symbol
        System.out.println(Utils.clj());
                           ^
  symbol:   variable Utils
  location: class Main
2 errors
Compilation of Java sources(lein javac) failed.

我错过了什么吗?我复制了project.clj

【问题讨论】:

    标签: java maven clojure clojure-java-interop


    【解决方案1】:

    This project 展示了如何使用 Leiningen 轻松做到这一点。只需输入 lein clean; lein jar 并选择要部署的 uberjar。

    project.clj 包含详细信息:

    (defproject demo "0.1.0-SNAPSHOT"
      :license {:name "Eclipse Public License"
                :url  "http://www.eclipse.org/legal/epl-v10.html"}
      :dependencies [
                     [org.clojure/clojure "1.10.2-alpha1"]
                     [org.clojure/spec.alpha "0.2.187"]
                     [prismatic/schema "1.1.12"]
                     [tupelo "20.08.27"]
                     ]
      :plugins [
                [com.jakemccrary/lein-test-refresh "0.24.1"]
                [lein-ancient "0.6.15"]
                [lein-codox "0.10.7"]
                ]
    
      :db "jdbc:postgresql://localhost/default"
      :settings "settings-default.edn"
    
      :profiles {:dev     {:dependencies []}
                 :uberjar {:aot :all}}
    
      :global-vars {*warn-on-reflection* false}
      :main ^:skip-aot demo.core
    
      :source-paths ["src/clj"]
      :java-source-paths ["src/java"]
      :test-paths ["test/clj"]
      :target-path "target/%s"
      :compile-path "%s/class-files"
      :clean-targets [:target-path]
    
      :jvm-opts ["-Xms500m" "-Xmx4g"]
      )
    

    确保您的代码符合预期的布局:

    ~/expr/demo > tree src
    src
    ├── clj
    │   └── demo
    │       └── core.clj
    └── java
        └── demo
            └── Calc.java
    

    运行测试:

    > lein clean ; lein test
    Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
    Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
    Compiling 1 source files to /home/alan/expr/demo/target/default+test+test/class-files
    
    lein test _bootstrap
    
    -------------------------------
       Clojure 1.10.1    Java 15
    -------------------------------
    
    lein test tst.demo.core
    (demo.Calc/theAnswer) => 42
    

    制作一个超级罐子:

     > lein uberjar
    Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
    Compiling 1 source files to /home/alan/expr/demo/target/uberjar/class-files
    Compiling demo.core
    Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method, or the namespace has not been AOT-compiled.
    Created /home/alan/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT.jar
    Created /home/alan/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar
    

    单元测试甚至使用 Java 互操作:

    (ns tst.demo.core
      (:use demo.core tupelo.core tupelo.test))
    
    (dotest
      (is= 42 (spyx (demo.Calc/theAnswer))))
    

    【讨论】:

    • 检查更新 2. 评论不是发送日志的最佳位置,所以我进行了更新。
    • 如果您想运行上述测试等,我做了一个小改动。重新开始并克隆到一个新的干净目录。
    • 我仍然得到错误。 Java源无法编译,因为它找不到应该由Clojure文件生成的utils.Utils包。
    猜你喜欢
    • 2019-06-18
    • 1970-01-01
    • 2017-08-07
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 2016-12-18
    • 1970-01-01
    相关资源
    最近更新 更多