【问题标题】:Gen-Class does not generate a .class fileGen-Class 不生成 .class 文件
【发布时间】:2014-10-15 14:40:55
【问题描述】:

我想在 Java 中使用 Clojure 代码。 Clojure 代码本身应该实现一个 Java 接口 (TestGenClassInterface)。

我的 project.clj 是:

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

Java 界面如下所示:

package com.stackoverflow.clojure;

public interface TestGenClassInterface {

    public String addToString(String text, String appendText);

}

Clojure 代码是:

(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")

我预计,在 eclipse+CounterClockwise 中运行 lein compile 或“作为 Clojure-Application 运行”之后,会生成一个 .class 文件(名为 TestGenClass.class)并保存在 *compile-path* 中(此处为:target/classes/com /stackoverflow/clojure/)。可惜不是。

:aot :all 添加到我的project.clj 时,我得到以下堆栈跟踪:

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

【问题讨论】:

  • 你不应该在方法名前加上-吗?
  • @MarkoTopolnik 你是对的。我在我的代码中添加了前缀。但仍然没有生成类文件。
  • 需要在project.clj中添加:aot :all。请参阅lein sample 了解更多信息。
  • @MarkoTopolnik 添加 :aot :all 给出了我添加到问题中的错误。
  • 嗯,听起来您终于将命名空间编译成一个类。您现在有一个语法错误,来自预期集合位置的符号。我的猜测::implements 接受向量,而不是单个符号。

标签: java interface clojure gen-class


【解决方案1】:

您遇到的最接近的问题是您的project.clj 文件中缺少:aot :all。否则,将不会尝试提前编译。

一旦你把它放进去,你会遇到以下进一步的问题:

  • 您必须在指定为Java方法的函数名称前加上前缀(默认前缀为-);

  • 您必须将this 作为每个此类方法的显式第一个参数包含(this 是推荐的约定,但任何名称都可以接受);

  • 您必须更正您的 :implements 子句:它采用 vector 作为值,即使它只有一个成员。

【讨论】:

    【解决方案2】:

    根据http://clojure.org/compilation

    ... 实例方法的实现函数将始终采用 与调用该方法的对象相对应的附加第一个参数 上,这里按惯例称为“this”。

    尝试在每个函数定义中添加“this”。

    (defn java-addToString [this text post]
      ...
    

    【讨论】:

    • 添加这个并没有改变任何东西。也没有显示错误消息(例如,在运行 lein compile 时)。 什么都没有发生时真的很烦人 - 至少一个错误会很棒。
    【解决方案3】:

    http://clojure.org/compilation 提到编译过程使用了

    ... *compile-path*,必须在类路径中

    默认位置是类文件夹。

    Stack Overflow 问题Compiling Clojure? 的第二个答案提到此路径是​​相对于 jvm 启动文件夹的。如果您从主项目文件夹(project.clj 所在的文件夹)中执行了 lein repl,那么在那里创建一个 classes 文件夹应该可以使其工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-29
      • 1970-01-01
      • 2012-11-21
      相关资源
      最近更新 更多