Permalink
Browse files

CLJ-733 data conveying exception

Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
  • Loading branch information...
1 parent 1538d80 commit 1f11ca3ef9cd0585abfbe4a9e7609be8b255123f @stuarthalloway stuarthalloway committed Dec 2, 2011
Showing with 65 additions and 1 deletion.
  1. +20 −0 src/clj/clojure/core.clj
  2. +3 −1 src/clj/clojure/repl.clj
  3. +42 −0 src/jvm/clojure/lang/ExceptionInfo.java
View
@@ -4221,6 +4221,26 @@
(with-out-str
(apply println xs)))
+(import clojure.lang.ExceptionInfo)
+(defn ex-info
+ "Alpha - subject to change.
+ Create an instance of ExceptionInfo, a RuntimeException subclass
+ that carries a map of additional data."
+ {:added "1.4"}
+ ([msg map]
+ (ExceptionInfo. msg map))
+ ([msg map cause]
+ (ExceptionInfo. msg map cause)))
+
+(defn ex-data
+ "Alpha - subject to change.
+ Returns exception data (a map) if ex is an ExceptionInfo.
+ Otherwise returns nil."
+ {:added "1.4"}
+ [ex]
+ (when (instance? ExceptionInfo ex)
+ (.getData ^ExceptionInfo ex)))
+
(defmacro assert
"Evaluates expr and throws an exception if it does not evaluate to
logical true."
View
@@ -251,7 +251,9 @@ str-or-pattern."
(pst (root-cause e) e-or-depth))))
([^Throwable e depth]
(binding [*out* *err*]
- (println (str (-> e class .getSimpleName) " " (.getMessage e)))
+ (println (str (-> e class .getSimpleName) " "
+ (.getMessage e)
+ (when-let [info (ex-data e)] (str " " (pr-str info)))))
(let [st (.getStackTrace e)
cause (.getCause e)]
(doseq [el (take depth
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) Rich Hickey. All rights reserved.
+ * The use and distribution terms for this software are covered by the
+ * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+ * which can be found in the file epl-v10.html at the root of this distribution.
+ * By using this software in any fashion, you are agreeing to be bound by
+ * the terms of this license.
+ * You must not remove this notice, or any other, from this software.
+ */
+
+package clojure.lang;
+
+/**
+ * Exception that carries data (a map) as additional payload. Clojure programs that need
+ * richer semantics for exceptions should use this in lieu of defining project-specific
+ * exception classes.
+ */
+public class ExceptionInfo extends RuntimeException{
+ public final IPersistentMap data;
+
+ public ExceptionInfo(String s, IPersistentMap data) {
+ super(s);
+ if (data instanceof IPersistentMap) {
+ this.data = data;
+ } else {
+ throw new IllegalArgumentException("Additional data must be a persistent map: " + data);
+ }
+ }
+
+ public ExceptionInfo(String s, IPersistentMap data, Throwable throwable) {
+ super(s, throwable);
+ this.data = data;
+ }
+
+ public IPersistentMap getData() {
+ return data;
+ }
+
+ public String toString() {
+ return "clojure.lang.ExceptionInfo: " + getMessage() + " " + data.toString();
+ }
+}

3 comments on commit 1f11ca3

Contributor

jeremyheiler replied Dec 14, 2011

Is the check for IPersistentMap necessary here?

Member

Chouser replied Jan 11, 2012

It allows receivers to be confident they can assoc more data into the map and re-throw.

Contributor

jeremyheiler replied Jan 11, 2012

I mean, why does the two arg constructor check for IPersistentMap when the three arg constructor doesn't? I can see why you would want to check for IPersistentMap if Clojure requires it in order to handle type checking for Java interop, but I'm just wondering about the inconsistency.

Please sign in to comment.