AOT-compilation, record types and DynamicClassLoader

70 views
Skip to first unread message

Chris Jeris

unread,
Oct 16, 2012, 5:17:28 PM10/16/12
to clo...@googlegroups.com
I have a problem where I am trying to do an isa? or instance? check on an object of a record type which is defined in an AOT-compiled namespace.  The isa? check fails because -- under circumstances which I do not yet well understand -- the object I actually have is an instance of its class in a clojure.lang.DynamicClassLoader, whereas a reference to the class by its literal name yields the class in the base sun.misc.Launcher$AppClassLoader.

My Clojure code is compiled into a jar which is included into a Jetty server whose app code is largely written in Java.  Here is an example which illustrates the problem:

;; src/foo/core.clj
(ns foo.core)
(defrecord T [a b])

;; project.clj
(defproject foo "1.0.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.4.0"]]
  :aot [foo.core])

Now if I add the artifact foo/foo as a Maven dependency of the Jetty server, and attach a liverepl to the running server (without taking any action to call the Clojure code from Java), I see the following:

Clojure 1.4.0
user=> (require '[foo.core])
nil
user=> (.getClassLoader foo.core.T)
#<AppClassLoader sun.misc.Launcher$AppClassLoader@a6eb38a>
user=> (.getClassLoader (type (foo.core.T. 1 2)))
#<AppClassLoader sun.misc.Launcher$AppClassLoader@a6eb38a>
user=> (.getClassLoader (type (foo.core/->T 1 2)))
#<DynamicClassLoader clojure.lang.DynamicClassLoader@433d3253>

My actual case is more complicated, but the principle is the same: instances of foo.core.T which were built by the defrecord constructor function ->T do not inhabit the AppClassLoader version of the class, but rather a DynamicClassLoader version.  The result is that instance? or instanceof checks -- whether in my own Clojure code or in that of Java clients of my library who are trying to downcast -- do not behave as expected.

This example cannot be reduced too far:  if one just builds an uberjar and invokes a repl on the Clojure library alone, using 'java -cp target/foo-1.0.0-SNAPSHOT-standalone.jar clojure.main', the result is different:

Clojure 1.4.0
user=> (require '[foo.core])
nil
user=> (.getClassLoader foo.core.T)
#<AppClassLoader sun.misc.Launcher$AppClassLoader@43be2d65>
user=> (.getClassLoader (type (foo.core.T. 1 2)))
#<AppClassLoader sun.misc.Launcher$AppClassLoader@43be2d65>
user=> (.getClassLoader (type (foo.core/->T 1 2)))
#<AppClassLoader sun.misc.Launcher$AppClassLoader@43be2d65>

Unfortunately I don't understand enough about the Clojure class loading mechanism to understand what might be causing the DynamicClassLoader to be invoked in one case and not the other.

This problem seems to have been described by Ryan Senior about 20 months ago on clojure-dev, but I do not find any follow-up posts: https://groups.google.com/forum/?fromgroups=#!topic/clojure-dev/VBJFMEFBeFY

Can anyone shed light on the situation?

thanks, Chris Jeris
--
Chris Jeris
cje...@brightcove.com (617) 686-3271
freenode/twitter/github: ystael

Kevin Downey

unread,
Oct 16, 2012, 9:47:24 PM10/16/12
to clo...@googlegroups.com
have you cleaned out the classes/ directory recently? AOT'ing,
deftypes/defrecords, and lein when combined can exhibit issues with
stale generate classes for deftypes/defrecords. I would also try
adding (:gen-class) to your ns form. AOT compilation is effectively a
nop for the namespace without it, except for any
deftypes/records/protocols in the namespace, so a possible place for
those to get out of sync with the rest of the code.

DynamicClassloader generally means some compilation (code generation)
has happened, if a namespace has been AOT'ed the generate classes will
be loaded and the DynamicClassloader isn't required.
> --
> 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+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en



--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?
Reply all
Reply to author
Forward
0 new messages