1/** 2 * Copyright 2006-2017 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.objenesis.tck.search; 17 18import java.io.File; 19import java.io.IOException; 20import java.net.URL; 21import java.util.*; 22import java.util.jar.JarEntry; 23import java.util.jar.JarFile; 24 25/** 26 * Taken and adapted from <a href="https://raw.githubusercontent.com/ddopson/java-class-enumerator/master/src/pro/ddopson/ClassEnumerator.java">here</a> 27 * 28 * @author Henri Tremblay 29 */ 30public class ClassEnumerator { 31 32 private static void processDirectory(File directory, String pkgname, SortedSet<String> classes) { 33 34 // Get the list of the files contained in the package 35 String[] files = directory.list(); 36 37 for (int i = 0; i < files.length; i++) { 38 String fileName = files[i]; 39 // we are only interested in .class files 40 if (fileName.endsWith(".class")) { 41 // removes the .class extension 42 String className = pkgname + '.' + fileName.substring(0, fileName.length() - 6); 43 classes.add(className); 44 continue; 45 } 46 47 File subdir = new File(directory, fileName); 48 if (subdir.isDirectory()) { 49 processDirectory(subdir, pkgname + '.' + fileName, classes); 50 } 51 } 52 } 53 54 private static void processJarfile(URL resource, String pkgname, SortedSet<String> classes) { 55 String relPath = pkgname.replace('.', '/'); 56 String resPath = resource.getPath(); 57 String jarPath = resPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", ""); 58 59 JarFile jarFile; 60 try { 61 jarFile = new JarFile(jarPath); 62 } catch (IOException e) { 63 throw new RuntimeException("Unexpected IOException reading JAR File '" + jarPath + "'", e); 64 } 65 Enumeration<JarEntry> entries = jarFile.entries(); 66 while(entries.hasMoreElements()) { 67 JarEntry entry = entries.nextElement(); 68 String entryName = entry.getName(); 69 String className = null; 70 if(entryName.endsWith(".class") && entryName.startsWith(relPath) && entryName.length() > (relPath.length() + "/".length())) { 71 className = entryName.replace('/', '.').replace('\\', '.').replace(".class", ""); 72 } 73 74 if (className != null) { 75 classes.add(className); 76 } 77 } 78 } 79 80 /** 81 * Return all the classes in this package recursively. The class loader of the {@code ClassEnumerator} class 82 * is used 83 * 84 * @param pkg the searched package 85 * @return list of full class names 86 */ 87 public static SortedSet<String> getClassesForPackage(Package pkg) { 88 return getClassesForPackage(pkg, ClassEnumerator.class.getClassLoader()); 89 } 90 91 /** 92 * Return all the classes in this package recursively. 93 * 94 * @param pkg the searched package 95 * @return list of full class names 96 */ 97 public static SortedSet<String> getClassesForPackage(Package pkg, ClassLoader classLoader) { 98 SortedSet<String> classes = new TreeSet<String>(new Comparator<String>() { 99 public int compare(String o1, String o2) { 100 String simpleName1 = getSimpleName(o1); 101 String simpleName2 = getSimpleName(o2); 102 return simpleName1.compareTo(simpleName2); 103 } 104 105 private String getSimpleName(String className) { 106 return className.substring(className.lastIndexOf('.')); 107 } 108 }); 109 110 String pkgname = pkg.getName(); 111 String relPath = pkgname.replace('.', '/'); 112 113 // Get a File object for the package 114 Enumeration<URL> resources; 115 try { 116 resources = classLoader.getResources(relPath); 117 } catch (IOException e) { 118 throw new RuntimeException(e); 119 } 120 121 while(resources.hasMoreElements()) { 122 URL resource = resources.nextElement(); 123 if (resource.toString().startsWith("jar:")) { 124 processJarfile(resource, pkgname, classes); 125 } else { 126 processDirectory(new File(resource.getPath()), pkgname, classes); 127 } 128 } 129 130 return classes; 131 } 132 133} 134