Clojure 1.2.1/1.3/1.4 'proxy generated in Grails 2.0.0 runtime fails. 1.2.0 is fine
I'm working on extending the Grails Clojure plugin in Grails 2.0.0 (and 2.1.0-SNAPSHOT) and I wanted to update it to Clojure 1.3.0 and add clojure.tools.logging.
Clojure throws an exception during compilation of a
proxy of a ByteArrayOutputStream
in clojure.tools.logging
's log-stream function:
ClassCastException: clojure.asm.Type cannot be cast to clojure.lang.IFn
( https://gist.github.com/a6ae681c37091a3d2379 )
I went and removed clojure.tools.logging
and wrote a stripped down proxy of Object
:
(proxy [java.lang.Object] [] (toString [] "proxy's toString"))
and it also threw that same ClassCastException
and message.
I tried to print a macroexpand-1 of the proxy and got the same thing.
I reverted to Clojure 1.2.0 and proxy worked fine again.
I tried a number of incarnations of 1.4.0 and they exhibit the same behavior as 1.3.0. 1.2.1 also throws some sort of exception but I'm trying to hit 1.3.0 so I didn't spend much time with that.
The stack trace points to the 'gen-method function defined in one of the let forms of generate-proxy
in core_proxy.clj
.
I added a small smattering of println
's around there to see if I could catch what was happening. Maybe this next statement will betray a huge misunderstanding of the reader on my part but simply adding those println
s changed the compile time behavior in a way I totally didn't expect. The exception location and exception type completely changed, even though all the Clojure tests in mvn package
continue to pass.
For instance, just adding a single println
to gen-method right before it starts generating bytecode caused Clojure to throw
ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.Class
( https://gist.github.com/5a7a40929a6c4a104bd5 )
I've seen various other errors depending on where I put the println
(s) but this is the most prevalent.
Obviously some aspect of Grails and Clojure are not meshing correctly here, but I am not seeing the connection. At first I suspected ASM incompatibility but since Clojure has its own ASM namespace, I can't see that being the issue. But maybe I'm wrong, I've been staring at clojure.lang.Compiler
, proxy and generate-proxy for days now trying to get this to work and I've pretty much stopped making forward progress because I've run out of steam :(
I apologize for the lack of links. You can copy and paste from below:
Grails Clojure - github.com/grails-plugins/grails-clojure
Clojure Tools Logging - github.com/clojure/tools.logging/blob/master/src/main/clojure/clojure/tools/logging.clj line 133 is the 'proxy
I found an Issue called CLJ-944
on clojure.org. There you can find a fix for ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to java.lang.Class
issue
The problem is:
that the compiler injects an incorrect cast to clojure.lang.PersistentHashMap. In this case it should probably be cast to a clojure.lang.Associative, the highest common interface having the .containsKey method.
Patch 1 - 0001-Fix-for-CLJ-944.patch
Patch 2 - 0002-Fix-for-CLJ-944.patch
I hope it helps.