Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 printlns 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

like image 526
John Courtland Avatar asked Feb 01 '12 19:02

John Courtland


1 Answers

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.

like image 172
Sentencio Avatar answered Sep 29 '22 04:09

Sentencio