Renato Byrro
Renato Byrro

Reputation: 3784

How to extract metadata from a Clojure Exception?

I'm just starting to learn Clojure and struggling to extract Exception metadata. When I run this:

(try  
  (/ 1 0)  
  (catch Exception error (println error)))

I get an ArithmeticException, as expected. The stacktrace printed looks like this:

#error {
 :cause Divide by zero
 :via
 [{:type java.lang.ArithmeticException
   :message Divide by zero
   :at [clojure.lang.Numbers divide Numbers.java 188]}]
 :trace
 [[clojure.lang.Numbers divide Numbers.java 188]
  [clojure.lang.Numbers divide Numbers.java 3901]
  ...
 ]}

It looks like a map to me, so I tried to extract the value from :cause with (:cause error), but it evaluates to nil.

How can I do that?


UPDATE:

After digging a bit, I found that #error {...} is a java.lang.Throwable class, is that correct?

I tried using Java interop (.getCause error), but also returns nil. Turns out (.getMessage) error) does return "Divide by zero".

Are there other ways to get specific attributes from that class, other than .getMessage()?

Upvotes: 4

Views: 563

Answers (1)

Sean Corfield
Sean Corfield

Reputation: 6666

Clojure has ex-message to retrieve the message from an exception and ex-cause to retrieve the cause -- if there is one. The printed display of #error is a bit misleading here because there actually is no "cause" in the exception (in the Java sense of .getCause) because there is no chained exception.

Another useful function is Throwable->map which turns the exception (all exceptions are java.lang.Throwable at their root) into a regular Clojure hash map on which you can perform all the regular operations:

user=> (ex-message (try (/ 1 0) (catch Exception e e)))
"Divide by zero"
user=> (keys (Throwable->map (try (/ 1 0) (catch Exception e e))))
(:via :trace :cause)
user=> (:cause (Throwable->map (try (/ 1 0) (catch Exception e e))))
"Divide by zero"
user=> 

Upvotes: 13

Related Questions