Java library for analyzing the classpath of an application, e.g., used to
determine dynamic class hierarchies (simply add a jar with additional classes
in packages that the ClassLister
monitors and they are automatically located).
Used by ADAMS.
Defining class hierarchies is very easy. Just supply a java.util.Properties
object to the ClassLister.setPackages(Properties)
method that lists for
each superclass (or interface) the packages that need inspecting.
Here is the basic format:
class.name=package1,package2,...
Blacklisting of classes is extremely easy. You just need to supply a
java.util.Properties
object to the ClassLister.setBlacklist(Properties)
method that lists a comma-separated list of regular expressions for matching
class names to exclude. The simplest is to use the full class name of the
class to exclude.
Here is the basic format:
class.name=regexp1,regexp2,...
The following code is taken from nz.ac.waikato.cms.locator.example.ClassListerExample
:
import nz.ac.waikato.cms.locator.ClassLister;
import java.util.Properties;
// configuring the class hierarchies
Properties pkgs = new Properties();
pkgs.put(AbstractAncestor.class.getName(), "nz.ac.waikato.cms.locator.example.pkgA,nz.ac.waikato.cms.locator.example.pkgB");
pkgs.put(SomeInterface.class.getName(), "nz.ac.waikato.cms.locator.example.pkgA,nz.ac.waikato.cms.locator.example.pkgB");
// blacklisted classes
Properties black = new Properties();
black.put(AbstractAncestor.class.getName(), ".*C"); // anything that ends with a capital "C"
black.put(SomeInterface.class.getName(), "nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplInternal"); // specific class
// initialize
ClassLister lister = ClassLister.getSingleton();
lister.setPackages(pkgs);
lister.setBlacklist(black);
lister.initialize();
Class[] classes;
// abstract class
System.out.println("\nAbstract super class: " + AbstractAncestor.class.getName());
classes = lister.getClasses(AbstractAncestor.class);
for (Class cls: classes)
System.out.println("- " + cls.getName());
// interface
System.out.println("\nInterface: " + SomeInterface.class.getName());
classes = lister.getClasses(SomeInterface.class);
for (Class cls: classes)
System.out.println("- " + cls.getName());
Generates this output:
Abstract super class: nz.ac.waikato.cms.locator.example.AbstractAncestor
- nz.ac.waikato.cms.locator.example.pkgA.ConcreteClassA
- nz.ac.waikato.cms.locator.example.pkgA.ConcreteClassB
Interface: nz.ac.waikato.cms.locator.example.SomeInterface
- nz.ac.waikato.cms.locator.example.pkgA.InterfaceImplA
- nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplB
- nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplC
Instead of manually creating java.util.Properties
objects, you can also
use .props
files and load them instead.
Listing packages (ClassLister.props
):
nz.ac.waikato.cms.locator.example.AbstractAncestor=\
nz.ac.waikato.cms.locator.example.pkgA,\
nz.ac.waikato.cms.locator.example.pkgB
nz.ac.waikato.cms.locator.example.SomeInterface=\
nz.ac.waikato.cms.locator.example.pkgA,\
nz.ac.waikato.cms.locator.example.pkgB
Blacklisting classes (ClassLister.blacklist
)
nz.ac.waikato.cms.locator.example.AbstractAncestor=.*C
nz.ac.waikato.cms.locator.example.SomeInterface=nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplInternal
import nz.ac.waikato.cms.locator.ClassLister;
import java.util.Properties;
// loading the props files (path might need adjusting)
Properties pkgs = ClassLister.load("ClassLister.props");
Properties black = ClassLister.load("ClassLister.blacklist");
// initialize
ClassLister lister = ClassLister.getSingleton();
lister.setPackages(pkgs);
lister.setBlacklist(black);
lister.initialize();
Class[] classes;
// abstract class
System.out.println("\nAbstract super class: " + AbstractAncestor.class.getName());
classes = lister.getClasses(AbstractAncestor.class);
for (Class cls: classes)
System.out.println("- " + cls.getName());
// interface
System.out.println("\nInterface: " + SomeInterface.class.getName());
classes = lister.getClasses(SomeInterface.class);
for (Class cls: classes)
System.out.println("- " + cls.getName());
Logging is by default restricted to WARNING
or higher (like SEVERE
).
However, you can enable logging for debugging purposes via environment
variables:
nz.ac.waikato.cms.locator.ClassCache.LOGLEVEL
nz.ac.waikato.cms.locator.ClassLister.LOGLEVEL
nz.ac.waikato.cms.locator.ClassLocator.LOGLEVEL
nz.ac.waikato.cms.locator.ClassPathTraversal.LOGLEVEL
These environment variables can take the following values:
{OFF|SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST}
In case the classpath is empty, i.e., System.getProperty("java.class.path")
returns an empty string, you can initialize the ClassCache
instance with a
fixed list of class names. For that you need to provide an instance of the
FixedClassListTraversal
class to the ClassLister.getSingleton(ClassTraversal)
method. FixedClassListTraversal
can be instantiated either with a
java.util.List<String>
that lists all class names or with an java.io.InputStream
object, from which to read the class names. Empty lines and lines starting with
#
get automatically skipped.
The example classes could be stored in the file nz/ac/waikato/cms/locator/example/fixed.classes
like this:
# first package
nz.ac.waikato.cms.locator.example.pkgA.ConcreteClassA
nz.ac.waikato.cms.locator.example.pkgA.ConcreteClassB
nz.ac.waikato.cms.locator.example.pkgA.InterfaceImplA
# second package
nz.ac.waikato.cms.locator.example.pkgB.ConcreteClassC
nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplB
nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplC
nz.ac.waikato.cms.locator.example.pkgB.InterfaceImplInternal
The code therefore looks like this for initializing the ClassLister
:
FixedClassListTraversal fixed = new FixedClassListTraversal(
ClassLoader.getSystemResourceAsStream("nz/ac/waikato/cms/locator/example/fixed.classes"));
ClassLister lister = ClassLister.getSingleton(fixed);
The above code is taken from nz.ac.waikato.cms.locator.example.ClassListerExampleFixedClassList
.
Example nz.ac.waikato.cms.locator.example.ClassListerExamplePropertiesBasedClassList
shows
how to initialize from a java.utils.Properties
object. Each of the properties contains a
comma-separated list of classnames.
ClassLister.toProperties()
- returns the class hierarchies as ajava.util.Properties
object. The key of a property is the superclass name and the associated value is the comma-separated list of classnames.ClassLister.toPackages()
- returns the class hierarchies as ajava.util.Properties
object. The key of a property is the superclass name and the associated value is the comma-separated list of packages.
Add the following dependency to your pom.xml
:
<dependency>
<groupId>com.github.waikato</groupId>
<artifactId>jclasslocator</artifactId>
<version>0.0.22</version>
</dependency>