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