Create an instance of ExceptionInfo, a RuntimeException subclass that carries a map of additional data.
(try (throw (ex-info "The ice cream has melted!" {:causes #{:fridge-door-open :dangerously-high-temperature} :current-temperature {:value 25 :unit :celsius}})) (catch Exception e (ex-data e))) ;;=> {:causes #{:fridge-door-open :dangerously-high-temperature} ;; :current-temperature {:value 25 :unit :celsius}}))
;; From https://stackoverflow.com/questions/25211457/ ;; Catching ExceptionInfo will only catch throwables created with ex-info: (try (throw (ex-info "bad" {:a 1 :b 2})) (catch clojure.lang.ExceptionInfo e (prn "caught" e))) ;; => "caught" #<ExceptionInfo clojure.lang.ExceptionInfo: bad {:b 2, :a 1}>
;; The 3-arg arity is for linking exceptions in accordance with Java convention. ;; For example you could write an exception wrapper: (ns clojure.example) (defn exception-wrapper "Wrap exceptions to embed `:event` information from the `request` such that we preserve the `Caused by` convention." [request exception] (let [event (:event request) exc (ex-info (.getMessage ^Throwable exception) {:event event} exception)] (throw exc))) clojure.example> (exception-wrapper {:event "some-event-info"} (ex-info "Dang." {:trilobites :everywhere})) ;; => Execution error (ExceptionInfo) at clojure.example/eval5596 (REPL:26). ;; => Dang. clojure.example> (clojure.repl/pst *e) ;; => ExceptionInfo Dang. {:event "some-event-info"} ;; => clojure.example/exception-wrapper (NO_SOURCE_FILE:7) ;; => [...] ;; => clojure.main/repl (main.clj:458) ;; => Caused by: ;; => ExceptionInfo Dang. {:trilobites :everywhere} ;; Like in Java, you should chain exceptions (ex-cause). ;; This lets you rank the exception in context. ;; An exception chain is like an interrogation ;; -> Who are you? (type e) => clojure.lang.ExceptionInfo ;; -> What is your meaning? (ex-message e) => Divide by Zero ;; -> Why did you behave badly? (ex-data e) => :divisor was 0 ;; -> Who else was involved? (ex-cause e) => #ArithmeticException{} ;; --> Who are you? (-> e ex-cause type) => ArithmeticException ;; ---> Who are you? (-> e ex-cause ex-cause type) => ... (def a 1) (def b 0) (try (/ a b) (catch ArithmeticException ae ;; <-- "defuse" Throwable (throw ;; <-- re-throw exception (ex-info ;; <-- contextualize ae (ex-message ae) ;; <-- chain exception message {:divisor b :dividend a} ;; <-- give your new ex-info context ae)))) ;; <-- chain ae as cause
;; Be careful that when thrown in a future ;; exceptions are cast into an ExecutionException (ns clojure.example) (try @(future (throw (ex-info "This exception is not caught as an ExceptionInfo but an ExecutionException" {:useless :data}))) (catch clojure.lang.ExceptionInfo e (println "Is not executed")) (catch java.util.concurrent.ExecutionException e (println "This one is executed")))
Returns exception data (a map) if ex is an IExceptionInfo. Otherwise returns nil.
The expr is evaluated and thrown, therefore it should yield an instance of some derivee of Throwable...
The exprs are evaluated and, if no exceptions occur, the value of the last is returned. If an except...
The exprs are evaluated and, if no exceptions occur, the value of the last is returned. If an except...
The exprs are evaluated and, if no exceptions occur, the value of the last is returned. If an except...
Prints a Clojure-oriented stack trace of tr, a Throwable. Prints a maximum of n stack frames (defa...
ex-info