This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-21
Channels
- # adventofcode (27)
- # announcements (2)
- # babashka (1)
- # beginners (111)
- # calva (11)
- # cider (82)
- # clara (6)
- # clojure (44)
- # clojure-dev (5)
- # clojure-europe (27)
- # clojure-nl (5)
- # clojure-spec (3)
- # clojure-uk (3)
- # clojurescript (29)
- # core-async (5)
- # cursive (4)
- # datalevin (1)
- # datomic (39)
- # exercism (4)
- # figwheel-main (1)
- # fulcro (32)
- # graalvm (7)
- # gratitude (1)
- # integrant (4)
- # jobs (1)
- # lein-figwheel (3)
- # leiningen (4)
- # lsp (3)
- # luminus (3)
- # meander (2)
- # nextjournal (1)
- # off-topic (10)
- # other-languages (26)
- # pathom (14)
- # polylith (9)
- # re-frame (16)
- # remote-jobs (1)
- # shadow-cljs (4)
- # specter (2)
- # sql (6)
- # timbre (2)
- # tools-build (12)
- # xtdb (9)
I’m trying to make a custom throwable subclass that I can catch by name. I’ve copied the https://clojuredocs.org/clojure.core/gen-class#example-60e69dfee4b0b1e3652d7513 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.Then you can do:
$ lein repl
Compiling my.CustomException
...
max.core=> (import '(my CustomException))
my.CustomException
max.core=> (CustomException. "Ex" (ex-info "t" {}) {:a 1})
#error {
:cause "t"
:data {}
:via
[{: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]}]
...
Thanks Sean! Here’s the file I’m trying to gen-class: scratch/CustomException.clj
(ns scratch.CustomException
(:gen-class
: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 ClassNotFoundExceptionLooking 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 Compiler.java 7652]}
{:type java.lang.ClassNotFoundException
:message scratch
:at [java.net.URLClassLoader findClass URLClassLoader.java 471]}]
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.
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)
Hello Folks, question: I am using clojure.tools.logging, 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
So like: require timbre, configure it to use tools.logging, configure THAT to use logback?
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
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?
sure, just use require
to load the others like any other clj file
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.