我正在尝试围绕 Java API 编写一个 Clojure 层,如下所示:
public class Executor {
public interface ExecutorJob<Result> {
public Result execute () throws Exception;
}
public static <R> R executeAsUser(RunAsWork<R> executorJob, String uid) {
try {
//...
R result = executorJob.execute();
return result;
}
finally {
//...
}
}
}
我的目标是创建一个 Clojure API,允许将 afn
作为execute
ExecutorJob 的方法体执行。这就是我想出的:
(defmacro execute-as
"Runs the form f while impersonating the given user"
[user f]
`(let [work# (reify Executor$ExecutorJob
(~'execute [~'this]
(~f)))]
(Executor/executeAsUser work# ~user)))
不幸的是,鉴于这个电话:
user> (macroexpand '(run-as "admin" (.println System/out "test")))
(let* [work__2928__auto__ (clojure.core/reify package.to.Executor$ExecutorJob (execute [this] ((.println System/out "test"))))] (package.to.Executor/executeAsUser work__2928__auto__ "admin"))
它会导致 NPE:
user> (execute-as "admin" (.println System/out "test"))
No message.
[Thrown class java.lang.NullPointerException]
Restarts:
0: [QUIT] Quit to the SLIME top level
Backtrace:
0: user$eval2936$reify__2937.doWork(NO_SOURCE_FILE:1)
1: package.to.Executor.executeAsUser(Executor.java:508)
2: user$eval2936.invoke(NO_SOURCE_FILE:1)
3: clojure.lang.Compiler.eval(Compiler.java:5424)
4: clojure.lang.Compiler.eval(Compiler.java:5391)
5: clojure.core$eval.invoke(core.clj:2382)
--more--
我尝试在execute-as
第二个参数中放入一些有意义的 Java 调用,我可以看到使用调试器执行得很好。
那个宏有什么问题?