This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-02
Channels
- # aleph (2)
- # announcements (3)
- # babashka (12)
- # beginners (55)
- # calva (11)
- # clj-http (12)
- # cljs-dev (41)
- # cljtogether (2)
- # clojure (51)
- # clojure-denmark (2)
- # clojure-europe (32)
- # clojure-nl (17)
- # clojure-norway (2)
- # clojure-switzerland (1)
- # clojure-uk (3)
- # clojurescript (34)
- # cursive (20)
- # data-science (3)
- # datahike (23)
- # datomic (3)
- # events (1)
- # fulcro (1)
- # honeysql (4)
- # inf-clojure (2)
- # interop (38)
- # java (3)
- # kaocha (8)
- # lsp (51)
- # luminus (2)
- # malli (2)
- # nextjournal (5)
- # off-topic (21)
- # pedestal (2)
- # polylith (12)
- # re-frame (4)
- # reagent (8)
- # reitit (4)
- # releases (1)
- # ring (4)
- # shadow-cljs (179)
- # spacemacs (2)
- # specter (1)
- # xtdb (13)
Is there a way to create a class with specific methods available via reflection at runtime?
I dont have an interface. I just need a class with two methods (that will be invoked via reflection)
using proxy generates a class and instance, but the methods on that class are not direct
instead it has __initClojureFnMappings
, __updateClojureFnMappings
and __getClojureFnMappings
so I got it working with ns
and compiled into an uberjar. But I can't seem to get a reflectable class instance in a jacked in repl.
just end up getting ClassNotFoundException on an import, or IllegalArgumentException: Unable to resolve classname: Resolver on attempting direct instantiation
I assume evaluating namespaces and forms in the repl does not compile classes and class load them?
@retrogradeorbit If you have an ns
with (:gen-class)
you need to explicitly compile
that namespace.
How are you building the uberjar?
(mostly, the uberjar-building process will compile that namespace if you have the build steps configured properly)
So lein uberjar
?
And you have :aot
specified in project.clj
with your ns that has the (:gen-class)
? Or :aot :all
? (I haven't used lein
for years so I'm a bit rusty -- we switched to deps.edn
four years ago at work).
OK, so what do you mean by "jacked in repl"?
Ah, I always start a REPL manually at the command-line and then connect my editor to it.
You'll need to explicitly compile
that namespace and you'll need classes
on your classpath for it to be picked up.
ah ok... so if I lein repl from the command line it may have access to the gen-classed class?
(compile the.ns)
in a REPL would work, regardless of how you start it
But I can't remember how to tell lein
about the classes
folder that needs to be on the classpath.
It's been too long since I used Leiningen to remember how to make this work with it.
(I don't use nREPL either, just a Socket REPL)
lein
has a :prep-tasks
option, as I recall, so you can get it to compile code prior to starting a REPL automatically. With that and having classes
on the classpath, you should be fine. But you'll have to read the Leiningen docs for details.
OK, so I did lein new app crispin
and then updated project.clj
to look like this:
(defproject crispin "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url ""
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url " "}
:dependencies [[org.clojure/clojure "1.10.1"]]
:main ^:skip-aot crispin.core
:prep-tasks ["compile"]
:aot [crispin.core]
:target-path "target/%s"
:profiles {:uberjar {:aot :all
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
and now when I start lein repl
it compiles crispin.core
(which has (:gen-class)
) and I can (import crispin.core)
in that REPL.Seems that lein
generates classes into target/default/classes
by default and that seems to be already on the classpath. So much "magic" happening in Leiningen 🙂