[java] 클래스 경로에서 Java 패키지의 모든 클래스를 어떻게 읽습니까?

Java 패키지에 포함 된 클래스를 읽어야합니다. 이러한 클래스는 클래스 경로에 있습니다. 이 작업을 Java 프로그램에서 직접 수행해야합니다. 간단한 방법을 알고 계십니까?

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



답변

당신이있는 경우 봄을 당신이 다음 클래스 경로에 다음이 그것을 할 것입니다.

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;
}


답변

여기에 설명 된 Reflections Project를 사용할 수 있습니다.

매우 완전하고 사용하기 쉽습니다.

위 웹 사이트의 간략한 설명 :

Reflections는 클래스 경로를 스캔하고 메타 데이터의 색인을 생성하며 런타임시 쿼리 할 수 ​​있으며 프로젝트 내의 많은 모듈에 대해 해당 정보를 저장하고 수집 할 수 있습니다.

예:

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


답변

나는 이것을 사용하며 파일 또는 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;
}


답변

Spring은 .NET에서 뛰어난 클래스 경로 검색 기능을 구현했습니다 PathMatchingResourcePatternResolver. classpath*: 접두사 를 사용하면 주어진 계층 구조의 클래스를 포함한 모든 리소스를 찾을 수 있으며 원하는 경우 필터링 할 수도 있습니다. 그럼 당신의 자식을 사용할 수 있습니다 AbstractTypeHierarchyTraversingFilter, AnnotationTypeFilter그리고 AssignableTypeFilter클래스 수준 주석에 하나 이러한 리소스를 필터링하거나 인터페이스를 그들은 구현합니다.


답변

자바 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[]{});
}

이 솔루션은 EJB 환경 에서 테스트되었습니다 .


답변

ScannotationReflections 는 클래스 경로 스캔 방식을 사용합니다.

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

또 다른 접근 방식은 Java Pluggable Annotation Processing API 를 사용 하여 컴파일 타임에 모든 주석 처리 된 클래스를 수집하고 런타임 사용을위한 색인 파일을 빌드하는 주석 프로세서를 작성하는 것입니다. 이 메커니즘은 ClassIndex 라이브러리 에서 구현됩니다 .

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


답변

이 기능은 내가 아는 한 Java 리플렉션 API에서 여전히 의심스럽게 누락되었습니다. 다음과 같이 패키지 객체를 얻을 수 있습니다.

Package packageObj = Package.getPackage("my.package");

그러나 아마 눈치 채 셨겠지만, 그 패키지의 클래스를 나열 할 수는 없습니다. 현재로서는 좀 더 파일 시스템 지향적 인 접근 방식을 취해야합니다.

게시물 에서 몇 가지 샘플 구현을 찾았 습니다.

클래스가 JAR 파일에 묻혀있을 때 이러한 메서드가 작동 할 것이라고 100 % 확신하지는 않지만 그중 하나가이를 수행하기를 바랍니다.

나는 @skaffman에 동의합니다 … 이에 대해 다른 방법이 있다면 대신 그렇게하는 것이 좋습니다.