Skip to content

Commit a046a49

Browse files
committed
Improvements to work with Java 9
Changes include: * update to dynapath 0.2.5 (0.2.4 was broken when AOT'd under < Java 9, but used under Java 9) * conditionally seal the AppClassLoader if it is available (it isn't under Java 9) * seal the new ParentClassLoader from boot-bin * use a URLClassLoader subclass that exposes .addURL so it can be modified (we can't call .setAccessible on URLClassLoader.addURL by default under Java 9) as the highest loader in the shim
1 parent 20efe5b commit a046a49

File tree

4 files changed

+57
-12
lines changed

4 files changed

+57
-12
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package boot;
2+
3+
import java.net.URL;
4+
import java.net.URLClassLoader;
5+
6+
// Allows us to have a modifiable ClassLoader without having to call
7+
// .setAccessible on URLClassLoader.addURL(), since that's not allowed
8+
// by default under Java 9
9+
public class AddableClassLoader extends URLClassLoader {
10+
public AddableClassLoader(URL[] urls, ClassLoader parent) {
11+
super(urls, parent); }
12+
13+
public void addURL(URL url) {
14+
super.addURL(url); }}

boot/base/src/main/java/boot/App.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.nio.channels.FileChannel;
88
import java.lang.ref.WeakReference;
99
import java.net.URL;
10-
import java.net.URLClassLoader;
1110
import java.util.Map;
1211
import java.util.Date;
1312
import java.util.UUID;
@@ -306,7 +305,7 @@ public class App {
306305

307306
for (int i=0; i<jarFiles.length; i++) urls[i] = jarFiles[i].toURI().toURL();
308307

309-
ClassLoader cl = new URLClassLoader(urls, App.class.getClassLoader());
308+
ClassLoader cl = new AddableClassLoader(urls, App.class.getClassLoader());
310309
ClojureRuntimeShim rt = ClojureRuntimeShim.newRuntime(cl);
311310

312311
rt.setName(name != null ? name : "anonymous");
@@ -319,6 +318,7 @@ public class App {
319318

320319
rt.require("boot.pod");
321320
rt.invoke("boot.pod/seal-app-classloader");
321+
rt.invoke("boot.pod/extend-addable-classloader");
322322
rt.invoke("boot.pod/set-data!", data);
323323
rt.invoke("boot.pod/set-pods!", pods);
324324
rt.invoke("boot.pod/set-this-pod!", new WeakReference<ClojureRuntimeShim>(rt));

boot/pod/project.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@
1717
:url "http://www.eclipse.org/legal/epl-v10.html"}
1818
:dependencies [[boot/base ~version :scope "provided"]
1919
[org.clojure/clojure "1.6.0" :scope "provided"]
20-
[org.tcrawley/dynapath "0.2.4" :scope "compile"]
20+
[org.tcrawley/dynapath "0.2.5" :scope "compile"]
2121
[org.projectodd.shimdandy/shimdandy-impl "1.2.0" :scope "compile"]])

boot/pod/src/boot/pod.clj

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,32 @@
2626
(let [[group artifact] ((juxt namespace name) sym)]
2727
[(or group artifact) artifact]))
2828

29+
(defn extend-addable-classloader
30+
"Opens up the class loader used to create the shim for
31+
modification. Once seal-app-classloader is called, this will be the
32+
highest class loader user code can modify.
33+
34+
This function is called during Boot's bootstrapping phase, and shouldn't
35+
be needed in client code under normal circumstances."
36+
[]
37+
(extend boot.AddableClassLoader
38+
cp/DynamicClasspath
39+
(assoc dynapath.dynamic-classpath/base-readable-addable-classpath
40+
:classpath-urls #(seq (.getURLs %))
41+
:add-classpath-url #(.addURL %1 %2))))
42+
43+
(def sealed-classloader-fns
44+
(assoc cp/base-readable-addable-classpath
45+
:classpath-urls #(seq (.getURLs %))
46+
:can-add? (constantly false)))
47+
2948
(defn seal-app-classloader
30-
"Implements the DynamicClasspath protocol to the AppClassLoader class such
31-
that instances of this class will refuse attempts at runtime modification
32-
by libraries that do so via dynapath[1]. The system class loader is of the
33-
type AppClassLoader.
49+
"Implements the DynamicClasspath protocol to the AppClassLoader and
50+
boot's ParentClassLoader classes such that instances of those
51+
classes will refuse attempts at runtime modification by libraries
52+
that do so via dynapath[1]. The system class loader is of the type
53+
AppClassLoader under Java < 9, and the top-level class loader used
54+
by boot is a ParentClassLoader.
3455
3556
The purpose of this is to ensure that Clojure libraries do not pollute the
3657
higher-level class loaders with classes and interfaces created dynamically
@@ -42,11 +63,21 @@
4263
[1]: https://github.com/tobias/dynapath
4364
[2]: https://github.com/clojure-emacs/cider-nrepl/blob/36333cae25fd510747321f86e2f0369fcb7b4afd/README.md#with-jboss-asjboss-eapwildfly"
4465
[]
45-
(extend sun.misc.Launcher$AppClassLoader
46-
cp/DynamicClasspath
47-
(assoc cp/base-readable-addable-classpath
48-
:classpath-urls #(seq (.getURLs %))
49-
:can-add? (constantly false))))
66+
(try
67+
;; this import will fail if the user doesn't have a new enough boot.sh
68+
(import boot.bin.ParentClassLoader)
69+
(eval '(extend boot.bin.ParentClassLoader
70+
dynapath.dynamic-classpath/DynamicClasspath
71+
boot.pod/sealed-classloader-fns))
72+
(catch Exception _))
73+
74+
(try
75+
;; this import will fail if the user is using Java 9
76+
(import sun.misc.Launcher$AppClassLoader)
77+
(eval '(extend sun.misc.Launcher$AppClassLoader
78+
dynapath.dynamic-classpath/DynamicClasspath
79+
boot.pod/sealed-classloader-fns))
80+
(catch Exception _)))
5081

5182
(defn ^{:boot/from :cemerick/pomegranate} classloader-hierarchy
5283
"Returns a seq of classloaders, with the tip of the hierarchy first.

0 commit comments

Comments
 (0)