jfreerails.util
Class ClassLocater

java.lang.Object
  extended by jfreerails.util.ClassLocater

public class ClassLocater
extends java.lang.Object

An essential part of Java - locates any Class, anywhere.

This class should have been part of the JDK for the last 7 years, but Sun hasn't added it, so we did it instead :).

No static methods since people are already using this in environments where they need multiple separately configured copies running in parallel. Sun's JVM design (caching classloaders) ensure that cached class data is automatically shared between instances; it could be made faster by storing an internal DB rather than re-instantiating, but the time-savings are minuscule (might save some milliseconds if you have 1000 classes).

Usage Tips

If you are using this to automatically find all plugins that your users have for your API then the easiest thing to do is declare a package that plugins are in. Note: you could also declare a naming convention, as many open-source projects have done when writing poor alternatives to this method. This is bad practice, since java already has a naming-convention system - packages - and we can easily use that - but it required more coding to make it work. There are cases where you cannot use the packages this way (though personally I'd recommend you re-think your design in that case), and in those cases you can easily use a class-naming convention instead. So, everyone should be happy.

If you reserve a package for plugins, e.g. declare that all plugins must be in package "org.javagamesfactory.plugins", then you simply pass something like "org\.javagamesfactory\.plugins\..*" in (regex meaning "all things in that package). This class will actually find all things in that pacakge even if they are in different copies of that package, in different JAR files, or different directories.

To use a naming convention, e.g. all plugin class names start with the text "PLUGIN" you would do something like: ".*\.PLUGIN.*".

In all cases, note the fact that regex's have special meaning for dot, so you have to escape it when you just mean a full-stop. Read the java API docs for java.util.regex for more information

See Also:
Pattern

Field Summary
protected static java.util.logging.Logger logger
           
protected  java.util.LinkedList<java.lang.String> skipPrefixes
           
 
Constructor Summary
ClassLocater()
          Automatically adds sun's classes, the java library classes, and the Apache log4j classes (a lib used by ClassLocater!) to the skip list; it's very unlikely that you're trying to locate any of these!
 
Method Summary
 void addSkipPrefix(java.lang.String s)
          Adds a prefix for classes (and packages) to completely ignore, based on their package + class name.
 java.lang.Class[] getSubclassesOf(java.lang.Class targetType)
          Find all instances of the given Class or interface by loading all classes on the class path.
 java.lang.Class[] getSubclassesOf(java.lang.Class targetType, java.lang.String regex)
          Find all subclasses of the given Class or interface by loading only those classes with names that match the given regular expression.
static java.util.List instantiateOneOfEach(java.lang.String className, java.lang.String[] skipPrefixes)
          Finds all classes that implement or extend a given class name, and instantiates precisely one copy of each
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

logger

protected static java.util.logging.Logger logger

skipPrefixes

protected java.util.LinkedList<java.lang.String> skipPrefixes
Constructor Detail

ClassLocater

public ClassLocater()
Automatically adds sun's classes, the java library classes, and the Apache log4j classes (a lib used by ClassLocater!) to the skip list; it's very unlikely that you're trying to locate any of these!

Method Detail

instantiateOneOfEach

public static java.util.List instantiateOneOfEach(java.lang.String className,
                                                  java.lang.String[] skipPrefixes)
Finds all classes that implement or extend a given class name, and instantiates precisely one copy of each

Parameters:
className - fully qualified class or interface to find subclasses of, e.g. "java.lang.String"
skipPrefixes - prefixes of fully qualified packages or class names to completely ignore (i.e. not bother to check), making it faster, e.g. "java.", "com.sun"
Returns:
instantiated objects

addSkipPrefix

public void addSkipPrefix(java.lang.String s)
Adds a prefix for classes (and packages) to completely ignore, based on their package + class name.

For example, "org.apache.log4j".

The advantage of this method is that you don't have to bother with regex syntax. Also, it is remembered between calls to getSubclassesOf - so it's useful if you know you never care about certain packages.

Parameters:
s - prefix of fully qualified class names to ignore

getSubclassesOf

public java.lang.Class[] getSubclassesOf(java.lang.Class targetType)
Find all instances of the given Class or interface by loading all classes on the class path.

Delegates to the other version, but passing in ".*" as the regex, i.e. "anything at all"

Parameters:
targetType - the superclass of all returned classes.
Returns:
an array of all subclasses of targetType

getSubclassesOf

public java.lang.Class[] getSubclassesOf(java.lang.Class targetType,
                                         java.lang.String regex)
Find all subclasses of the given Class or interface by loading only those classes with names that match the given regular expression.

Once all classes have been checked, it will output at WARN a list of all the classes that were referenced by other classes but are not installed in the classpath. This can be incredibly useful - it catches situations where e.g. you thought a class was on the classpath but you put it in the wrong directory etc.

It can also be very annoying because java uses dynamic linking so it is LEGAL for many classes to be missing, just so long as you never use them at runtime. Because this class tries to use *every* class, it triggers errors on lots that you don't care about - use addSkipPrefix( class or package you dont use even though its on the classpath ) and they will be skipped (i.e. not even examined by this method).

OR improve your regex so that it is more selective about the packages where your classes could conceivable be located!

Parameters:
targetType - the superclass of all returned classes.
regex - a regular expression that will match with every subclass
Returns:
an array of all subclasses of targetType