Class Path Container Enhancement

Last Modified April 23, 2002

Background

JDT supports to switch the JDK that is used for building. It is currently implemented as follows: Characteristics of the current implementation:

Motivation for enhancing the current implementation

New Requirements

There are new requirements with regard to the handling of the JRE/JDK on the build class path that need to be addressed by 2.0:

Existing characteristics to be preserved in the new implementation

Proposal

The proposal affects core, launching, java debug UI, and the Java UI components.

JavaCore

JavaCore provides a new type of classpath entry "CPE_CONTAINER", which is just a named reference to a set of other classpath entries. A container entry refers to a container path, which can be resolved by a ClasspathContainerInitializer through an extension point, or explicitly assigned using a setter method. The actual binding from the CPE_Container entry to the target classpath entries is implemented in term of an extension point to keep Java Core independent of VM install concerns:

   <!ELEMENT classpathContainerInitializer EMPTY>
   <!ATTLIST classpathContainerInitializer
      id      CDATA #REQUIRED
      class   CDATA #REQUIRED
   >

   abstract class ClasspathContainerResolver {
        void initialize(IPath containerPath, IJavaProject project) throws CoreException;
      }

The initialize call passes in a project, this enables to resolve a classpath container in the context of a particular project. The initialize method should only be called once to resolve the class path entry (in case of failure, the container will not be considered as having been resolved).

It is possible to register an initializer per container ID. The full container path being passed along to the initializer. Its first segment is the container ID for which an initializer should be registered. The remaining segments can be used to provide additional hints for the container expansion. In case multiple resolvers are registered on the same container ID, the first registered one will be used).

JavaCore provides a method to perform explicit modifications of a container:

JavaCore#setClasspathContainer(
	IPath containerPath, 
	IJavaProject[] affectedProjects, 
	IClasspathContainer[] respectiveContainers, 
	IProgressMonitor monitor)
In particular, this method is to be used in the context of a classpath initializer so as to perform the actual initialization. Note that it allows to modify the value of a container for a set of projects at once. In reaction to invoking this method, the JavaModel will be refreshed and corresponding Java element changes will be notified.

A classpath container implements org.eclipse.jdt.core.IClasspathContainer and can be queried through a JavaCore API: JavaCore#getClasspathContainer(IPath containerPath, IJavaProject project) . There is no assumption that the returned container must answer the exact same containerPath when requested IClasspathContainer#getPath. Indeed, the containerPath is just an indication for resolving it to an actual container object.

Classpath container values are persisted locally to the workspace, but are not preserved from a session to another. It is thus highly recommended to register a ClasspathContainerInitializer for each referenced container (through the extension point "org.eclipse.jdt.core.ClasspathContainerInitializer").

public interface IClasspathContainer {
	
	/**
	 * Kind for a container mapping to an application library
	 */
	int K_APPLICATION = 1;

	/**
	 * Kind for a container mapping to a system library
	 */
	int K_SYSTEM = 2;

	/**
	 * Kind for a container mapping to a default system library, implicitly contributed by the runtime
	 */
	int K_DEFAULT_SYSTEM = 3;
	
	/**
	 * Answers the set of classpath entries this container is mapping to.
	 * The set of entries associated with a classpath container may contain any of the following:
	 * - library entries (CPE_LIBRARY) 
	 * - project entries (CPE_PROJECT) 
	 * A classpath container can neither reference further classpath containers or classpath variables.
	 */	
    IClasspathEntry[] getClasspathEntries();

	/**
	 * Answers a readable description of this container
	 */	
    String getDescription();

	/**
	 * Answers the kind of this container. Can be either:
	 * - K_APPLICATION  if this container maps to an application library
	 * - K_SYSTEM  if this container maps to a system library
	 * Typically, system containers should be placed first on a build path.
	 */	
    int getKind();

	/**
	 * Answers the container path identifying this container.
	 * A container path is formed by a first ID segment followed with extra segments.
	 * which can provide additional hint for resolving.
	 * This container ID is used in conjunction with the hints for resolving to this container.
	 * The container ID is also used to identify a ClasspathContainerInitializer 
	 * registered on the extension point "org.eclipse.jdt.core.classpathContainerInitializer", which can
	 * be invoked if needing to resolve the container before it is explicitely set.
	 */	
    IPath getPath();
}

Issue: The Mac OS X JDK install is an interesting case. There the rt.jar is split into two binary JARs (classes.jar, ui.jar), but there is still a single src.jar. This cases needs to be handled by the source lookup. For example, when src.jar is attached to classes.jar then when looking up java.awt.Frame out of ui.jar, the source attachment of classes.jar needs to searched as well.

Example

The class path of a project will look as follows:

              <classpath>
                        <classpathentry kind="src" path="/src"/>
                        <classpathentry kind="container" path="JDK/1.3"/>
                        <classpathentry kind="output" path="bin"/>
             </classpath>

In the case where the user didn't override the VM install at the project level. Then the Java launching contributed container resolver (registered for container prefixes: "JDK") would resolve "JDK/1.3" using the default VM install, using "1.3" as an hint, and may expand it into the following:

             <classpathentry kind="lib" path="d:/jdk/1.3.1/jre/lib/rt.jar" rootpath="d:/jdk1.3.1/lib/src.jar" sourcepath="/src"/>