是否有可能找到给定包中的所有类或接口?(快速看了一下e.g. Package,似乎没有。)


当前回答

谷歌Guava 14包含了一个新类ClassPath,它有三个方法来扫描顶级类:

getTopLevelClasses () getTopLevelClasses(管柱packageName) getTopLevelClassesRecursive(管柱packageName)

有关更多信息,请参阅ClassPath javadocs。

其他回答

一般来说,类装入器不允许扫描类路径上的所有类。但通常唯一使用的类加载器是UrlClassLoader,我们可以从中检索目录和jar文件的列表(参见getURLs),并逐个打开它们以列出可用的类。这种方法称为类路径扫描,在Scannotation和Reflections中实现。

Reflections reflections = new Reflections("my.package");
Set<Class<? extends Object>> classes = reflections.getSubTypesOf(Object.class);

另一种方法是使用Java可插入注释处理API编写注释处理器,该处理器将在编译时收集所有注释类,并构建索引文件供运行时使用。此机制在ClassIndex库中实现:

// package-info.java
@IndexSubclasses
package my.package;

// your code
Iterable<Class> classes = ClassIndex.getPackageClasses("my.package");

注意,由于Java编译器自动发现类路径上的任何处理器,因此扫描是完全自动化的,因此不需要额外的设置。

谷歌Guava 14包含了一个新类ClassPath,它有三个方法来扫描顶级类:

getTopLevelClasses () getTopLevelClasses(管柱packageName) getTopLevelClassesRecursive(管柱packageName)

有关更多信息,请参阅ClassPath javadocs。

我是这样做的。我扫描所有的子文件夹(子包),我不尝试加载匿名类:

   /**
   * Attempts to list all the classes in the specified package as determined
   * by the context class loader, recursively, avoiding anonymous classes
   * 
   * @param pckgname
   *            the package name to search
   * @return a list of classes that exist within that package
   * @throws ClassNotFoundException
   *             if something went wrong
   */
  private static List<Class> getClassesForPackage(String pckgname) throws ClassNotFoundException {
      // This will hold a list of directories matching the pckgname. There may be more than one if a package is split over multiple jars/paths
      ArrayList<File> directories = new ArrayList<File>();
      String packageToPath = pckgname.replace('.', '/');
      try {
          ClassLoader cld = Thread.currentThread().getContextClassLoader();
          if (cld == null) {
              throw new ClassNotFoundException("Can't get class loader.");
          }

          // Ask for all resources for the packageToPath
          Enumeration<URL> resources = cld.getResources(packageToPath);
          while (resources.hasMoreElements()) {
              directories.add(new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8")));
          }
      } catch (NullPointerException x) {
          throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Null pointer exception)");
      } catch (UnsupportedEncodingException encex) {
          throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Unsupported encoding)");
      } catch (IOException ioex) {
          throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + pckgname);
      }

      ArrayList<Class> classes = new ArrayList<Class>();
      // For every directoryFile identified capture all the .class files
      while (!directories.isEmpty()){
          File directoryFile  = directories.remove(0);             
          if (directoryFile.exists()) {
              // Get the list of the files contained in the package
              File[] files = directoryFile.listFiles();

              for (File file : files) {
                  // we are only interested in .class files
                  if ((file.getName().endsWith(".class")) && (!file.getName().contains("$"))) {
                      // removes the .class extension
                      int index = directoryFile.getPath().indexOf(packageToPath);
                      String packagePrefix = directoryFile.getPath().substring(index).replace('/', '.');;                          
                    try {                  
                      String className = packagePrefix + '.' + file.getName().substring(0, file.getName().length() - 6);                            
                      classes.add(Class.forName(className));                                
                    } catch (NoClassDefFoundError e)
                    {
                      // do nothing. this class hasn't been found by the loader, and we don't care.
                    }
                  } else if (file.isDirectory()){ // If we got to a subdirectory
                      directories.add(new File(file.getPath()));                          
                  }
              }
          } else {
              throw new ClassNotFoundException(pckgname + " (" + directoryFile.getPath() + ") does not appear to be a valid package");
          }
      }
      return classes;
  }  

我无法为如此简单的东西找到一个简短的工作片段。所以在这里,我自己做了一段时间后:

Reflections reflections =
    new Reflections(new ConfigurationBuilder()
            .filterInputsBy(new FilterBuilder().includePackage(packagePath))
            .setUrls(ClasspathHelper.forPackage(packagePath))
            .setScanners(new SubTypesScanner(false)));

Set<String> typeList = reflections.getAllTypes();

它使用组织反射。

是的,你可以使用很少的API,这是我喜欢做的,面对这个问题,我使用hibernate核心&必须找到类,其中注释了某个注释。

使这些自定义注释使用,您将标记哪些类您想要获得。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EntityToBeScanned {

}

然后用它来标记你的课

@EntityToBeScanned 
public MyClass{

}

创建具有以下方法的实用程序类

public class ClassScanner {

    public static Set<Class<?>> allFoundClassesAnnotatedWithEntityToBeScanned(){
        Reflections reflections = new Reflections(".*");
        Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(EntityToBeScanned.class);
        return annotated;
    }

}

调用allfoundclassesannotatedwithentitytobescans()方法获取找到的类集。

你将需要下列的参考书目

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>21.0</version>
    </dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.22.0-CR1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.10</version>
</dependency>