106 votes

Comment lire toutes les classes d'un paquetage Java dans le classpath ?

J'ai besoin de lire les classes contenues dans un paquetage Java. Ces classes sont dans le classpath. Je dois effectuer cette tâche directement à partir d'un programme Java. Connaissez-vous un moyen simple de le faire ?

List<Class> classes = readClassesFrom("my.package")

56voto

Shalom938 Points 352

Si vous avez Printemps dans votre classpath alors ce qui suit le fera.

Trouver toutes les classes d'un paquetage qui sont annotées avec XmlRootElement :

private List<Class> findMyTypes(String basePackage) throws IOException, ClassNotFoundException
{
    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);

    List<Class> candidates = new ArrayList<Class>();
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                               resolveBasePackage(basePackage) + "/" + "**/*.class";
    Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
    for (Resource resource : resources) {
        if (resource.isReadable()) {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            if (isCandidate(metadataReader)) {
                candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
            }
        }
    }
    return candidates;
}

private String resolveBasePackage(String basePackage) {
    return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
}

private boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException
{
    try {
        Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
        if (c.getAnnotation(XmlRootElement.class) != null) {
            return true;
        }
    }
    catch(Throwable e){
    }
    return false;
}

32voto

Renato Points 2667

Vous pouvez utiliser le projet de réflexion décrit aquí

Il est assez complet et facile à utiliser.

Brève description du site web susmentionné :

Reflections scanne votre classpath, indexe les métadonnées, vous permet de de les interroger au moment de l'exécution et peut enregistrer et collecter ces informations pour de nombreux modules de votre projet.

Ejemplo:

Reflections reflections = new Reflections(
    new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);

31voto

Edoardo Panfili Points 191

J'utilise celui-ci, il fonctionne avec des fichiers ou des archives jar.

public static ArrayList<String>getClassNamesFromPackage(String packageName) throws IOException{
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL packageURL;
    ArrayList<String> names = new ArrayList<String>();;

    packageName = packageName.replace(".", "/");
    packageURL = classLoader.getResource(packageName);

    if(packageURL.getProtocol().equals("jar")){
        String jarFileName;
        JarFile jf ;
        Enumeration<JarEntry> jarEntries;
        String entryName;

        // build jar file name, then loop through zipped entries
        jarFileName = URLDecoder.decode(packageURL.getFile(), "UTF-8");
        jarFileName = jarFileName.substring(5,jarFileName.indexOf("!"));
        System.out.println(">"+jarFileName);
        jf = new JarFile(jarFileName);
        jarEntries = jf.entries();
        while(jarEntries.hasMoreElements()){
            entryName = jarEntries.nextElement().getName();
            if(entryName.startsWith(packageName) && entryName.length()>packageName.length()+5){
                entryName = entryName.substring(packageName.length(),entryName.lastIndexOf('.'));
                names.add(entryName);
            }
        }

    // loop through files in classpath
    }else{
    URI uri = new URI(packageURL.toString());
    File folder = new File(uri.getPath());
        // won't work with path which contains blank (%20)
        // File folder = new File(packageURL.getFile()); 
        File[] contenuti = folder.listFiles();
        String entryName;
        for(File actual: contenuti){
            entryName = actual.getName();
            entryName = entryName.substring(0, entryName.lastIndexOf('.'));
            names.add(entryName);
        }
    }
    return names;
}

12voto

John Ellinwood Points 6578

Spring a mis en place une excellente fonction de recherche dans le classpath dans la fonction PathMatchingResourcePatternResolver . Si vous utilisez le classpath* : préfixe, vous pouvez trouver toutes les ressources, y compris les classes dans une hiérarchie donnée, et même les filtrer si vous le souhaitez. Ensuite, vous pouvez utiliser les enfants de AbstractTypeHierarchyTraversingFilter , AnnotationTypeFilter y AssignableTypeFilter pour filtrer ces ressources soit sur les annotations au niveau des classes, soit sur les interfaces qu'elles mettent en œuvre.

6voto

Paul Kuit Points 107

Java 1.6.0_24 :

public static File[] getPackageContent(String packageName) throws IOException{
    ArrayList<File> list = new ArrayList<File>();
    Enumeration<URL> urls = Thread.currentThread().getContextClassLoader()
                            .getResources(packageName);
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        File dir = new File(url.getFile());
        for (File f : dir.listFiles()) {
            list.add(f);
        }
    }
    return list.toArray(new File[]{});
}

Cette solution a été testée dans le cadre de la EJB l'environnement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X