Fork me on GitHub
#clojure-dev
<
2018-07-30
>
seancorfield21:07:36

Encountered a weird/interesting issue with Clojure 1.9.0 and uberjars. See #clojure for background. It seems that building an uberjar with Clojure 1.9.0 and :aot :all in Leiningen produces a JAR with these entries

clojure/core__init.class
clojure/core_deftype.clj
clojure/core_deftype__init.class
clojure/core_instant18.clj
clojure/core_print.clj
clojure/core_print__init.class
clojure/core_proxy.clj
clojure/core_proxy__init.class
Note: there is no core_instant18__init.class file. Should there be? The user is importing an uberjar into Robocode to provide both the Clojure runtime and their robot class. When Robocode tries to load the robot class, it tries to load/initialize Clojure and that fails on the attempt to (load "core_instant18.clj") that is in clojure.core. All the other files load up just file, which is why I suspect the missing __init.class file is the cause... but I have no idea why it's missing?

ghadi21:07:24

What JDK did you compile it on? (I believe that was guarded by a when-class conditional)

seancorfield21:07:28

Java 8. It's all I have installed. I confirmed Robocode runs on Java 8 too (the fact that it tries to load that file confirms that).

seancorfield21:07:34

Ah, is it possible that core_instant18.clj won't compile standalone? It refers to Inst which is defined in clojure.core...

hiredman21:07:33

something very weird is going on there, because the stacktrace has the error coming from the check that load does on the lastmodified time when determining if it should use a compiled class file, or load the source

hiredman21:07:24

which it only does if getResource didn't return null

hiredman21:07:35

implying that it does exist and it doesn't

seancorfield22:07:35

FWIW, I can repro in any of my local Leiningen projects using 1.9.0 (in terms of there being no core_instant18__init.class file)

hiredman22:07:37

but they load fine, right?

seancorfield22:07:08

Well, the issue here (I think) is how Clojure is loaded/initialized in Robocode (does something different to how it would be loaded normally via clojure.main etc)?

hiredman22:07:54

maybe, hard to say, if I recall Robocode does some sandboxing kinds of things

seancorfield22:07:58

As far as I can tell, Robocode is just looking to load one class and call methods on it so the initialization path isn't through clojure.main or any of the standard entry points -- and Robocode is doing something dynamic (to load the JAR at runtime) so... ¯\(ツ)

hiredman22:07:20

but where the exception comes from indicates that clojure was able to find a resource named clojure/core_instant18__init.class and that the protocol of the resource url is "jar", but that the jar file named in the url doesn't have an entry for clojure/core_instant18__init.class, which sounds like classloader sorcery to me

seancorfield22:07:28

Yup, definitely something weird going on. But, at the root, why isn't core_instant18__init.class in the uberjar?

hiredman22:07:16

I guess the uberjar was built with some java less than 1.8, java 1.6 was the minimum version then, I think

seancorfield22:07:08

I built the uberjars here on my system to repro, using Java 8.

seancorfield22:07:32

But Clojure 1.9 itself might well have been built on pre-Java 8?

seancorfield22:07:40

(! 934)-> jar tf ~/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar|fgrep core_|sort
clojure/core__init.class
clojure/core_deftype.clj
clojure/core_deftype__init.class
clojure/core_instant18.clj
clojure/core_print.clj
clojure/core_print__init.class
clojure/core_proxy.clj
clojure/core_proxy__init.class
clojure/pprint$add_core_ns$fn__10758.class
clojure/pprint$add_core_ns.class
Yup, so it's missing in the Clojure JAR file.

ghadi22:07:26

if it were built on JDK1.8 that file would exist for sure

hiredman22:07:36

I wouldn't say missing, it isn't present and it makes sense that it isn't present, because of all that, and it should be ok to not be present, clojure should be fine loading the source code

seancorfield22:07:03

I guess I'm a bit surprised that building an uberjar on Java 8 doesn't "fill in" the missing .class file from Clojure...

hiredman22:07:06

but for some reason in the robocode environment, clojure is being told the classfile does exist, and then being told it doesn't exist when it goes to check the last mode it

seancorfield22:07:40

Anyways, for the curious... the instructions are in the #clojure channel 🙂

hiredman22:07:45

my guess is robocode has a classloader that doesn't return null when a resource doesn't exist

cfleming23:07:25

That is one suspect piece of code.

cfleming23:07:26

It will return the last url tried, even if that one couldn’t open its connection - yuk.

ghadi23:07:36

not to mention totally busted wrt modules

cfleming23:07:08

I guess if they’re always planning to run Java 8 that’s not an issue, but yeah…