1
2
3
4
5
6 package mockit.internal;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9 import edu.umd.cs.findbugs.annotations.Nullable;
10
11 import java.io.File;
12 import java.io.FileInputStream;
13 import java.lang.reflect.InvocationHandler;
14 import java.net.URL;
15 import java.util.Hashtable;
16 import java.util.Vector;
17 import java.util.concurrent.locks.ReentrantLock;
18 import java.util.jar.JarEntry;
19 import java.util.jar.JarFile;
20 import java.util.jar.Manifest;
21
22 import mockit.internal.expectations.mocking.MockedBridge;
23 import mockit.internal.faking.FakeBridge;
24 import mockit.internal.faking.FakeMethodBridge;
25 import mockit.internal.util.ClassLoad;
26 import mockit.internal.util.StackTrace;
27
28 import org.checkerframework.checker.index.qual.NonNegative;
29
30 public abstract class ClassLoadingBridge implements InvocationHandler {
31 private static final Object[] EMPTY_ARGS = {};
32 private static final ReentrantLock LOCK = new ReentrantLock();
33 private static boolean fieldsSet;
34 public static String hostJREClassName;
35
36 public final String id;
37
38
39
40
41
42 protected ClassLoadingBridge(@NonNull String id) {
43 this.id = id;
44 }
45
46 protected static boolean notToBeMocked(@Nullable Object instance, @NonNull String classDesc) {
47 return (instance == null && "java/lang/System".equals(classDesc)
48 || instance != null && instanceOfClassThatParticipatesInClassLoading(instance.getClass()))
49 && wasCalledDuringClassLoading();
50 }
51
52 public static boolean instanceOfClassThatParticipatesInClassLoading(@NonNull Class<?> aClass) {
53 return aClass == File.class || aClass == URL.class || aClass == FileInputStream.class
54 || aClass == Manifest.class || JarFile.class.isAssignableFrom(aClass)
55 || JarEntry.class.isAssignableFrom(aClass) || Vector.class.isAssignableFrom(aClass)
56 || Hashtable.class.isAssignableFrom(aClass);
57 }
58
59 private static boolean wasCalledDuringClassLoading() {
60 if (LOCK.isHeldByCurrentThread()) {
61 return true;
62 }
63
64 LOCK.lock();
65
66 try {
67 StackTrace st = new StackTrace(new Throwable());
68 int n = st.getDepth();
69
70 for (int i = 3; i < n; i++) {
71 StackTraceElement ste = st.getElement(i);
72
73 if ("ClassLoader.java".equals(ste.getFileName())
74 && "loadClass getResource loadLibrary".contains(ste.getMethodName())) {
75 return true;
76 }
77 }
78
79 return false;
80 } finally {
81 LOCK.unlock();
82 }
83 }
84
85 @NonNull
86 protected static Object[] extractArguments(@NonNegative int startingIndex, @NonNull Object[] args) {
87 if (args.length > startingIndex) {
88 Object[] targetMemberArgs = new Object[args.length - startingIndex];
89 System.arraycopy(args, startingIndex, targetMemberArgs, 0, targetMemberArgs.length);
90 return targetMemberArgs;
91 }
92
93 return EMPTY_ARGS;
94 }
95
96 @NonNull
97 static String getHostClassName() {
98 if (!fieldsSet) {
99 setBridgeFields();
100 fieldsSet = true;
101 }
102
103 return hostJREClassName;
104 }
105
106 private static void setBridgeFields() {
107 Class<?> hostClass = ClassLoad.loadByInternalName(hostJREClassName);
108 setBridgeField(hostClass, MockedBridge.MB);
109 setBridgeField(hostClass, FakeBridge.MB);
110 setBridgeField(hostClass, FakeMethodBridge.MB);
111 }
112
113 private static void setBridgeField(@NonNull Class<?> hostClass, @NonNull ClassLoadingBridge bridge) {
114 try {
115 hostClass.getDeclaredField(bridge.id).set(null, bridge);
116 } catch (NoSuchFieldException ignore) {
117 } catch (IllegalAccessException e) {
118 throw new RuntimeException(e);
119 }
120 }
121 }