public class ClasspathScanner extends Object
new FastClasspathScanner(
// Whitelisted package prefixes to scan:
new String[] { "com.xyz.widget", "com.xyz.gizmo" })
.matchSubclassesOf(DBModel.class,
// c is a subclass of DBModel or a descendant subclass
c -> System.out.println("Subclass of DBModel: " + c.getName()))
.matchSubinterfacesOf(Role.class,
// c is an interface that extends the interface Role
c -> System.out.println("Subinterface of Role: " + c.getName()))
.matchClassesImplementing(Runnable.class,
// c is a class that implements the interface Runnable; more precisely,
// c or one of its superclasses implements the interface Runnable, or
// implements an interface that is a descendant of Runnable
c -> System.out.println("Implements Runnable: " + c.getName()))
.matchClassesWithAnnotation(RestHandler.class,
// c is a class annotated with RestHandler
c -> System.out.println("Has a RestHandler class annotation: " + c.getName()))
.matchStaticFinalFieldNames(
Stream.of("com.xyz.Config.POLL_INTERVAL", "com.xyz.Config.LOG_LEVEL")
.collect(Collectors.toCollection(HashSet::new)),
// The following method is called when any static final fields with
// names matching one of the above fully-qualified names are
// encountered, as long as those fields are initialized to constant
// values. The value returned is the value in the classfile, not the
// value that would be returned by reflection, so this can be useful
// in hot-swapping of changes to static constants in classfiles if
// the constant value is changed and the class is re-compiled while
// the code is running. (Eclipse doesn't hot-replace static constant
// initializer values if you change them while running code in the
// debugger, so you can pick up changes this way instead).
// Note that the visibility of the fields is not checked; the value
// of the field in the classfile is returned whether or not it
// should be visible.
(String className, String fieldName, Object fieldConstantValue) ->
System.out.println("Static field " + fieldName + " of class "
+ className + " " + " has constant literal value "
+ fieldConstantValue + " in classfile"))
.matchFilenamePattern("^template/.\*\.html",
// templatePath is a path on the classpath that matches the above
// pattern; inputStream is a stream opened on the file or zipfile entry
// No need to close inputStream before exiting, it is closed by caller.
(absolutePath, relativePath, inputStream) -> {
try {
String template = IOUtils.toString(inputStream, "UTF-8");
System.out.println("Found template: " + absolutePath
+ " (size " + template.length() + ")");
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.scan(); // Actually perform the scan
// [...Some time later...]
// See if any timestamps on the classpath are more recent than the time of the
// previous scan. (Even faster than classpath scanning, because classfiles
// don't have to be opened.)
boolean classpathContentsModified =
fastClassPathScanner.classpathContentsModifiedSinceScan();
Note that you need to pass a whitelist of package prefixes to scan into the constructor, and the ability to detect
that a class or interface extends another depends upon the entire ancestral path between the two classes or interfaces having
one of the whitelisted package prefixes. When matching involves classfiles (i.e. in all cases except
FastClasspathScanner#matchFilenamePattern, which deals with arbitrary files on the classpath), if the same fully-qualified
class name is encountered more than once on the classpath, the second and subsequent definitions of the class are ignored.
The scanner also records the latest last-modified timestamp of any file or directory encountered, and you can see if that
latest last-modified timestamp has increased (indicating that something on the classpath has been updated) by calling
classpathContentsModifiedSinceScan(). This can be used to enable dynamic class-reloading if something on the classpath is
updated, for example to support hot-replace of route handler classes in a webserver. classpathContentsModifiedSinceScan() is
several times faster than the original call to scan(), since only modification timestamps need to be checked. Inspired by:
https://github.com/rmuller/infomas-asl/tree/master/annotation-detector See also:
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 Please let me know if you find this useful!コンストラクタと説明 |
---|
ClasspathScanner(String[] packagesToScan)
Construct a FastClasspathScanner instance.
|
ClasspathScanner(String[] packagesToScan,
String[] classpathElements) |
修飾子とタイプ | メソッドと説明 |
---|---|
boolean |
classpathContentsModifiedSinceScan()
Returns true if the classpath contents have been changed since scan() was last called.
|
List<File> |
getUniqueClasspathElements()
Get a list of unique elements on the classpath (directories and files) as File objects, preserving order.
|
<T> ClasspathScanner |
matchClassesImplementing(Class<T> implementedInterface,
InterfaceMatchProcessor<T> interfaceMatchProcessor)
Call the provided InterfaceMatchProcessor for classes on the classpath that implement the specified interface or a
subinterface, or whose superclasses implement the specified interface or a sub- interface.
|
ClasspathScanner |
matchClassesWithAnnotation(Class<?> annotation,
ClassAnnotationMatchProcessor classAnnotationMatchProcessor)
Call the provided ClassMatchProcessor if classes are found on the classpath that have the specified annotation.
|
ClasspathScanner |
matchFilenamePattern(String filenameMatchPattern,
FileMatchProcessor fileMatchProcessor)
Call the given FileMatchProcessor if files are found on the classpath with the given regexp pattern in their path.
|
ClasspathScanner |
matchStaticFinalFieldNames(HashSet<String> fullyQualifiedStaticFinalFieldNames,
StaticFinalFieldMatchProcessor staticFinalFieldMatchProcessor)
Call the given StaticFinalFieldMatchProcessor if classes are found on the classpath that contain static final fields that
match one of a set of fully-qualified field names, e.g.
|
<T> ClasspathScanner |
matchSubclassesOf(Class<T> superclass,
SubclassMatchProcessor<T> subclassMatchProcessor)
Call the provided SubclassMatchProcessor if classes are found on the classpath that extend the specified superclass.
|
<T> ClasspathScanner |
matchSubinterfacesOf(Class<T> superInterface,
SubinterfaceMatchProcessor<T> subinterfaceMatchProcessor)
Call the provided SubInterfaceMatchProcessor if an interface that extends a given superinterface is found on the
classpath.
|
void |
scan()
Scan classpath for matching files.
|
public ClasspathScanner(String[] packagesToScan)
packagesToScan
- package prefixes to scan, e.g. new String[] { "com.xyz.widget", "com.xyz.gizmo" }public boolean classpathContentsModifiedSinceScan()
public List<File> getUniqueClasspathElements()
public <T> ClasspathScanner matchClassesImplementing(Class<T> implementedInterface, InterfaceMatchProcessor<T> interfaceMatchProcessor)
implementedInterface
- The interface that classes need to implement to match.interfaceMatchProcessor
- the ClassMatchProcessor to call when a match is found.public ClasspathScanner matchClassesWithAnnotation(Class<?> annotation, ClassAnnotationMatchProcessor classAnnotationMatchProcessor)
annotation
- The class annotation to match.classAnnotationMatchProcessor
- the ClassAnnotationMatchProcessor to call when a match is found.public ClasspathScanner matchFilenamePattern(String filenameMatchPattern, FileMatchProcessor fileMatchProcessor)
filenameMatchPattern
- The regexp to match, e.g. "app/templates/.\*\.html"fileMatchProcessor
- The FileMatchProcessor to call when each match is found.public ClasspathScanner matchStaticFinalFieldNames(HashSet<String> fullyQualifiedStaticFinalFieldNames, StaticFinalFieldMatchProcessor staticFinalFieldMatchProcessor)
fullyQualifiedStaticFinalFieldNames
- The set of fully-qualified static field names to match.staticFinalFieldMatchProcessor
- the StaticFinalFieldMatchProcessor to call when a match is found.public <T> ClasspathScanner matchSubclassesOf(Class<T> superclass, SubclassMatchProcessor<T> subclassMatchProcessor)
superclass
- The superclass to match (i.e. the class that subclasses need to extend to match).subclassMatchProcessor
- the SubclassMatchProcessor to call when a match is found.public <T> ClasspathScanner matchSubinterfacesOf(Class<T> superInterface, SubinterfaceMatchProcessor<T> subinterfaceMatchProcessor)
superInterface
- The superinterface to match (i.e. the interface that subinterfaces need to extend to match).subinterfaceMatchProcessor
- the SubinterfaceMatchProcessor to call when a match is found.public void scan()
Copyright © 2012 NTT DATA INTRAMART CORPORATION