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