我正在尝试围绕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,允许执行fn
作为ExecutorJob的execute
方法的主体。这就是我想出的:
(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调用,我可以看到使用调试器执行得很好。
该宏出了什么问题?
答案 0 :(得分:2)
没关系,我明白了:我误用了宏参数,试图实际调用执行表格f
的结果。它产生零,因此是NPE。
更正版本:
(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)))