Fork me on GitHub

I’m trying to make a custom throwable subclass that I can catch by name. I’ve copied the from clojuredocs, but how do I actually use it? I tried adding (:import myproject CustomException) to my ns form, but it tells me it can’t find a class with that name. I get the sense I’m supposed to do something with my ~package.json~ project.clj to get it compiled, but I’m not sure what. Are there any decent docs or examples out there on how to do this? To head the obvious responses off at the pass: I know custom exception subclasses aren’t idiomatic, and I know there are other ways to make unnamed anonymous subclass instances. I’m specifically trying to throw an exception that I can catch without accidentally catching other exceptions and messing up their stack traces for a weird experiment thing.


Maybe share the code you've tried + your project.clj in a thread?


I haven't used Leiningen for years, but I'm happy to try and help with this @U01EB0V3H39


FWIW, you'll probably need this in your project.clj:

:prep-tasks ["compile"]
  :aot [my.CustomException]
That tells lein to run the compile task before any task you ask for (e.g., lein repl), and :aot tells lein which namespaces to compile.


why do you want a custom exception class?


Then you can do:

$ lein repl
Compiling my.CustomException
max.core=> (import '(my CustomException))
max.core=> (CustomException. "Ex" (ex-info "t" {}) {:a 1})
#error {
 :cause "t"
 :data {}
 [{:type my.CustomException
   :message "Ex"
   :data {:a 1}
   :at [max.core$eval1619 invokeStatic "form-init4063394007754078810.clj" 1]}
  {:type clojure.lang.ExceptionInfo
   :message "t"
   :data {}
   :at [max.core$eval1619 invokeStatic "form-init4063394007754078810.clj" 1]}]


@U050ECB92 he said it was "for a weird experiment thing."


(he posted a whole bunch of caveats he wanted to head off 🙂 )

🙏 1

Thanks Sean! Here’s the file I’m trying to gen-class: scratch/CustomException.clj

(ns scratch.CustomException
   :extends java.lang.Error
   :constructors {[String Throwable clojure.lang.IPersistentMap] [String Throwable]} ; mapping of my-constructor -> superclass constuctor
   :init init
   :state state ; name for the var that holds your internal state
   :main false
   :prefix "my-ex-"))

(defn my-ex-init [msg t context]
  ;; first element of vector contains parameters for the superclass constructor
  ;; Second element will be your internal state 
  [[msg t] context])

(defn my-ex-getData [this]
  (.state this)) ; accessing the internal state
I basically just copied it from the linked clojuredocs example. My project.clj is similarly bare-bones:
(defproject scratch "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.10.3"]]
  :main ^:skip-aot scratch.core
  :target-path "target/%s")
I tried to import the class in scratch/core.clj:
(ns scratch.core
  (:import scratch CustomException))
and I get a ClassNotFoundException


Looking into this a little more, it seems like in the REPL I might need to compile the class? I ran (compile 'scratch.CustomException) but I still get the class not found exception


I’ll try the leiningen think you suggested as well and see if that works. it’d still be nice to have a way to iterate on it in the repl


Ok, trying the project.clj changes you suggested, I get this error (abbreviated) when starting the repl:

[{:type clojure.lang.Compiler$CompilerException
   :message Syntax error compiling at (scratch/core.clj:1:1).
   :data #:clojure.error{:phase :compile-syntax-check, :line 1, :column 1, :source scratch/core.clj}
   :at [clojure.lang.Compiler load 7652]}
  {:type java.lang.ClassNotFoundException
   :message scratch
   :at [ findClass 471]}]


Maybe my ns’s/files aren’t matching up? What should a gen-class’d clj file be named?


It should be (:import (scratch CustomException))


or (:import scratch.CustomException)


In the first one, you're importing CustomException from the package scratch -- and you can import multiple classes if needed. In the second one, you're importing a specific class.


In your code, you're telling it to import scratch and to import CustomException, neither of which exist as top-level classes.


(sorry I didn't answer sooner but it seemed you'd already gone to bed so I wasn't watching Slack after a while)


No worries, I was bouncing around between a few things last night. I really appreciate the help!


Ok, I think I’ve got everything hooked up now. Only one small thing isn’t working: when I make changes to the gen-classed ns, I can’t seem to see those changes in other ns’s without restarting the repl. I’ve been running (compile scratch.CustomException) , but I think perhaps my (:import ) isn’t refreshing even when I re-eval the ns?


Yeah, I'm not sure that you can hot reload gen-class'd classes. I try to avoid gen-class as much as possible because it's a bit of a mess all around.


What’s the alternative? Can you hot-reload plain old .java files?


java files are not classes, in java when you recompile a class the program generally needs to be restarted before you can use the new version


java doesn't have "loading files" the way clojure does, as the compiler is not built into the vm


(IDE's provide versions of this, I'm not specific on the details, I assume the cursive IDE is most likely to make this usable)


package.json is not a clojure thing


picard-facepalm I meant project.clj


Hello Folks, question: I am using, and logback for a good while now. But I never really got line numbers to work in the logs. Before, I used Timbre, with which that worked, but there are some reasons I want to use tools.logging. Is it possible?


Likely not, I believe logback inspects the stack to get line numbers, and tools.logging, if I recall, can add stackframes


you can use timbre through tools.logging btw


So like: require timbre, configure it to use tools.logging, configure THAT to use logback?


require timbre in the code I mean


no, you said, you wanted to use tools.logging rather than timbre, but there is a timbre adapter for tools.logging, so they are not mutually exclusive


e.g. babashka exposes with timbre as the logging impl


yeah ok yeah gotcha


thanks! will look into that


Is there a way to create one spec file tha references all the others so I can only require one file and have all specs loaded?

Alex Miller (Clojure team)15:12:42

sure, just use require to load the others like any other clj file

Steve H22:12:43

Heyo, I'm new to Clojure and trying to execute a simple jQuery script using etaoin. This is what I have:

(js-execute d "$('#mainmenuli-report').trigger('mouseenter');")
Here's my error:
loaders.core=> (js-execute d "$('#mainmenuli-report').trigger('mouseenter');")
Execution error (ExceptionInfo) at (support.clj:201).
throw+: {:response {:sessionId "95536bb4edb78c51dcbf593d8f8c1325", :status 17, :value {:message "javascript error: 
$ is not defined\n  (Session info: chrome=96.0.4664.110)\n  (Driver info: chromedriver=96.0.4664.45 (76e4c1bb2ab4671b8beba3444e61c0f17584b2fc-refs/branch-heads/[email protected]{#947}),platform=Windows NT 10.0.19043 x86_64)"}}, :path "session/95536bb4edb78c51dcbf593d8f8c1325/execute", :payload {:script "$('#mainmenuli-report').trigger('mouseenter');", :args []}, :method :post, :type :etaoin/http-error, :port 35178, :host "", :status 200, :driver {:args ("chromedriver" "--port=35178"), :capabilities {:loggingPrefs {:browser "ALL"}, :chromeOptions {:args ("--window-size=1400,850")}}, :process #object[java.lang.ProcessImpl 0x2ef5c28d "Process[pid=20916, exitValue=\"not exited\"]"], :locator "xpath", :type :chrome, :env nil, :port 35178, :host "", :url "", :session "95536bb4edb78c51dcbf593d8f8c1325"}}
Appreciate any thoughts or workarounds.


do you have jQuery on that page? > $ is not defined

Steve H22:12:24

Hello, so if I run $('#mainmenuli-report').trigger('mouseenter'); in the console the desired effect is acheived (mouseover a hidden navigational element to reveal sub-nav). Just not sure of the proper syntax to use with etaoin, if this is even possible?


Are you using chrome console for that? It adds $ as a synonym of document.querySelector but it is available only in the context of console.

Steve H16:12:06

I am @U04V4KLKC, thanks for clarifying


i have no other suggestions. There’s an #etaoin channel where you might have good luck finding someone well-versed in that library

🙏 2