Thanks, Guys, for all your help. Here is an update on where I have got to :
I've given up no trying to aspect the DynamicClassLoader for a while (maybe forever) as spring/aspecjt/load-time-weaving does not seem to work at the repl - I've posted another thread regarding this - no answers as yet. I've pulled a copy of the latest DynamicClassLoader (DCL) into my own source tree and hacked it thus : ... protected static Map<String, byte[]> nameToByteCode = new HashMap<String, byte[]>(); public static byte[] byteCodeForName(String name) { synchronized (nameToByteCode) { return nameToByteCode.get(name); } } public Class defineClass(String name, byte[] bytes, Object srcForm){ Util.clearCache(rq, classCache); Class c = defineClass(name, bytes, 0, bytes.length); classCache.put(name, new SoftReference(c,rq)); synchronized (nameToByteCode) {nameToByteCode.put(name, bytes);} // this is the point of the hack return c; } ... I'm not suggesting this as a patch - it doesn't consider GC, lockless concurrency etc - but simply as a way to test my idea. I've set up a webserver in my server to serve URLClassLoader requests for classes created server-side of which instances have been deserialised client side : ;; only works when URLClassLoader has been given a URL ending in '/' (defn handle-request [^String target ^Request base-request ^Request request ^HttpServletResponse response] (let [^String path-info (.getPathInfo base-request) class-name (.replace (.substring path-info 1 (- (.length path-info) 6)) \/ \.)] (if-let [^"[B" bytes (DynamicClassLoader/byteCodeForName class- name)] (let [size (count bytes)] (info (str "Serving: " class-name " (" size " bytes)")) (doto response (.setContentType "application/binary") (.setContentLength (count bytes)) (.setStatus 200)) (with-open [^OutputStream stream (.getOutputStream response)] (doseq [byte bytes] (.write stream (int byte))))) (do (info (str "Not Serving: " class-name)) (doto response (.setContentLength 0) (.setStatus 404))))) (.setHandled request true)) (defn ^Server start-jetty [^Integer port] (doto (Server. port) (.setHandler (proxy [AbstractHandler] [] (handle [& args] (apply handle-request args)))) (.start))) (defn stop-jetty [^Server jetty] (.stop jetty)) (start-jetty 8888) I've installed my own ClassLoader into the hierarchy in the Client JVM : (let [current-thread (Thread/currentThread)] (.setContextClassLoader current-thread (URLClassLoader. (into-array [(URL. "http://localhost:8888/")]) (.getContextClassLoader current-thread)))) Now for the magic : server-side: user=> (defrecord Foo [a b c]) user.Foo user=> (Foo. 1 2 3) #:user.Foo{:a 1, :b 2, :c 3} user=> and now client-side user=> (Class/forName "user.Foo") user.Foo user=> (Foo. 1 2 3) CompilerException java.lang.IllegalArgumentException: Unable to resolve classname: Foo, compiling:(NO_SOURCE_PATH:5) user=> (user.Foo. 1 2 3) {:a 1, :b 2, :c 3} user=> as you can see - not quite there yet (I seem to have namespace issues) - but possibilities. I guess when I called this thread "Serialising functions" I should have called it "Serialising types" instead, as that is my ultimate goal. server-side in response to the requests for unknown classes from the client I get : user=> [INFO] web - Serving: user.Foo (9901 bytes) [INFO] web - Serving: user.Foo$reify__601 (1546 bytes) [INFO] web - Serving: user.Foo$reify__603 (1546 bytes) [INFO] web - Not Serving: Foo looks like trying (Foo. 1 2 3) fell through and looked for user.Foo again server side... I then plugged all this in underneath my app to see how it behaved and I think that I have come up against class name collisions in my client jvm : Caused by: java.io.InvalidClassException: org.dada.demo.whales $fn__330$fn__331; local class incompatible: stream classdesc serialVersionUID = -2470942646180928550, local class serialVersionUID = -6698199004290814850 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java: 1583) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java: 1496) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java: 1732) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329) at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1667) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1323) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java: 1947) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java: 1871) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java: 1753) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java: 1947) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java: 1871) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java: 1753) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java: 1947) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java: 1871) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java: 1753) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329) at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java: 1947) at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java: 1871) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java: 1753) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351) at org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java: 177) ... 9 more This is caused by an object of which the class has already been pulled by the URLClassLoader, arriving client-side in an ActiveMQMessage but mistaking a homonymous local class for a remote one of different shape and trying to use it to deserialise itself - I think.. ! I don't have time to look at this any further today, but I think it is looking promising if I can find a way to avoid class name collisions - more hacking of clojure.lang I'm afraid :-( Apologies for posting all the source code here - but I thought that it would enable others to follow my track if interested. That's all for now. I'll post if I get any further. cheers Jules -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@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+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en