views:

242

answers:

2

I'm working on some Java / Clojure interoperability and came across a reflection warning for the following code:

(defn load-image [resource-name]
  (javax.imageio.ImageIO/read 
    (.getResource 
      (class javax.imageio.ImageIO) 
      resource-name)))

=> Reflection warning, clojure/repl.clj:37 - reference to field read can't be resolved.

I'm surprised at this because getResource always returns a URL and I would therefore expect the compiler to use the appropriate static method in javax.imageio.ImageIO/read.

The code works fine BTW so it is clearly finding the right method at run time.

So two questions:

  1. Why is this returning a reflection warning?
  2. What type hint do I need to fix this?
+3  A: 

AFAICS has this nothing to do with your code or compilation. It is part of the source-fn function of the REPL :

 ...
      (let [text (StringBuilder.)
            pbr (proxy [PushbackReader] [rdr]
                  (read [] (let [i (proxy-super read)]
                             (.append text (char i))
                             i)))]
 ...

and used to display source code in the REPL shell, AFAICT.

Peter Tillemans
Very good spot! Guess this is warning for the Clojure development team to fix up then?
mikera
Reflection warnings are emitted at compile time. By the time anything can be typed into the REPL, the REPL code is of course done compiling. In fact, stuff in `clojure.jar` is compiled ahead-of-time, so I can't see how any reflection warnings connected to it would ever appear at the REPL. Moreover, I still can't reproduce this issue, and I've tried a current Hudson snapshot, two local 1.2 builds and the 1.1 release jar. Just trying to bring some constructive rain to the parade so as to help wash away any remaining obstacles to our understanding of this...
Michał Marczyk
The line it appears to be complaining about in repl.clj is: (proxy [PushbackReader] [rdr] (read [] (let [i (proxy-super read)] (.append text (char i)) i))) - interestingly I note that the warning goes away if I put (:use [clojure.repl]) in the ns declaration before the (set! *warn-on-reflection* true) line so maybe what is happening is that this changes the timing of the compilation?
mikera
+1  A: 

For others who find this post (as I did) when wondering why they get reflection warnings when using proxy-super...

Every proxy method has an implicit this first arg, which, alas, is not type-hinted (presumably because there are a number of possible types being implemented by the proxy and the resultant proxy class is created later).

So, if you ever call methods on this from inside the proxy (which is what proxy-super ends up doing), then you'll see reflection warnings.

The simple solution is to just wrap your code in a let that uses type-hinting. E.g.:

(let [^SomeClass this this]
  (proxy-super foo)
  (.bar this))
Alex Taggart