Search code examples
clojureleiningenring

What Is The Reason For The Lein Cyclic Dependency Error When I build uberwar?


Building ring server-headless works -- lein ring server-headless -- but when I try to build the war or uberwar I get the following error, and cannot figure out why this is happening.

No namespaces to :aot compile listed in project.clj.
Exception in thread "main" java.lang.ExceptionInInitializerError, compiling:(ring/util/servlet.clj:62)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6416)
at clojure.lang.Compiler.analyze(Compiler.java:6216)
...

Caused by: java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.classForName(RT.java:2013)
at clojure.lang.Compiler$HostExpr.maybeClass(Compiler.java:938)
at clojure.lang.Compiler$HostExpr.access$400(Compiler.java:710)
at clojure.lang.Compiler.macroexpand1(Compiler.java:6342)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6395)
... 69 more
Caused by: java.lang.Exception: Cyclic load dependency: [ /servlet ]->/ring/util/servlet->[ /servlet ]
at clojure.core$check_cyclic_dependency.invoke(core.clj:5288)
at clojure.core$load.doInvoke(core.clj:5383)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:401)
at servlet.<clinit>(Unknown Source)
... 76 more

My project.clj file is:

(defproject myproj "0.1"
:description "the sample"
:dependencies [
    [org.clojure/clojure "1.3.0"]
    [compojure "1.0.4"]
    [hiccup "1.0.0"]
    [clj-json "0.5.0"]
    [ring/ring "1.1.0"]
    [clj-http "0.1.1"]
]   
:plugins [
    [lein-ring "0.7.0"]
]   
:ring {:handler routes/start})

If I remove the :ring {:handler routes/start} then I get a NPE somewhere else.

I don't know if I'm missing something in my project.clj, or if the particular version of lein is broken for this use case. Can someone clarify this for me?


Solution

  • I solved the issue, which was a bit of a mistake on my part. Posting the answer here in case anyone makes the same mistake.

    I had something like the following in src/routes.clj:

    (defroutes main-routes
        (GET "/some/path" [& params] (some-code params))
        (route/resources "/")
        (route/not-found "not found"))
    
    (def start (run-jetty (handler/site main-routes) {:port 8080}))
    

    This is all standard code to setup routes and provide a hook to start the jetty webapp from the command line via lein ring server-headless. Except that I declared start as a global instead of a function. That means when I run lein ring server-headless things still work, but when I run lein ring uberwar I end up with a weird configuration--a full jetty server will try to start up with it's servlet, AND uberwar has generated a servlet and is trying to package it into a jar.

    When I was comparing my code against the compojure examples I kept missing this difference I guess because def and defn optically look so similar. But anyway I just made this change to get it working:

    (defn start [] (run-jetty (handler/site main-routes) {:port 8080}))