2

I'm trying to write a Clojure layer around a Java API that looks like the following:

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 {
      //...
    }
  }

}

My goal is to create a Clojure API that allows to execute a fn as the body of the execute method of of an ExecutorJob. This is what I came up with:

(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)))

Unfortunately, given this call:

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"))

it causes an 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--

I tried to put some meaningful Java calls in the execute-as second parameters, which I can see being executed just fine with a debugger.

What's wrong with that macro?

skuro
  • 13,414
  • 1
  • 48
  • 67

1 Answers1

2

Nevermind, I got it: I was misusing the macro parameter and trying to actually call the result of the execution of form f. And it was yielding nil, hence the NPE.

Corrected version:

(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)))
skuro
  • 13,414
  • 1
  • 48
  • 67
  • Thanks for answering your own question! It is good to see developers who are willing to take the time to contribute to the community and let others learn from their experiences. – A. Levy Apr 21 '11 at 23:07