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