9
votes

I'm a novice in clojure and java.

In order to access a Java field in Clojure you can do:

Classname/staticField

which is just the same as

(. Classname staticField)

(correct me if I'm wrong)

How can I access a static field when the name of the field in held within a variable? i.e.:

(let [key-stroke 'VK_L
      key-event KeyEvent/key-stroke])

I want key-stroke to be evaluated into the symbol VK_L before it tries to access the field.

4
In addition to skuro's answer, you can look at the Java reflection API. See the "Changing Values of Fields" section at java.sun.com/developer/technicalArticles/ALT/Reflection . - gatoatigrado
To explaing a bit more: Access of fields or method calls have to be compiled in the byte code. That's why you can't construct them with runtime information. If you need that, you'll have to use reflection. (see Joost's answer) - kotarak

4 Answers

10
votes

In this case you might want to do something like the following:

user=> (def m 'parseInt)          
#'user/m
user=> `(. Integer ~m "10")       
(. java.lang.Integer parseInt "10")
user=> (eval `(. Integer ~m "10"))
10

If you feel like it's a bit hack-ish, it's because it really is such. There might be better ways to structure the code, but at least this should work.

7
votes

I made a small clojure library that translates public fields to clojure maps using the reflection API:

(ns your.namespace
 (:use nl.zeekat.java.fields))

(deftype TestType
    [field1 field2])

; fully dynamic:

(fields (TestType. 1 2)) 
=> {:field1 1 :field2 2}

; optimized for specific class:
(def-fields rec-map TestType)

(rec-map (TestType. 1 2)) 
=> {:field1 1 :field2 2}

See https://github.com/joodie/clj-java-fields

5
votes

Reflection is probably the proper route to take, but the easiest way is

(eval (read-string (str "KeyEvent/" key-stroke)))

This will just convert the generated string into valid clojure and then evaluate it.

1
votes

You can construct the right call as an s-expression and evaluate it as follows:

(let [key-stroke 'VK_L
      key-event (eval `(. KeyEvent ~key-stroke))]
  ....do things with your key-event......)

However, if what you are trying to do is test whether a particular key has been pressed, you may not need any of this: I usually find that it is easiest to write code something like:

(cond
  (= KeyEvent/VK_L key-value) 
    "Handle L"
  (= KeyEvent/VK_M key-value) 
    "Handle M"
  :else
    "Handle some other key")