Spring, Hibernate gibi bir çok framework; bir paket altındaki sınıfları tarayıp annotation’ları vs. işleyerek bir takım ilklendirmeler, işlemler yapıyor. Bu tarz bir gereksinimle karşılaşıp işe koyulduğumuzda, bunun çok da kolay olmadığını görüyoruz. Reflection Api bize sınıf metadatalarına ulaşmamız için güzellikler sağlasa da, böyle bir işlem için malesef yetersiz kalıyor.
Neyse ki Spring, bize classpath üzerinde sınıfları tarama gibi işlemler yapmamızı sağlayan sınıflar sağlıyor. Spring’in sunduğu sınıflar ile bir paket altındaki sınıfları tarayabiliyor, sınıfı yüklemeden sınıfın metadatasına, annotationlarına ulaşabiliyor; sınıfı Class.forName()
ile class nesnesine erişebiliyoruz.
public List scan(String packageToScan) {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolve(packageToScan) + "/" + "**/*.class";
List candidates = new ArrayList();
try {
Resource[] resources = resourcePatternResolver
.getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
ClassMetadata classMetadata = metadataReader.getClassMetadata();
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return candidates;
}
public String resolve(String packageToScan) {
return ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils
.resolvePlaceholders(packageToScan));
}
Öncelikle PathMatchingResourcePatternResolver
gerçekleştirimi ile bir ResourcePatternResolver
tanımlıyoruz. ResourcePatternResolver
interface’i, location pattern’larını Resource
nesnelerine dönüştürme işlemini tanımlıyor. MetadataReaderFactory
interface’i ise, ResourcePatternResolver
ile elde ettiğimiz Resource nesnelerinin bilgilerini okumamızı sağlayacak olan MetadataReader
nesnelerinin yaratılmasını işlemini tanımlayan interface. CachingMetadataReaderFactory
gerçekleştirimi, Resource nesnelerine karşılık olan MetadataReader
nesnelerini, her çağrıda yaratmak yerine cacheliyor.
ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
ise classpath*:
stringini tutuyor ki bu string, PathMatchingResourcePatternResolver
in classes dizininin yanısıra classpath’teki jar’ları da taramasını sağlıyor.
Elde ettiğimiz MetadataReader
nesnesi üzerinden, ClassMetadata
ve AnnotationMetadata
gerçekleştirimlerine ulaşarak, ilgili sınıfa ait metadata bilgilerine ulaşabiliyoruz. Ayrıca ClassMetadata.getClassName()
çağrısı sınıfın adına ulaştıktan sonra Class.forName()
çağrısı ile sınıfın Class
nesnesine ulaşabilir, reflection api ile Class
nesnesi üzerinde işlem yapabiliriz.
Yukarıdaki kodda yer almıyor ama TypeFilter
interface’i sayesinde de, MetadataReader
ı kullanarak filtreleme yapabiliyoruz. TypeFilter
ın AnnotationTypeFilter
, AssignableTypeFilter
gibi gerçekleştirimleri bulunuyor.
http://stackoverflow.com/questions/1456930/read-all-classes-from-java-package-in-classpath