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