• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / jmockit1 / 745

14 Mar 2026 09:03PM UTC coverage: 73.977% (-0.06%) from 74.032%
745

push

github

web-flow
Merge pull request #476 from hazendaz/copilot/fix-mocking-violation-alerts

Improve JVM mocking restriction detection and error messaging

5885 of 8458 branches covered (69.58%)

Branch coverage included in aggregate %.

4 of 13 new or added lines in 1 file covered. (30.77%)

6 existing lines in 2 files now uncovered.

12329 of 16163 relevant lines covered (76.28%)

0.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.19
/main/src/main/java/mockit/internal/startup/Startup.java
1
/*
2
 * MIT License
3
 * Copyright (c) 2006-2025 JMockit developers
4
 * See LICENSE file for full license text.
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
 * This is the "agent class" that initializes the JMockit "Java agent", provided the JVM is initialized with
23
 *
24
 * <pre>{@code -javaagent:&lt;properPathTo>/jmockit-1-x.jar }</pre>
25
 *
26
 * .
27
 *
28
 * @see #premain(String, Instrumentation)
29
 */
30
public final class Startup {
31
    @Nullable
32
    private static Instrumentation instrumentation;
33
    public static boolean initializing;
34

35
    private static final String UNMOCKABLE_CLASS_SUGGESTION = "This typically occurs with classes from restricted JDK"
36
            + " modules (such as java.net, java.nio) in JDK 9+. Consider wrapping the class in a testable abstraction"
37
            + " or interface that can be mocked instead. For example, define an interface for the operations you need"
38
            + " to test and inject it into the class under test.";
39

40
    private Startup() {
41
    }
42

43
    /**
44
     * User-specified fakes will applied at this time, if the "fakes" system property is set to the fully qualified
45
     * class names.
46
     *
47
     * @param agentArgs
48
     *            if "coverage", the coverage tool is activated
49
     * @param inst
50
     *            the instrumentation service provided by the JVM
51
     */
52
    public static void premain(@Nullable String agentArgs, @NonNull Instrumentation inst) {
53
        createSyntheticFieldsInJREClassToHoldClassLoadingBridges(inst);
1✔
54

55
        instrumentation = inst;
1✔
56
        inst.addTransformer(CachedClassfiles.INSTANCE, true);
1✔
57

58
        initializing = true;
1✔
59
        try {
60
            JMockitInitialization.initialize(inst, "coverage".equals(agentArgs));
1✔
61
        } finally {
62
            initializing = false;
1✔
63
        }
64

65
        inst.addTransformer(new ExpectationsTransformer());
1✔
66
    }
1✔
67

68
    @NonNull
69
    @SuppressWarnings("ConstantConditions")
70
    public static Instrumentation instrumentation() {
71
        return instrumentation;
1✔
72
    }
73

74
    public static void verifyInitialization() {
75
        if (instrumentation == null) {
1!
76
            throw new IllegalStateException(
×
77
                    "JMockit didn't get initialized; please check the -javaagent JVM initialization parameter was used");
78
        }
79
    }
1✔
80

81
    @SuppressWarnings("ConstantConditions")
82
    public static void retransformClass(@NonNull Class<?> aClass) {
83
        try {
84
            instrumentation.retransformClasses(aClass);
1✔
85
        } catch (UnmodifiableClassException ignore) {
1✔
86
        }
1✔
87
    }
1✔
88

89
    public static void redefineMethods(@NonNull ClassIdentification classToRedefine,
90
            @NonNull byte[] modifiedClassfile) {
91
        Class<?> loadedClass = classToRedefine.getLoadedClass();
1✔
92
        redefineMethods(loadedClass, modifiedClassfile);
1✔
93
    }
1✔
94

95
    public static void redefineMethods(@NonNull Class<?> classToRedefine, @NonNull byte[] modifiedClassfile) {
96
        redefineMethods(new ClassDefinition(classToRedefine, modifiedClassfile));
1✔
97
    }
1✔
98

99
    public static void redefineMethods(@NonNull ClassDefinition... classDefs) {
100
        for (ClassDefinition classDef : classDefs) {
1✔
101
            checkClassIsModifiable(classDef.getDefinitionClass());
1✔
102
        }
103

104
        try {
105
            // noinspection ConstantConditions
106
            instrumentation.redefineClasses(classDefs);
1✔
NEW
107
        } catch (ClassNotFoundException e) {
×
108
            throw new RuntimeException(e); // should never happen
×
NEW
109
        } catch (UnmodifiableClassException e) {
×
110
            // This can happen if a class is in a restricted JDK module that the JVM does not allow to be modified.
111
            // Provide a clear error to help the user understand what to do.
NEW
112
            throw new IllegalArgumentException(buildUnmockableErrorMessage(classDefs), e);
×
UNCOV
113
        } catch (InternalError ignore) {
×
114
            // If a class to be redefined hasn't been loaded yet, the JVM may get a NoClassDefFoundError during
115
            // redefinition. Unfortunately, it then throws a plain InternalError instead.
116
            for (ClassDefinition classDef : classDefs) {
×
117
                detectMissingDependenciesIfAny(classDef.getDefinitionClass());
×
118
            }
119

120
            // If the above didn't throw upon detecting a NoClassDefFoundError, then ignore the original error and
121
            // continue, in order to prevent secondary failures.
122
        }
1✔
123
    }
1✔
124

125
    private static void checkClassIsModifiable(@NonNull Class<?> classToRedefine) {
126
        // noinspection ConstantConditions
127
        if (!instrumentation.isModifiableClass(classToRedefine)) {
1!
NEW
128
            throw new IllegalArgumentException("Class " + classToRedefine.getName()
×
129
                    + " cannot be mocked/faked because the JVM does not allow it to be modified. "
130
                    + UNMOCKABLE_CLASS_SUGGESTION);
131
        }
132
    }
1✔
133

134
    @NonNull
135
    private static String buildUnmockableErrorMessage(@NonNull ClassDefinition[] classDefs) {
NEW
136
        StringBuilder sb = new StringBuilder("The JVM prevented modification of class(es):");
×
NEW
137
        for (ClassDefinition classDef : classDefs) {
×
NEW
138
            sb.append(' ').append(classDef.getDefinitionClass().getName());
×
139
        }
NEW
140
        sb.append(". ").append(UNMOCKABLE_CLASS_SUGGESTION);
×
NEW
141
        return sb.toString();
×
142
    }
143

144
    private static void detectMissingDependenciesIfAny(@NonNull Class<?> mockedClass) {
145
        try {
146
            Class.forName(mockedClass.getName(), false, mockedClass.getClassLoader());
×
147
        } catch (NoClassDefFoundError e) {
×
148
            throw new RuntimeException("Unable to mock " + mockedClass + " due to a missing dependency", e);
×
149
        } catch (ClassNotFoundException ignore) {
×
150
            // Shouldn't happen since the mocked class would already have been found in the classpath.
151
        }
×
152
    }
×
153

154
    @Nullable
155
    public static Class<?> getClassIfLoaded(@NonNull String classDescOrName) {
156
        String className = classDescOrName.replace('/', '.');
1✔
157
        @SuppressWarnings("ConstantConditions")
158
        Class<?>[] loadedClasses = instrumentation.getAllLoadedClasses();
1✔
159

160
        for (Class<?> aClass : loadedClasses) {
1✔
161
            if (aClass.getName().equals(className)) {
1✔
162
                return aClass;
1✔
163
            }
164
        }
165

166
        return null;
1✔
167
    }
168
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc