<-- home

Spring ile bir paket altındaki sınıfları taramak

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.

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

	private 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

http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/io/support/ResourcePatternResolver.html

http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/type/classreading/MetadataReader.html

http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/type/classreading/MetadataReaderFactory.html

http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/type/ClassMetadata.html

http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/type/AnnotationMetadata.html

http://static.springsource.org/spring/docs/3.1.0.M2/javadoc-api/org/springframework/core/type/filter/TypeFilter.html