Skip to content

Commit dddc412

Browse files
puredangerstuarthalloway
authored andcommitted
CLJ-2414 Fix reflective lookup to include interfaces which may contain default methods
Signed-off-by: Stuart Halloway <stu@cognitect.com>
1 parent 00d03ba commit dddc412

2 files changed

Lines changed: 49 additions & 12 deletions

File tree

src/jvm/clojure/lang/Reflector.java

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
import java.lang.reflect.Field;
2020
import java.lang.reflect.Method;
2121
import java.lang.reflect.Modifier;
22-
import java.util.ArrayList;
23-
import java.util.Iterator;
24-
import java.util.List;
22+
import java.util.*;
2523
import java.util.stream.Collectors;
2624

2725
public class Reflector{
@@ -58,17 +56,41 @@ private static boolean canAccess(Method m, Object target) {
5856
}
5957
}
6058

59+
private static Collection<Class> interfaces(Class c) {
60+
Set<Class> interfaces = new HashSet<Class>();
61+
Deque<Class> toWalk = new ArrayDeque<Class>();
62+
toWalk.addAll(Arrays.asList(c.getInterfaces()));
63+
Class iface = toWalk.poll();
64+
while (iface != null) {
65+
interfaces.add(iface);
66+
toWalk.addAll(Arrays.asList(iface.getInterfaces()));
67+
iface = toWalk.poll();
68+
}
69+
return interfaces;
70+
}
71+
72+
private static Method tryFindMethod(Class c, Method m) {
73+
if(c == null) return null;
74+
try {
75+
return c.getMethod(m.getName(), m.getParameterTypes());
76+
} catch(NoSuchMethodException e) {
77+
return null;
78+
}
79+
}
80+
6181
private static Method toAccessibleSuperMethod(Method m, Object target) {
6282
Method selected = m;
63-
while(selected != null && !canAccess(selected, target)) {
64-
Class<?> s = selected.getDeclaringClass().getSuperclass();
65-
try {
66-
selected = s.getMethod(m.getName(), m.getParameterTypes());
67-
} catch(NoSuchMethodException e) {
68-
// ignore
69-
}
83+
while(selected != null) {
84+
if(canAccess(selected, target)) return selected;
85+
selected = tryFindMethod(selected.getDeclaringClass().getSuperclass(), m);
7086
}
71-
return selected;
87+
88+
Collection<Class> interfaces = interfaces(m.getDeclaringClass());
89+
for(Class c : interfaces) {
90+
selected = tryFindMethod(c, m);
91+
if(selected != null) return selected;
92+
}
93+
return null;
7294
}
7395

7496
public static Object invokeInstanceMethod(Object target, String methodName, Object[] args) {

test/clojure/test_clojure/reflect.clj

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,19 @@
3636

3737
(def inst (IBar$Factory/get))
3838
(deftest invoking-nonpublic-super
39-
(is (= "stuff" (.stuff inst))))
39+
(is (= "stuff" (.stuff inst))))
40+
41+
(defn- checkCLJ2066 [f]
42+
;; intentionally reflective call
43+
(is (not (nil? (.createXMLStreamReader f (java.io.StringReader. ""))))))
44+
45+
(defn- checkCLJ2414 [p]
46+
;; intentionally reflective call
47+
(is (false? (.startsWith p "s"))))
48+
49+
(deftest invoke-checks-accessibility
50+
;; CLJ-2066 - reflector finds method in private class. this is invokable, but an illegal access per modules
51+
(checkCLJ2066 (javax.xml.stream.XMLInputFactory/newInstance))
52+
53+
;; CLJ-2414 - find default method on interface of inaccessible class
54+
(checkCLJ2414 (java.nio.file.Paths/get "src" (into-array String []))))

0 commit comments

Comments
 (0)