【问题标题】:java mixed with clojure in maven and eclipsejava在maven和eclipse中与clojure混合
【发布时间】:2013-01-01 12:55:13
【问题描述】:

我创建了一个示例多语言程序。我有一个用 java 实现的传感器和一个机器人,以及用 clojure 实现的 AI。我无法正确连接 maven

--src/main/java/clojuretest
                          |
                           DistanceSensor.java
                           AI.clj       (uses DistanceSensor)
                           Robot.java   (uses AI)

DistanceSensor.java:

package clojuretest;

public class DistanceSensor {

    public int getValue() {return 5;}
}

AI.clj:

(ns clojuretest.AI
  (:gen-class :methods [[isObstacleAhead [] boolean]]))

(defn -isObstacleAhead [this] (< (.getValue (clojuretest.DistanceSensor.)) 10))

Robot.java:

package clojuretest;

public class Robot {

    public boolean shouldStop() {
        return new AI().isObstacleAhead();
    }
}

我什至可以手动强制 maven 编译它: mvn clean clojure:compile 产生错误 - 没有 DistanceSensor 类(但由于某种原因创建了 AI.class)。那么那么 mvn compile 看到 AI.class 并正确编译所有内容并通过测试。但是我该怎么做才能让mvn clean compile 通过?我的 pom.xml 应该是什么样子?我还能做些什么来让 eclipse 停止抱怨不存在的 AI.class?

【问题讨论】:

    标签: java eclipse maven clojure interop


    【解决方案1】:

    您需要更改项目中源代码的布局。 Clojure maven 插件要求,该 clojure 代码位于单独的目录中,因此您应该具有以下布局:

     src/
        main/
          java/
            java-code
          clojure/
            clojure code
        test/
          java/
            java tests code
          clojure/
            clojure tests code
    

    您可以在following article找到更多详细信息

    【讨论】:

    • 这不是问题。我将 clojure-maven-plugin 源设置为 src/main/java。但即使按照你的建议改变了结构,我仍然有同样的错误。当 clojure:compile 首先完成时,没有找到 DistanceSensor.class。如果先完成 java 编译,则找不到 AI.class
    • 对不起,错误地阅读了您的问题。请看我对 Sergiu 的回答的 cmets
    【解决方案2】:

    我认为:gen-class 通常是一种代码味道,就像尝试使用 new AI() 从 Java 代码中实例化这样的类一样。

    这是一种可以解决循环依赖问题的替代方法:

    1. 在您的 Java 代码中将 AI 定义为 Java 接口
    2. 写一个Clojure函数来创建一个符合使用reify的接口的实例
    3. 从 Java 动态调用 Clojure 函数(例如,使用 this blog post 中概述的技术)
    4. 您现在有了一个 AI 接口实例,您可以在 Java 中随意使用它

    这种方法的优点是一切都会顺利进行,尤其是:

    • Java 代码库可以独立于 Clojure 代码进行编译
    • Clojure 代码库可以访问所有已定义的 Java 类和接口
    • 您不需要任何特殊的 IDE / Maven 配置。实际上,您可以将 is 视为恰好包含 clojure.jar 作为依赖项的常规 Java 应用程序。

    【讨论】:

      【解决方案3】:

      Java 代码和 Clojure 代码之间存在相互依赖关系。不管你先编译哪种类型的类,都会报错。​​

      由于它不是实际的循环依赖,您仍然可以通过将 Java 编译部分一分为二来解决此问题。

      首先,编译DistanceSensor,它不依赖其他任何东西。

      其次,编译AI,它依赖于DistanceSensor

      最后,编译依赖AIRobot

      要将java编译分成两步,你需要配置maven-compiler-plugin的默认执行,使其excludesRobot,并在clujure:compile目标之后添加另一个执行,排除DistanceSensor。您可能不得不误用 phases 来正确排序三个执行。

      【讨论】:

      • 也许可以在generate-sources阶段使用maven-antrun-plugin先编译DistanceSensor,然后再编译其余部分。
      • 另一种可能的解决方案是将项目拆分为子模块,并使用提供相应的执行顺序。在 Leiningen 中,可以使用钩子在其他任务之前执行一些任务,我不确定 Maven 中的这种可能性(尽管有 Invoker 插件能够在阶段之前和/或之后运行一些脚本
      • 但是我将不得不排除所有依赖于机器人的类。更重要的是,可能有很多层调用clojure的java,反之亦然。而且我担心使用自动构建系统毫无意义,因为一切都必须手动完成。 java 可以编译类,即使它们之间存在循环。 lein 不能以某种方式对 java 和 clojure 做同样的事情吗?
      • 确实,将项目拆分为模块是更好的方法。如果您只是为了混合语言而混合语言,那么您并没有做一些有用的事情。但是,如果您确实需要/想要用不同的语言编写程序的不同部分(为每项工作使用最好的工具),那么您应该正确考虑应该如何组织您的项目,并且应该可以有单独的层,而它们之间没有相互依赖关系。
      • 一种选择是将接口与实际实现分离,使接口不依赖于上层,实际实现只依赖于其他接口。这样一来,相互依赖关系就被隐藏起来了,并且只会在运行时,当所有类都被编译时才会显现出来。
      猜你喜欢
      • 2018-03-08
      • 2012-11-02
      • 2014-10-17
      • 1970-01-01
      • 2016-02-23
      • 2011-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多