Representation of Java classpaths, and the ability to find the classpath needed for a particular purpose.


Interface Summary
GlobalPathRegistryListener Event listener interface for being notified of changes in the set of available paths.

Class Summary
ClassPath ClassPath objects should be used to access contents of the ClassPath, searching for resources, objects reachable using the ClassPath at runtime.
GlobalPathRegistry Maintains a global registry of "interesting" classpaths of various kinds.
GlobalPathRegistryEvent Event object giving details of a change in the path registry.

Package Description

Representation of Java classpaths, and the ability to find the classpath needed for a particular purpose.

Using the Classpath API you can look up the classpath used for a certain purpose (such as compilation or running) on a certain file.


ClassPath API


At runtime, there's often only a single Classpath available through the application classloader. The application is often developed against a set of APIs, with some implementation provided at runtime. For example, if using JDBC, the application is compiled against JDBC API only and the proper driver is added to the runtime classpath. To avoid unintentional dependencies on implementation, the implementation classes are often stripped off the compilation path. Another case is debugging with special implementation libraries that - for example - perform special sanity checks or logging. Again, the classpath is different from those used during build or application's execution.

Since the IDE supports the whole development cycle, it needs to provide different classpaths for each of the purposes mentioned, and maybe for others, too. See ClassLoader.

Obtaining ClassPath

The ClassPath API uses concept similar to Services to categorize ClassPaths. Instead of the class, a string token is used to name a service type. Various types such as ClassPath.COMPILE are defined.

In addition to different services, the API also permits different files to have different classpaths configured for them. In addition to the desired classpath type, clients are required to pass in a FileObject of the user file, which is the "starting point" for the classpath search.

To obtain a ClassPath instance for the given FileObject and intended usage, you want to call ClassPath.getClassPath(org.openide.filesystems.FileObject, java.lang.String) as in this example for getting compilation classpath:

FileObject f = getSomeJavaSourceFile();
ClassPath cp = ClassPath.getClassPath(f, ClassPath.COMPILE);

Roots and definition of the classpath

The classpath is formed from one or more roots. JRE itself supports at least two types of of them: a root can be either a directory or an archive (.jar or .zip file). The definition of the classpath cannot maintain integrity with the root folders or archives. If one of them is renamed, deleted or otherwise changed, its entry in the classpath becomes invalid and does not contribute to the contents of the classpath. Note that the entry cannot be removed automagically, since an archive can disappear (for example) because of the compilation products in a subproject. Note that regardless of where the classpath entry is an archive, or a folder, the root returned for it will be always a folder. For archive files, it will be the root folder of the archive filesystem.

For most purposes, working with only those roots which are valid, is sufficient enough. The error condition can be detected when a required resource is missing, for example. For some tasks checking for validity of individual classpath entries may be appropriate, the build process being a notable example. For others, like searches or parsing, such behaviour is hihgly undesirable.

If you don't need to notify the user that the definition of classpath is not correct (there are other ways or another, more appropriate, time to notify the user), you can use ClassPath.getRoots() to find out what folders are the roots:

ClassPath cp = ClassPath.getClassPath(myClassFile, ClassPath.EXECUTE);
FileObject[] roots = cp.getRoots();
for (int i = 0; i < roots.length; i++) {
    System.err.print(roots[i] + ":");

Clients who need to find out whether the environment is set up well, may work more thoroughly using ClassPath.Entry objects:

ClassPath cp = ClassPath.getClassPath(myClassObject, ClassPath.EXECUTE);
List entries = cp.entries();
for (Iterator it = entries.iterator(); it.hasNext(); ) {
    ClassPath.Entry en = (ClassPath.Entry);
    if (!en.isValid()) {
        IOException x = en.getError();
        // Report the error somehow, perhaps using org.openide.ErrorManager.
    } else {
        FileObject root = en.getRoot();
        // Do something with the root folder

Resource Names and FileObjects

The resource name is essentially a file name, relative to the root of classpath. If the classpath has more roots (it's a classpath forest rather than a single tree), they are combined and merged together to give one "logical" tree. The merge operation has one subtle property, resource hiding: when there are several resources of the same name in the classpath forest, the order of the roots that define the classpath matters and the only the first resource encountered (in that order) is visible for the ClassLoader.

Often a FileObject is viewed as a resource to the application being developed. It's the most used view for Java sources, as they are required to appear in an appropriate folder in the source tree, but for other objects as well. For example, the IDE support for images need to record the resource name of the image so that it can be loaded at runtime using ClassLoader.getResourceAsStream(java.lang.String). If you need to obtain a name for FileObject, which is relative to the classpath, you first have to think about for which service do you need it. For resource bundles, for example, it will be mostly the execution service. Then you will get the appropriate ClassPath instance and ask it to compute the name for you:

FileObject f = bundleDataObject.getPrimaryFile();
ClassPath cp = ClassPath.getClassPath(theSourceDataObject.getPrimaryFile(), ClassPath.EXECUTE);
String bundleResource = cp.getResourceName(f);

To check whether a resource (FileObject) is visible or not to the service, you may want to call ClassPath.isResourceVisible(org.openide.filesystems.FileObject). You may want to do just the opposite, to get a FileObject for a resource name you have. Since there may be more resources of that name, the API supports ClassPath.findResource(java.lang.String) to get the visible one, or ClassPath.findAllResources(java.lang.String) to get a collection of all resources matching the name.

Listening to changes in ClassPath

The ClassPath interface supports listening to either root folder set changes or entry set changes. Changes in root folder set can be observed by property change listeners, they are reported as additions, deletions or changes to the order of roots. For example, to watch out for new compile-time dependencies, you may do:

FileObject f; // some interesting FileObject.
ClassPath cp = ClassPath.getClassPath(f, ClassPath.COMPILE);
cp.addPropertyChangeListener(new PropertyChangeListener() {
    public void propertyChange(PropertyChangeEvent evt) {
        if (ClassPath.PROP_ROOTS.equals(evt.getPropertyName())) {
            // Update your stuff, because classpath roots have changed.

You may also listen entries property. Note that the root folder set may change even though the entry set did not change, as a result of some entry becoming (in)valid.

Replacements of FileSystems API methods

The now-deprecated way how to obtain a resource name for a file object was to call FileObject.getPackageNameExt(char, char). But the getPackageNameExt() method gives a name of the file within the FileSystem rather than its relative path from some classpath root point. Therefore it is no longer recommended to use the Filesystems API to obtain classpaths.

As the Repository searches through FileSystems without regard to the intended usage for individual services, Repository.findResource(java.lang.String) and Repository.findAllResources(java.lang.String) should not be used at all. GlobalPathRegistry may be used to find certain kinds of files that are available among open projects in the GUI, but this should be used only as a last resort if there is no other possible source of information about where a file might be located according to specific classpaths. The usage of the class FileSystemCapability is deprecated; you should use methods of ClassPath instead of that.

Old methodNew method
FileObject.getPackageName(char) and FileObject.getPackageName(char) ClassPath.getResourceName(org.openide.filesystems.FileObject)
FileSystemCapability.findResource(java.lang.String) ClassPath.findResource(java.lang.String)
FileSystemCapability.findAllResources(java.lang.String) ClassPath.findAllResources(java.lang.String)
FileSystemCapability.fileSystems() ClassPath.getRoots()
Repository.findResource(java.lang.String) GlobalPathRegistry.findResource(java.lang.String)
Repository.findAllResources(java.lang.String) GlobalPathRegistry.getSourceRoots() 1.10.22

Built on July 11 2007.  |  Portions Copyright 1997-2005 Sun Microsystems, Inc. All rights reserved.