Skip to content

Commit 9f277c8

Browse files
bronsastuarthalloway
authored andcommitted
CLJ-979: make clojure resolve to the correct Class instances
Signed-off-by: Stuart Halloway <stu@cognitect.com>
1 parent e5a104e commit 9f277c8

7 files changed

Lines changed: 80 additions & 29 deletions

File tree

src/clj/clojure/genclass.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -717,10 +717,10 @@
717717
[& options]
718718
(let [options-map (apply hash-map options)
719719
[cname bytecode] (generate-interface options-map)]
720-
(if *compile-files*
721-
(clojure.lang.Compiler/writeClassFile cname bytecode)
722-
(.defineClass ^DynamicClassLoader (deref clojure.lang.Compiler/LOADER)
723-
(str (:name options-map)) bytecode options))))
720+
(when *compile-files*
721+
(clojure.lang.Compiler/writeClassFile cname bytecode))
722+
(.defineClass ^DynamicClassLoader (deref clojure.lang.Compiler/LOADER)
723+
(str (:name options-map)) bytecode options)))
724724

725725
(comment
726726

src/clj/clojure/reflect/java.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ the kinds of objects to which they can apply."}
166166
(deftype JavaReflector [classloader]
167167
Reflector
168168
(do-reflect [_ typeref]
169-
(let [cls (Class/forName (typename typeref) false classloader)]
169+
(let [cls (clojure.lang.RT/classForName (typename typeref) false classloader)]
170170
{:bases (not-empty (set (map typesym (bases cls))))
171171
:flags (parse-flags (.getModifiers cls) :class)
172172
:members (set/union (declared-fields cls)

src/jvm/clojure/lang/Compiler.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,7 +1596,7 @@ static class StaticMethodExpr extends MethodExpr{
15961596
public final int column;
15971597
public final java.lang.reflect.Method method;
15981598
public final Symbol tag;
1599-
final static Method forNameMethod = Method.getMethod("Class forName(String)");
1599+
final static Method forNameMethod = Method.getMethod("Class classForName(String)");
16001600
final static Method invokeStaticMethodMethod =
16011601
Method.getMethod("Object invokeStaticMethod(Class,String,Object[])");
16021602
final static Keyword warnOnBoxedKeyword = Keyword.intern("warn-on-boxed");
@@ -1773,7 +1773,7 @@ else if(retClass != void.class)
17731773
else
17741774
{
17751775
gen.push(c.getName());
1776-
gen.invokeStatic(CLASS_TYPE, forNameMethod);
1776+
gen.invokeStatic(RT_TYPE, forNameMethod);
17771777
gen.push(methodName);
17781778
emitArgsAsArray(args, objx, gen);
17791779
if(context == C.RETURN)
@@ -2482,8 +2482,7 @@ public static class NewExpr implements Expr{
24822482
public final Class c;
24832483
final static Method invokeConstructorMethod =
24842484
Method.getMethod("Object invokeConstructor(Class,Object[])");
2485-
// final static Method forNameMethod = Method.getMethod("Class classForName(String)");
2486-
final static Method forNameMethod = Method.getMethod("Class forName(String)");
2485+
final static Method forNameMethod = Method.getMethod("Class classForName(String)");
24872486

24882487

24892488
public NewExpr(Class c, IPersistentVector args, int line, int column) {
@@ -2556,7 +2555,7 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
25562555
else
25572556
{
25582557
gen.push(destubClassName(c.getName()));
2559-
gen.invokeStatic(CLASS_TYPE, forNameMethod);
2558+
gen.invokeStatic(RT_TYPE, forNameMethod);
25602559
MethodExpr.emitArgsAsArray(args, objx, gen);
25612560
if(context == C.RETURN)
25622561
{
@@ -4601,7 +4600,7 @@ else if(value instanceof Class)
46014600
else
46024601
{
46034602
gen.push(destubClassName(cc.getName()));
4604-
gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)"));
4603+
gen.invokeStatic(RT_TYPE, Method.getMethod("Class classForName(String)"));
46054604
}
46064605
}
46074606
else if(value instanceof Symbol)
@@ -7421,7 +7420,7 @@ CONSTANT_IDS, new IdentityHashMap(),
74217420
clinitgen.invokeStatic(objx.objtype, Method.getMethod("void __init" + n + "()"));
74227421

74237422
clinitgen.push(objx.internalName.replace('/','.'));
7424-
clinitgen.invokeStatic(CLASS_TYPE, Method.getMethod("Class forName(String)"));
7423+
clinitgen.invokeStatic(RT_TYPE, Method.getMethod("Class classForName(String)"));
74257424
clinitgen.invokeVirtual(CLASS_TYPE,Method.getMethod("ClassLoader getClassLoader()"));
74267425
clinitgen.invokeStatic(Type.getType(Compiler.class), Method.getMethod("void pushNSandLoader(ClassLoader)"));
74277426
clinitgen.mark(startTry);

src/jvm/clojure/lang/DynamicClassLoader.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public Class defineClass(String name, byte[] bytes, Object srcForm){
4848
return c;
4949
}
5050

51-
protected Class<?> findClass(String name) throws ClassNotFoundException{
51+
static Class<?> findInMemoryClass(String name) {
5252
Reference<Class> cr = classCache.get(name);
5353
if(cr != null)
5454
{
@@ -58,7 +58,27 @@ protected Class<?> findClass(String name) throws ClassNotFoundException{
5858
else
5959
classCache.remove(name, cr);
6060
}
61-
return super.findClass(name);
61+
return null;
62+
}
63+
64+
protected Class<?>findClass(String name) throws ClassNotFoundException {
65+
Class c = findInMemoryClass(name);
66+
if (c != null)
67+
return c;
68+
else
69+
return super.findClass(name);
70+
}
71+
72+
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
73+
Class c = findLoadedClass(name);
74+
if (c == null) {
75+
c = findInMemoryClass(name);
76+
if (c == null)
77+
c = getParent().loadClass(name);
78+
}
79+
if (resolve)
80+
resolveClass(c);
81+
return c;
6282
}
6383

6484
public void registerConstants(int id, Object[] val){

src/jvm/clojure/lang/RT.java

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,39 +2106,44 @@ static public URL getResource(ClassLoader loader, String name){
21062106
}
21072107
}
21082108

2109-
static public Class classForName(String name) {
2109+
static public Class classForName(String name, boolean load, ClassLoader loader) {
21102110

21112111
try
21122112
{
2113-
return Class.forName(name, true, baseLoader());
2113+
Class c = null;
2114+
if (!(loader instanceof DynamicClassLoader))
2115+
c = DynamicClassLoader.findInMemoryClass(name);
2116+
if (c != null)
2117+
return c;
2118+
return Class.forName(name, load, loader);
21142119
}
21152120
catch(ClassNotFoundException e)
21162121
{
21172122
throw Util.sneakyThrow(e);
21182123
}
21192124
}
21202125

2126+
static public Class classForName(String name) {
2127+
return classForName(name, true, baseLoader());
2128+
}
2129+
21212130
static public Class classForNameNonLoading(String name) {
2122-
try
2123-
{
2124-
return Class.forName(name, false, baseLoader());
2125-
}
2126-
catch(ClassNotFoundException e)
2127-
{
2128-
throw Util.sneakyThrow(e);
2129-
}
2131+
return classForName(name, false, baseLoader());
21302132
}
21312133

2132-
static public Class loadClassForName(String name) throws ClassNotFoundException{
2134+
static public Class loadClassForName(String name) {
21332135
try
21342136
{
2135-
Class.forName(name, false, baseLoader());
2137+
classForNameNonLoading(name);
21362138
}
2137-
catch(ClassNotFoundException e)
2139+
catch(Exception e)
21382140
{
2139-
return null;
2141+
if (e instanceof ClassNotFoundException)
2142+
return null;
2143+
else
2144+
throw Util.sneakyThrow(e);
21402145
}
2141-
return Class.forName(name, true, baseLoader());
2146+
return classForName(name);
21422147
}
21432148

21442149
static public float aget(float[] xs, int i){

test/clojure/test_clojure/compilation.clj

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,18 @@
249249
(load-string "(.submit (java.util.concurrent.Executors/newCachedThreadPool) #())")))
250250
(is (try (load-string "(.submit (java.util.concurrent.Executors/newCachedThreadPool) ^Runnable #())")
251251
(catch Compiler$CompilerException e nil)))))
252+
253+
(defrecord Y [a])
254+
#clojure.test_clojure.compilation.Y[1]
255+
(defrecord Y [b])
256+
257+
(binding [*compile-path* "target/test-classes"]
258+
(compile 'clojure.test-clojure.compilation.examples))
259+
260+
(deftest CLJ-979
261+
(is (= clojure.test_clojure.compilation.examples.X
262+
(class (clojure.test-clojure.compilation.examples/->X))))
263+
(is (.b (clojure.test_clojure.compilation.Y. 1)))
264+
(is (= clojure.test_clojure.compilation.examples.T
265+
(class (clojure.test_clojure.compilation.examples.T.))
266+
(class (clojure.test-clojure.compilation.examples/->T)))))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
;; Copyright (c) Rich Hickey. All rights reserved.
2+
;; The use and distribution terms for this software are covered by the
3+
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4+
;; which can be found in the file epl-v10.html at the root of this distribution.
5+
;; By using this software in any fashion, you are agreeing to be bound by
6+
;; the terms of this license.
7+
;; You must not remove this notice, or any other, from this software.
8+
9+
(ns clojure.test-clojure.compilation.examples)
10+
11+
(eval '(deftype X []))
12+
(deftype T [])

0 commit comments

Comments
 (0)