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.coverage.modification;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   
10  import java.io.File;
11  import java.net.URI;
12  import java.net.URISyntaxException;
13  import java.nio.file.Path;
14  import java.security.ProtectionDomain;
15  import java.util.HashSet;
16  import java.util.Set;
17  
18  import org.checkerframework.checker.index.qual.NonNegative;
19  
20  /**
21   * Finds and loads all classes that should also be measured, but were not loaded until now.
22   */
23  public final class ClassesNotLoaded {
24      @NonNull
25      private final ClassModification classModification;
26      @NonNegative
27      private int firstPosAfterParentDir;
28  
29      public ClassesNotLoaded(@NonNull ClassModification classModification) {
30          this.classModification = classModification;
31      }
32  
33      public void gatherCoverageData() {
34          Set<ProtectionDomain> protectionDomainsSoFar = new HashSet<>(
35                  classModification.protectionDomainsWithUniqueLocations);
36  
37          for (ProtectionDomain pd : protectionDomainsSoFar) {
38              URI location;
39              try {
40                  location = pd.getCodeSource().getLocation().toURI();
41                  File classPathEntry = Path.of(location).toFile();
42  
43                  if (!classPathEntry.getPath().endsWith(".jar")) {
44                      firstPosAfterParentDir = classPathEntry.getPath().length() + 1;
45                      loadAdditionalClasses(classPathEntry, pd);
46                  }
47              } catch (URISyntaxException e) {
48                  // Do nothing at this point
49              }
50          }
51      }
52  
53      private void loadAdditionalClasses(@NonNull File classPathEntry, @NonNull ProtectionDomain protectionDomain) {
54          File[] filesInDir = classPathEntry.listFiles();
55  
56          if (filesInDir != null) {
57              for (File fileInDir : filesInDir) {
58                  if (fileInDir.isDirectory()) {
59                      loadAdditionalClasses(fileInDir, protectionDomain);
60                  } else {
61                      loadAdditionalClass(fileInDir.getPath(), protectionDomain);
62                  }
63              }
64          }
65      }
66  
67      private void loadAdditionalClass(@NonNull String filePath, @NonNull ProtectionDomain protectionDomain) {
68          int p = filePath.lastIndexOf(".class");
69  
70          if (p > 0) {
71              String relativePath = filePath.substring(firstPosAfterParentDir, p);
72              String className = relativePath.replace(File.separatorChar, '.');
73  
74              if (classModification.isToBeConsideredForCoverage(className, protectionDomain)) {
75                  loadClass(className, protectionDomain);
76              }
77          }
78      }
79  
80      private static void loadClass(@NonNull String className, @NonNull ProtectionDomain protectionDomain) {
81          try {
82              Class.forName(className, false, protectionDomain.getClassLoader());
83          } catch (ClassNotFoundException | NoClassDefFoundError ignore) {
84          }
85      }
86  }