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

hazendaz / jmockit1 / 496

15 Nov 2025 05:33PM UTC coverage: 72.192% (-0.008%) from 72.2%
496

push

github

web-flow
Merge pull request #412 from hazendaz/renovate/major-spring-core

Update spring core to v7 (major)

5677 of 8360 branches covered (67.91%)

Branch coverage included in aggregate %.

11922 of 16018 relevant lines covered (74.43%)

0.74 hits per line

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

92.69
/main/src/main/java/mockit/internal/injection/constructor/ConstructorSearch.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.injection.constructor;
7

8
import static java.lang.reflect.Modifier.PRIVATE;
9
import static java.lang.reflect.Modifier.PROTECTED;
10
import static java.lang.reflect.Modifier.PUBLIC;
11

12
import static mockit.internal.injection.InjectionPoint.getQualifiedName;
13
import static mockit.internal.injection.InjectionPoint.getTypeOfInjectionPointFromVarargsParameter;
14
import static mockit.internal.injection.InjectionPoint.kindOfInjectionPoint;
15

16
import edu.umd.cs.findbugs.annotations.NonNull;
17
import edu.umd.cs.findbugs.annotations.Nullable;
18

19
import java.lang.annotation.Annotation;
20
import java.lang.reflect.Constructor;
21
import java.lang.reflect.Type;
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.Comparator;
25
import java.util.List;
26

27
import mockit.asm.types.JavaType;
28
import mockit.internal.injection.InjectionPoint;
29
import mockit.internal.injection.InjectionPoint.KindOfInjectionPoint;
30
import mockit.internal.injection.InjectionProvider;
31
import mockit.internal.injection.InjectionProviders;
32
import mockit.internal.injection.InjectionState;
33
import mockit.internal.injection.TestedClass;
34
import mockit.internal.state.ParameterNames;
35
import mockit.internal.util.ParameterNameExtractor;
36

37
public final class ConstructorSearch {
38
    private static final int CONSTRUCTOR_ACCESS = PUBLIC + PROTECTED + PRIVATE;
39

40
    @NonNull
41
    private final InjectionState injectionState;
42
    @NonNull
43
    private final TestedClass testedClass;
44
    @NonNull
45
    private final String testedClassDesc;
46
    @NonNull
47
    public List<InjectionProvider> parameterProviders;
48
    private final boolean withFullInjection;
49
    @Nullable
50
    private Constructor<?> constructor;
51
    @Nullable
52
    private StringBuilder searchResults;
53

54
    public ConstructorSearch(@NonNull InjectionState injectionState, @NonNull TestedClass testedClass,
55
            boolean withFullInjection) {
1✔
56
        this.injectionState = injectionState;
1✔
57
        this.testedClass = testedClass;
1✔
58
        Class<?> declaredClass = testedClass.getDeclaredClass();
1✔
59
        testedClassDesc = ParameterNameExtractor.extractNames(declaredClass);
1✔
60
        parameterProviders = new ArrayList<>();
1✔
61
        this.withFullInjection = withFullInjection;
1✔
62
    }
1✔
63

64
    @Nullable
65
    public Constructor<?> findConstructorToUse() {
66
        constructor = null;
1✔
67
        Class<?> declaredClass = testedClass.targetClass;
1✔
68
        Constructor<?>[] constructors = declaredClass.getDeclaredConstructors();
1✔
69

70
        if (!findSingleAnnotatedConstructor(constructors)) {
1✔
71
            findSatisfiedConstructorWithMostParameters(constructors);
1✔
72
        }
73

74
        return constructor;
1✔
75
    }
76

77
    private boolean findSingleAnnotatedConstructor(@NonNull Constructor<?>[] constructors) {
78
        for (Constructor<?> c : constructors) {
1✔
79
            if (kindOfInjectionPoint(c) != KindOfInjectionPoint.NotAnnotated) {
1✔
80
                List<InjectionProvider> providersFound = findParameterProvidersForConstructor(c);
1✔
81

82
                if (providersFound != null) {
1✔
83
                    parameterProviders = providersFound;
1✔
84
                    constructor = c;
1✔
85
                }
86

87
                return true;
1✔
88
            }
89
        }
90

91
        return false;
1✔
92
    }
93

94
    private void findSatisfiedConstructorWithMostParameters(@NonNull Constructor<?>[] constructors) {
95
        sortConstructorsWithMostAccessibleFirst(constructors);
1✔
96

97
        Constructor<?> unresolvedConstructor = null;
1✔
98
        List<InjectionProvider> incompleteProviders = null;
1✔
99

100
        for (Constructor<?> candidateConstructor : constructors) {
1✔
101
            List<InjectionProvider> providersFound = findParameterProvidersForConstructor(candidateConstructor);
1✔
102

103
            if (providersFound != null) {
1✔
104
                if (withFullInjection && containsUnresolvedProvider(providersFound)) {
1✔
105
                    if (unresolvedConstructor == null || isLargerConstructor(candidateConstructor, providersFound,
1!
106
                            unresolvedConstructor, incompleteProviders)) {
107
                        unresolvedConstructor = candidateConstructor;
1✔
108
                        incompleteProviders = providersFound;
1✔
109
                    }
110
                } else if (constructor == null
1✔
111
                        || isLargerConstructor(candidateConstructor, providersFound, constructor, parameterProviders)) {
1✔
112
                    constructor = candidateConstructor;
1✔
113
                    parameterProviders = providersFound;
1✔
114
                }
115
            }
116
        }
117

118
        selectConstructorWithUnresolvedParameterIfMoreAccessible(unresolvedConstructor, incompleteProviders);
1✔
119
    }
1✔
120

121
    private static void sortConstructorsWithMostAccessibleFirst(@NonNull Constructor<?>[] constructors) {
122
        if (constructors.length > 1) {
1✔
123
            Arrays.sort(constructors, CONSTRUCTOR_COMPARATOR);
1✔
124
        }
125
    }
1✔
126

127
    private static final Comparator<Constructor<?>> CONSTRUCTOR_COMPARATOR = ConstructorSearch::compareAccessibility;
1✔
128

129
    private static int compareAccessibility(@NonNull Constructor<?> c1, @NonNull Constructor<?> c2) {
130
        int m1 = getModifiers(c1);
1✔
131
        int m2 = getModifiers(c2);
1✔
132
        if (m1 == m2) {
1✔
133
            return 0;
1✔
134
        }
135
        if (m1 == PUBLIC) {
1✔
136
            return -1;
1✔
137
        }
138
        if (m2 == PUBLIC) {
1✔
139
            return 1;
1✔
140
        }
141
        if (m1 == PROTECTED) {
1!
142
            return -1;
×
143
        }
144
        if (m2 == PROTECTED) {
1!
145
            return 1;
×
146
        }
147
        if (m2 == PRIVATE) {
1✔
148
            return -1;
1✔
149
        }
150
        return 1;
1✔
151
    }
152

153
    private static boolean containsUnresolvedProvider(@NonNull List<InjectionProvider> providersFound) {
154
        for (InjectionProvider provider : providersFound) {
1✔
155
            if (provider instanceof ConstructorParameter && provider.getValue(null) == null) {
1✔
156
                return true;
1✔
157
            }
158
        }
1✔
159

160
        return false;
1✔
161
    }
162

163
    private static boolean isLargerConstructor(@NonNull Constructor<?> candidateConstructor,
164
            @NonNull List<InjectionProvider> providersFound, @NonNull Constructor<?> previousSatisfiableConstructor,
165
            @NonNull List<InjectionProvider> previousProviders) {
166
        return getModifiers(candidateConstructor) == getModifiers(previousSatisfiableConstructor)
1✔
167
                && providersFound.size() >= previousProviders.size();
1✔
168
    }
169

170
    private static int getModifiers(@NonNull Constructor<?> c) {
171
        return CONSTRUCTOR_ACCESS & c.getModifiers();
1✔
172
    }
173

174
    @Nullable
175
    private List<InjectionProvider> findParameterProvidersForConstructor(@NonNull Constructor<?> candidate) {
176
        Type[] parameterTypes = candidate.getGenericParameterTypes();
1✔
177
        Annotation[][] parameterAnnotations = candidate.getParameterAnnotations();
1✔
178
        int n = parameterTypes.length;
1✔
179
        List<InjectionProvider> providersFound = new ArrayList<>(n);
1✔
180
        boolean varArgs = candidate.isVarArgs();
1✔
181

182
        if (varArgs) {
1✔
183
            n--;
1✔
184
        }
185

186
        printCandidateConstructorNameIfRequested(candidate);
1✔
187

188
        String constructorDesc = "<init>" + JavaType.getConstructorDescriptor(candidate);
1✔
189
        InjectionProviders injectionProviders = injectionState.injectionProviders;
1✔
190
        KindOfInjectionPoint kindOfInjectionPoint = kindOfInjectionPoint(candidate);
1✔
191

192
        for (int i = 0; i < n; i++) {
1✔
193
            Type parameterType = parameterTypes[i];
1✔
194
            injectionProviders.setTypeOfInjectionPoint(parameterType, kindOfInjectionPoint);
1✔
195

196
            String parameterName = ParameterNames.getName(testedClassDesc, constructorDesc, i);
1✔
197
            Annotation[] appliedAnnotations = parameterAnnotations[i];
1✔
198
            InjectionProvider provider = findOrCreateInjectionProvider(parameterType, parameterName,
1✔
199
                    appliedAnnotations);
200

201
            if (provider == null || providersFound.contains(provider)) {
1✔
202
                printParameterOfCandidateConstructorIfRequested(parameterName, provider);
1✔
203
                return null;
1✔
204
            }
205

206
            providersFound.add(provider);
1✔
207
        }
208

209
        if (varArgs) {
1✔
210
            Type parameterType = parameterTypes[n];
1✔
211
            InjectionProvider injectable = hasInjectedValuesForVarargsParameter(parameterType, kindOfInjectionPoint,
1✔
212
                    injectionProviders);
213

214
            if (injectable != null) {
1!
215
                providersFound.add(injectable);
1✔
216
            }
217
        }
218

219
        return providersFound;
1✔
220
    }
221

222
    @Nullable
223
    private InjectionProvider findOrCreateInjectionProvider(@NonNull Type parameterType, @Nullable String parameterName,
224
            @NonNull Annotation[] parameterAnnotations) {
225
        String qualifiedName = getQualifiedName(parameterAnnotations);
1✔
226

227
        if (parameterName == null && qualifiedName == null) {
1!
228
            return null;
×
229
        }
230

231
        boolean qualified = qualifiedName != null;
1✔
232
        String targetName = qualified ? qualifiedName : parameterName;
1✔
233
        InjectionProvider provider = injectionState.injectionProviders.getProviderByTypeAndOptionallyName(targetName,
1✔
234
                testedClass);
235

236
        if (provider != null) {
1✔
237
            return provider;
1✔
238
        }
239

240
        InjectionPoint injectionPoint = new InjectionPoint(parameterType, targetName, qualifiedName);
1✔
241
        Object valueForParameter = injectionState.getTestedValue(testedClass, injectionPoint);
1✔
242

243
        if (valueForParameter == null && !withFullInjection) {
1✔
244
            return null;
1✔
245
        }
246

247
        return new ConstructorParameter(parameterType, parameterAnnotations, targetName, valueForParameter);
1✔
248
    }
249

250
    @Nullable
251
    private InjectionProvider hasInjectedValuesForVarargsParameter(@NonNull Type parameterType,
252
            @NonNull KindOfInjectionPoint kindOfInjectionPoint, @NonNull InjectionProviders injectionProviders) {
253
        Type varargsElementType = getTypeOfInjectionPointFromVarargsParameter(parameterType);
1✔
254
        injectionProviders.setTypeOfInjectionPoint(varargsElementType, kindOfInjectionPoint);
1✔
255
        return injectionProviders.findNextInjectableForInjectionPoint(testedClass);
1✔
256
    }
257

258
    private void selectConstructorWithUnresolvedParameterIfMoreAccessible(
259
            @Nullable Constructor<?> unresolvedConstructor, List<InjectionProvider> incompleteProviders) {
260
        if (unresolvedConstructor != null
1✔
261
                && (constructor == null || compareAccessibility(unresolvedConstructor, constructor) < 0)) {
1✔
262
            constructor = unresolvedConstructor;
1✔
263
            parameterProviders = incompleteProviders;
1✔
264
        }
265
    }
1✔
266

267
    // Methods used only when no satisfiable constructor is found //////////////////////////////////////////////////////
268

269
    @NonNull
270
    public String getDescription() {
271
        searchResults = new StringBuilder();
1✔
272
        findConstructorToUse();
1✔
273
        String contents = searchResults.toString();
1✔
274
        searchResults = null;
1✔
275
        return contents;
1✔
276
    }
277

278
    @SuppressWarnings("DynamicRegexReplaceableByCompiledPattern")
279
    private void printCandidateConstructorNameIfRequested(@NonNull Constructor<?> candidate) {
280
        if (searchResults != null) {
1✔
281
            String constructorDesc = candidate.toGenericString().replace("java.lang.", "").replace(",", ", ");
1✔
282
            searchResults.append("\r\n  ").append(constructorDesc).append("\r\n");
1✔
283
        }
284
    }
1✔
285

286
    private void printParameterOfCandidateConstructorIfRequested(@Nullable String parameterName,
287
            @Nullable InjectionProvider injectableFound) {
288
        if (searchResults != null) {
1✔
289
            searchResults.append("    disregarded because ");
1✔
290

291
            if (parameterName == null) {
1!
292
                searchResults.append("parameter names are not available");
×
293
            } else {
294
                searchResults.append("no tested/injectable value was found for parameter \"").append(parameterName)
1✔
295
                        .append('"');
1✔
296

297
                if (injectableFound != null) {
1!
298
                    searchResults.append(" that hadn't been used already");
×
299
                }
300
            }
301
        }
302
    }
1✔
303
}
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