1 package eu.svjatoslav.inspector.java.commandline;
3 import eu.svjatoslav.inspector.java.structure.ClassGraph;
6 import java.io.FileInputStream;
7 import java.io.IOException;
8 import java.net.MalformedURLException;
10 import java.net.URLClassLoader;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.jar.JarEntry;
14 import java.util.jar.JarInputStream;
17 * This class acts as a commandline interface for JavaInspect.
20 public static void main(String[] args) throws IOException, ClassNotFoundException {
21 CommandlineConfiguration configuration = new CommandlineConfiguration(args);
22 if (!configuration.configurationOk) {
23 configuration.parser.showHelp();
27 if (configuration.showHelp.isSpecified()) configuration.parser.showHelp();
29 getClassGraph(configuration).generateGraph(configuration.graphName.getValue());
31 if (configuration.isDebug())
32 System.out.println("Graph ready.");
35 private static ClassGraph getClassGraph(CommandlineConfiguration configuration) throws IOException, ClassNotFoundException {
36 List<File> jarFiles = configuration.jarFiles.getValue();
38 URLClassLoader classLoader = new URLClassLoader(
39 getClasspathUrls(jarFiles, configuration.classPaths.getValue()),
40 configuration.getClass().getClassLoader());
42 ClassGraph classGraph = new ClassGraph();
44 if (configuration.targetDirectory.isSpecified())
45 classGraph.setTargetDirectory(configuration.targetDirectory.getValue());
47 if (configuration.targetImageType.isSpecified())
48 classGraph.setTargetImageType(configuration.targetImageType.getValue());
50 classGraph.setKeepDotFile(configuration.keepDotFile.getValue());
52 if (configuration.rootClasses.isSpecified()) {
53 // add only selected root classes
54 for (String rootClass : configuration.rootClasses.getValue())
55 attemptClassAdditionByName(classLoader, classGraph, configuration, rootClass);
58 // add all classes in the jar files to graph
59 for (File jarFile : jarFiles)
60 addJarToGraph(jarFile, classLoader, classGraph, configuration);
62 configuration.blacklistGlob.getValue().forEach(classGraph::blacklistClassGlob);
63 configuration.whitelistGlob.getValue().forEach(classGraph::whitelistClassGlob);
65 if (configuration.hideOrphanedClasses.getValue())
66 classGraph.hideOrphanedClasses();
71 private static URL[] getClasspathUrls(List<File> jarFiles, List<File> classpathDirectories) {
72 List<URL> urls = new ArrayList<>();
74 classpathDirectories.forEach(classpathDirectory -> {
76 urls.add(classpathDirectory.toURI().toURL());
77 } catch (MalformedURLException e) {
78 throw new RuntimeException(e);
82 jarFiles.forEach((File file) -> {
84 urls.add(file.toURI().toURL());
85 } catch (MalformedURLException e) {
86 throw new RuntimeException(e);
90 return urls.toArray(new URL[urls.size()]);
93 private static void addJarToGraph(
94 File jarFile, URLClassLoader classLoader, ClassGraph classGraph, CommandlineConfiguration configuration)
95 throws IOException, ClassNotFoundException {
97 for (String className : getClassNamesFromJar(jarFile))
98 attemptClassAdditionByName(classLoader, classGraph, configuration, className);
101 private static void attemptClassAdditionByName(URLClassLoader classLoader, ClassGraph classGraph, CommandlineConfiguration configuration, String className) throws ClassNotFoundException {
102 if (configuration.isDebug())
103 System.out.println("Adding class to graph: " + className);
105 classGraph.add(loadClassByName(classLoader, className));
106 } catch (NoClassDefFoundError e) {
107 if (configuration.isDebug())
108 System.out.println("Class definition was not found.");
109 // Sometimes referenced classes are not found in the same Jar.
110 // Let's ignore this and proceed with the classes that we have.
114 private static Class loadClassByName(URLClassLoader classLoader, String className) throws ClassNotFoundException {
115 return Class.forName(className, true, classLoader);
118 public static List<String> getClassNamesFromJar(File jarFile) throws IOException {
119 List<String> result = new ArrayList<>();
121 JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile))
124 JarEntry jarEntry = jarInputStream.getNextJarEntry();
125 if (jarEntry == null)
128 if (isClassFile(jarEntry))
129 result.add(getClassNameFromFileName(jarEntry));
136 private static boolean isClassFile(JarEntry jarEntry) {
137 return jarEntry.getName().endsWith(".class");
140 private static String getClassNameFromFileName(JarEntry jarEntry) {
141 String result = jarEntry.getName().replaceAll("/", "\\.");
142 return result.substring(0, result.lastIndexOf('.'));