我正在扩展 Grails 2.0.0(和 2.1.0-SNAPSHOT)中的 Grails Clojure plugin,我想将其更新为 Clojure 1.3.0 并添加 clojure.tools.logging。
Clojure 在 clojure.tools.logging
的日志流函数中编译 ByteArrayOutputStream
的 代理 期间引发异常:
ClassCastException: clojure.asm.Type cannot be cast to clojure.lang.IFn
(https://gist.github.com/a6ae681c37091a3d2379)
我去删除了 clojure.tools.logging
并写了一个 Object
的精简proxy:
(proxy [java.lang.Object] [] (toString [] "proxy's toString"))
它还抛出了相同的 ClassCastException
和消息。
我试图打印代理的macroexpand-1 并得到了同样的结果。
我恢复到 Clojure 1.2.0 并且代理再次正常工作。
我尝试了许多 1.4.0 的化身,它们表现出与 1.3.0 相同的行为。 1.2.1 也会引发某种异常,但我正在尝试访问 1.3.0,所以我没有花太多时间。
堆栈跟踪指向 core_proxy.clj
中 generate-proxy
的 let 形式之一定义的 'gen-method 函数。
我在那里添加了一小部分println
,看看我是否能抓住正在发生的事情。也许下一条语句会暴露出我对读者的巨大误解,但简单地添加这些 println
以一种我完全没想到的方式改变了编译时行为。异常位置和异常类型完全改变,即使 mvn package
中的所有 Clojure 测试继续通过。
例如,仅仅在 gen-method 开始生成字节码之前添加一个 println
会导致 Clojure 抛出
ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.Class
(https://gist.github.com/5a7a40929a6c4a104bd5)
根据我放置 println
(s) 的位置,我看到了各种其他错误,但这是最普遍的。
显然 Grails 和 Clojure 的某些方面在这里没有正确啮合,但我没有看到连接。起初我怀疑 ASM 不兼容,但由于 Clojure 有自己的 ASM 命名空间,我看不出这是问题所在。但也许我错了,我一直盯着 clojure.lang.Compiler
、proxy 和 generate-proxy 好几天试图让它工作,我已经很漂亮了很多事情都停止了前进,因为我已经筋疲力尽了:(
对于缺少链接,我深表歉意。您可以从下面复制和粘贴:
Grails Clojure - github.com/grails-plugins/grails-clojure
Clojure 工具日志记录 - github.com/clojure/tools.logging/blob/master/src/main/clojure/clojure/tools/logging.clj 第 133 行是“代理”
我在 clojure.org 上发现了一个名为 CLJ-944
的问题。在那里您可以找到 ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.Class
问题的修复程序
问题是:
编译器向 clojure.lang.PersistentHashMap 注入了不正确的强制转换。在这种情况下,它可能应该被转换为具有 .containsKey 方法的最高通用接口 clojure.lang.Associative。
补丁 1 - 0001-Fix-for-CLJ-944.patch
补丁 2 - 0002-Fix-for-CLJ-944.patch
我希望它有所帮助。
不定期副业成功案例分享