clojure-noir project with generated uberjar - NoClassDefFoundError - clojure

Following http://www.webnoir.org/ instructions to create a new project - I ran lein uberwar - this generates a single (executable) jar - however it is not able to find the main class as mentioned in the manifest - no class file found.
The app runs run with "lein run".
Is the uberjar meant to be able to run this way (I expect it launches an embedded jetty?)
FYI Jar produced with lein uberjar fails on NoClassDefFoundError is similar - but out of date (this is with a newer version of leiningen where that specific bug is fixed).

The trick is to add gen-class to server.clj
(ns myproject.server ... (:gen-class))
For example:
I've just deployed using lein uberjar, and I have the following:
In my project.clj:
:main myproject.server
In my server.clj:
(ns myproject.server
(:require [noir.server :as server]
[myproject.views.common]
[myproject.views.index])
(:gen-class))
(server/load-views "src/myproject/views/")
(defn -main [& m]
(let [mode (keyword (or (first m) :dev))
port (Integer. (get (System/getenv) "PORT" "8080"))]
(server/start port {:mode mode
:ns 'myproject})))
require the views at the top
gen-class
load-views
Now it works fine to java -jar myproject-standalone.jar.

Related

how to get meaningful dependency errors in clojure?

If I add the following require:
(ns project.core
(:require
[compojure.route :as route])
(:gen-class))
(defn -main [& {:as args}]
(println "hello"))
an do
lein run
I get
Syntax error macroexpanding clojure.core/ns at (ring/util/mime_type.clj:1:1).
((require [clojure.string :as str])) - failed: Extra input spec: :clojure.core.specs.alpha/ns-form
is there a way I can get
"compojure.route not found; not defined; or whatever" e.g. something meaningful?
if I remove it it works fine. e.g. it says Hello
using Leiningen 2.9.4 on Java 14.0.1 OpenJDK 64-Bit Server VM
The project you are using is using very old dependencies. Clojure spec (introduced "recenlty") added macro/compile time checks and the mentioned file there triggers it.
compojure.route actually is found and it then requires its transitive deps. And while going down the chain ring.util.mime-type is required and the version you are using is not ready for current Clojure versions.
Your best bet here is to upgrade your deps. E.g. if you are following a book or if you are using a template this things can happen. If you have lein-ancient installed, it can attempt the update for you. Otherwise your best bet is to start in your project.clj and compare versions (e.g. check clojars).
If the problem still persists, have a look at lein deps :tree and see what is going on with the transtive deps.

Clojure: Cannot launch cider repl with boot

I have the following build.boot file,
(set-env!
:resource-paths #{"src"}
:dependencies '[[me.raynes/conch "0.8.0"]
[boot.core :as boot]])
(task-options!
pom {:project 'myapp
:version "0.1.0"}
jar {:manifest {"Foo" "bar"}})
(boot/deftask cider "CIDER profile"
[]
(require 'boot.repl)
(swap! #(resolve 'boot.repl/default-dependencies)
concat '[[org.clojure/tools.nrepl "0.2.12"]
[cider/cider-nrepl "0.15.0"]
[refactor-nrepl "2.3.1"]])
(swap! #(resolve 'boot.repl/default-middleware)
concat '[cider.nrepl/cider-middleware
refactor-nrepl.middleware/wrap-refactor])
identity)
following this documentation: https://github.com/boot-clj/boot/wiki/Cider-REPL
However, upon doing cider-jack-in I get the error "refusing to run as root. set BOOT_AS_ROOT=yes to force.", and yet after doing export BOOT_AS_ROOT=yes, I get the same error. What's wrong?
This wiki page is super outdated, so I don't recommend following it. I'd be best to read CIDER's documentation instead.
Just make sure you're using Boot 2.8.3. You don't really need any special CIDER profile. Just create a Boot project, open a file from it in CIDER and do M-x cider-jack-in-clj.

Launch the REPL from within my app

Suppose that I have implemented a few functions for some personal calculation at work. I'd like to build a .jar (uberjar) that my colleagues would use too in a REPL, like:
megacorpcalcs.core=> (+ 2 2)
4
megacorpcalcs.core=> (salary 8 0.4)
666$
What code should I type for a REPL to start when the .jar launches?
EDIT: after your comments I've split this answer into 2
1. Running your uberjar with a REPL
Create your uberjar, and start it with:
java -cp /path/to/your/application-X.Y.Z-standalone.jar clojure.main -i #your_application/foo.clj -r
I had to add the -i parameter and point it to one of my clj files in order to get any of my classes in the project to actually load in the repl. There may be a better way to do this, but I haven't found it yet. Without it, you get a standard clojure repl but your application isn't loaded.
Note, you need the # symbol so that it loads from the jar file relative to the classpath (i.e from root of jar).
This should start a repl which you can change namespace and run your application functions in.
Additionally, you can install rlwrap and prepend the java command with it so you can use history and arrow keys sanely.
2. Embedding a REPL server in your application to connect to from another client
You can embed your own repl on startup of your application (e.g. a simple main that just starts a repl instance), and then your users can run your jar file, and separately connect to it with their choice of tool (cider-jack-in, 'lein repl connect ...')
The simple version of this is:
(start-server :port 7890 :handler cider-nrepl-handler)
Substitute the port you want, see below for the appropriate namespaces to import.
Here is a more complete example:
(ns your-app.server
(:gen-class)
(:require [cider.nrepl :refer (cider-nrepl-handler)]
[clojure.tools.nrepl.server :refer [start-server]]))
(def repl-server (atom nil))
(defn create-nrepl-server!
[repl-port]
(println (format "starting nrepl server on port %d" repl-port))
(reset! repl-server (start-server :port repl-port :handler cider-nrepl-handler)))
(defn -main []
;; ...
(let [repl-port 7890]
(create-nrepl-server! repl-port)
(spit ".nrepl-port" repl-port)))
You'll need the following in your project.clj file
:plugins [[cider/cider-nrepl "0.10.0"]] ;; or whatever version you prefer
:dependencies [[org.clojure/tools.nrepl "0.2.12"]]
Once connected to your custom repl, standard rules apply, just change namespace and call your functions.

How to Run Jetty Example with Ring in Clojure

I am following along with this example on creating a simple web service in Clojure using ring and jetty.
I have this in my project.clj:
(defproject ws-example "0.0.1"
:description "REST datastore interface."
:dependencies
[[org.clojure/clojure "1.5.1"]
[ring/ring-jetty-adapter "0.2.5"]
[ring-json-params "0.1.0"]
[compojure "0.4.0"]
[clj-json "0.5.3"]]
:dev-dependencies
[[lein-run "1.0.0-SNAPSHOT"]])
This in script/run.clj
(use 'ring.adapter.jetty)
(require '[ws-example.web :as web])
(run-jetty #'web/app {:port 8080})
And this in src/ws_example/web.clj
(ns ws-example.web
(:use compojure.core)
(:use ring.middleware.json-params)
(:require [clj-json.core :as json]))
(defn json-response [data & [status]]
{:status (or status 200)
:headers {"Content-Type" "application/json"}
:body (json/generate-string data)})
(defroutes handler
(GET "/" []
(json-response {"hello" "world"}))
(PUT "/" [name]
(json-response {"hello" name})))
(def app
(-> handler
wrap-json-params))
However, when I execute:
lein run script/run.clj
I get this error:
No :main namespace specified in project.clj.
Why am I getting this and how do I fix it?
You're getting this error because the purpose of lein run (according to lein help run) is to "Run the project's -main function." You don't have a -main function in your ws-example.web namespace, nor do you have a :main specified in your project.clj file, which is what lein run is complaining about.
To fix this, you have a few options. You could move the run-jetty code to a new -main function of the ws-example.web function and then say lein run -m ws-example.web. Or you could do that and also add a line :main ws-example.web to project.clj and then just say lein run. Or you could try using the lein exec plugin to execute a file, rather than a namespace.
For more info, check out the Leiningen Tutorial.
You have to put that (run-jetty) stuff into a -main somewhere and then add it to the project.clj like
:main ws-example.core)
From lein help run:
USAGE: lein run -m NAMESPACE[/MAIN_FUNCTION] [ARGS...]
Calls the main function in the specified namespace.
So, you would need to put your script.clj somewhere on the project source path and then call it as:
lein run -m script

Clojure jdbc create-table statement does not run unless using Leiningen REPL

I've got a small Clojure program that uses the Clojure JDBC tools to create a table in an HSQL database. However, it only seems to actually create the table if I run it from Leiningen's REPL. It does not create the table if I run the code using lein run or from my IDE (IntelliJ). There are no exceptions reported. In both cases, the output is just "(0)".
Here's the code snippet:
(ns tramway.core
(:require [clojure.java.io :as io]
[clojure.java.jdbc :as sql]))
(def hsql-db {:subprotocol "hsqldb"
:subname "file:/tmp/tramwaydb"
:user "SA"
:password ""})
(defn -main []
(println (sql/with-connection hsql-db (sql/create-table
:footfall
[:id "INTEGER" "GENERATED ALWAYS AS IDENTITY(START WITH 1)"]
[:sample_date "DATE"]
[:exhibition "varchar(255)"]))))
And since I'm using Leiningen, here's my project.clj:
(defproject tramway "1.0.0-SNAPSHOT"
:description "Description here"
:dependencies [[org.clojure/clojure "1.3.0"]
[org.clojure/java.jdbc "0.1.4"]
[org.hsqldb/hsqldb "2.2.8"]]
:main tramway.core)
If I do:
$ lein repl
tramway.core=> (-main)
(0)
nil
and then check /tmp/tramway.log I can see the CREATE TABLE executed successfully.
However, if I do:
$ rm -rf /tmp/tramway.*
$ lein run
(0)
and then check the same file, it is empty. It does create the .log, .properties, and .script files. All but the .log file have content; there's just no record of the CREATE TABLE having been run.
What am I doing wrong? I would expect to have the same result whether I run my (-main) function from the REPL or have Leiningen run it automatically.
I have also tried taking the table creation out of the -main function and running it just as a script through my IDE, and I still get the same bad result.
This is a common HSQLDB configuration question.
HSQLDB's default configuration is not intended for test usage. As a result, it delays writing and synching the .log entries by 500 milliseconds and it does not shutdown the database when the connection is closed. Try either of these settings in your URL:
:subname "file:/tmp/tramwaydb;hsqldb.write_delay=false"
or
:subname "file:/tmp/tramwaydb;shutdown=true"
See the various option here: http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html