4

I am building a server program to provide an API to a mongo database containing details of photos. All works well running it from the REPL, or if I start it using lein run.

The problems happen when I try and run the uberjar. Building the uberjar works ok:

(master) photo-api: lein uberjar
Compiling photo-api.env
Compiling photo-api.config
Compiling photo-api.core
WARNING: find-keyword already refers to: #'clojure.core/find-keyword in        namespace: image-lib.core, being replaced by: #'image-lib.core/find-keyword
Compiling photo-api.db.core
Compiling photo-api.handler
Compiling photo-api.layout
Compiling photo-api.middleware
Compiling photo-api.routes.home
Compiling photo-api.routes.services
Created /Users/iain/Code/Clojure/Luminus/photo-api/target/uberjar/photo-api-0.1.0-SNAPSHOT.jar
Created /Users/iain/Code/Clojure/Luminus/photo-api/target/uberjar/photo-api.jar
(master) photo-api:

but running the jar gives an error:

(master) photo-api: java -jar target/uberjar/photo-api.jar
WARNING: find-keyword already refers to: #'clojure.core/find-keyword in   namespace: image-lib.core, being replaced by: #'image-lib.core/find-keyword
read config from resource: "config.edn"
Exception in thread "main" java.lang.RuntimeException: could not start    [#'photo-api.db.core/db*] due to
    at mount.core$up$fn__420.invoke(core.cljc:92)
    at mount.core$up.invokeStatic(core.cljc:92)
    at mount.core$up.invoke(core.cljc:90)
    at mount.core$bring.invokeStatic(core.cljc:210)
    at mount.core$bring.invoke(core.cljc:202)
    at mount.core$start.invokeStatic(core.cljc:252)
    at mount.core$start.doInvoke(core.cljc:244)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at mount.core$start_with_args.invokeStatic(core.cljc:350)
    at mount.core$start_with_args.doInvoke(core.cljc:346)
    at clojure.lang.RestFn.invoke(RestFn.java:410)
    at photo_api.core$start_app.invokeStatic(core.clj:42)
    at photo_api.core$start_app.invoke(core.clj:41)
    at photo_api.core$_main.invokeStatic(core.clj:50)
    at photo_api.core$_main.doInvoke(core.clj:49)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at clojure.lang.AFn.applyToHelper(AFn.java:152)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at photo_api.core.main(Unknown Source)
Caused by: java.lang.NullPointerException
    at com.mongodb.ConnectionString.<init>(ConnectionString.java:222)
    at com.mongodb.MongoClientURI.<init>(MongoClientURI.java:189)
    at com.mongodb.MongoClientURI.<init>(MongoClientURI.java:171)
    at monger.core$connect_via_uri.invokeStatic(core.clj:230)
    at monger.core$connect_via_uri.invoke(core.clj:230)
    at photo_api.db.core$fn__12620.invokeStatic(core.clj:29)
    at photo_api.db.core$fn__12620.invoke(core.clj:28)
    at mount.core$record_BANG_.invokeStatic(core.cljc:86)
    at mount.core$record_BANG_.invoke(core.cljc:85)
    at mount.core$up$fn__420.invoke(core.cljc:93)
    ... 18 more

Or the SNAPSHOT jar.

(master) photo-api: java -jar target/uberjar/photo-api-0.1.0-SNAPSHOT.jar

Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var
    at photo_api.core.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: clojure.lang.Var
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more
(master) photo-api:

What am I missing here? I'm guessing it's something to do with dev build and production build differences, but I can't spot anything obvious and the error messages are not a lot of help to me.

This is the project file which as far as I remember is mostly straight from the original luminus template:

(defproject photo-api "0.1.0-SNAPSHOT"

  :description "API for geting data from photos db"
  :url "http://soulflyer.com"

  :dependencies [[cider/cider-nrepl "0.14.0"]
             [clj-time "0.13.0"]
             [com.google.guava/guava "20.0"]
             [com.novemberain/monger "3.1.0" :exclusions [com.google.guava/guava]]
             [compojure "1.6.0"]
             [cprop "0.1.10"]
             [funcool/struct "1.0.0"]
             [luminus-immutant "0.2.3"]
             [luminus-nrepl "0.1.4"]
             [luminus/ring-ttl-session "0.3.2"]
             [markdown-clj "0.9.99"]
             [metosin/compojure-api "1.1.10"]
             [metosin/muuntaja "0.3.1"]
             [metosin/ring-http-response "0.9.0"]
             [mount "0.1.11"]
             [org.clojure/clojure "1.8.0"]
             [org.clojure/tools.cli "0.3.5"]
             [org.clojure/tools.logging "0.4.0"]
             [org.clojure/data.json "0.2.6"]
             [org.webjars.bower/tether "1.4.0"]
             [org.webjars/bootstrap "4.0.0-alpha.5"]
             [org.webjars/font-awesome "4.7.0"]
             [org.webjars/jquery "3.1.1"]
             [ring-webjars "0.2.0"]
             [ring/ring-core "1.6.1"]
             [ring/ring-defaults "0.3.0"]
             [selmer "1.10.7"]
             [image-lib "0.2.1-SNAPSHOT"]]

  :min-lein-version "2.0.0"

  :jvm-opts ["-server" "-Dconf=.lein-env"]
  :source-paths ["src/clj"]
  :test-paths ["test/clj"]
  :resource-paths ["resources"]
  :target-path "target/%s/"
  :main ^:skip-aot photo-api.core

  :plugins [[lein-cprop "1.0.3"]
        [org.clojars.punkisdead/lein-cucumber "1.0.5"]
        [lein-immutant "2.1.0"]]
  :cucumber-feature-paths ["test/clj/features"]


  :profiles
  {:uberjar {:omit-source true
         :aot :all
         :uberjar-name "photo-api.jar"
         :source-paths ["env/prod/clj"]
         :resource-paths ["env/prod/resources"]}

   :dev           [:project/dev :profiles/dev]
   :test          [:project/dev :project/test :profiles/test]

   :project/dev  {:dependencies [[prone "1.1.4"]
                             [ring/ring-mock "0.3.0"]
                             [ring/ring-devel "1.6.1"]
                             [pjstadig/humane-test-output "0.8.2"]
                             [clj-webdriver/clj-webdriver "0.7.2"]
                             [org.apache.httpcomponents/httpcore "4.4"]
                             [org.clojure/core.cache "0.6.3"]
                             [org.seleniumhq.selenium/selenium-server "2.48.2"]]
              :plugins      [[com.jakemccrary/lein-test-refresh "0.19.0"]
                             [refactor-nrepl "2.3.0-SNAPSHOT"]]
              :source-paths ["env/dev/clj"]
              :resource-paths ["env/dev/resources"]
              :repl-options {:init-ns user}
              :injections [(require 'pjstadig.humane-test-output)
                           (pjstadig.humane-test-output/activate!)]}
   :project/test {:resource-paths ["env/test/resources"]}
   :profiles/dev {}
   :profiles/test {}})
Iain
  • 300
  • 2
  • 13
  • `Caused by: java.lang.NullPointerException at com.mongodb.ConnectionString.(ConnectionString.java:222)`. Is `ConnectionString` your file? If it's not, are you passing something in that file a `nil`? – Carcigenicate Sep 19 '17 at 04:49
  • I also see a lot of references to `mount.core$up$`. Is that your function? – Carcigenicate Sep 19 '17 at 04:52
  • I don't recognise ConnectionString and grep -r ConnectionString . gives: Binary file ./target/uberjar/photo-api.jar matches. I think it must be part of mongo. mount.core$up$ sounds like something from the luminus boilerplate to start the server. (mount/start) from the repl is one of the ways of starting the server, but it's not something I wrote. – Iain Sep 19 '17 at 04:57
  • It looks like the problem is that your problem is that your program is not able to establish a connection with mongo. How do you pass connection parameters? From the stack trace it looks like the problem is somewhere around `at photo_api.db.core$fn__12620.invokeStatic(core.clj:29) at photo_api.db.core$fn__12620.invoke(core.clj:28)` – r00tt Sep 20 '17 at 00:07

1 Answers1

2

I think you're just missing required configuration - at least Mongo connection string.

When running in dev mode, the luminus (and cprops configuration library) uses the config from your profiles.clj. However, this is the leiningen thing and it's not available when running from uberjar.

You can specify all your "production" configuration in "config.edn" file and run uberjar like this:

java -Dconf=config.edn -jar target/uberjar/photo-api.jar

You can also use java system properties to set configuration values one by one. See http://www.luminusweb.net/docs/environment.md for more details.

Juraj Martinka
  • 3,991
  • 2
  • 23
  • 25
  • Definitely a step in the right direction. If I run the jar with -Ddatabase-url="mongodb:127.0.0.1/photos" then it starts ok with no error. Still not getting any info back from the database though, I just get a MongoTimeoutException. The lein generated file .lein-env only contains one line specifying the database-url, nothing else. Also the mongo db is working fine. I can get to that using other methods. – Iain Sep 22 '17 at 01:06
  • Ahh. The port number for the service is different in my dev and prod versions. Changing that fixed it, all works now. – Iain Sep 22 '17 at 02:10