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.capturing;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import mockit.asm.classes.ClassReader;
11  import mockit.internal.BaseClassModifier;
12  import mockit.internal.ClassFile;
13  import mockit.internal.startup.Startup;
14  import mockit.internal.state.TestRun;
15  
16  public abstract class CaptureOfImplementations<M> {
17      protected CaptureOfImplementations() {
18      }
19  
20      protected final void makeSureAllSubtypesAreModified(@NonNull Class<?> baseType, boolean registerCapturedClasses,
21              @Nullable M typeMetadata) {
22          CapturedType captureMetadata = new CapturedType(baseType);
23          redefineClassesAlreadyLoaded(captureMetadata, baseType, typeMetadata);
24          createCaptureTransformer(captureMetadata, registerCapturedClasses, typeMetadata);
25      }
26  
27      private void redefineClassesAlreadyLoaded(@NonNull CapturedType captureMetadata, @NonNull Class<?> baseType,
28              @Nullable M typeMetadata) {
29          Class<?>[] classesLoaded = Startup.instrumentation().getAllLoadedClasses();
30  
31          for (Class<?> aClass : classesLoaded) {
32              if (captureMetadata.isToBeCaptured(aClass)) {
33                  redefineClass(aClass, baseType, typeMetadata);
34              }
35          }
36      }
37  
38      protected final void redefineClass(@NonNull Class<?> realClass, @NonNull Class<?> baseType,
39              @Nullable M typeMetadata) {
40          if (!TestRun.mockFixture().containsRedefinedClass(realClass)) {
41              ClassReader classReader;
42  
43              try {
44                  classReader = ClassFile.createReaderOrGetFromCache(realClass);
45              } catch (ClassFile.NotFoundException ignore) {
46                  return;
47              }
48  
49              TestRun.ensureThatClassIsInitialized(realClass);
50  
51              BaseClassModifier modifier = createModifier(realClass.getClassLoader(), classReader, baseType,
52                      typeMetadata);
53              classReader.accept(modifier);
54  
55              if (modifier.wasModified()) {
56                  byte[] modifiedClass = modifier.toByteArray();
57                  redefineClass(realClass, modifiedClass);
58              }
59          }
60      }
61  
62      @NonNull
63      protected abstract BaseClassModifier createModifier(@Nullable ClassLoader cl, @NonNull ClassReader cr,
64              @NonNull Class<?> baseType, @Nullable M typeMetadata);
65  
66      protected abstract void redefineClass(@NonNull Class<?> realClass, @NonNull byte[] modifiedClass);
67  
68      private void createCaptureTransformer(@NonNull CapturedType captureMetadata, boolean registerCapturedClasses,
69              @Nullable M typeMetadata) {
70          CaptureTransformer<M> transformer = new CaptureTransformer<>(captureMetadata, this, registerCapturedClasses,
71                  typeMetadata);
72          Startup.instrumentation().addTransformer(transformer, true);
73          TestRun.mockFixture().addCaptureTransformer(transformer);
74      }
75  }