Custom Exceptions in Clojure?
Solution 1:
Rather than generating custom classes, there are two much simpler ways to use custom exceptions:
Use slingshot - this provides custom
throw+
andcatch+
macros that let you throw and catch any object, as well as exceptions.In clojure 1.4 and above, you can use clojure.core/ex-info and clojure.core/ex-data to generate and catch a
clojure.lang.ExceptionInfo
class, which wraps a message and a map of data.
Using this is straightforward:
(throw (ex-info "My hovercraft is full of eels"
{:type :python-exception, :cause :eels}))
(try (...)
(catch clojure.lang.ExceptionInfo e
(if (= :eels (-> e ex-data :cause))
(println "beware the shrieking eels!")
(println "???"))))
Or in a midje test:
(fact "should throw some eels"
(...)
=> (throws clojure.lang.ExceptionInfo
#(= :eels (-> % ex-data :cause))))
Solution 2:
Make a file src/user/MyException.clj
(where src
is on CLASSPATH
) containing:
(ns user.MyException
(:gen-class :extends java.lang.Exception))
Check the value of *compile-path*
at the REPL. Make sure this directory exists and is on CLASSPATH
. Create the directory if it doesn't exist; Clojure won't do so for you.
user> *compile-path*
"/home/user/foo/target/classes/"
user> (System/getProperty "java.class.path")
".......:/home/user/foo/target/classes/:......."
Compile your class:
user> (compile 'user.MyException)
user.MyException
If it worked, in *compile-path*
you should now have files something like this:
/home/user/foo/target/
/home/user/foo/target/classes
/home/user/foo/target/classes/user
/home/user/foo/target/classes/user/MyException.class
/home/user/foo/target/classes/user/MyException__init.class
/home/user/foo/target/classes/user/MyException$loading__4410__auto__.class
Restart your Clojure REPL / JVM to load these classes. Again, make sure these new class files are on CLASSPATH
. Now you should be able to use your class:
user> (user.MyException.)
#<MyException user.MyException>
Solution 3:
FWIW, unless you are creating a custom exception for interop reasons you may want to consider using clojure.contrib.condition
instead. It comes with a precompiled custom exception that you piggy-back custom data onto using it's API. I've been able to avoid creating many custom exceptions by using it instead. The docs are here:
http://clojure.github.com/clojure-contrib/condition-api.html