如何使用 Maven 将 Clojure 依赖项包含到 Java 项目中

How to include Clojure dependencies to a Java project with Maven

我对 JVM 的所有事物都很陌生,想开始一个涉及 Clojure 库作为依赖项的 Java 项目。我看过 this question 关于如何 运行 来自 Java 的 Clojure 代码,但是当我尝试 运行 mvn package 之后的 jar 文件时,我得到 cannot find symbol 对于 variable Clojure。到目前为止,我的代码如下所示:

package org.example;

import clojure.java.api.Clojure;
import clojure.lang.IFn;

public class App 
{
    public static void main( String[] args )
    {

        IFn plus = Clojure.var("clojure.core", "+");
    }
}

到目前为止,我的 pom 文件如下所示:

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>project</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>poi</name>
  <properties>
    <maven.compiler.source>1.6</maven.compiler.source>
    <maven.compiler.target>1.6</maven.compiler.target>
  </properties>
  <url>http://maven.apache.org</url>
  <repositories>
    <repository>
      <id>clojars</id>
      <url>https://repo.clojars.org/</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <releases>
        <enabled>true</enabled>
      </releases>
    </repository>
  </repositories>
  <build>
  <plugins>
    <plugin>
      <groupId>com.theoryinpractise</groupId>
      <artifactId>clojure-maven-plugin</artifactId>
      <version>1.8.3</version>
      <extensions>true</extensions>
    </plugin>
  </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure</artifactId>
      <version>1.10.1</version>
    </dependency>
    <dependency>
      <groupId>clj-python</groupId>
      <artifactId>libpython-clj</artifactId>
      <version>1.45</version>
    </dependency>
  </dependencies>
</project>

clojure-maven-plugin 似乎 下载依赖项(我看到通常的下载在屏幕上飞舞),但在调用 Clojure 之后仍然没有运气导入。

最终,我希望能够从Java.

中引用libpython-clj

更新

我尝试了 Alan Thompson 的回答,需要 运行 lein pom 来获取 pom.xml 文件。然后我需要在项目级别将以下内容添加到 pom 中以使其进入 mvn -q compile <properties> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties>

然而,在 mvn -q exec 给了我以

结尾的长堆栈跟踪
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:java (default-cli) on project demo: An exception occured while executing the Java class. example.Main -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:java (default-cli) on project demo: An exception occured while executing the Java class. example.Main
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:216)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.MojoExecutionException: An exception occured while executing the Java class. example.Main
    at org.codehaus.mojo.exec.ExecJavaMojo.execute(ExecJavaMojo.java:311)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
    ... 19 more
Caused by: java.lang.ClassNotFoundException: example.Main
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at org.codehaus.mojo.exec.ExecJavaMojo.run(ExecJavaMojo.java:246)
    at java.base/java.lang.Thread.run(Thread.java:834)
[ERROR]
[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/MojoExecutionException

更新 2

当您将以下代码片段添加到 <plugins> 部分中的 pom.xml 时,似乎 运行ning mvn clean install && java -jar target/<whatever-it's called>.jar 有效。

  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <mainClass>demo.Main</mainClass>
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
    <executions>
      <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      </execution>
    </executions>
  </plugin>

简介

我有一个工作演示供您使用 lein 进行构建。 Maven部分,示例工程在最后。


使用lein构建

文件:

~/expr/demo > ls -ldF  **/*.{java,clj}
-rwxr-xr-x  1 alanthompson  staff  904 Jul 24 13:25 project.clj*
-rw-r--r--  1 alanthompson  staff  130 Jul 24 13:24 src/clj/demo/core.clj
-rw-r--r--  1 alanthompson  staff  373 Jul 24 13:17 src/java/demo/Main.java
-rw-r--r--  1 alanthompson  staff  129 Jul 24 13:20 test/clj/tst/demo/core.clj

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"]
                 [prismatic/schema "1.1.12"]
                 [tupelo "20.07.01"]]
    
  :profiles {:uberjar {:aot :all}}

  :global-vars {*warn-on-reflection* false}
  :main demo.core   ;  when use ^:skip-aot   ???

  :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" ]
)

Java 来源

package demo;
import clojure.java.api.*;
import clojure.lang.IFn;

public class Main {
  public static double add2(double x, double y) {
    return (x + y);
  }

  public static void main(String[] args) {
    System.out.println("java main - enter");
    IFn plus = Clojure.var("clojure.core", "+");
    plus.invoke(1, 2);
    System.out.println("java main - leave");
  }
}

Clojure 主程序

(ns demo.core
  (:use tupelo.core)
  (:gen-class))

(defn -main [& args]
  (println :clj-main-enter)
  (println :clj-main-leave))

Clojure 测试

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:import [demo Main])
  (:gen-class))

(dotest
  (spyx (Main/add2 2 3)))

Clojure 部分使用 lein 很简单:

~/expr/demo > lein clean; lein run
:clj-main-enter
:clj-main-leave

~/expr/demo > lein test

------------------------------------------
   Clojure 1.10.2-alpha1    Java 14.0.1
------------------------------------------

lein test tst.demo.core
(Main/add2 2 3) => 5.0

Ran 2 tests containing 0 assertions.
0 failures, 0 errors.

我们将使用 lein 构建 uberjar:

~/expr/demo > lein uberjar
Compiling demo.core
Created /Users/alanthompson/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT.jar
Created /Users/alanthompson/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar

然后 运行 Clojure main 使用 java -jar 或 Java main 使用 java -cp

# Entrypoint controlled by `:main` key in `project.clj` => clojure `demo.main/-main` function
~/expr/demo > java -jar /Users/alanthompson/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar
:clj-main-enter
:clj-main-leave

# ***** notice `demo.Main` Java class name *****
~/expr/demo > java \
  -cp /Users/alanthompson/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar  \
  demo.Main   
java main - enter
java main - leave

更新

刚试过 Stuart Halloway 的 Clojure Maven example

它将在 Java 14 时崩溃,所以要小心!

结果:

~/expr/demo/clojure-from-java > java -version
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.252-b09, mixed mode)

~/expr/demo/clojure-from-java > mvn  -q clean
~/expr/demo/clojure-from-java > mvn  -q compile
~/expr/demo/clojure-from-java > mvn  -q exec:java  -Dexec.mainClass=example.Main
fn says hello
file filter returns false
object toString returns <object created Fri Jul 24 13:55:11 PDT 2020>

更新 #2

如果更新 pom.xml 以输出 Java 1.8 功能,则可以解决 Java 14 的问题。摘录:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!-- put your configurations here -->
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
    <sourceDirectory>src/java</sourceDirectory>
    <resources>
        <resource>
            <directory>src/clojure</directory>
        </resource>
    </resources>
</build>

重要的部分是在此处添加 1.8

<source>1.8</source>
<target>1.8</target>

尽情享受吧!