source

클래스 경로의 Java 패키지에서 모든 클래스를 읽으려면 어떻게 해야 합니까?

goodcode 2022. 10. 26. 22:24
반응형

클래스 경로의 Java 패키지에서 모든 클래스를 읽으려면 어떻게 해야 합니까?

자바 패키지에 포함된 클래스를 읽어야 합니다.그 수업들은 수업 경로에 있다.자바 프로그램에서 직접 이 작업을 수행해야 합니다.간단한 방법 아세요?

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

클래스 패스에 Spring이 있는 경우, 다음과 같이 처리됩니다.

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 reflections = new Reflections(
    new ConfigurationBuilder()
        .setUrls(ClasspathHelper.forJavaClassPath())
);
Set<Class<?>> types = reflections.getTypesAnnotatedWith(Scannable.class);

이건 파일이나 항아리 아카이브와 함께 사용할 수 있습니다.

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은 뛰어난 클래스 패스 검색 기능을 에 구현했습니다.를 사용하는 경우classpath*: prefix는 특정 계층의 클래스를 포함한 모든 리소스를 검색할 수 있으며 필요에 따라 필터링할 수도 있습니다.다음으로 의 자식을 사용할 수 있습니다.AnnotationTypeFilter그리고.AssignableTypeFilter클래스 레벨 주석 또는 구현 인터페이스에서 이러한 리소스를 필터링합니다.

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

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

스캔 주석 리플렉션은 클래스 경로 스캔 방식을 사용합니다.

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");

특정 패키지의 모든 클래스를 나열하는 가장 강력한 메커니즘은 ClassGraph입니다.이는 새로운 JPMS 모듈 시스템을 포함하여 가능한 한 광범위한 클래스 경로 지정 메커니즘을 처리하기 때문입니다.(저는 저자입니다.)

List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
        .enableClassInfo().scan()) {
    classNames = scanResult.getAllClasses().getNames();
}

eXtcos는 유망해 보인다.다음과 같은 모든 클래스를 찾고 싶다고 상상해 보십시오.

  1. 클래스 "Component"에서 확장하여 저장합니다.
  2. "My Component"에 주석을 달았다.
  3. "공통" 패키지에 들어 있습니다.

eXtcos의 경우 이는 다음과 같이 간단합니다.

ClasspathScanner scanner = new ClasspathScanner();
final Set<Class> classStore = new ArraySet<Class>();

Set<Class> classes = scanner.getClasses(new ClassQuery() {
    protected void query() {
        select().
        from(“common”).
        andStore(thoseExtending(Component.class).into(classStore)).
        returning(allAnnotatedWith(MyComponent.class));
    }
});
  1. Bill Burke는 Scannotation을 쓰고 Scannotation을 썼다.

  2. 휴지 상태에는, 다음과 같이 써 있습니다.

    • org.contractate.ejb.contract.gl스캐너
    • org.contractate.ejb.contract.gl네이티브 스캔너
  3. CDI로 해결할 수 있지만 아직 충분히 조사하지 않았습니다.

.

@Inject Instance< MyClass> x;
...
x.iterator() 

주석의 경우도:

abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}

제가 알기로는 Java reflection API에는 아직 그 기능이 없는 것으로 알고 있습니다.패키지 오브젝트는 다음과 같이 취득할 수 있습니다.

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

하지만 눈치채셨겠지만, 이 패키지에 있는 클래스는 나열할 수 없습니다.현재로서는 파일 시스템 중심의 접근 방식을 취해야 합니다.

투고에서 몇 가지 구현 예를 찾았습니다.

당신의 수업이 JAR 파일에 묻혀있을 때 이 방법들이 100% 효과가 있을지는 모르겠지만, 그 중 하나가 당신에게 도움이 되었으면 합니다.

@skaffman에 동의합니다...다른 방법이 있다면 대신 그렇게 하는 게 좋을 것 같아요.

저는 그것을 구현했고, 대부분의 경우 효과가 있습니다.길이가 길어서 여기 파일에 넣어놨어요.

이 아이디어는 대부분의 경우 사용 가능한 클래스 소스 파일의 위치를 찾는 것입니다(제가 테스트한 범위에서는 JVM 클래스 파일은 예외로 알려져 있습니다).코드가 디렉토리에 있는 경우는, 모든 파일을 스캔 해, 스폿 클래스 파일만을 스캔 합니다.코드가 JAR 파일에 있는 경우는, 모든 엔트리를 스캔 합니다.

이 방법은 다음 경우에만 사용할 수 있습니다.

  1. 검색하려는 것과 동일한 패키지에 포함된 클래스가 있습니다. 이 클래스를 시드 클래스라고 합니다.를 들어, 'io 클래스는 'java.io'으로 하면 됩니다.java.io.File.

  2. 클래스는 디렉토리 또는 JAR 파일에 있습니다(소스 코드 파일이 아니라 소스 파일만).지금까지 JVM 클래스를 제외하고 거의 100% 작동합니다(이러한 클래스는 JVM과 함께 제공됩니다).

  3. 프로그램에 해당 클래스의 ProtectionDomain에 액세스할 수 있는 권한이 있어야 합니다.프로그램이 로컬로 로드되어 있으면 문제가 없습니다.

평소 사용하는 프로그램만 테스트했기 때문에 아직 문제가 있을 수 있습니다.

이게 도움이 됐으면 좋겠어요.

다음은 상기/아래의 다른 답변에 대한 약간의 수정 옵션입니다.

Reflections reflections = new Reflections("com.example.project.package", 
    new SubTypesScanner(false));
Set<Class<? extends Object>> allClasses = 
    reflections.getSubTypesOf(Object.class);

애플릿이 일반적인 장소였을 때는 클래스 경로에 URL이 있을 수 있습니다.클래스로더가 클래스를 필요로 하면 http 리소스를 포함한 클래스 경로 상의 모든 위치를 검색합니다.클래스 패스에 URL이나 디렉토리등의 정보를 포함할 수 있기 때문에, 클래스의 최종 리스트를 취득하는 것은 간단하지 않습니다.

하지만, 당신은 꽤 가까이 갈 수 있습니다.스프링 도서관들 중 몇 군데에서 지금 이걸 하고 있어요.교실 통로에 있는 모든 항아리를 파일처럼 열 수 있어요그런 다음 이 파일 목록을 가져와 클래스를 포함하는 데이터 구조를 생성할 수 있습니다.

종속성 맵 사용:

groupId: net.sf.extcos
artifactId: extcos
version: 0.4b

다음 코드를 사용합니다.

ComponentScanner scanner = new ComponentScanner();
        Set classes = scanner.getClasses(new ComponentQuery() {
            @Override
            protected void query() {
                select().from("com.leyton").returning(allExtending(DynamicForm.class));
            }
        });

브렌트 - 관련성이 한 가지 방법인 이유는 CLASSPATH의 임의의 컴포넌트 상의 클래스가 (java/javax를 제외한) 어떤 패키지로도 자신을 선언할 수 있다는 사실과 관련이 있습니다.따라서 아무도 알 수도 없고 알 수도 없기 때문에 특정 "패키지"에 포함된 모든 클래스의 매핑은 존재하지 않습니다.내일 jar 파일을 업데이트하고 클래스를 제거하거나 추가할 수 있습니다.그것은 전 세계 모든 나라에서 존/존/조한이라는 이름을 가진 모든 사람들의 목록을 얻으려고 하는 것과 같다. 우리 중 누구도 전지전능하기 때문에 우리 중 누구도 정답을 알 수 없을 것이다.

언급URL : https://stackoverflow.com/questions/1456930/how-do-i-read-all-classes-from-a-java-package-in-the-classpath

반응형