Java 패키지에 포함 된 클래스를 읽어야합니다. 이러한 클래스는 클래스 경로에 있습니다. 이 작업을 Java 프로그램에서 직접 수행해야합니다. 간단한 방법을 알고 계십니까?
List<Class> classes = readClassesFrom("my.package")
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 환경 에서 테스트되었습니다 .
Scannotation 및 Reflections 는 클래스 경로 스캔 방식을 사용합니다.
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에 동의합니다 ... 이에 대해 다른 방법이 있다면 대신 그렇게하는 것이 좋습니다.
주어진 패키지의 모든 클래스를 나열하는 가장 강력한 메커니즘은 현재 ClassGraph 입니다. 새로운 JPMS 모듈 시스템을 포함하여 가능한 가장 광범위한 클래스 경로 사양 메커니즘 배열을 처리하기 때문 입니다. (저자입니다.)
List<String> classNames;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("my.package")
.enableClassInfo().scan()) {
classNames = scanResult.getAllClasses().getNames();
}
eXtcos 는 유망 해 보입니다. 다음과 같은 모든 클래스를 찾고 싶다고 상상해보십시오.
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));
}
});
Bill Burke는 ( 클래스 스캔에 대한 멋진 기사) 를 썼고 Scannotation 을 썼습니다 .
Hibernate 는 이미 다음과 같이 작성했습니다.
CDI 가이 문제를 해결할 수 있지만 모르겠습니다. 아직 완전히 조사하지 않았습니다.
.
@Inject Instance< MyClass> x;
...
x.iterator()
또한 주석의 경우 :
abstract class MyAnnotationQualifier
extends AnnotationLiteral<Entity> implements Entity {}
나는 그것을 구현했으며 대부분의 경우 작동합니다. 길기 때문에 여기 파일에 넣었습니다 .
아이디어는 대부분의 경우 사용할 수있는 클래스 소스 파일의 위치를 찾는 것입니다 (알려진 예외는 JVM 클래스 파일입니다-제가 테스트 한 한). 코드가 디렉토리에있는 경우 모든 파일과 스팟 클래스 파일 만 스캔합니다. 코드가 JAR 파일에있는 경우 모든 항목을 스캔하십시오.
이 방법은 다음과 같은 경우에만 사용할 수 있습니다.
발견하려는 동일한 패키지에 클래스가 있습니다.이 클래스를 SeedClass라고합니다. 예를 들어 'java.io'의 모든 클래스를 나열하려는 경우 시드 클래스는 java.io.File
.
클래스는 디렉토리 또는 JAR 파일에 있으며 소스 파일 정보 (소스 코드 파일이 아니라 소스 파일)가 있습니다. 내가 시도한 한 JVM 클래스를 제외하고 거의 100 % 작동합니다 (이 클래스는 JVM과 함께 제공됨).
프로그램에는 해당 클래스의 ProtectionDomain에 액세스 할 수있는 권한이 있어야합니다. 프로그램이 로컬로로드되면 문제가 없습니다.
정기적 인 사용을 위해서만 프로그램을 테스트 했으므로 여전히 문제가있을 수 있습니다.
이게 도움이 되길 바란다.
애플릿이 일반적인 장소 였을 때 클래스 경로에 URL이있을 수 있습니다. 클래스 로더가 클래스를 필요로 할 때 http 리소스를 포함하여 클래스 경로의 모든 위치를 검색합니다. 클래스 경로에 URL 및 디렉토리와 같은 것을 가질 수 있기 때문에 클래스의 최종 목록을 얻는 쉬운 방법은 없습니다.
그러나 꽤 가까워 질 수 있습니다. 현재 일부 Spring 라이브러리에서이 작업을 수행하고 있습니다. 클래스 경로에있는 모든 항아리를 가져 와서 파일처럼 열 수 있습니다. 그런 다음이 파일 목록을 가져 와서 클래스를 포함하는 데이터 구조를 만들 수 있습니다.
종속성 maven을 사용하십시오.
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));
}
});
Brent-연결이 한 가지 방법 인 이유는 CLASSPATH의 모든 구성 요소에있는 모든 클래스가 모든 패키지 (java / javax 제외)에서 자신을 선언 할 수 있다는 사실과 관련이 있습니다. 따라서 아무도 모르거나 알 수 없기 때문에 주어진 "패키지"에있는 모든 클래스의 매핑이 없습니다. 내일 jar 파일을 업데이트하고 클래스를 제거하거나 추가 할 수 있습니다. 그것은 세계의 모든 나라에서 John / Jon / Johan이라는 이름의 모든 사람들의 목록을 얻으려는 것과 같습니다. 우리 중 누구도 전지전능하지 않으므로 아무도 정답을 얻지 못할 것입니다.