AOT classes with clj files on classpath causing ClassNotFoundException

149 views
Skip to first unread message

Piotr Bzdyl

unread,
Oct 12, 2016, 2:29:51 PM10/12/16
to Clojure
Hello,

I am trying to solve an issue in my project where I have the following setup. My application modules are AOT-compiled into several jars and then packaged with their 3rd party dependencies into an uberjar. As a result my uberjar contains my project's namespaces compiled to class files and dependencies (in this case clojure.java.jdbc) source clj files.

When I try to start the application it fails with the following stacktrace. Is there any limitation that prevents me running AOT-compiled namespaces using other namespaces available as clj on classpath?

java.lang.reflect.InvocationTargetException: null
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
at com.example.Launcher$ThreadLauncher.run(Launcher.java:42) ~[na:na]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_102]
Caused by: java.lang.NoClassDefFoundError: clojure/java/jdbc/Connectable
at com.example.db.common.database__init.load(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.common.database__init.<clinit>(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_102]
at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_102]
at clojure.lang.RT.classForName(RT.java:2154) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.classForName(RT.java:2163) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.loadClassForName(RT.java:2182) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:436) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:412) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load$fn__5448.invoke(core.clj:5866) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load.doInvoke(core.clj:5865) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:408) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_one.invoke(core.clj:5671) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib.doInvoke(core.clj:5710) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:142) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_libs.doInvoke(core.clj:5749) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:137) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$require.doInvoke(core.clj:5832) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:421) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.password$loading__5340__auto____1250.invoke(password.clj:1) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.password__init.load(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.password__init.<clinit>(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_102]
at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_102]
at clojure.lang.RT.classForName(RT.java:2154) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.classForName(RT.java:2163) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.loadClassForName(RT.java:2182) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:436) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:412) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load$fn__5448.invoke(core.clj:5866) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load.doInvoke(core.clj:5865) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:408) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_one.invoke(core.clj:5671) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib.doInvoke(core.clj:5710) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:142) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_libs.doInvoke(core.clj:5749) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:137) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:634) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$use.doInvoke(core.clj:5843) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:436) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.user$loading__5340__auto____1248.invoke(user.clj:1) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.user__init.load(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.user__init.<clinit>(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_102]
at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_102]
at clojure.lang.RT.classForName(RT.java:2154) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.classForName(RT.java:2163) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.loadClassForName(RT.java:2182) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:436) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:412) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load$fn__5448.invoke(core.clj:5866) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load.doInvoke(core.clj:5865) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:408) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_one.invoke(core.clj:5671) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib.doInvoke(core.clj:5710) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:142) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_libs.doInvoke(core.clj:5753) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:137) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$require.doInvoke(core.clj:5832) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:436) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.init$loading__5340__auto____1246.invoke(init.clj:1) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.init__init.load(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.db.auth.init__init.<clinit>(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at java.lang.Class.forName0(Native Method) ~[na:1.8.0_102]
at java.lang.Class.forName(Class.java:348) ~[na:1.8.0_102]
at clojure.lang.RT.classForName(RT.java:2154) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.classForName(RT.java:2163) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.loadClassForName(RT.java:2182) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:436) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RT.load(RT.java:412) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load$fn__5448.invoke(core.clj:5866) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load.doInvoke(core.clj:5865) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:408) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_one.invoke(core.clj:5671) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_lib.doInvoke(core.clj:5710) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:142) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$load_libs.doInvoke(core.clj:5749) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:137) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$apply.invoke(core.clj:632) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.core$require.doInvoke(core.clj:5832) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:408) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.services.activator$register_services.invoke(activator.clj:61) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.services.activator$startup.invoke(activator.clj:131) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.services.activator$_main.doInvoke(activator.clj:139) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.invoke(RestFn.java:397) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.AFn.applyToHelper(AFn.java:152) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at clojure.lang.RestFn.applyTo(RestFn.java:132) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
at com.example.services.activator.main(Unknown Source) ~[example-2.5.0-SNAPSHOT-standalone.jar:na]
... 6 common frames omitted
Caused by: java.lang.ClassNotFoundException: clojure.java.jdbc.Connectable
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_102]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_102]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_102]
... 104 common frames omitted


Best regards,
Piotr

Stuart Halloway

unread,
Oct 12, 2016, 4:26:32 PM10/12/16
to clo...@googlegroups.com
Hi Piotr,

Yes, the limitation is how the Java classpath works.  If you AOT your app, you need to AOT compile other Clojure code your app uses.


Cheers,
Stu

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Gary Trakhman

unread,
Oct 12, 2016, 4:39:46 PM10/12/16
to clo...@googlegroups.com
It's possible to do a mixed AOT (your code) non-aot (third-party code) setup, but it's a huge pain.

The particular issue you're seeing is probably the result of multiple versions of a class existing across jars and classloaders.  Unfortunately there is no consistent way to get this right, but the solution would involve a lot of manual inspection and stripping classes with filters like the maven jar plugin's 'exclude' functionality.  There are some libraries that are more troublesome than others.  In particular, any AOT'd 1st-party code that references protocols from 3rd party code will break if those classes are compiled dynamically, forcing you to include them, so I think your multi-module AOT setup is likely to break hard in this case unless the modules don't share dependencies. 

One of the other big sources of problems occurs when there is mixed source and AOT classes, as with the clojure artifact jar itself.  Uberjarring would be sensitive to timestamps, the clj source should be older than the compiled class files.  This is specifically a problem with the maven-shade-plugin and I experienced it on a mixed-java/clojure project.

In short, it's probably more trouble than it's worth to split the build into module jars only to combine them again.  If I were to do the shared-AOT-library consumed by clojure code scenario over again, I'd include the shared source into the build system of the consuming project, instead of including the jar artifact.


For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

Luc

unread,
Oct 12, 2016, 7:39:38 PM10/12/16
to Clojure
We AOT often dependent projects.
We are very careful meeting the exclusions suggestions reported
by lein deps :tree.

Luc P.

Piotr Bzdyl

unread,
Oct 13, 2016, 5:50:16 AM10/13/16
to Clojure
Thank you all for the replies - now I understand where the problem comes from.

Best regards,
Piotr
Reply all
Reply to author
Forward
0 new messages