如何在Maven的Java项目中包含Clojure依赖。

huangapple go评论127阅读模式
英文:

How to include Clojure dependencies to a Java project with Maven

问题

我对JVM的所有事物都很陌生,想要开始一个涉及Clojure库的Java项目。我在这个问题上看到了如何从Java运行Clojure代码,但是在我尝试在mvn package之后运行jar文件时,variable Clojure会报错cannot find symbol。我的代码目前如下:

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后运行mvn -q exec

<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
...

更新 2

当您在pom.xml中的<plugins>部分添加以下片段后,似乎运行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>
英文:

I'm very new to all things JVM and want to start a Java project that involves a Clojure library as a dependency. I've seen this question on how to run Clojure code from Java, but when I try to run the jar file after mvn package, I get cannot find symbol for variable Clojure. My code looks like this so far:

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(&quot;clojure.core&quot;, &quot;+&quot;);
    }
}

So far, my pom file looks like this:

&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
  xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
  &lt;groupId&gt;org.example&lt;/groupId&gt;
  &lt;artifactId&gt;project&lt;/artifactId&gt;
  &lt;packaging&gt;jar&lt;/packaging&gt;
  &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
  &lt;name&gt;poi&lt;/name&gt;
  &lt;properties&gt;
    &lt;maven.compiler.source&gt;1.6&lt;/maven.compiler.source&gt;
    &lt;maven.compiler.target&gt;1.6&lt;/maven.compiler.target&gt;
  &lt;/properties&gt;
  &lt;url&gt;http://maven.apache.org&lt;/url&gt;
  &lt;repositories&gt;
    &lt;repository&gt;
      &lt;id&gt;clojars&lt;/id&gt;
      &lt;url&gt;https://repo.clojars.org/&lt;/url&gt;
      &lt;snapshots&gt;
        &lt;enabled&gt;true&lt;/enabled&gt;
      &lt;/snapshots&gt;
      &lt;releases&gt;
        &lt;enabled&gt;true&lt;/enabled&gt;
      &lt;/releases&gt;
    &lt;/repository&gt;
  &lt;/repositories&gt;
  &lt;build&gt;
  &lt;plugins&gt;
    &lt;plugin&gt;
      &lt;groupId&gt;com.theoryinpractise&lt;/groupId&gt;
      &lt;artifactId&gt;clojure-maven-plugin&lt;/artifactId&gt;
      &lt;version&gt;1.8.3&lt;/version&gt;
      &lt;extensions&gt;true&lt;/extensions&gt;
    &lt;/plugin&gt;
  &lt;/plugins&gt;
  &lt;/build&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;junit&lt;/groupId&gt;
      &lt;artifactId&gt;junit&lt;/artifactId&gt;
      &lt;version&gt;3.8.1&lt;/version&gt;
      &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.clojure&lt;/groupId&gt;
      &lt;artifactId&gt;clojure&lt;/artifactId&gt;
      &lt;version&gt;1.10.1&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;clj-python&lt;/groupId&gt;
      &lt;artifactId&gt;libpython-clj&lt;/artifactId&gt;
      &lt;version&gt;1.45&lt;/version&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/project&gt;

The clojure-maven-plugin seemed to download the dependencies (I watched the usual downloads fly up the screen), but still no luck on invoking Clojure after an import.

Ultimately, I hope to be able to reference libpython-clj from within Java.

Update

I tried Alan Thompson's answer and needed to run lein pom to get a pom.xml file. Then I needed to add the following to the pom at the project level to get it to mvn -q compile
&lt;properties&gt; &lt;maven.compiler.source&gt;1.6&lt;/maven.compiler.source&gt; &lt;maven.compiler.target&gt;1.6&lt;/maven.compiler.target&gt; &lt;/properties&gt;

However, at mvn -q exec gives me long stack trace ending with

[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 -&gt; [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$1.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

Update 2

It seems running mvn clean install &amp;&amp; java -jar target/&lt;whatever-it&#39;s called&gt;.jar works when you add the following snippet to the pom.xml within the &lt;plugins&gt; section.

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

答案1

得分: 2

Intro

我有一个使用lein构建的工作演示。至于Maven部分,在末尾有示例项目。

Using lein to build

文件:

~/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

然后使用java -jar运行Clojure主要部分或使用java -cp运行Java主要部分:

# 由`project.clj`中的`:main`键控制入口点 => Clojure的`demo.main/-main`函数
~/expr/demo > java -jar /Users/alanthompson/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar
:clj-main-enter
:clj-main-leave

# ***** 注意 `demo.Main` Java类名 *****
~/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

Update

刚刚尝试了Stuart Halloway的用Clojure构建的Maven示例

在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>

Update #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>
                    <!-- 在这里放置您的配置 -->
                    <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>

尽情享受!

英文:

Intro

I have a working demo for you using lein to build. For the Maven part, the example project at the end.


Using lein to build

Files:

~/expr/demo &gt; 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 &quot;0.1.0-SNAPSHOT&quot;
  :license {:name &quot;Eclipse Public License&quot;
            :url  &quot;http://www.eclipse.org/legal/epl-v10.html&quot;}
  :dependencies [[org.clojure/clojure &quot;1.10.2-alpha1&quot;]
                 [prismatic/schema &quot;1.1.12&quot;]
                 [tupelo &quot;20.07.01&quot;]]
    
  :profiles {:uberjar {:aot :all}}

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

  :source-paths            [&quot;src/clj&quot;]
  :java-source-paths       [&quot;src/java&quot;]
  :test-paths              [&quot;test/clj&quot;]
  :target-path             &quot;target/%s&quot;
  :compile-path            &quot;%s/class-files&quot;
  :clean-targets           [:target-path]

  :jvm-opts [&quot;-Xms500m&quot; &quot;-Xmx4g&quot; ]
)

Java source

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(&quot;java main - enter&quot;);
    IFn plus = Clojure.var(&quot;clojure.core&quot;, &quot;+&quot;);
    plus.invoke(1, 2);
    System.out.println(&quot;java main - leave&quot;);
  }
}

Clojure main

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

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

Clojure test

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

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

The Clojure part is straightforward using lein:

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

~/expr/demo &gt; lein test

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

lein test tst.demo.core
(Main/add2 2 3) =&gt; 5.0

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

We will use lein to build the uberjar:

~/expr/demo &gt; 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

then run either Clojure main using java -jar or Java main using java -cp

# Entrypoint controlled by `:main` key in `project.clj` =&gt; clojure `demo.main/-main` function
~/expr/demo &gt; 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 &gt; java \
  -cp /Users/alanthompson/expr/demo/target/uberjar/demo-0.1.0-SNAPSHOT-standalone.jar  \
  demo.Main   
java main - enter
java main - leave

Update

Just tried Stuart Halloway's Clojure Maven example.

It will crash with Java 14, so beware!

Results:

~/expr/demo/clojure-from-java &gt; java -version
openjdk version &quot;1.8.0_252&quot;
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 &gt; mvn  -q clean
~/expr/demo/clojure-from-java &gt; mvn  -q compile
~/expr/demo/clojure-from-java &gt; mvn  -q exec:java  -Dexec.mainClass=example.Main
fn says hello
file filter returns false
object toString returns &lt;object created Fri Jul 24 13:55:11 PDT 2020&gt;

Update #2

You can fix the problem with Java 14 if you update the pom.xml to output Java 1.8 features. Excerpt:

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

The part that matters is adding 1.8 here:

&lt;source&gt;1.8&lt;/source&gt;
&lt;target&gt;1.8&lt;/target&gt;

Enjoy!

huangapple
  • 本文由 发表于 2020年7月25日 03:40:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/63080434.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定