Discover candidate classes with Spring 2.5
I recently started using the Spring framework and discovered how it could help me writing better code. I just stumbled upon the following problem: I need to be able to provide the ability to 3rd party developers to define the implementation of an interface to plug custom behaviour in a server. Since those guys are writing their code in their own space, I don’t want to force them to place the implementation at a given place in the classpath and I don’t want them to force some kind of naming conventions for the implementation. Besides, the implementation is different based on a version flag so we also need to identify to which version the implementation refers to.
So basically, here’s the easy stuff. I need an interface to define the contract of my custom behaviour and I can use an annotation to define the version to which the implementation refers to. All this boils down to
@MyAnnotation(version=2)
public class MyCustomImplementation implements ServerBehaviour {
// bla bla bla
}
Now what? I can obviously scan the classpath by hand with all the mistakes I could make in my own custom code. That’s were Spring comes into play. The ClassPathScanningCandidateComponentProvider has surely a long name but it proved to be very useful and very easy to use. Say that the developer provides a base package for his application (com.company.foo). Scanning the classpath (including sub packages!) is as easy as:
final ClassPathScanningCandidateComponentProvider provider =
new ClassPathScanningCandidateComponentProvider(false);
// I want only classes that are flagged with my custom annotation
provider.addIncludeFilter(new AnnotationTypeFilter(MyAnnotation.class));
// I want only classes that implements my CustomBehaviour interface
provider.addIncludeFilter(new AssignableTypeFilter(CustomBehaviour.class));
String basePackage = "com/company/foo";
final Set<beandefinition> components = provider.findCandidateComponents(basePackage);
System.out.println("Found["+components.size()+"] candidate(s)");
for (BeanDefinition component : components) {
System.out.printf("Component: %sn", component.getBeanClassName());
}
Notice that the BeanDefinition class provides a lot of useful information about the discovered classes. The good news is that all this is available from plain stupid Java. You don’t even need to start the spring container to use this.
Updated: the syntax highlighter that I am using puts the Set<BeanDefinition> in lower case for whatever reason. I keep trying to update it without any success. Just translate on-the-fly please.
Wednesday 19 Nov 2008 | Stéphane | Java
Interesting - especially if “This implementation is based on Spring’s MetadataReader facility, backed by an ASM ClassReader.” means the classes are *not* actually loaded. Any idea ?