Как включить зависимости Clojure в проект Java с помощью Maven

Я очень новичок во всех вещах JVM и хочу начать проект Java, который включает библиотеку Clojure в качестве зависимости. Я видел этот вопрос о том, как запустить код Clojure из Java, но когда я пытаюсь запустите файл jar после mvn package, я получаю 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 после импорта.

В конечном счете, я надеюсь, что смогу ссылаться на libpython-clj из Java.

Обновлять

Я попробовал ответ Алана Томпсона, и мне нужно было запустить 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$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

Обновление 2

Кажется, запуск mvn clean install && java -jar target/<whatever-it's called>.jar работает, когда вы добавляете следующий фрагмент в pom.xml в разделе <plugins>.

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

person Alex Eftimiades    schedule 24.07.2020    source источник
comment
Не уверен, загружает ли плагин Clojure maven зависимости для самого Clojure. Вам нужно будет добавить как минимум две дополнительные зависимости (фрагменты pom в ссылках): mvnrepository.com/artifact/org.clojure/core.specs.alpha/0.2.44 и mvnrepository.com/artifact/org.clojure/spec.alpha/0.2.176   -  person Denis Fuenzalida    schedule 25.07.2020


Ответы (1)


вступление

У меня есть рабочая демонстрация для вас, использующая 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

проект.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

Обновлять

Только что попробовал пример 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>

Обновление №2

Вы можете решить проблему с Java 14, если обновите pom.xml для вывода функций Java 1.8. Выдержка:

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

Наслаждаться!

person Alan Thompson    schedule 24.07.2020
comment
Пожалуйста, обновите свой вопрос, указав эту информацию, а затем удалите эти комментарии. - person Alan Thompson; 25.07.2020