View Javadoc
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;
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  }