请在2024 Clojure 状态调查!中分享您的想法。

欢迎!请参阅关于页面获取更多关于这个工作的信息。

0
Java 服务
  (deftype l [^java.util.List x])
  (use '[clojure.reflect :as r])
  (:members (r/reflect (l. `())))

尽管有 java.util.List 的类型提示,但在反射中 x 总是是一个 Object

我特别想在一个100% Clojure的应用中运行 optaplanner 的示例 https://github.com/joinr/optaplanner-clj/tree/163d326a6433b88ca9811e33d30758ceff42b91f。代码正在评估,但在运行 (solve (->problem)) 时不断出现此错误。

  1. 未处理的 java.lang.IllegalStateException:solutionClass(类 optaplanner_clj.data.TimeTable)有一个
    PlanningEntityCollectionProperty 标注的成员(public final
    java.lang.Object optaplanner_clj.data.TimeTable.lessonList)不返回 Collection 或数组。
    jvm

2 答案

0

除了我,其他人可以更权威地回答这里,但我非常确定Clojure编译器为Clojure函数和deftype方法创建的方法可以为参数类型和返回类型的三种类型之一:java.lang.Object、基本类型long或基本类型double。如果不是这些类型,您最好的办法是使用Clojure编译器以外的工具来创建JVM字节码,例如编写一些Java包装代码并使用javac编译,或者学习一些库,如asm库(Clojure库使用的),用于生成JVM字节码。

这是正确的。如果你想有一个具有特定类型的类,你需要创建一个具有特定类型的接口,然后让deftype实现该接口。
这里的问题是 optaplanner 强制执行大量的注解,并在其验证阶段特别关注类上的注解字段。如果字段未进行类型注解(deftype 促使将其作为对象),则 optaplanner 会卡住。即使提供了带有 get 和 set 方法的接口。反射发生在字段上。我们虽然让其他注解问题得到解决,但看来完全符合 optaplanner 互操作性需要自定义类定义(例如使用 insn 库),或者与 deftype 发出的内容进行交互。
0

对于参考,看起来 clojure.tools.emitter.jvm 确实保留了非原始字段的类型...

 (require '[clojure.tools.emitter.jvm :as e])

(e/eval '(deftype blah [^String x]) {:debug? true})
;;;
// class version 50.0 (50)
// access flags 0x31
public final class user/blah implements clojure/lang/IType  {

  // compiled from: user/blah

  // access flags 0x11
  public final Ljava/lang/String; x
...

user> (require '[clojure.reflect :as r])
nil
user> (r/reflect (user.blah. "hello"))
{:bases #{java.lang.Object clojure.lang.IType},
 :flags #{:public :final},
 :members
 #{{:name getBasis,
    :return-type clojure.lang.IPersistentVector,
    :declaring-class user.blah,
    :parameter-types [],
    :exception-types [],
    :flags #{:public :static}}
   {:name user.blah,
    :declaring-class user.blah,
    :parameter-types [java.lang.Object],
    :exception-types [],
    :flags #{:public}}
   {:name x,
    :type java.lang.String,  ;;in clojure
    :declaring-class user.blah,
    :flags #{:public :final}}}}
...