Wednesday, October 14, 2009

Recursively Scanning Packages for Marked Classes with Spring

I thought I'd share a neat snippet of code which allows you to recursively scan all of the classes in a given package for those which have been marked with a particular annotation. This could be useful, for example, if you have a static factory class that wanted to know all of the classes which could be instantiated for a particular purpose, without having to add them in some sort of static block at the top of the factory.

String pkg = MyBaseClass.class.getPackage().getName();
String pkgPath = pkg.replace('.', '/');

List<Class<?>> classes = new ArrayList<Class<?>>();

PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
Resource[] packageClasses = resourceResolver.getResources("classpath*:" + pkgPath + "/**/*.class");

for( Resource res : packageClasses ){
classes.add(Class.forName(pkg + '.' + FilenameUtils.getBaseName(res.getFilename())));
}

for( Class<?> c : classes ){
MyAnnotation myAnnotation = c.getAnnotation(MyAnnotation.class);

if( myAnnotation != null ){
// this class was marked with @MyAnnotation; handle accordingly
}
}



I could devote a whole post to Spring's resource loading capabilities; they are the nicest I've used. The above snippet utilizes Spring's PathMatchingResourcePatternResolver, which is able to list resources which match a given ant-style path description. The secret is "classpath*:some/path"; note the asterisk before the colon. This searches *all* accessible jars on the classpath, instead of stopping in the first one in which we find a match. One gotcha here is that you can't do something like "classpath*:*/service/*Service.class"; it will choke if you attempt a leading wildcard search.

No comments: