I have a clojure function which calls another function to update the database.
(^{PUT true
Path "/{id}"
Produces ["application/json"]
Consumes ["application/json"]
ApiOperation {:value "Update" :notes ""}}
updateFeedback [this
^{PathParam "id"} id
body]
(require 'com.xx.x.xx.xx.xx-response)
(let [doc (json/read-json body)]
(if-let [valid-doc (validate doc)]
(try+
(->>
(assoc valid-doc :modificationDate (Utilities/getCurrentDate))
(couch/update-document dbs/xx-db)
(core/ok-response))
(catch java.io.IOException ex
(log/error "line num 197"))
(catch java.lang.Exception ex
(log/error "line num 200"))))))
The update-document function throws an exception. I would like to throw it back to the caller -- in this case updateFeedback so that the content in the catch block gets executed. For some reason, clojure logs the exception and the catch block in the caller never executes.
To verify I wrapped the code in the update-document function in a try catch block. There the catch block got executed.
How do I add a throws clause to the function?
Update: I have updated the function. Apologies for the syntax issues. I have updated the code we are using. I am not familiar with clojure. This is a code which we inherited and we are asked to fix a bug. Any pointers would be really helpful.
If you are trying to catch and then re-throw an exception you can do something like this:
(defn throwing-function
[]
(/ 7 0))
(defn catching-function
[]
(try
(throwing-function)
(catch Exception e
(println "Caught exception:" e)
(println "Re-throwing ...")
(throw e))))
Related
I want my web page to behave as expected when there's an exception by a function, now (openid/validate r) doesn't return a value unless a user is redirected from /login. But since this is a home page, I want it also be visible without a problem. So I wonder why the "if" there doesn't work as I expect?
java.lang.NullPointerException at /
NullPointerException [no message]
tfs.routes.home/[fn]
home.clj, line 48
--> line 48
(if (openid/validate r)
So instead of NullPointerException, I expected (home-page r) to execute.
(openid/validate r) fails in itself and causes an exception because its not fed by the needed parameters, is that the cause? If so how can I fix it? If not, why my (home-page r) function doesn't get executed?
(if (openid/validate r)
(show-response (:params r))
(home-page r))
So I did this with try/catch, it seems to be working fine now. Just not sure if I still should use the if there or not since I'm using try/catch?
(GET "/" [:as r] (home-page r)
(try (if (openid/validate r)
(show-response (:params r))
(home-page r))
(catch Exception e (home-page r))))
On my clojure script I have got a try/catch that should handle exception
datalayer (try (parse-dl line)
(catch Exception e []))
But when I execute my code i'have got an exception:
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected end-of-input: was expecting closing quote for a string value
What should I do to ignore those exceptions
this is just a guess because I don't know what parse-dl does, though there is a common pattern that causes Exceptions to be thrown outside the try catch where they are expected. If you start with some lazy code in a try catch:
user> (def my-data [1 2 3])
#'user/my-data
user> (defn my-work [data]
(throw (Exception. "hi")))
#'user/my-work
user> (try
(map my-work my-data)
(catch Exception e []))
Exception hi user/my-work (form-init3735135586498578464.clj:1)
Because map returns a lazy sequence, the actual computation occurs when the REPL prints the result, so the exception is thrown after the try catch block has returned. To fix the lazy-bug, wrap the map in a call to doall
user> (try
(doall (map my-work my-data))
(catch Exception e []))
[]
Another related lazy-bug occurs when a lazy sequence is returned from a with-open expression so that by the time the computation takes place the file was already closed by the with-open macro.
The function forkFinally requires you to write a handler against SomeException. What I need is a way to rethrow the unhandled exceptions. Here's a sample code, which fails to compile because on the last line the e is ambiguous:
finallyHandler :: Either SomeException () -> IO ()
finallyHandler z = case z of
Right () -> cleanUp
Left someE | Just ThreadKilled <- fromException someE -> cleanUp
| Just e <- fromException someE -> cleanUp >> throwIO e
Of course the first thing coming to mind is to simply throw the someE instead, i.e.:
...
| otherwise -> cleanUp >> throwIO someE
And indeed it will compile, but then it will result in wrapping of all of incoming exceptions in SomeException when they pass this handler. This just can't be right. And what if I have multiple such handlers down the stack - I'll get a trash like SomeException $ SomeException $ RealException.
Am I missing something? What's the proper way of handling this situation?
Are you seeing unexpected behavior? If you haven't actually triggered something undersirable then I think you are worrying over nothing. A quick test indicates that the "right thing" is already being done. That is, if you catch then throw a SomeException you can still catch the original exception. Here's an example using ErrorCall as the underlying exception:
> catch (catch (throw (SomeException (ErrorCall "hi")))
(\(e::SomeException) -> throw e))
(\(ErrorCall e) -> putStrLn e)
hi
This is because the definition of throw uses toException and toException is identity for SomeException:
instance Exception SomeException where
toException se = se
fromException = Just
I'm coding something like REPL Server. Request from users evaluates in such function:
(defn execute [request]
(str (try
(eval (read-string request))
(catch Exception e (.getLocalizedMessage e)))))
Each client in separate thread. But they have the same namespace. How can I run code in dynamic created namespace ? So when new client connected, I want to create new namespace and to run client handling loop code there. Or maybe it's possible to run (eval ..) in other namespace ?
Thanks.
upd.
Solved!
Execute function:
(defn execute
"evaluates s-forms"
([request] (execute request *ns*))
([request user-ns]
(str
(try
(binding [*ns* user-ns] (eval (read-string request)))
(catch Exception e (.getLocalizedMessage e))))))
Each client gets it's own namespace by:
(defn generate-ns
"generates ns for client connection"
[] (let [user-ns (create-ns (symbol (str "client-" (Math/abs (.nextInt random)))))]
(execute (str "(clojure.core/refer 'clojure.core)") user-ns)
user-ns))`
(defn delete-ns
"deletes ns after client disconnected"
[user-ns] (remove-ns (symbol (ns-name user-ns))))
offtop: How to make offsets in code snippets on begin of line ?
Solved:
(binding [*ns* user-ns] (eval (read-string request)))
(symbol (str "client-" (Math/abs (.nextInt random)))
I just wanted to add, that this could be achieved with
(gensym "client-")
(I wanted to comment, but it turns our that I can't :))
Changing namespace means that you will have to reinitialize all the aliases, or refer to even clojure.core stuff with a fully qualified name:
user=> (defn alien-eval [ns str]
(let [cur *ns*]
(try ; needed to prevent failures in the eval code from skipping ns rollback
(in-ns ns)
(eval (read-string str))
(finally
(in-ns (ns-name cur))
(remove-ns ns))))) ; cleanup, skip if you reuse the alien ns
#'user/alien-eval
user=> (alien-eval 'alien "(clojure.core/println clojure.core/*ns*)") ; note the FQN
#<Namespace alien> ; the effect of println
nil ; the return value of alien-eval
You can write a macro that mimics
(defmacro my-eval [s] `~(read-string s))
It works better that eval because the symbol resolution of s occurs in the context that calls my-eval. Thanks to #Matthias Benkard for the clarifications.
I wish to throw an exception and have the following:
(throw "Some text")
However it seems to be ignored.
You need to wrap your string in a Throwable:
(throw (Throwable. "Some text"))
or
(throw (Exception. "Some text"))
You can set up a try/catch/finally block as well:
(defn myDivision [x y]
(try
(/ x y)
(catch ArithmeticException e
(println "Exception message: " (.getMessage e)))
(finally
(println "Done."))))
REPL session:
user=> (myDivision 4 2)
Done.
2
user=> (myDivision 4 0)
Exception message: Divide by zero
Done.
nil
clojure.contrib.condition provides a Clojure-friendly means of handling exceptions. You can raise conditons with causes. Each condition can have its own handler.
There are a number of examples in the source on github.
It's quite flexible, in that you can provide your own key, value pairs when raising and then decide what to do in your handler based on the keys/values.
E.g. (mangling the example code):
(if (something-wrong x)
(raise :type :something-is-wrong :arg 'x :value x))
You can then have a handler for :something-is-wrong:
(handler-case :type
(do-non-error-condition-stuff)
(handle :something-is-wrong
(print-stack-trace *condition*)))
If you want to throw an exception and include some debugging info in it (in addition to a message string), you can use the built-in ex-info function.
To extract the data from the previously-constructed ex-info object, use ex-data.
Example from clojuredocs:
(try
(throw
(ex-info "The ice cream has melted!"
{:causes #{:fridge-door-open :dangerously-high-temperature}
:current-temperature {:value 25 :unit :celcius}}))
(catch Exception e (ex-data e))
In a comment kolen mentioned slingshot, which provides advanced functionality that allows you not only to throw objects of arbitrary type (with throw+), but also use a more flexible catch syntax to inspect data inside thrown objects (with try+). Examples from the project repo:
tensor/parse.clj
(ns tensor.parse
(:use [slingshot.slingshot :only [throw+]]))
(defn parse-tree [tree hint]
(if (bad-tree? tree)
(throw+ {:type ::bad-tree :tree tree :hint hint})
(parse-good-tree tree hint)))
math/expression.clj
(ns math.expression
(:require [tensor.parse]
[clojure.tools.logging :as log])
(:use [slingshot.slingshot :only [throw+ try+]]))
(defn read-file [file]
(try+
[...]
(tensor.parse/parse-tree tree)
[...]
(catch [:type :tensor.parse/bad-tree] {:keys [tree hint]}
(log/error "failed to parse tensor" tree "with hint" hint)
(throw+))
(catch Object _
(log/error (:throwable &throw-context) "unexpected error")
(throw+))))