(ns test
(:refer-clojure))
(def output System/out)
(def output-stream
(let [buffer (new java.io.ByteArrayOutputStream)]
(proxy [java.io.OutputStream] []
(flush []
(.append output (.toString buffer "UTF-8"))
(.reset buffer))
(write [x]
(when (>= (.size buffer) 32)
(.flush this))
(.write buffer x))
(write [x off len]
(.write buffer x off len)))))
(in-ns 'clojure)
(def *out* (new java.io.OutputStreamWriter test/output-stream "UTF-8"))
This works, but according to the the documentation of clojure/proxy it
seems that "If a method fn is not provided for a class method, the
superclass methd will be called." [1] However if I omit the second write
method in the proxy definition, I get the following error:
user=> (load-file "test.clj")
#=(var clojure/*out*)
user=> (prn "hello")
java.lang.IllegalArgumentException: Wrong number of args passed to: fn--2490$fn (NO_SOURCE_FILE:0)
user=> (.printStackTrace *e)
java.lang.IllegalArgumentException: Wrong number of args passed to: fn--2490$fn (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:4122)
at clojure.lang.Repl.main(Repl.java:91)
Caused by: java.lang.IllegalArgumentException: Wrong number of args passed to: fn--2490$fn
at clojure.lang.AFn.throwArity(AFn.java:460)
at clojure.lang.AFn.invoke(AFn.java:75)
at clojure.lang.Proxy__2499.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
at clojure.flush__906.invoke(boot.clj:1658)
at clojure.prn__909.doInvoke(boot.clj:1667)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at user.eval__2503.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:4111)
... 1 more
--------------------------------
[1] http://clojure.org/java_interop#toc20
Nice. Never heard of proxy-super before. Would be nice to mention it on
the Java interop page and not only on the API page.
>
> (write
> ([x]
> (when (>= (.size buffer) 32)
> (.flush this))
> (.write buffer x))
> ([x off len]
> (proxy-super write x off len)))
>
> Since there is a write method, we have to call the super-class'
> method explicitely.
Tried it but it fails with:
java.lang.reflect.InvocationTargetException (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:4122)
at clojure.lang.Repl.main(Repl.java:91)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:86)
at
clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
at test.fn__2490$fn__2492$fn__2495.invoke(test.clj:18)
at clojure.proxy_call_with_super__2077.invoke(proxy.clj:264)
at test.fn__2490$fn__2492.invoke(test.clj:18)
at clojure.lang.Proxy__2503.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
at
sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
at clojure.flush__906.invoke(boot.clj:1658)
at clojure.prn__909.doInvoke(boot.clj:1667)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at user.eval__2507.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:4111)
... 1 more
Caused by: java.lang.AbstractMethodError: java.io.OutputStream.write(I)V
at clojure.lang.Proxy__2503.write(Unknown Source)
at java.io.OutputStream.write(OutputStream.java:99)
at clojure.lang.Proxy__2503.write(Unknown Source)
... 21 more
Interestingly java.io.OutputStream.write(I)V is invoked even though this
should be covered by the proxy write method.
> Hope this helps.
Despite the error it did. Thanks!
Yes, after I looked into proxy-super I came to the the same conclusion.
I wonder though what can be done about this limitation of the proxy
approach, as according to the documentation of proxy, access to super
can not be proxied. What a pity.