2010-09-30 11 views
42

J'ai essayé de créer une exception définie par l'utilisateur dans Clojure, et j'ai eu toutes sortes de problèmes. J'ai essayé la méthode décrite ici:Exceptions personnalisées dans Clojure?

http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#User-Defined_Exceptions

(gen-and-load-class 'user.MyException :extends Exception) 

Mais cela ne semble pas fonctionner dans Clojure 1.2 (ou que je fais quelque chose de mal ...). Mon environnement est Clojure 1.2, Emacs, et lein Swank.

Merci pour votre aide!

Répondre

24

Faire un fichier src/user/MyException.clj (où src est sur CLASSPATH) contenant:

(ns user.MyException 
    (:gen-class :extends java.lang.Exception)) 

Vérifiez la valeur de *compile-path* au REPL. Assurez-vous que ce répertoire existe et est sur CLASSPATH. Créez le répertoire s'il n'existe pas; Clojure ne le fera pas pour vous.

user> *compile-path* 
"/home/user/foo/target/classes/" 
user> (System/getProperty "java.class.path") 
".......:/home/user/foo/target/classes/:......." 

compiler votre classe:

user> (compile 'user.MyException) 
user.MyException 

Si cela a fonctionné, en *compile-path* vous devriez maintenant avoir des fichiers quelque chose comme ceci:

/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 

Redémarrez votre Clojure REPL/machine virtuelle Java pour charger ces classes . Encore une fois, assurez-vous que ces nouveaux fichiers de classe sont sur CLASSPATH. Maintenant, vous devriez être en mesure d'utiliser votre classe:

user> (user.MyException.) 
#<MyException user.MyException> 
9

FWIW, sauf si vous créez une exception personnalisée pour des raisons interop vous pouvez envisager d'utiliser clojure.contrib.condition à la place. Il s'agit d'une exception personnalisée précompilée selon laquelle vous utilisez des données personnalisées pour utiliser son API. J'ai pu éviter de créer de nombreuses exceptions personnalisées en l'utilisant à la place. Les documents sont ici: http://clojure.github.com/clojure-contrib/condition-api.html

+1

De plus, on peut signaler kit clojure.contrib.error. – kotarak

+2

'clojure-contrib' est maintenant obsolète. – m0skit0

63

Plutôt que de générer des classes personnalisées, il y a deux façons beaucoup plus simples à utiliser des exceptions personnalisées:

  1. Utilisez slingshot - cela donne personnalisés throw+ et catch+ macros qui vous permettent de jeter et attraper un objet, ainsi que des exceptions.

  2. Dans clojure 1.4 et au-dessus, vous pouvez utiliser clojure.core/ex-info et clojure.core/ex-data pour générer et attraper une classe clojure.lang.ExceptionInfo, qui enveloppe un message et une carte de données.

L'utilisation de c'est simple:

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

Ou dans un test de midje:

(fact "should throw some eels" 
    (...) 
    => (throws clojure.lang.ExceptionInfo 
      #(= :eels (-> % ex-data :cause)))) 
+0

Merci beaucoup, j'ai longtemps cherché une solution simple à la gestion des exceptions transparentes dans Clojure! –

+0

pour les exceptions personnalisées en ring-service, je vous recommande d'utiliser l'approche suggérée ici: https://8thlight.com/blog/mike-knepper/2015/05/19/handling-exceptions-with-middleware-in-clojure .html – danfromisrael