1
2
3
4
5
6 package mockit.internal.startup;
7
8 import static mockit.internal.startup.ClassLoadingBridgeFields.createSyntheticFieldsInJREClassToHoldClassLoadingBridges;
9
10 import edu.umd.cs.findbugs.annotations.NonNull;
11 import edu.umd.cs.findbugs.annotations.Nullable;
12
13 import java.lang.instrument.ClassDefinition;
14 import java.lang.instrument.Instrumentation;
15 import java.lang.instrument.UnmodifiableClassException;
16
17 import mockit.internal.ClassIdentification;
18 import mockit.internal.expectations.transformation.ExpectationsTransformer;
19 import mockit.internal.state.CachedClassfiles;
20
21
22
23
24
25
26
27
28
29
30 public final class Startup {
31 @Nullable
32 private static Instrumentation instrumentation;
33 public static boolean initializing;
34
35 private Startup() {
36 }
37
38
39
40
41
42
43
44
45
46
47 public static void premain(@Nullable String agentArgs, @NonNull Instrumentation inst) {
48 createSyntheticFieldsInJREClassToHoldClassLoadingBridges(inst);
49
50 instrumentation = inst;
51 inst.addTransformer(CachedClassfiles.INSTANCE, true);
52
53 initializing = true;
54 try {
55 JMockitInitialization.initialize(inst, "coverage".equals(agentArgs));
56 } finally {
57 initializing = false;
58 }
59
60 inst.addTransformer(new ExpectationsTransformer());
61 }
62
63 @NonNull
64 @SuppressWarnings("ConstantConditions")
65 public static Instrumentation instrumentation() {
66 return instrumentation;
67 }
68
69 public static void verifyInitialization() {
70 if (instrumentation == null) {
71 throw new IllegalStateException(
72 "JMockit didn't get initialized; please check the -javaagent JVM initialization parameter was used");
73 }
74 }
75
76 @SuppressWarnings("ConstantConditions")
77 public static void retransformClass(@NonNull Class<?> aClass) {
78 try {
79 instrumentation.retransformClasses(aClass);
80 } catch (UnmodifiableClassException ignore) {
81 }
82 }
83
84 public static void redefineMethods(@NonNull ClassIdentification classToRedefine,
85 @NonNull byte[] modifiedClassfile) {
86 Class<?> loadedClass = classToRedefine.getLoadedClass();
87 redefineMethods(loadedClass, modifiedClassfile);
88 }
89
90 public static void redefineMethods(@NonNull Class<?> classToRedefine, @NonNull byte[] modifiedClassfile) {
91 redefineMethods(new ClassDefinition(classToRedefine, modifiedClassfile));
92 }
93
94 public static void redefineMethods(@NonNull ClassDefinition... classDefs) {
95 try {
96
97 instrumentation.redefineClasses(classDefs);
98 } catch (ClassNotFoundException | UnmodifiableClassException e) {
99 throw new RuntimeException(e);
100 } catch (InternalError ignore) {
101
102
103 for (ClassDefinition classDef : classDefs) {
104 detectMissingDependenciesIfAny(classDef.getDefinitionClass());
105 }
106
107
108
109 }
110 }
111
112 private static void detectMissingDependenciesIfAny(@NonNull Class<?> mockedClass) {
113 try {
114 Class.forName(mockedClass.getName(), false, mockedClass.getClassLoader());
115 } catch (NoClassDefFoundError e) {
116 throw new RuntimeException("Unable to mock " + mockedClass + " due to a missing dependency", e);
117 } catch (ClassNotFoundException ignore) {
118
119 }
120 }
121
122 @Nullable
123 public static Class<?> getClassIfLoaded(@NonNull String classDescOrName) {
124 String className = classDescOrName.replace('/', '.');
125 @SuppressWarnings("ConstantConditions")
126 Class<?>[] loadedClasses = instrumentation.getAllLoadedClasses();
127
128 for (Class<?> aClass : loadedClasses) {
129 if (aClass.getName().equals(className)) {
130 return aClass;
131 }
132 }
133
134 return null;
135 }
136 }