Contents

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.

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.

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:

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:

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:

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.