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