문제

Java 패키지가 있다고 가정 해 보겠습니다. commands 여기에는 모두 상속되는 클래스가 포함되어 있습니다. ICommand 어떻게든 그 수업을 다 들을 수 있나요?나는 다음과 같은 내용을 잠그고 있습니다.

Package p = Package.getPackage("commands");
Class<ICommand>[] c = p.getAllPackagedClasses(); //not real 

그런 일이 가능합니까?

도움이 되었습니까?

해결책

다음은 클래스가 jar 포장되지 않았다고 가정하는 기본 예입니다.

// Prepare.
String packageName = "com.example.commands";
List<Class<ICommand>> commands = new ArrayList<Class<ICommand>>();
URL root = Thread.currentThread().getContextClassLoader().getResource(packageName.replace(".", "/"));

// Filter .class files.
File[] files = new File(root.getFile()).listFiles(new FilenameFilter() {
    public boolean accept(File dir, String name) {
        return name.endsWith(".class");
    }
});

// Find classes implementing ICommand.
for (File file : files) {
    String className = file.getName().replaceAll(".class$", "");
    Class<?> cls = Class.forName(packageName + "." + className);
    if (ICommand.class.isAssignableFrom(cls)) {
        commands.add((Class<ICommand>) cls);
    }
}

다른 팁

아래, JSR-199 API IE 클래스를 사용한 구현. javax.tools.*:

List<Class> commands = new ArrayList<Class>();

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(
        null, null, null);

Location location = StandardLocation.CLASS_PATH;
String packageName = "commands";
Set<JavaFileObject.Kind> kinds = new HashSet<JavaFileObject.Kind>();
kinds.add(JavaFileObject.Kind.CLASS);
boolean recurse = false;

Iterable<JavaFileObject> list = fileManager.list(location, packageName,
        kinds, recurse);

for (JavaFileObject javaFileObject : list) {
    commands.add(javaFileObject.getClass());
}

다음은 스프링을 사용하는 유틸리티 방법입니다.

패턴에 대한 세부 사항을 찾을 수 있습니다 여기

    public static List<Class> listMatchingClasses(String matchPattern) throws IOException {
    List<Class> classes = new LinkedList<Class>();
    PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
    Resource[] resources = scanner.getResources(matchPattern);

    for (Resource resource : resources) {
        Class<?> clazz = getClassFromResource(resource);
        classes.add(clazz);
    }

    return classes;
}



public static Class getClassFromResource(Resource resource) {
    try {
        String resourceUri = resource.getURI().toString();
        resourceUri = resourceUri.replace(esourceUri.indexOf(".class"), "").replace("/", ".");
        // try printing the resourceUri before calling forName, to see if it is OK.
        return Class.forName(resourceUri);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public classload.getResources (문자열 이름)로 시작하십시오. 관심있는 패키지의 각 이름에 해당하는 클래스에 대한 클래스 로더에게 문의하십시오. 관련성의 모든 클래스 로더에 대해 반복하십시오.

그렇습니다. 그러나 가장 쉬운 일은 아닙니다. 이것에는 많은 문제가 있습니다. 모든 수업이 쉽게 찾을 수있는 것은 아닙니다. 일부 클래스는 A : JAR, 클래스 파일, 네트워크를 통해 등에있을 수 있습니다.

구경하다 이 스레드에서.

그들이 iCommand 유형인지 확인하려면 상속 클래스를 확인하기 위해 반사를 사용해야합니다.

이는 우리에게 필요한 매우 유용한 도구이며 JDK는 일부 지원을 제공해야 합니다.

그러나 아마도 빌드 중에 수행하는 것이 더 나을 것입니다.모든 클래스 파일이 어디에 있는지 알고 정적으로 검사하고 그래프를 작성할 수 있습니다.런타임 시 이 그래프를 쿼리하여 모든 하위 유형을 얻을 수 있습니다.이를 위해서는 더 많은 작업이 필요하지만 실제로는 빌드 프로세스에 속한다고 생각합니다.

사용 Johannes Link의 ClassPathsuite, 나는 이것처럼 그것을 할 수 있었다 :

import org.junit.extensions.cpsuite.ClassTester;
import org.junit.extensions.cpsuite.ClasspathClassesFinder;

public static List<Class<?>> getClasses(final Package pkg, final boolean includeChildPackages) {
    return new ClasspathClassesFinder(new ClassTester() {
        @Override public boolean searchInJars() { return true; }
        @Override public boolean acceptInnerClass() { return false; }
        @Override public boolean acceptClassName(String name) {
            return name.startsWith(pkg.getName()) && (includeChildPackages || name.indexOf(".", pkg.getName().length()) != -1);
        }
        @Override public boolean acceptClass(Class<?> c) { return true; }
    }, System.getProperty("java.class.path")).find();
}

ClassPathClassSfinder는 시스템 클래스 경로에서 클래스 파일과 항아리를 찾습니다.

특정한 경우에는 다음과 같이 acceptClass를 수정할 수 있습니다.

@Override public boolean acceptClass(Class<?> c) {
    return ICommand.class.isAssignableFrom(c);
}

주목해야 할 사항 : ClassPathClassSfinder가 수행하는 다음 작업은 클래스를로드하고 acceptClass를 호출하는 것입니다. acceptClassName이 항상 true를 반환하면 클래스 경로의 모든 클래스를로드하여 OutofMemoryError가 발생할 수 있습니다.

당신은 사용할 수 있습니다 OpenPojo 그리고 이것을하십시오 :

final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);

그런 다음 목록을 넘어 원하는 기능을 수행 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top