accessing private/protected fields

1,141 views
Skip to first unread message

kyle smith

unread,
Jun 21, 2008, 6:48:51 PM6/21/08
to Clojure
Does clojure support accessing the private/protected fields of Java
classes? If not, why?

Rich Hickey

unread,
Jun 21, 2008, 7:48:07 PM6/21/08
to Clojure


On Jun 21, 6:48 pm, kyle smith <the1physic...@gmail.com> wrote:
> Does clojure support accessing the private/protected fields of Java
> classes?

No.

> If not, why?

Because it's a violation of encapsulation.

Rich

kyle smith

unread,
Jun 21, 2008, 9:01:15 PM6/21/08
to Clojure
Well of course, but that doesn't mean it wouldn't be useful. For
example, right now I'm using clojure to script/debug a java gui. I'm
developing on linux, but I just got a bug report that on a mac, the
text in a particular JLabel doesn't fit. I don't have access to a
mac, but since I've embedded MikeM's gui repl into my app, I was going
to write a clojure script to let the user adjust the size at runtime
(and report to me a better default). The problem is the JLabel is
private (for good encapsulation), and so clojure won't let me. From
my limited experience with Java's reflection, I know you can get the
private fields. Would it be acceptable to create a flag (similar to
*warn-on-reflection*) to optionally enable this?

Rich Hickey

unread,
Jun 22, 2008, 8:34:58 AM6/22/08
to Clojure
I don't think so, any more than it would be a good idea for Java
itself to support this with some flag - you'd end up with ordinary-
looking code that needed access protection dropped in order to run.
However, those same reflective techniques you could use from Java to
get at private members can be used from Clojure. So you can write call-
private or get-set-private functions that do what you want.

Rich

kyle smith

unread,
Jun 22, 2008, 2:32:44 PM6/22/08
to Clojure
(defn get-private-field [instance field-name] (. (doto (first (filter
(fn [x] (.. x getName (equals field-name))) (.. instance getClass
getDeclaredFields))) (setAccessible true)) (get instance)))

Someone may be able to write this more elegantly, but it works.

kyle smith

unread,
Jun 22, 2008, 7:03:31 PM6/22/08
to Clojure
(defn get-private-fields [instance field-names] (if-let x (first field-
names) (get-private-fields (get-private-field instance x) (rest field-
names)) instance))

This also works, but you have to supply field-names as a quoted list.

kyle smith

unread,
Jul 31, 2008, 5:43:57 PM7/31/08
to Clojure
For completeness, here's how to invoke a private method.

(defn invoke-private-method [obj fn-name-string & args]
(let [m (first (filter (fn [x] (.. x getName (equals fn-name)))
(.. obj getClass getDeclaredMethods)))]
(. m (setAccessible true))
(. m (invoke obj args))))
Reply all
Reply to author
Forward
0 new messages