A fast and flexible way to scan the class paths in Java

Burningwave
4 min readDec 8, 2020

Overview

In this tutorial we will talk about a new class paths scanning engine and how to use it: the ClassHunter of Burningwave Core, a Java library useful for building frameworks. This class paths scanning engine gives the ability to search classes over paths or the runtime class paths by concatenable and nestable criteria using the lambda expressions on the native Java reflection elements such as Class, Field, Method, Constructor, Module, Package, Annotation.

Maven Dependencies

First, let’s add the Burningwave Core library to our pom.xml:

Usage

Now we are going to find all classes of a package and in particular all classes, in the runtime class paths, that have a package name that matches a regular expression. Here the code:

Let’s break down the example above:

  • we started by retrieving the ClassHunter through the ComponentContainer
  • we define a regular expression that we pass to the ClassCriteria object that will be injected into the SearchConfig object
  • finally we call the findBy method that loads all loadable classes of the indicated paths that in this case are the class paths indicated by the burningwave.properties file (see the paragraph 5 for more informations), then applies the criteria filter and then returns the SearchResult object which contains the classes that match the criteria

It is also possible to expressly indicate the paths on which to search (folders, zip, jar, ear and war will be recursively scanned), so the example above can also be written like this:

And now let’s examine a more detailed example by finding all annotated class of a particular library:

In the example above unlike the previous example:

  • we are assuming that in the runtime class paths is present a jar named “spring-core-4.3.4.RELEASE.jar” that we set up as the unique resource to be scanned
  • we create a complex ClassCriteria with which we ask for all classes that have at least one annotation on class declaration or at least one annotation on the declaration of any of its members (fields, methods or constructors). Notice the call to the ‘byScanUpTo’ method: it receives a lambda expression as input through which, in this case, we ask the scanning engine to apply the filter of the criteria for member (ConstructorCriteria, FieldCriteria and MethodCriteria) only on the iterated class and not on its entire hierarchy because otherwise, by default, the filters injected in the member criterias, are applied to the entire hierarchy

Main component characteristics and configuration

The ClassHunter is a component that queries the classes present in the paths received in input and returns only the classes that match a chosen criterion. The searches performed by it are executed in a multithreaded context and recursively through folders and supported compressed files (zip, jar, jmod, war and ear) and even in nested compressed files and folders. This component can cache the classes found in the class paths in order to perform the next searches faster and uses a PathScannerClassLoader which is configurable through the Java coded property ‘class-hunter.default-path-scanner-class-loader’ of the burningwave.properties file. A Java coded property is a property made of Java code that will be resolved after its compilation at runtime. The default value of the ‘class-hunter.default-path-scanner-class-loader’ property, as you can see in the default burningwave.properties file, is the following:

… Which means that the default class loader used by the ClassHunter is the class loader supplied by the method ‘getPathScannerClassLoader’ of ComponentContainer. The parent class loader of this class loader can be indicated through the Java coded property ‘path-scanner-class-loader.parent’ that has the following default value:

… Which means that the parent class loader is the context class loader of the current thread: this implies that if you’re scanning a path that is present in the runtime class paths, the classes used for comparison are all the loadable classes of the JVM main class loader, otherwise the classes used for comparison are all the loadable classes of the PathScannerClassLoader.

Search configuration components

The main search configuration object is represented by the SearchConfig class to which must be (optionally) passed the paths to be scanned and (optionally too) the query criteria represented by the ClassCriteria. If no path will be passed to SearchConfig, the scan will be executed on the paths indicated by the ‘paths.hunters.default-search-config.paths’ property of the burningwave.properties file that has the following default value:

… And includes the following properties:

… Which means that the scan will be executed through:

  • the runtime class paths (which is indicated by the system property ‘java.class.path’)
  • the direct children of the ‘lib’ folder of the jvm home that have ‘jar’ as extension
  • the direct children of the ‘jmods’ folder of the jvm (9 or later) home that have ‘jmod’ as extension

If no ClassCriteria will be passed to SearchConfig object the search will be executed with no filter and all loadable classes of the paths will be returned.

Conclusion

In this article, we learned how to effectively filter classes of some class paths for different criteria.

The complete source code of all the examples in this article is available on GitHub along with other examples and for more articles about Burningwave Core you can go to the main page.

--

--

Burningwave

A collection of Java libraries for building frameworks and applications: https://www.burningwave.org