英文:
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("clojure.core", "+");
}
}
So far, my pom file looks like this:
<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>
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
<properties> <maven.compiler.source>1.6</maven.compiler.source> <maven.compiler.target>1.6</maven.compiler.target> </properties>
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 -> [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 && java -jar target/<whatever-it's called>.jar
works when you add the following snippet to the pom.xml within the <plugins>
section.
<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>
答案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 > 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 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("java main - enter");
IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);
System.out.println("java main - leave");
}
}
Clojure main
(ns demo.core
(:use tupelo.core)
(:gen-class))
(defn -main [& 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 > 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.
We will use lein to build the 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
then run either Clojure main using java -jar
or Java main using 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
Update
Just tried Stuart Halloway's Clojure Maven example.
It will crash with Java 14, so beware!
Results:
~/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
You can fix the problem with Java 14 if you update the pom.xml
to output Java 1.8 features. Excerpt:
<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>
The part that matters is adding 1.8
here:
<source>1.8</source>
<target>1.8</target>
Enjoy!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论