简体   繁体   中英

java mixed with clojure in maven and eclipse

i created a sample polyglot program. i have a sensor and a robot implemented in java and AI implemented in clojure. and i can't connect maven properly

--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();
    }
}

i can even manually force maven to compile it: mvn clean clojure:compile produces error - no DistanceSensor class (but for some reason creates AI.class). so then mvn compile sees AI.class and compiles everything correctly and tests pass. but what can i do to make mvn clean compile pass? how should my pom.xml look like? also what can i do to make eclipse stop complaining about non existing AI.class?

You need to change layout of source code in your project. Clojure maven plugin requires, that clojure code went to separate directory, so you should have following layout:

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

More details you can find in following article

You have an inter-dependency between Java code and Clojure code. No matter which type of classes you'll compile first, you'll get an error.

Since it's not an actual cyclic dependency, you can still fix this by splitting the Java compilation part in two.

First, compile DistanceSensor , which doesn't depend on anything else.

Second, compile AI , which depends on DistanceSensor .

Finally, compile Robot which depends on AI .

To split the java compilation in two steps, you need to configure the default execution of the maven-compiler-plugin so that it excludes Robot , and add another execution after the clujure:compile goal that excludes DistanceSensor . You'll probably have to misuse the phases to properly order the three executions.

I think :gen-class is usually a code smell, as is trying to instantiate such a class from Java code with new AI() .

Here's an alternative approach that can solve this problem of cyclic dependencies:

  1. Define AI as a Java interface in your Java code
  2. Write a Clojure function to create an instance conforming to the interface using reify
  3. Dynamically invoke the Clojure function from Java (eg using the technique outlined in this blog post )
  4. You now have an instance of the AI interface that you can use however you like in Java

The advantage is this approach is that everything will work smoothly, in particular:

  • The Java code base can be compiled independently of the Clojure code
  • The Clojure code base can access all the defined Java classes and interfaces
  • You don't need any special IDE / Maven config. In fact, you can treat is as just a regular Java app that happens to include clojure.jar as a dependency.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM