我正在尝试使用Clojure绑定包装Java库。 Java库中的一个特定类定义了一堆静态最终常量,例如:
class Foo {
public static final int BAR = 0;
public static final int SOME_CONSTANT = 1;
...
}
我想到我可以检查这个类并将这些常量拉到我的Clojure命名空间中,而不是明确def
- 每个。
例如,不要像这样明确地连接它:
(def foo-bar Foo/BAR)
(def foo-some-constant Foo/SOME_CONSTANT)
我可以检查Foo
类,并在加载模块时在我的Clojure命名空间中动态连接foo-bar
和foo-some-constant
。
我认为有两个原因:
A)在将新常量添加到Foo
类时自动引入它们。换句话说,在Java接口添加新常量的情况下,我不必修改我的Clojure包装器。
B)我可以保证常量遵循更多Clojure-esque命名约定
我并不是真的这么做,但是要求扩展我对Clojure / Java互操作的知识似乎是一个很好的问题。
由于
答案 0 :(得分:3)
很遗憾,宏 clojure.contrib.import-static 不允许导入 所有 静态最终字段。您必须提供要导入的字段列表。
此宏是 import-static 的惯用包装:
(ns stackoverflow
(:use clojure.contrib.import-static)
(:import (java.lang.reflect Modifier)))
(defmacro import-static-fields
"Imports all static final fields of the class as (private) symbols
in the current namespace.
Example:
user> (import-static-fields java.lang.Integer)
#'user/TYPE
user> MAX_VALUE
2147483647
Note: The class name must be fully qualified, even if it has already
been imported."
[class]
(let [final-static-field? (fn [field]
(let [modifiers (.getModifiers field)]
(and (Modifier/isStatic modifiers) (Modifier/isFinal modifiers))))
static-fields (map #(.getName %)
(filter
final-static-field?
(.. Class (forName (str class)) getFields)))]
`(import-static ~class ~@static-fields)))
答案 1 :(得分:2)
(这个答案现在包括两个有效的解决方案,一个基于我最初的想法intern
,一个基于danlei建议使用c.c.import-static
。我想我需要清理这个稍后,但我现在不能花更多的时间......)
提取静态字段:
(filter #(bit-and java.lang.reflect.Modifier/STATIC (.getModifiers %))
(.getFields YourClass))
然后在该序列中映射 #(intern *ns* (str "a-prefix-" (.getName %)) (.get YourClass nil))
以获取值...请注意此位未经测试,特别是,我不确定{{ 1}} nil
;尝试使用.get
并查看适合您班级的内容。
更新2:
好的,实际上基于java.lang.Field
的方法并不是那么糟糕的可读性:
intern
更新: (保留第一个更新作为替代解决方案)
将danlei对user> (map #(intern *ns* (symbol (str "integer-" (.getName %))) (.get % java.lang.Integer))
(filter #(bit-and java.lang.reflect.Modifier/STATIC
(.getModifiers %))
(.getFields java.lang.Integer)))
(#'user/integer-MIN_VALUE #'user/integer-MAX_VALUE #'user/integer-TYPE #'user/integer-SIZE)
user> integer-MIN_VALUE
-2147483648
user> integer-MAX_VALUE
2147483647
user> integer-TYPE
int
user> integer-SIZE
32
的了解与上述结合起来得出以下结论:
clojure.contrib
它使用user> (map #(eval `(import-static java.lang.Integer ~(symbol (.getName %))))
(filter #(bit-and java.lang.reflect.Modifier/STATIC
(.getModifiers %))
(.getFields java.lang.Integer)))
(#'user/MIN_VALUE #'user/MAX_VALUE #'user/TYPE #'user/SIZE)
user> MIN_VALUE
-2147483648
user> MAX_VALUE
2147483647
user> TYPE
int
user> SIZE
32
......好吧,那么,它几乎不会“杀死性能”并且它实际上相当可读,使用eval
的详细表达可能不是。 (实际上并不是那么糟糕......: - )) 如果你更喜欢 intern
,至少intern
的实现可以给你正确的想法如果上面的草图以某种方式证明是不正确的。
答案 2 :(得分:1)
我还没有尝试过,但也许clojure.contrib.import-static可以做到。
刚刚检查过:你必须在使用import-static时命名方法/字段,但我会在这里留下这个答案,因为它可能对搜索相关答案的人有所帮助。