1
2
3
4
5
6 package mockit.internal.util;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9 import edu.umd.cs.findbugs.annotations.Nullable;
10
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13
14 import mockit.internal.state.TestRun;
15
16 public final class ClassLoad {
17 public static final String OBJECT = "java/lang/Object";
18
19 private static final ClassLoader THIS_CL = ClassLoad.class.getClassLoader();
20 private static final Map<String, Class<?>> LOADED_CLASSES = new ConcurrentHashMap<>();
21 private static final Map<String, String> SUPER_CLASSES = new ConcurrentHashMap<>();
22
23 private ClassLoad() {
24 }
25
26 public static void registerLoadedClass(@NonNull Class<?> aClass) {
27 LOADED_CLASSES.put(aClass.getName(), aClass);
28 }
29
30 @NonNull
31 public static <T> Class<T> loadByInternalName(@NonNull String internalClassName) {
32 return loadClass(internalClassName.replace('/', '.'));
33 }
34
35 @NonNull
36 public static <T> Class<T> loadClass(@NonNull String className) {
37 @Nullable
38 Class<?> loadedClass = LOADED_CLASSES.get(className);
39
40 if (loadedClass == null) {
41 try {
42 loadedClass = loadClassFromAClassLoader(className);
43 } catch (LinkageError e) {
44 e.printStackTrace();
45 throw e;
46 }
47 }
48
49
50 return (Class<T>) loadedClass;
51 }
52
53 @NonNull
54 private static Class<?> loadClassFromAClassLoader(@NonNull String className) {
55 Class<?> loadedClass = loadClass(null, className);
56
57 if (loadedClass == null) {
58 if (className.startsWith("mockit.")) {
59 loadedClass = loadClass(THIS_CL, className);
60 }
61
62 if (loadedClass == null) {
63 Class<?> testClass = TestRun.getCurrentTestClass();
64 loadedClass = testClass == null ? null : loadClass(testClass.getClassLoader(), className);
65
66 if (loadedClass == null) {
67 ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
68 loadedClass = loadClass(contextCL, className);
69
70 if (loadedClass == null) {
71 throw new IllegalArgumentException("No class with name \"" + className + "\" found");
72 }
73 }
74 }
75 }
76
77 return loadedClass;
78 }
79
80 @NonNull
81 public static <T> Class<T> loadClassAtStartup(@NonNull String className) {
82 ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
83 Class<?> loadedClass;
84
85 try {
86 loadedClass = loadClass(contextCL, className);
87
88 if (loadedClass == null) {
89 loadedClass = loadClass(THIS_CL, className);
90
91 if (loadedClass == null) {
92 throw new IllegalArgumentException("No class with name \"" + className + "\" found");
93 }
94 }
95 } catch (LinkageError e) {
96 e.printStackTrace();
97 throw e;
98 }
99
100
101 return (Class<T>) loadedClass;
102 }
103
104 @Nullable
105 public static Class<?> loadClass(@Nullable ClassLoader loader, @NonNull String className) {
106 try {
107 return Class.forName(className, false, loader);
108 } catch (ClassNotFoundException ignore) {
109 return null;
110 }
111 }
112
113 @NonNull
114 public static <T> Class<T> loadFromLoader(@Nullable ClassLoader loader, @NonNull String className) {
115 try {
116
117 return (Class<T>) Class.forName(className, false, loader);
118 } catch (ClassNotFoundException ignore) {
119 throw new IllegalArgumentException("No class with name \"" + className + "\" found");
120 }
121 }
122
123 @Nullable
124 public static <T> Class<? extends T> searchTypeInClasspath(@NonNull String typeName) {
125 return searchTypeInClasspath(typeName, false);
126 }
127
128 @Nullable
129 public static <T> Class<? extends T> searchTypeInClasspath(@NonNull String typeName, boolean initializeType) {
130
131 try {
132
133 return (Class<? extends T>) Class.forName(typeName, initializeType, THIS_CL);
134 } catch (Throwable ignore) {
135 return null;
136 }
137 }
138
139 public static void addSuperClass(@NonNull String classInternalName, @NonNull String superClassInternalName) {
140 SUPER_CLASSES.put(classInternalName.intern(), superClassInternalName.intern());
141 }
142
143 @NonNull
144 public static String getSuperClass(@NonNull String classInternalName) {
145 String classDesc = classInternalName.intern();
146 String superName = SUPER_CLASSES.computeIfAbsent(classDesc, key -> {
147 Class<?> theClass = loadByInternalName(key);
148 Class<?> superClass = theClass.getSuperclass();
149 return superClass != null ? superClass.getName().replace('.', '/').intern() : null;
150 });
151 return superName == null ? OBJECT : superName;
152 }
153
154 @Nullable
155 public static String whichIsSuperClass(@NonNull String internalClassName1, @NonNull String internalClassName2) {
156 String class1 = actualSuperClass(internalClassName1, internalClassName2);
157
158 if (class1 != null) {
159 return class1;
160 }
161
162 return actualSuperClass(internalClassName2, internalClassName1);
163 }
164
165 @Nullable
166 private static String actualSuperClass(@NonNull String candidateSuperClass, @NonNull String candidateSubclass) {
167 String subclass = candidateSubclass;
168
169 while (true) {
170 String superClass = getSuperClass(subclass);
171
172 if (superClass.equals(OBJECT)) {
173 return null;
174 }
175
176 if (superClass.equals(candidateSuperClass)) {
177 return candidateSuperClass;
178 }
179
180 subclass = superClass;
181 }
182 }
183
184 public static boolean isClassLoaderWithNoDirectAccess(@Nullable ClassLoader classLoader) {
185 return classLoader == null || classLoader != THIS_CL && classLoader.getParent() != THIS_CL;
186 }
187
188 public static ClassLoader getClassLoaderWithAccess(@NonNull Class<?> classToBeAccessed) {
189 ClassLoader cl = classToBeAccessed.getClassLoader();
190 return isClassLoaderWithNoDirectAccess(cl) ? THIS_CL : cl;
191 }
192 }