View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
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  }