How to find annotated methods in a given package?

前端 未结 3 1029
再見小時候
再見小時候 2020-11-28 23:25

I have a simple marker annotation for methods (similar to the first example in Item 35 in Effective Java (2nd ed)):

/**
 * Marker annotation for met         


        
相关标签:
3条回答
  • 2020-11-28 23:52

    If you're happy to use Spring, then that does something along these lines using it's context:component-scan functionality, where Spring scans for annotated classes in a given package. Under the covers, it's pretty gruesome, and involves grubbing about on the filesystem and in JAR files looking for classes in the package.

    Even if you can't use Spring directly, having a look through its source code might give you some ideas.

    Certainly, the Java reflection APi is no use here, it specifically does not provide a means to obtain all classes in a package.

    0 讨论(0)
  • 2020-11-29 00:06

    If you want to implement it yourself, these methods will find all the classes in a given package:

    /**
     * Scans all classes accessible from the context class loader which belong
     * to the given package and subpackages.
     * 
     * @param packageName
     *            The base package
     * @return The classes
     * @throws ClassNotFoundException
     * @throws IOException
     */
    private Iterable<Class> getClasses(String packageName) throws ClassNotFoundException, IOException
    {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        String path = packageName.replace('.', '/');
        Enumeration<URL> resources = classLoader.getResources(path);
        List<File> dirs = new ArrayList<File>();
        while (resources.hasMoreElements())
        {
            URL resource = resources.nextElement();
            URI uri = new URI(resource.toString());
            dirs.add(new File(uri.getPath()));
        }
        List<Class> classes = new ArrayList<Class>();
        for (File directory : dirs)
        {
            classes.addAll(findClasses(directory, packageName));
        }
    
        return classes;
    }
    
    /**
     * Recursive method used to find all classes in a given directory and
     * subdirs.
     * 
     * @param directory
     *            The base directory
     * @param packageName
     *            The package name for classes found inside the base directory
     * @return The classes
     * @throws ClassNotFoundException
     */
    private List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException
    {
        List<Class> classes = new ArrayList<Class>();
        if (!directory.exists())
        {
            return classes;
        }
        File[] files = directory.listFiles();
        for (File file : files)
        {
            if (file.isDirectory())
            {
                classes.addAll(findClasses(file, packageName + "." + file.getName()));
            }
            else if (file.getName().endsWith(".class"))
            {
                classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
            }
        }
        return classes;
    }
    

    Then you can just filter on those classes with the given annotation:

    for (Method method : testClass.getMethods())
    {
        if (method.isAnnotationPresent(InstallerMethod.class))
        {
            // do something
        }
    }
    
    0 讨论(0)
  • 2020-11-29 00:06

    You should probably take a look at the open source Reflections library. With it you can easily achieve what you want with few lines of code:

    Reflections reflections = new Reflections( 
        new ConfigurationBuilder().setUrls( 
        ClasspathHelper.forPackage( "com.acme.installer" ) ).setScanners(
        new MethodAnnotationsScanner() ) );
    Set<Method> methods = reflections.getMethodsAnnotatedWith(InstallerMethod.class);
    
    0 讨论(0)
提交回复
热议问题