1
2
3
4
5 package mockit.internal.injection;
6
7 import static java.lang.reflect.Modifier.isAbstract;
8
9 import edu.umd.cs.findbugs.annotations.NonNull;
10 import edu.umd.cs.findbugs.annotations.Nullable;
11
12 import java.lang.reflect.Constructor;
13 import java.lang.reflect.Type;
14
15 import mockit.asm.classes.ClassReader;
16 import mockit.asm.classes.ClassVisitor;
17 import mockit.internal.classGeneration.ImplementationClass;
18 import mockit.internal.expectations.mocking.SubclassGenerationModifier;
19 import mockit.internal.injection.constructor.ConstructorInjection;
20 import mockit.internal.injection.constructor.ConstructorSearch;
21 import mockit.internal.injection.full.FullInjection;
22 import mockit.internal.state.TestRun;
23
24 public final class TestedObjectCreation {
25 @NonNull
26 private final InjectionState injectionState;
27 @Nullable
28 private final FullInjection fullInjection;
29 @NonNull
30 final TestedClass testedClass;
31
32 TestedObjectCreation(@NonNull InjectionState injectionState, @Nullable FullInjection fullInjection,
33 @NonNull Type declaredType, @NonNull Class<?> declaredClass) {
34 this.injectionState = injectionState;
35 this.fullInjection = fullInjection;
36 Class<?> actualTestedClass = isAbstract(declaredClass.getModifiers())
37 ? generateSubclass(declaredType, declaredClass)
38 : declaredClass;
39 testedClass = new TestedClass(declaredType, actualTestedClass);
40 }
41
42 @NonNull
43 private static Class<?> generateSubclass(@NonNull final Type testedType, @NonNull final Class<?> abstractClass) {
44 Class<?> generatedSubclass = new ImplementationClass<>(abstractClass) {
45 @NonNull
46 @Override
47 protected ClassVisitor createMethodBodyGenerator(@NonNull ClassReader cr) {
48 return new SubclassGenerationModifier(abstractClass, testedType, cr, generatedClassName, true);
49 }
50 }.generateClass();
51
52 TestRun.mockFixture().registerMockedClass(generatedSubclass);
53 return generatedSubclass;
54 }
55
56 public TestedObjectCreation(@NonNull InjectionState injectionState, @Nullable FullInjection fullInjection,
57 @NonNull Class<?> implementationClass) {
58 this.injectionState = injectionState;
59 this.fullInjection = fullInjection;
60 testedClass = new TestedClass(implementationClass, implementationClass);
61 }
62
63 @Nullable
64 public Object create(boolean required, boolean needToConstruct) {
65 ConstructorSearch constructorSearch = new ConstructorSearch(injectionState, testedClass, fullInjection != null);
66 Constructor<?> constructor = constructorSearch.findConstructorToUse();
67
68 if (constructor == null) {
69 String description = constructorSearch.getDescription();
70 throw new IllegalArgumentException(
71 "No constructor in tested class that can be satisfied by available tested/injectable values"
72 + description);
73 }
74
75 ConstructorInjection constructorInjection = new ConstructorInjection(injectionState, fullInjection,
76 constructor);
77 return constructorInjection.instantiate(constructorSearch.parameterProviders, testedClass, required,
78 needToConstruct);
79 }
80 }