Classpath Scanning: Hidden Spring Gems


Class path scanning is not a trivial task in Java. There is no standard way to do it.

Fortunately, Spring framework can help here, as it does in many other aspects. It has an option for implicitly detecting the candidate components by scanning the classpath and matching it against the filters. But all you can do with standard Spring configuration is auto-creation of a  bunch of beans and possbly autowire them to some other bean.

What if you don’t want to create beans, but just want to find specific classes and create their instances later? This can be accomplished by using ClassPathScanningCandidateComponentProvider – class that provides magic behind the Spring’s class path scanning. Using it I created a simple utility class which can be used as a basis for your specific class scaners:


public class ComponentClassScanner extends ClassPathScanningCandidateComponentProvider {

	public ComponentClassScanner() {
		super(false);
	}

	@SuppressWarnings("unchecked")
	public final  Collection getComponentClasses(String basePackage) {
		basePackage = basePackage == null ? "" : basePackage;
		List<Class<? extends T>> classes = new ArrayList<Class<? extends T>>();
		for (BeanDefinition candidate : findCandidateComponents(basePackage)) {
			try {
				Class cls = ClassUtils.resolveClassName(candidate.getBeanClassName(),
						ClassUtils.getDefaultClassLoader());
				classes.add((Class) cls);
			} catch (Throwable ex) {
				ex.printStackTrace();
			}
		}
		return classes;
	}

}

Here the example of specific class scanner to load classes inherited from JComponent and marked with @PreferencePage annotation:


class PreferencePageClassScanner extends ComponentClassScanner {

	public PreferencePageClassScanner() {
		super();
		addIncludeFilter( new AssignableTypeFilter(JComponent.class));
		addIncludeFilter( new AnnotationTypeFilter(PreferencePage.class));
	}

}

Now we have a very powerful tool, which gives us plug in-like abilities. The program can scan the class path for specific services or GUI components and if they are present – load them. Even thaw this solution does not go as far as real plug in framework, it still allows for a greater degree of decoupling in your application.


12 comments

  1. Using the spring class has so far been the only known way for class path scanning. There are some drawbacks to that approach however. For one thing you need to depend on the spring jars, just for class path scanning. If you don’t need them for anything else this is quite cumbersome. For another the API you need to use this way is not really straight-forward.

    But now there is a better way for class path scanning. It’s called eXtcos, which is short for Extensible Component Scanner. This little library is inspired by the spring feature but is a small library solely focused on that task.

    Furthermore it provides an easy to use query language for requesting the classes. Imagine you want to find all the classes annotated with the PreferencePage annotation given in the article in the “sample” package. Your code with eXtcos is just

    ClasspathScanner scanner = new ClasspathScanner();

    Set<Class> classes = scanner.getClasses(new ClassQuery() {
    protected void query() {
    select().
    from(“sample”).
    returning(allAnnotatedWith(PreferencePage.class));
    }
    });

    That’s all.

    In case you want to get several different kinds of classes that’s possible with just one query as well. Consider the following listing looking up all classes annotated with the PreferencePage annotation and all classes extending the JComponent class in two different sets.

    ClasspathScanner scanner = new ClasspathScanner();

    final Set<Class> jComponentStore = new ArraySet<Class>();

    Set<Class> classes = scanner.getClasses(new ClassQuery() {
    protected void query() {
    select().
    from(“sample”).
    andStore(thoseExtending(JComponent.class).into(jComponentStore)).
    returning(allAnnotatedWith(PreferencePage.class));
    }
    });

    Like the look and feel of it? Download it now and test drive it yourself. Just go to http://sourceforge.net/projects/extcos/. After testing, please leave a comment and spread the word. It’s completely free software. 🙂

    • Wow…this tiny library is absolutely awsome!!! Thanks, you saved my week :-).

      After messing arround with spring I was totally frustrated. I wanted to list all classes located in a JAR in the classpath that extend a certain abstract class (without knowledge of their actual package names). After playing arround a couple of hours a gave up and luckily tried extcos:

      ComponentScanner scanner = new ComponentScanner();
      Set<Class> classes = scanner.getClasses(new ComponentQuery() {
      protected void query() {
      select().
      from(“de.uni_leipzig.dbs.cloud_matching.map_reduce”).
      returning(allExtending(MapReduceJobDriver.class));
      }
      });

  2. Excellent code. Exactly what I was looking for. Thanks.

    There’s a typo in on line 08 of your ComponentClassScanner, though. The line should read

    public final Collection<Class> getComponentClasses(String basePackage)

    • Oops, looks like WordPress is munching away the same characters as yours in my reply 😉

      So basically in words: In the signature of the getComponentClasses method the definition of the generic is missing and the return type should by a collection of classes which extend the T

      • Thanks for the tip, shame WordPress ate the important bits! To save someone else the headache I’ve just had trying to make that line correct again… it should read:-

        public final [T] Collection[Class[? extends T]] getComponentClasses(String basePackage)

        …but you need to swap all the square brackets for angled ones.

        HTH

  3. Can we set classpath to scan the files in case of ?
    When spring makes the use of tag in the XML files, it look for all the locations in class path to find bean classes. Though is it possible to specify the custom location where spring should look for classes for bean creation , insted of looking into the default class path location?
    Typical need for this kinda facility is I am having huge jar (about 800 jars)files in my class path and I am interested in scanning only fiew (hardly 5 to 6) jar files for creating beans. Though because of the default behaviour of spring, spring scans through EVERY jar file in the class path to check whether bean class is in any of the jar.This way spring will end up in scanning all 800 jar files in search of the bean .class files where as actually it needs to scan only few jar files and this ultimatly ruins performance

  4. Hi,
    First of all, thanks for a nice post. I really need this one for my tool, but there’s still one thing,
    I need to get the implementation for interfaces in jdk like List, Set, Map, ..etc. But the returned list of classes is empty. It seems work well with other interfaces in referent jars, but not in jdk. Do I miss something?

    Thanks advance for the help,

    • The classes you’re talking about have generics and Java compiler applies type erasure to them. So after compilation there is no way to distinguish List from List for example, since types are lost. This is why I does not work for you, There is not much can be done about it, unfortunately.

  5. Pingback: Search Java classpath for JUnit tests | T. C. Mits 108


Leave a reply to javarevisited Cancel reply