0

I'd like to use Clojure code within Java. The Clojure code itself should implement a Java-interface (TestGenClassInterface).

My project.clj is:

(defproject com.stackoverflow.clojure/tests "0.1.0-SNAPSHOT"
  :description "Tests of Clojure test-framework."
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [instaparse "1.3.4"]]
  :source-paths      ["src/main/clojure"]
  :java-source-paths ["src/main/java"]
  :test-paths        ["src/test/clojure"]
  :java-test-paths   ["src/test/java"]
  ;:aot :all
  )

The Java interface looks like this:

package com.stackoverflow.clojure;

public interface TestGenClassInterface {

    public String addToString(String text, String appendText);

}

The Clojure code is:

(ns com.stackoverflow.clojure.testGenClass
  (:gen-class
     :name com.stackoverflow.clojure.TestGenClass
     :implements com.stackoverflow.clojure.TestGenClassInterface
     :prefix "java-"))

(def ^:private pre "START: ")

(defn java-addToString [this text post]
  (str pre text post))

(java-addToString "TexT" " :END")

I expected, that after running lein compile or "Run as Clojure-Application" in eclipse+CounterClockwise a .class file (named TestGenClass.class) is generated an saved within *compile-path* (here: target/classes/com/stackoverflow/clojure/). Unfortunately it's not.

When adding :aot :all to my project.clj, I get the following stacktrace:

Compiling com.stackoverflow.clojure.testGenClass
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling:(com/stackoverflow/clojure/testGenClass.clj:1:1)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6651)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5782)
    at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2191)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6644)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5782)
    at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5217)
    at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3846)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6642)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6632)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3665)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6646)
    at clojure.lang.Compiler.analyze(Compiler.java:6445)
    at clojure.lang.Compiler.analyze(Compiler.java:6406)
    at clojure.lang.Compiler.compile1(Compiler.java:7221)
    at clojure.lang.Compiler.compile1(Compiler.java:7216)
    at clojure.lang.Compiler.compile(Compiler.java:7292)
    at clojure.lang.RT.compile(RT.java:398)
    at clojure.lang.RT.load(RT.java:438)
    at clojure.lang.RT.load(RT.java:411)
    at clojure.core$load$fn__5066.invoke(core.clj:5641)
    at clojure.core$load.doInvoke(core.clj:5640)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5446)
    at clojure.core$compile$fn__5071.invoke(core.clj:5652)
    at clojure.core$compile.invoke(core.clj:5651)
    at user$eval9.invoke(form-init4595004281107083893.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6693)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at clojure.lang.Compiler.loadFile(Compiler.java:7086)
    at clojure.main$load_script.invoke(main.clj:274)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invoke(main.clj:307)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.doInvoke(main.clj:420)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
    at clojure.lang.RT.seqFrom(RT.java:505)
    at clojure.lang.RT.seq(RT.java:486)
    at clojure.core$seq.invoke(core.clj:133)
    at clojure.core$map$fn__4245.invoke(core.clj:2551)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.RT.seq(RT.java:484)
    at clojure.core$seq.invoke(core.clj:133)
    at clojure.core$map$fn__4245.invoke(core.clj:2551)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.Cons.next(Cons.java:39)
    at clojure.lang.RT.boundedLength(RT.java:1654)
    at clojure.lang.RestFn.applyTo(RestFn.java:130)
    at clojure.core$apply.invoke(core.clj:624)
    at clojure.core$mapcat.doInvoke(core.clj:2586)
    at clojure.lang.RestFn.invoke(RestFn.java:423)
    at clojure.core$generate_class.invoke(genclass.clj:164)
    at clojure.core$gen_class.doInvoke(genclass.clj:638)
    at clojure.lang.RestFn.invoke(RestFn.java:1557)
    at clojure.lang.Var.invoke(Var.java:519)
    at clojure.lang.AFn.applyToHelper(AFn.java:270)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.lang.Compiler.macroexpand1(Compiler.java:6552)
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6630)
    ... 46 more
Compilation failed: Subprocess failed
Edward
  • 4,453
  • 8
  • 44
  • 82
  • Shouldn't you prefix method names with `-`? – Marko Topolnik Oct 15 '14 at 15:21
  • @MarkoTopolnik You're right. I added the prefix to my code. But still no class file is generated. – Edward Oct 15 '14 at 15:29
  • 1
    You need to add `:aot :all` to project.clj. See `lein sample` for more info. – Marko Topolnik Oct 15 '14 at 15:46
  • @MarkoTopolnik adding `:aot :all` gives the error I added to my question. – Edward Oct 16 '14 at 11:20
  • 1
    Well, that sounds like you're finally compiling your namespace into a class. You have a syntax error now, coming from a symbol at a place where a collection is expected. My guess: `:implements` takes a vector, not a single symbol. – Marko Topolnik Oct 16 '14 at 11:46
  • @MarkoTopolnik It was the missing `AOT`, the fact that `:implements` takes a vector and the missing this ( @G_A ). Can anyone of you write an answer out of it, so that I can accept it? – Edward Oct 16 '14 at 14:37

3 Answers3

1

According to http://clojure.org/compilation

... the implementation functions for instance methods will always take an additional first arg corresponding to the object the method is called upon, called by convention 'this' here.

Try adding 'this' to each function definition.

(defn java-addToString [this text post]
  ...
GregA100k
  • 1,385
  • 1
  • 11
  • 16
  • 1
    Adding this did not change anything. There is also no error message shown (e.g. when running `lein compile`). It is really annoying when **nothing** happens - at least an error would be great. – Edward Oct 16 '14 at 10:18
1

The proximate issue you have is a missing :aot :all in your project.clj file. Without that the ahead-of-time compilation will not be attempted.

Once you put that in, you'll have the following further issues:

  • you must prefix the names of the functions designated to become Java methods (default prefix is -);

  • you must include this as an explicit first argument of each such method (this is the recommended convention, but any name is acceptable);

  • you must correct your :implements clause: it takes a vector as the value, even if it has a single member.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
0

http://clojure.org/compilation mentions the compilation process makes use of

... *compile-path*, which must be in the classpath

The default location is a classes folder.

The second answer to Stack Overflow question Compiling Clojure? mentions that this path is relative to the jvm startup folder. If you did lein repl from the main project folder (the folder where project.clj lives) then creating a classes folder there should make it work.

Community
  • 1
  • 1
GregA100k
  • 1,385
  • 1
  • 11
  • 16