### Eclipse Workspace Patch 1.0
#P org.eclipse.jdt.core
Index: model/org/eclipse/jdt/core/IClasspathEntry.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java,v
retrieving revision 1.65
diff -u -r1.65 IClasspathEntry.java
--- model/org/eclipse/jdt/core/IClasspathEntry.java 27 Jun 2008 16:04:00 -0000 1.65
+++ model/org/eclipse/jdt/core/IClasspathEntry.java 2 Mar 2010 06:13:46 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -418,6 +418,28 @@
*/
IPath getSourceAttachmentRootPath();
+
+ /**
+ * Returns the classpath entry that is making a reference to this classpath entry. For entry kinds
+ * {@link #CPE_LIBRARY}, the return value is the entry that is representing the JAR that includes
+ * this
in the MANIFEST.MF file's Class-Path section. For entry kinds other than
+ * {@link #CPE_LIBRARY}, this returns null
. For those entries that are on the raw classpath already,
+ * this returns null
+ *
+ * It is possible that multiple library entries refer to the same entry + * via the MANIFEST.MF file. In those cases, this method returns the first classpath entry + * that appears in the raw classpath. However, this does not mean that the other referencing + * entries do not relate to their referenced entries. + * See {@link JavaCore#getReferencedClasspathEntries(IClasspathEntry, IJavaProject)} for + * more details. + *
+ * + * @return the classpath entry that is referencing this entry ornull
if
+ * not applicable.
+ * @since 3.6
+ */
+ IClasspathEntry getReferencingEntry();
+
/**
* Returns whether this entry is exported to dependent projects.
* Always returns false
for source entries (kind
Index: model/org/eclipse/jdt/core/IJavaProject.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java,v
retrieving revision 1.103
diff -u -r1.103 IJavaProject.java
--- model/org/eclipse/jdt/core/IJavaProject.java 27 Oct 2008 14:47:36 -0000 1.103
+++ model/org/eclipse/jdt/core/IJavaProject.java 2 Mar 2010 06:13:48 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -1008,6 +1008,56 @@
void setRawClasspath(IClasspathEntry[] entries, boolean canModifyResources, IProgressMonitor monitor) throws JavaModelException;
/**
+ * Works similar to {@link #setRawClasspath(IClasspathEntry[], IPath, IProgressMonitor)} and
+ * additionally allows persisting the given array of referenced entries for this project.
+ * The referenced entries and their attributes are stored in the .classpath file of this
+ * project. For details on referenced entries, see
+ * {@link JavaCore#getReferencedClasspathEntries(IClasspathEntry, IJavaProject)}
+ * and {@link IClasspathEntry#getReferencingEntry()}.
+ *
+ * Since the referenced entries are stored in the .classpath file, clients can store additional
+ * information that belong to these entries and retrieve them across sessions, though the referenced
+ * entries themselves may not be present in the raw classpath. By passing a null
+ * referencedEntries, clients can choose not to modify the already persisted referenced entries,
+ * which is fully equivalent to {@link #setRawClasspath(IClasspathEntry[], IPath, IProgressMonitor)}.
+ * If an empty array is passed as referencedEntries, the already persisted referenced entries,
+ * if any, will be cleared.
+ *
+ * If there are duplicates of a referenced entry or if any of the referencedEntries
+ * is already present in the raw classpath(entries
) those referenced entries will
+ * be excluded and not be persisted.
+ *
this
+ * java project. Clients can store the referenced classpath entries using
+ * {@link #setRawClasspath(IClasspathEntry[], IClasspathEntry[], IPath, IProgressMonitor)}
+ * If the client has not stored any referenced entries for this project, an empty array is returned.
+ *
+ * @throws JavaModelException
+ * @return an array of referenced classpath entries stored for this java project or an empty array if none
+ * stored earlier.
+ * @since 3.6
+ */
+ IClasspathEntry[] getReferencedClasspathEntries() throws JavaModelException;
+
+ /**
* Sets the classpath of this project using a list of classpath entries. In particular such a classpath may contain
* classpath variable entries. Classpath variable entries can be resolved individually ({@link JavaCore#getClasspathVariable(String)}),
* or the full classpath can be resolved at once using the helper method {@link #getResolvedClasspath(boolean)}.
Index: model/org/eclipse/jdt/core/IPackageFragmentRoot.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java,v
retrieving revision 1.54
diff -u -r1.54 IPackageFragmentRoot.java
--- model/org/eclipse/jdt/core/IPackageFragmentRoot.java 27 Jun 2008 16:04:00 -0000 1.54
+++ model/org/eclipse/jdt/core/IPackageFragmentRoot.java 2 Mar 2010 06:13:48 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -311,6 +311,18 @@
* @since 2.0
*/
IClasspathEntry getRawClasspathEntry() throws JavaModelException;
+
+ /**
+ * Returns the first resolved classpath entry that corresponds to this package fragment root.
+ * A resolved classpath entry is said to correspond to a root if the path of the resolved
+ * entry is equal to the root's path.
+ *
+ * @return the first resolved classpath entry that corresponds to this package fragment root
+ * @throws JavaModelException if this element does not exist or if an
+ * exception occurs while accessing its corresponding resource.
+ * @since 3.6
+ */
+ IClasspathEntry getResolvedClasspathEntry() throws JavaModelException;
/**
* Returns the absolute path to the source archive attached to
Index: model/org/eclipse/jdt/core/JavaCore.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java,v
retrieving revision 1.648
diff -u -r1.648 JavaCore.java
--- model/org/eclipse/jdt/core/JavaCore.java 25 Feb 2010 19:17:02 -0000 1.648
+++ model/org/eclipse/jdt/core/JavaCore.java 2 Mar 2010 06:13:53 -0000
@@ -4587,6 +4587,33 @@
false, // no access rules to combine
extraAttributes);
}
+
+ /**
+ * Returns an array of classpath entries that are referenced directly or indirectly
+ * by a given classpath entry. For the entry kind {@link IClasspathEntry#CPE_LIBRARY},
+ * the method returns the libraries that are included in the Class-Path section of
+ * the MANIFEST.MF file. If a referenced JAR file has further references to other library
+ * entries, they are processed recursively and added to the list. For entry kinds other
+ * than {@link IClasspathEntry#CPE_LIBRARY}, this method returns an empty array.
+ * + * If a referenced entry has already been stored + * in the given project's .classpath, the stored attributes are populated in the corresponding + * referenced entry. For more details on storing referenced entries see + * see {@link IJavaProject#setRawClasspath(IClasspathEntry[], IClasspathEntry[], IPath, + * IProgressMonitor)}. + *
+ * + * @param libraryEntry the library entry whose referenced entries are sought + * @param project project where the persisted referenced entries to be retrieved from + * @return an array of classpath entries that are referenced directly or indirectly by the given entry. + * If not applicable, returns an empty array. + * @since 3.6 + */ + public static IClasspathEntry[] getReferencedClasspathEntries(IClasspathEntry libraryEntry, IJavaProject project) { + JavaModelManager manager = JavaModelManager.getJavaModelManager(); + return manager.getReferencedClasspathEntries(libraryEntry, project); + } + /** * Removed the given classpath variable. Does nothing if no value was * set for this classpath variable. Index: model/org/eclipse/jdt/internal/core/ClasspathEntry.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java,v retrieving revision 1.123 diff -u -r1.123 ClasspathEntry.java --- model/org/eclipse/jdt/internal/core/ClasspathEntry.java 1 Feb 2010 11:13:25 -0000 1.123 +++ model/org/eclipse/jdt/internal/core/ClasspathEntry.java 2 Mar 2010 06:13:54 -0000 @@ -77,6 +77,7 @@ public static final String TAG_CLASSPATH = "classpath"; //$NON-NLS-1$ public static final String TAG_CLASSPATHENTRY = "classpathentry"; //$NON-NLS-1$ + public static final String TAG_REFERENCED_ENTRY = "referencedentry"; //$NON-NLS-1$ public static final String TAG_OUTPUT = "output"; //$NON-NLS-1$ public static final String TAG_KIND = "kind"; //$NON-NLS-1$ public static final String TAG_PATH = "path"; //$NON-NLS-1$ @@ -141,7 +142,7 @@ private IPath[] exclusionPatterns; private char[][] fullExclusionPatternChars; private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$ - private final static ClasspathEntry[] NO_ENTRIES = new ClasspathEntry[0]; + public final static ClasspathEntry[] NO_ENTRIES = new ClasspathEntry[0]; private final static IPath[] NO_PATHS = new IPath[0]; private final static IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); @@ -197,6 +198,11 @@ * a non-null
value.
*/
public IPath sourceAttachmentRootPath;
+
+ /**
+ * See {@link IClasspathEntry#getReferencingEntry()}
+ */
+ public IClasspathEntry referencingEntry;
/**
* Specific output location (for this source entry)
@@ -215,11 +221,40 @@
*/
public boolean isExported;
- /*
+ /**
* The extra attributes
*/
- IClasspathAttribute[] extraAttributes;
+ public IClasspathAttribute[] extraAttributes;
+ public ClasspathEntry(
+ int contentKind,
+ int entryKind,
+ IPath path,
+ IPath[] inclusionPatterns,
+ IPath[] exclusionPatterns,
+ IPath sourceAttachmentPath,
+ IPath sourceAttachmentRootPath,
+ IPath specificOutputLocation,
+ boolean isExported,
+ IAccessRule[] accessRules,
+ boolean combineAccessRules,
+ IClasspathAttribute[] extraAttributes) {
+
+ this( contentKind,
+ entryKind,
+ path,
+ inclusionPatterns,
+ exclusionPatterns,
+ sourceAttachmentPath,
+ sourceAttachmentRootPath,
+ specificOutputLocation,
+ null,
+ isExported,
+ accessRules,
+ combineAccessRules,
+ extraAttributes);
+ }
+
/**
* Creates a class path entry of the specified kind with the given path.
*/
@@ -232,6 +267,7 @@
IPath sourceAttachmentPath,
IPath sourceAttachmentRootPath,
IPath specificOutputLocation,
+ IClasspathEntry referencingEntry,
boolean isExported,
IAccessRule[] accessRules,
boolean combineAccessRules,
@@ -242,7 +278,8 @@
this.path = path;
this.inclusionPatterns = inclusionPatterns;
this.exclusionPatterns = exclusionPatterns;
-
+ this.referencingEntry = referencingEntry;
+
int length;
if (accessRules != null && (length = accessRules.length) > 0) {
AccessRule[] rules = new AccessRule[length];
@@ -489,7 +526,7 @@
/**
* Returns the XML encoding of the class path.
*/
- public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine, Map unknownElements) {
+ public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine, Map unknownElements, boolean isReferencedEntry) {
HashMap parameters = new HashMap();
parameters.put(TAG_KIND, ClasspathEntry.kindToString(this.entryKind));
@@ -553,12 +590,15 @@
boolean hasRestrictions = getAccessRuleSet() != null; // access rule set is null if no access rules
ArrayList unknownChildren = unknownXmlElements != null ? unknownXmlElements.children : null;
boolean hasUnknownChildren = unknownChildren != null;
+
+ /* close tag if no extra attributes, no restriction and no unknown children */
+ String tagName = isReferencedEntry ? TAG_REFERENCED_ENTRY : TAG_CLASSPATHENTRY;
writer.printTag(
- TAG_CLASSPATHENTRY,
+ tagName,
parameters,
indent,
newLine,
- !hasExtraAttributes && !hasRestrictions && !hasUnknownChildren/*close tag if no extra attributes, no restriction and no unknown children*/);
+ !hasExtraAttributes && !hasRestrictions && !hasUnknownChildren);
if (hasExtraAttributes)
encodeExtraAttributes(writer, indent, newLine);
@@ -570,7 +610,7 @@
encodeUnknownChildren(writer, indent, newLine, unknownChildren);
if (hasExtraAttributes || hasRestrictions || hasUnknownChildren)
- writer.endTag(TAG_CLASSPATHENTRY, indent, true/*insert new line*/);
+ writer.endTag(tagName, indent, true/*insert new line*/);
}
void encodeExtraAttributes(XMLWriter writer, boolean indent, boolean newLine) {
@@ -1178,6 +1218,11 @@
return this.sourceAttachmentRootPath;
}
+
+ public IClasspathEntry getReferencingEntry() {
+ return this.referencingEntry;
+ }
+
/**
* Returns the hash code for this classpath entry
*/
@@ -1380,6 +1425,7 @@
getSourceAttachmentPath(),
getSourceAttachmentRootPath(),
getOutputLocation(),
+ this.getReferencingEntry(),
this.isExported,
getAccessRules(),
this.combineAccessRules,
@@ -1397,19 +1443,21 @@
return NO_ENTRIES;
ClasspathEntry[] result = new ClasspathEntry[length];
for (int i = 0; i < length; i++) {
+ // Chained(referenced) libraries can have their own attachment path. Hence, set them to null
result[i] = new ClasspathEntry(
- getContentKind(),
- getEntryKind(),
- paths[i],
- this.inclusionPatterns,
- this.exclusionPatterns,
- getSourceAttachmentPath(),
- getSourceAttachmentRootPath(),
- getOutputLocation(),
- this.isExported,
- getAccessRules(),
- this.combineAccessRules,
- this.extraAttributes);
+ getContentKind(),
+ getEntryKind(),
+ paths[i],
+ this.inclusionPatterns,
+ this.exclusionPatterns,
+ null,
+ null,
+ getOutputLocation(),
+ this,
+ this.isExported,
+ getAccessRules(),
+ this.combineAccessRules,
+ NO_EXTRA_ATTRIBUTES);
}
return result;
}
Index: model/org/eclipse/jdt/internal/core/JavaModelManager.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java,v
retrieving revision 1.444
diff -u -r1.444 JavaModelManager.java
--- model/org/eclipse/jdt/internal/core/JavaModelManager.java 24 Feb 2010 11:02:18 -0000 1.444
+++ model/org/eclipse/jdt/internal/core/JavaModelManager.java 2 Mar 2010 06:13:57 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -1095,6 +1095,7 @@
public Object savedState;
public boolean triedRead;
public IClasspathEntry[] rawClasspath;
+ public IClasspathEntry[] referencedEntries;
public IJavaModelStatus rawClasspathStatus;
public int rawTimeStamp = 0;
public boolean writtingRawClasspath = false;
@@ -1169,9 +1170,11 @@
return setResolvedClasspath(null, null, null, null, this.rawTimeStamp, true/*add classpath change*/);
}
- private ClasspathChange setClasspath(IClasspathEntry[] newRawClasspath, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus, IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, boolean addClasspathChange) {
+ private ClasspathChange setClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus, IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, boolean addClasspathChange) {
ClasspathChange classpathChange = addClasspathChange ? addClasspathChange() : null;
+ if (referencedEntries != null) this.referencedEntries = referencedEntries;
+ if (this.referencedEntries == null) this.referencedEntries = ClasspathEntry.NO_ENTRIES;
this.rawClasspath = newRawClasspath;
this.outputLocation = newOutputLocation;
this.rawClasspathStatus = newRawClasspathStatus;
@@ -1191,32 +1194,46 @@
return classpathChange;
}
- public synchronized ClasspathChange setRawClasspath(IClasspathEntry[] newRawClasspath, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus) {
+ public ClasspathChange setRawClasspath(IClasspathEntry[] newRawClasspath, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus) {
+ return setRawClasspath(newRawClasspath, null, newOutputLocation, newRawClasspathStatus);
+ }
+
+ public synchronized ClasspathChange setRawClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus) {
this.rawTimeStamp++;
- return setClasspath(newRawClasspath, newOutputLocation, newRawClasspathStatus, null/*resolved classpath*/, null/*root to raw map*/, null/*root to resolved map*/, null/*unresolved status*/, true/*add classpath change*/);
+ return setClasspath(newRawClasspath, referencedEntries, newOutputLocation, newRawClasspathStatus, null/*resolved classpath*/, null/*root to raw map*/, null/*root to resolved map*/, null/*unresolved status*/, true/*add classpath change*/);
}
- public synchronized ClasspathChange setResolvedClasspath(IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, int timeStamp, boolean addClasspathChange) {
+ public ClasspathChange setResolvedClasspath(IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, int timeStamp, boolean addClasspathChange) {
+ return setResolvedClasspath(newResolvedClasspath, null, newRootPathToRawEntries, newRootPathToResolvedEntries, newUnresolvedEntryStatus, timeStamp, addClasspathChange);
+ }
+
+ public synchronized ClasspathChange setResolvedClasspath(IClasspathEntry[] newResolvedClasspath, IClasspathEntry[] referencedEntries, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, int timeStamp, boolean addClasspathChange) {
if (this.rawTimeStamp != timeStamp)
return null;
- return setClasspath(this.rawClasspath, this.outputLocation, this.rawClasspathStatus, newResolvedClasspath, newRootPathToRawEntries, newRootPathToResolvedEntries, newUnresolvedEntryStatus, addClasspathChange);
+ return setClasspath(this.rawClasspath, referencedEntries, this.outputLocation, this.rawClasspathStatus, newResolvedClasspath, newRootPathToRawEntries, newRootPathToResolvedEntries, newUnresolvedEntryStatus, addClasspathChange);
}
- public synchronized IClasspathEntry[] readAndCacheClasspath(JavaProject javaProject) {
+ /**
+ * Reads the classpath and caches the entries. Returns a two-dimensional array, where the number of elements in the row is fixed to 2.
+ * The first element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored
+ * by the client earlier. See {@link IJavaProject#getReferencedClasspathEntries()} for more details.
+ *
+ */
+ public synchronized IClasspathEntry[][] readAndCacheClasspath(JavaProject javaProject) {
// read file entries and update status
- IClasspathEntry[] classpath;
+ IClasspathEntry[][] classpath;
IJavaModelStatus status;
try {
classpath = javaProject.readFileEntriesWithException(null/*not interested in unknown elements*/);
status = JavaModelStatus.VERIFIED_OK;
} catch (CoreException e) {
- classpath = JavaProject.INVALID_CLASSPATH;
+ classpath = new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES};
status =
new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName()));
} catch (IOException e) {
- classpath = JavaProject.INVALID_CLASSPATH;
+ classpath = new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES};
if (Messages.file_badFormat.equals(e.getMessage()))
status =
new JavaModelStatus(
@@ -1228,7 +1245,7 @@
IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName()));
} catch (ClasspathEntry.AssertionFailedException e) {
- classpath = JavaProject.INVALID_CLASSPATH;
+ classpath = new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES};
status =
new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
@@ -1236,19 +1253,20 @@
}
// extract out the output location
+ int rawClasspathLength = classpath[0].length;
IPath output = null;
- if (classpath.length > 0) {
- IClasspathEntry entry = classpath[classpath.length - 1];
+ if (rawClasspathLength > 0) {
+ IClasspathEntry entry = classpath[0][rawClasspathLength - 1];
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
output = entry.getPath();
- IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
- System.arraycopy(classpath, 0, copy, 0, copy.length);
- classpath = copy;
+ IClasspathEntry[] copy = new IClasspathEntry[rawClasspathLength - 1];
+ System.arraycopy(classpath[0], 0, copy, 0, copy.length);
+ classpath[0] = copy;
}
}
// store new raw classpath, new output and new status, and null out resolved info
- setRawClasspath(classpath, output, status);
+ setRawClasspath(classpath[0], classpath[1], output, status);
return classpath;
}
@@ -1292,20 +1310,31 @@
return buffer.toString();
}
- public boolean writeAndCacheClasspath(JavaProject javaProject, final IClasspathEntry[] newRawClasspath, final IPath newOutputLocation) throws JavaModelException {
+ public boolean writeAndCacheClasspath(
+ JavaProject javaProject,
+ final IClasspathEntry[] newRawClasspath,
+ IClasspathEntry[] newReferencedEntries,
+ final IPath newOutputLocation) throws JavaModelException {
try {
this.writtingRawClasspath = true;
+ if (newReferencedEntries == null) newReferencedEntries = this.referencedEntries;
+
// write .classpath
- if (!javaProject.writeFileEntries(newRawClasspath, newOutputLocation)) {
+ if (!javaProject.writeFileEntries(newRawClasspath, newReferencedEntries, newOutputLocation)) {
return false;
}
// store new raw classpath, new output and new status, and null out resolved info
- setRawClasspath(newRawClasspath, newOutputLocation, JavaModelStatus.VERIFIED_OK);
+ setRawClasspath(newRawClasspath, newReferencedEntries, newOutputLocation, JavaModelStatus.VERIFIED_OK);
} finally {
this.writtingRawClasspath = false;
}
return true;
}
+
+ public boolean writeAndCacheClasspath(JavaProject javaProject, final IClasspathEntry[] newRawClasspath, final IPath newOutputLocation) throws JavaModelException {
+ return writeAndCacheClasspath(javaProject, newRawClasspath, null, newOutputLocation);
+ }
+
}
public static class PerWorkingCopyInfo implements IProblemRequestor {
@@ -1819,6 +1848,30 @@
return container;
}
+ public IClasspathEntry[] getReferencedClasspathEntries(IClasspathEntry libraryEntry, IJavaProject project) {
+
+ IClasspathEntry[] referencedEntries = ((ClasspathEntry)libraryEntry).resolvedChainedLibraries();
+ PerProjectInfo perProjectInfo = getPerProjectInfo(project.getProject(), false);
+
+ if(perProjectInfo == null)
+ return referencedEntries;
+
+ List pathToReferencedEntries = new ArrayList(referencedEntries.length);
+ for (int index = 0; index < referencedEntries.length; index++) {
+
+ if (pathToReferencedEntries.contains(referencedEntries[index].getPath()))
+ continue;
+
+ IClasspathEntry persistedEntry = null;
+ if ((persistedEntry = (IClasspathEntry)perProjectInfo.rootPathToResolvedEntries.get(referencedEntries[index].getPath())) != null) {
+ // TODO: reconsider this - may want to copy the values instead of reference assignment?
+ referencedEntries[index] = persistedEntry;
+ }
+ pathToReferencedEntries.add(referencedEntries[index].getPath());
+ }
+ return referencedEntries;
+ }
+
public DeltaProcessor getDeltaProcessor() {
return this.deltaState.getDeltaProcessor();
}
@@ -3488,7 +3541,7 @@
} else {
IClasspathEntry[] entries;
try {
- entries = ((JavaProject) project).decodeClasspath(containerString, null/*not interested in unknown elements*/);
+ entries = ((JavaProject) project).decodeClasspath(containerString, null/*not interested in unknown elements*/)[0];
} catch (IOException e) {
Util.log(e, "Could not recreate persisted container: \n" + containerString); //$NON-NLS-1$
entries = JavaProject.INVALID_CLASSPATH;
Index: model/org/eclipse/jdt/internal/core/JavaProject.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java,v
retrieving revision 1.428
diff -u -r1.428 JavaProject.java
--- model/org/eclipse/jdt/internal/core/JavaProject.java 22 Feb 2010 07:50:00 -0000 1.428
+++ model/org/eclipse/jdt/internal/core/JavaProject.java 2 Mar 2010 06:14:00 -0000
@@ -18,6 +18,7 @@
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
@@ -45,6 +46,7 @@
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
@@ -260,6 +262,20 @@
return false;
return true;
}
+
+ private static boolean areClasspathsEqual(IClasspathEntry[] first, IClasspathEntry[] second) {
+ if (first != second){
+ if (first == null) return false;
+ int length = first.length;
+ if (second == null || second.length != length)
+ return false;
+ for (int i = 0; i < length; i++) {
+ if (!first[i].equals(second[i]))
+ return false;
+ }
+ }
+ return true;
+ }
/**
* Returns a canonicalized path from the given external path.
@@ -845,10 +861,13 @@
return new JavaProjectElementInfo();
}
- /*
- * Reads and decode an XML classpath string
+ /**
+ * Reads and decode an XML classpath string. Returns a two-dimensional array, where the number of elements in the row is fixed to 2.
+ * The first element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored
+ * by the client earlier. See {@link IJavaProject#getReferencedClasspathEntries()} for more details.
+ *
*/
- public IClasspathEntry[] decodeClasspath(String xmlClasspath, Map unknownElements) throws IOException, ClasspathEntry.AssertionFailedException {
+ public IClasspathEntry[][] decodeClasspath(String xmlClasspath, Map unknownElements) throws IOException, ClasspathEntry.AssertionFailedException {
ArrayList paths = new ArrayList();
IClasspathEntry defaultOutput = null;
@@ -868,7 +887,7 @@
if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
throw new IOException(Messages.file_badFormat);
}
- NodeList list = cpElement.getElementsByTagName("classpathentry"); //$NON-NLS-1$
+ NodeList list = cpElement.getElementsByTagName(ClasspathEntry.TAG_CLASSPATHENTRY);
int length = list.getLength();
for (int i = 0; i < length; ++i) {
@@ -880,15 +899,32 @@
defaultOutput = entry; // separate output
} else {
paths.add(entry);
+ }
+ }
}
}
+ int pathSize = paths.size();
+ IClasspathEntry[][] entries = new IClasspathEntry[2][];
+ entries[0] = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
+ paths.toArray(entries[0]);
+ if (defaultOutput != null) entries[0][pathSize] = defaultOutput; // ensure output is last item
+
+ paths.clear();
+ list = cpElement.getElementsByTagName(ClasspathEntry.TAG_REFERENCED_ENTRY);
+ length = list.getLength();
+
+ for (int i = 0; i < length; ++i) {
+ Node node = list.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ IClasspathEntry entry = ClasspathEntry.elementDecode((Element)node, this, unknownElements);
+ if (entry != null){
+ paths.add(entry);
+ }
}
}
- // return a new empty classpath is it size is 0, to differenciate from an INVALID_CLASSPATH
- int pathSize = paths.size();
- IClasspathEntry[] entries = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
- paths.toArray(entries);
- if (defaultOutput != null) entries[pathSize] = defaultOutput; // ensure output is last item
+ entries[1] = new IClasspathEntry[paths.size()];
+ paths.toArray(entries[1]);
+
return entries;
}
@@ -911,7 +947,7 @@
reader.close();
}
- if (!node.getNodeName().equalsIgnoreCase("classpathentry") //$NON-NLS-1$
+ if (!node.getNodeName().equalsIgnoreCase(ClasspathEntry.TAG_CLASSPATHENTRY)
|| node.getNodeType() != Node.ELEMENT_NODE) {
return null;
}
@@ -956,7 +992,7 @@
/**
* Returns the XML String encoding of the class path.
*/
- protected String encodeClasspath(IClasspathEntry[] classpath, IPath outputLocation, boolean indent, Map unknownElements) throws JavaModelException {
+ protected String encodeClasspath(IClasspathEntry[] classpath, IClasspathEntry[] referencedEntries, IPath outputLocation, boolean indent, Map unknownElements) throws JavaModelException {
try {
ByteArrayOutputStream s = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
@@ -964,7 +1000,7 @@
xmlWriter.startTag(ClasspathEntry.TAG_CLASSPATH, indent);
for (int i = 0; i < classpath.length; ++i) {
- ((ClasspathEntry)classpath[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true, unknownElements);
+ ((ClasspathEntry)classpath[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true, unknownElements, false);
}
if (outputLocation != null) {
@@ -976,6 +1012,12 @@
xmlWriter.printTag(ClasspathEntry.TAG_CLASSPATHENTRY, parameters, indent, true, true);
}
+ if (referencedEntries != null) {
+ for (int i = 0; i < referencedEntries.length; ++i) {
+ ((ClasspathEntry) referencedEntries[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true, unknownElements, true);
+ }
+ }
+
xmlWriter.endTag(ClasspathEntry.TAG_CLASSPATH, indent, true/*insert new line*/);
writer.flush();
writer.close();
@@ -991,7 +1033,7 @@
OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
XMLWriter xmlWriter = new XMLWriter(writer, this, false/*don't print XML version*/);
- ((ClasspathEntry)classpathEntry).elementEncode(xmlWriter, this.project.getFullPath(), true/*indent*/, true/*insert new line*/, null/*not interested in unknown elements*/);
+ ((ClasspathEntry)classpathEntry).elementEncode(xmlWriter, this.project.getFullPath(), true/*indent*/, true/*insert new line*/, null/*not interested in unknown elements*/, (classpathEntry.getReferencingEntry() != null));
writer.flush();
writer.close();
@@ -1841,7 +1883,7 @@
IClasspathEntry[] classpath = perProjectInfo.rawClasspath;
if (classpath != null) return classpath;
- classpath = perProjectInfo.readAndCacheClasspath(this);
+ classpath = perProjectInfo.readAndCacheClasspath(this)[0];
if (classpath == JavaProject.INVALID_CLASSPATH)
return defaultClasspath();
@@ -1850,6 +1892,13 @@
}
/**
+ * @see IJavaProject
+ */
+ public IClasspathEntry[] getReferencedClasspathEntries() throws JavaModelException {
+ return getPerProjectInfo().referencedEntries;
+ }
+
+ /**
* @see IJavaProject#getRequiredProjectNames()
*/
public String[] getRequiredProjectNames() throws JavaModelException {
@@ -2377,14 +2426,17 @@
return result;
}
}
-
- /*
+ /**
* Reads the classpath file entries of this project's .classpath file.
- * This includes the output entry.
+ * Returns a two-dimensional array, where the number of elements in the row is fixed to 2.
+ * The first element is an array of raw classpath entries, which includes the output entry,
+ * and the second element is an array of referenced entries that may have been stored
+ * by the client earlier.
+ * See {@link IJavaProject#getReferencedClasspathEntries()} for more details.
* As a side effect, unknown elements are stored in the given map (if not null)
* Throws exceptions if the file cannot be accessed or is malformed.
*/
- public IClasspathEntry[] readFileEntriesWithException(Map unknownElements) throws CoreException, IOException, ClasspathEntry.AssertionFailedException {
+ public IClasspathEntry[][] readFileEntriesWithException(Map unknownElements) throws CoreException, IOException, ClasspathEntry.AssertionFailedException {
IFile rscFile = this.project.getFile(JavaProject.CLASSPATH_FILENAME);
byte[] bytes;
if (rscFile.exists()) {
@@ -2403,7 +2455,7 @@
bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
} catch (IOException e) {
if (!file.exists())
- return defaultClasspath();
+ return new IClasspathEntry[][]{defaultClasspath(), ClasspathEntry.NO_ENTRIES};
throw e;
}
}
@@ -2427,18 +2479,18 @@
* This includes the output entry.
* As a side effect, unknown elements are stored in the given map (if not null)
*/
- private IClasspathEntry[] readFileEntries(Map unkwownElements) {
+ private IClasspathEntry[][] readFileEntries(Map unkwownElements) {
try {
return readFileEntriesWithException(unkwownElements);
} catch (CoreException e) {
Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
- return JavaProject.INVALID_CLASSPATH;
+ return new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES};
} catch (IOException e) {
Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
- return JavaProject.INVALID_CLASSPATH;
+ return new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES};
} catch (ClasspathEntry.AssertionFailedException e) {
Util.log(e, "Exception while reading " + getPath().append(JavaProject.CLASSPATH_FILENAME)); //$NON-NLS-1$
- return JavaProject.INVALID_CLASSPATH;
+ return new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES};
}
}
@@ -2447,14 +2499,14 @@
*/
public IPath readOutputLocation() {
// Read classpath file without creating markers nor logging problems
- IClasspathEntry[] classpath = readFileEntries(null/*not interested in unknown elements*/);
- if (classpath == JavaProject.INVALID_CLASSPATH)
+ IClasspathEntry[][] classpath = readFileEntries(null/*not interested in unknown elements*/);
+ if (classpath[0] == JavaProject.INVALID_CLASSPATH)
return defaultOutputLocation();
// extract the output location
IPath outputLocation = null;
- if (classpath.length > 0) {
- IClasspathEntry entry = classpath[classpath.length - 1];
+ if (classpath[0].length > 0) {
+ IClasspathEntry entry = classpath[0][classpath[0].length - 1];
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
outputLocation = entry.getPath();
}
@@ -2467,20 +2519,20 @@
*/
public IClasspathEntry[] readRawClasspath() {
// Read classpath file without creating markers nor logging problems
- IClasspathEntry[] classpath = readFileEntries(null/*not interested in unknown elements*/);
- if (classpath == JavaProject.INVALID_CLASSPATH)
+ IClasspathEntry[][] classpath = readFileEntries(null/*not interested in unknown elements*/);
+ if (classpath[0] == JavaProject.INVALID_CLASSPATH)
return defaultClasspath();
// discard the output location
- if (classpath.length > 0) {
- IClasspathEntry entry = classpath[classpath.length - 1];
+ if (classpath[0].length > 0) {
+ IClasspathEntry entry = classpath[0][classpath[0].length - 1];
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
- IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
- System.arraycopy(classpath, 0, copy, 0, copy.length);
- classpath = copy;
+ IClasspathEntry[] copy = new IClasspathEntry[classpath[0].length - 1];
+ System.arraycopy(classpath[0], 0, copy, 0, copy.length);
+ classpath[0] = copy;
}
}
- return classpath;
+ return classpath[0];
}
/**
@@ -2533,14 +2585,45 @@
IJavaModelStatus unresolvedEntryStatus = JavaModelStatus.VERIFIED_OK;
HashMap rawReverseMap = new HashMap();
Map rootPathToResolvedEntries = new HashMap();
+ IClasspathEntry[] referencedEntries = null;
}
public ResolvedClasspath resolveClasspath(IClasspathEntry[] rawClasspath, boolean usePreviousSession, boolean resolveChainedLibraries) throws JavaModelException {
+ return resolveClasspath(rawClasspath, null, usePreviousSession, resolveChainedLibraries);
+ }
+
+ public ResolvedClasspath resolveClasspath(IClasspathEntry[] rawClasspath, IClasspathEntry[] referencedEntries, boolean usePreviousSession, boolean resolveChainedLibraries) throws JavaModelException {
JavaModelManager manager = JavaModelManager.getJavaModelManager();
ExternalFoldersManager externalFoldersManager = JavaModelManager.getExternalManager();
ResolvedClasspath result = new ResolvedClasspath();
+ Map referencedEntriesMap = new HashMap();
+ List rawLibrariesPath = new ArrayList();
LinkedHashSet resolvedEntries = new LinkedHashSet();
+
+ if(resolveChainedLibraries) {
+ for (int index = 0; index < rawClasspath.length; index++) {
+ IClasspathEntry currentEntry = rawClasspath[index];
+ if (currentEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+ rawLibrariesPath.add(ClasspathEntry.resolveDotDot(currentEntry.getPath()));
+ }
+ }
+ if (referencedEntries != null) {
+ // The Set is required to keep the order intact while the referencedEntriesMap (Map)
+ // is used to map the referenced entries with path
+ LinkedHashSet referencedEntriesSet = new LinkedHashSet();
+ for (int index = 0; index < referencedEntries.length; index++) {
+ IPath path = referencedEntries[index].getPath();
+ if (!rawLibrariesPath.contains(path) && referencedEntriesMap.get(path) == null) {
+ referencedEntriesMap.put(path, referencedEntries[index]);
+ referencedEntriesSet.add(referencedEntries[index]);
+ }
+ }
+ result.referencedEntries = new IClasspathEntry[referencedEntriesSet.size()];
+ referencedEntriesSet.toArray(result.referencedEntries);
+ }
+ }
+
int length = rawClasspath.length;
for (int i = 0; i < length; i++) {
@@ -2561,14 +2644,19 @@
if (resolvedEntry == null) {
result.unresolvedEntryStatus = new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, this, rawEntry.getPath());
} else {
- if (resolveChainedLibraries && resolvedEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+ // If the entry is already present in the rawReversetMap, it means the entry and the chained libraries
+ // have already been processed. So, skip it.
+ if (resolveChainedLibraries && resolvedEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY
+ && result.rawReverseMap.get(resolvedEntry.getPath()) == null) {
// resolve Class-Path: in manifest
ClasspathEntry[] extraEntries = ((ClasspathEntry) resolvedEntry).resolvedChainedLibraries();
for (int j = 0, length2 = extraEntries.length; j < length2; j++) {
- addToResult(rawEntry, extraEntries[j], result, resolvedEntries, externalFoldersManager);
+ if (!rawLibrariesPath.contains(extraEntries[j].getPath())) {
+ addToResult(rawEntry, extraEntries[j], result, resolvedEntries, externalFoldersManager, referencedEntriesMap, true);
+ }
}
}
- addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager);
+ addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager, referencedEntriesMap, false);
}
break;
@@ -2603,15 +2691,17 @@
// resolve ".." in library path
cEntry = cEntry.resolvedDotDot();
- if (resolveChainedLibraries) {
+ if (resolveChainedLibraries && result.rawReverseMap.get(cEntry.getPath()) == null) {
// resolve Class-Path: in manifest
ClasspathEntry[] extraEntries = cEntry.resolvedChainedLibraries();
for (int k = 0, length2 = extraEntries.length; k < length2; k++) {
- addToResult(rawEntry, extraEntries[k], result, resolvedEntries, externalFoldersManager);
+ if (!rawLibrariesPath.contains(extraEntries[k].getPath())) {
+ addToResult(rawEntry, extraEntries[k], result, resolvedEntries, externalFoldersManager, referencedEntriesMap, true);
+ }
}
}
}
- addToResult(rawEntry, cEntry, result, resolvedEntries, externalFoldersManager);
+ addToResult(rawEntry, cEntry, result, resolvedEntries, externalFoldersManager, referencedEntriesMap, false);
}
break;
@@ -2619,18 +2709,20 @@
// resolve ".." in library path
resolvedEntry = ((ClasspathEntry) rawEntry).resolvedDotDot();
- if (resolveChainedLibraries) {
+ if (resolveChainedLibraries && result.rawReverseMap.get(resolvedEntry.getPath()) == null) {
// resolve Class-Path: in manifest
ClasspathEntry[] extraEntries = ((ClasspathEntry) resolvedEntry).resolvedChainedLibraries();
for (int k = 0, length2 = extraEntries.length; k < length2; k++) {
- addToResult(rawEntry, extraEntries[k], result, resolvedEntries, externalFoldersManager);
+ if (!rawLibrariesPath.contains(extraEntries[k].getPath())) {
+ addToResult(rawEntry, extraEntries[k], result, resolvedEntries, externalFoldersManager, referencedEntriesMap, true);
+ }
}
}
- addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager);
+ addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager, referencedEntriesMap, false);
break;
default :
- addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager);
+ addToResult(rawEntry, resolvedEntry, result, resolvedEntries, externalFoldersManager, referencedEntriesMap, false);
break;
}
}
@@ -2639,18 +2731,49 @@
return result;
}
- private void addToResult(IClasspathEntry rawEntry, IClasspathEntry resolvedEntry, ResolvedClasspath result, LinkedHashSet resolvedEntries, ExternalFoldersManager externalFoldersManager) {
+ private void addToResult(IClasspathEntry rawEntry, IClasspathEntry resolvedEntry, ResolvedClasspath result,
+ LinkedHashSet resolvedEntries, ExternalFoldersManager externalFoldersManager,
+ Map oldChainedEntriesMap, boolean addAsChainedEntry) {
+
IPath resolvedPath;
+ // If it's already been resolved, do not add to resolvedEntries
if (result.rawReverseMap.get(resolvedPath = resolvedEntry.getPath()) == null) {
result.rawReverseMap.put(resolvedPath, rawEntry);
result.rootPathToResolvedEntries.put(resolvedPath, resolvedEntry);
resolvedEntries.add(resolvedEntry);
+ if (addAsChainedEntry) {
+ IClasspathEntry chainedEntry = null;
+ if (rawEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+
+ chainedEntry = (ClasspathEntry) oldChainedEntriesMap.get(resolvedPath);
+ if (chainedEntry != null) {
+ // This is required to keep the attributes if any added by the user in
+ // the previous session such as source attachment path etc.
+ copyFromOldChainedEntry((ClasspathEntry) resolvedEntry, (ClasspathEntry) chainedEntry);
+ }
+ }
+ }
}
if (resolvedEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY && ExternalFoldersManager.isExternalFolderPath(resolvedPath)) {
externalFoldersManager.addFolder(resolvedPath); // no-op if not an external folder or if already registered
}
}
+ private void copyFromOldChainedEntry(ClasspathEntry resolvedEntry, ClasspathEntry chainedEntry) {
+ IPath path = chainedEntry.getSourceAttachmentPath();
+ if ( path != null) {
+ resolvedEntry.sourceAttachmentPath = path;
+ }
+ path = chainedEntry.getSourceAttachmentRootPath();
+ if (path != null) {
+ resolvedEntry.sourceAttachmentRootPath = path;
+ }
+ IClasspathAttribute[] attributes = chainedEntry.getExtraAttributes();
+ if (attributes != null) {
+ resolvedEntry.extraAttributes = attributes;
+ }
+ }
+
/*
* Resolve the given perProjectInfo's raw classpath and store the resolved classpath in the perProjectInfo.
*/
@@ -2665,22 +2788,24 @@
}
// get raw info inside a synchronized block to ensure that it is consistent
- IClasspathEntry[] rawClasspath;
+ IClasspathEntry[][] classpath = new IClasspathEntry[2][];
int timeStamp;
synchronized (perProjectInfo) {
- rawClasspath= perProjectInfo.rawClasspath;
- if (rawClasspath == null)
- rawClasspath = perProjectInfo.readAndCacheClasspath(this);
+ classpath[0] = perProjectInfo.rawClasspath;
+ classpath[1] = perProjectInfo.referencedEntries;
+ // Checking null only for rawClasspath enough
+ if (classpath[0] == null)
+ classpath = perProjectInfo.readAndCacheClasspath(this);
timeStamp = perProjectInfo.rawTimeStamp;
}
-
- ResolvedClasspath result = resolveClasspath(rawClasspath, usePreviousSession, true/*resolve chained libraries*/);
+ ResolvedClasspath result = resolveClasspath(classpath[0], classpath[1], usePreviousSession, true/*resolve chained libraries*/);
+
if (CP_RESOLUTION_BP_LISTENERS != null)
breakpoint(2, this);
// store resolved info along with the raw info to ensure consistency
- perProjectInfo.setResolvedClasspath(result.resolvedClasspath, result.rawReverseMap, result.rootPathToResolvedEntries, usePreviousSession ? PerProjectInfo.NEED_RESOLUTION : result.unresolvedEntryStatus, timeStamp, addClasspathChange);
+ perProjectInfo.setResolvedClasspath(result.resolvedClasspath, result.referencedEntries, result.rawReverseMap, result.rootPathToResolvedEntries, usePreviousSession ? PerProjectInfo.NEED_RESOLUTION : result.unresolvedEntryStatus, timeStamp, addClasspathChange);
} finally {
if (!isClasspathBeingResolved) {
manager.setClasspathBeingResolved(this, false);
@@ -2708,25 +2833,30 @@
* @return boolean Return whether the .classpath file was modified.
* @throws JavaModelException
*/
- public boolean writeFileEntries(IClasspathEntry[] newClasspath, IPath newOutputLocation) throws JavaModelException {
+ public boolean writeFileEntries(IClasspathEntry[] newClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation) throws JavaModelException {
if (!this.project.isAccessible()) return false;
Map unknownElements = new HashMap();
- IClasspathEntry[] fileEntries = readFileEntries(unknownElements);
- if (fileEntries != JavaProject.INVALID_CLASSPATH && areClasspathsEqual(newClasspath, newOutputLocation, fileEntries)) {
+ IClasspathEntry[][] fileEntries = readFileEntries(unknownElements);
+ if (fileEntries[0] != JavaProject.INVALID_CLASSPATH &&
+ areClasspathsEqual(newClasspath, newOutputLocation, fileEntries[0])
+ && (referencedEntries == null || areClasspathsEqual(referencedEntries, fileEntries[1])) ) {
// no need to save it, it is the same
return false;
}
// actual file saving
try {
- setSharedProperty(JavaProject.CLASSPATH_FILENAME, encodeClasspath(newClasspath, newOutputLocation, true, unknownElements));
+ setSharedProperty(JavaProject.CLASSPATH_FILENAME, encodeClasspath(newClasspath, referencedEntries, newOutputLocation, true, unknownElements));
return true;
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
+ public boolean writeFileEntries(IClasspathEntry[] newClasspath, IPath newOutputLocation) throws JavaModelException {
+ return writeFileEntries(newClasspath, ClasspathEntry.NO_ENTRIES, newOutputLocation);
+ }
/**
* Update the Java command in the build spec (replace existing one if present,
@@ -2874,22 +3004,7 @@
boolean canModifyResources,
IProgressMonitor monitor)
throws JavaModelException {
-
- try {
- if (newRawClasspath == null) //are we already with the default classpath
- newRawClasspath = defaultClasspath();
-
- SetClasspathOperation op =
- new SetClasspathOperation(
- this,
- newRawClasspath,
- newOutputLocation,
- canModifyResources);
- op.runOperation(monitor);
- } catch (JavaModelException e) {
- JavaModelManager.getJavaModelManager().getDeltaProcessor().flush();
- throw e;
- }
+ setRawClasspath(newRawClasspath, null, newOutputLocation, canModifyResources, monitor);
}
/**
@@ -2907,6 +3022,32 @@
true/*can change resource (as per API contract)*/,
monitor);
}
+
+ public void setRawClasspath(IClasspathEntry[] entries, IClasspathEntry[] referencedEntries, IPath outputLocation,
+ IProgressMonitor monitor) throws JavaModelException {
+ setRawClasspath(entries, referencedEntries, outputLocation, true, monitor);
+ }
+
+ protected void setRawClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation,
+ boolean canModifyResources, IProgressMonitor monitor) throws JavaModelException {
+
+ try {
+ if (newRawClasspath == null) //are we already with the default classpath
+ newRawClasspath = defaultClasspath();
+
+ SetClasspathOperation op =
+ new SetClasspathOperation(
+ this,
+ newRawClasspath,
+ referencedEntries,
+ newOutputLocation,
+ canModifyResources);
+ op.runOperation(monitor);
+ } catch (JavaModelException e) {
+ JavaModelManager.getJavaModelManager().getDeltaProcessor().flush();
+ throw e;
+ }
+ }
/**
* @see IJavaProject
Index: model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java,v
retrieving revision 1.134
diff -u -r1.134 PackageFragmentRoot.java
--- model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java 25 Nov 2008 14:38:15 -0000 1.134
+++ model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java 2 Mar 2010 06:14:00 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -554,6 +554,22 @@
}
return rawEntry;
}
+/*
+ * @see IPackageFragmentRoot
+ */
+public IClasspathEntry getResolvedClasspathEntry() throws JavaModelException {
+ IClasspathEntry resolvedEntry = null;
+ JavaProject project = (JavaProject)getJavaProject();
+ project.getResolvedClasspath(); // force the resolved entry cache to be populated
+ Map rootPathToResolvedEntries = project.getPerProjectInfo().rootPathToResolvedEntries;
+ if (rootPathToResolvedEntries != null) {
+ resolvedEntry = (IClasspathEntry) rootPathToResolvedEntries.get(getPath());
+ }
+ if (resolvedEntry == null) {
+ throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH, this));
+ }
+ return resolvedEntry;
+}
public IResource resource() {
Index: model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java,v
retrieving revision 1.156
diff -u -r1.156 SetClasspathOperation.java
--- model/org/eclipse/jdt/internal/core/SetClasspathOperation.java 10 Oct 2008 09:48:05 -0000 1.156
+++ model/org/eclipse/jdt/internal/core/SetClasspathOperation.java 2 Mar 2010 06:14:00 -0000
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -30,21 +30,33 @@
public class SetClasspathOperation extends ChangeClasspathOperation {
IClasspathEntry[] newRawClasspath;
+ IClasspathEntry[] referencedEntries;
IPath newOutputLocation;
JavaProject project;
+ public SetClasspathOperation(
+ JavaProject project,
+ IClasspathEntry[] newRawClasspath,
+ IPath newOutputLocation,
+ boolean canChangeResource) {
+
+ this(project, newRawClasspath, null, newOutputLocation, canChangeResource);
+ }
+
/**
* When executed, this operation sets the raw classpath and output location of the given project.
*/
public SetClasspathOperation(
JavaProject project,
IClasspathEntry[] newRawClasspath,
+ IClasspathEntry[] referencedEntries,
IPath newOutputLocation,
boolean canChangeResource) {
super(new IJavaElement[] { project }, canChangeResource);
this.project = project;
this.newRawClasspath = newRawClasspath;
+ this.referencedEntries = referencedEntries;
this.newOutputLocation = newOutputLocation;
}
@@ -56,7 +68,7 @@
try {
// set raw classpath and null out resolved info
PerProjectInfo perProjectInfo = this.project.getPerProjectInfo();
- ClasspathChange classpathChange = perProjectInfo.setRawClasspath(this.newRawClasspath, this.newOutputLocation, JavaModelStatus.VERIFIED_OK/*format is ok*/);
+ ClasspathChange classpathChange = perProjectInfo.setRawClasspath(this.newRawClasspath, this.referencedEntries, this.newOutputLocation, JavaModelStatus.VERIFIED_OK/*format is ok*/);
// if needed, generate delta, update project ref, create markers, ...
classpathChanged(classpathChange);
#P org.eclipse.jdt.core.tests.model
Index: src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
===================================================================
RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java,v
retrieving revision 1.207
diff -u -r1.207 ClasspathTests.java
--- src/org/eclipse/jdt/core/tests/model/ClasspathTests.java 22 Feb 2010 07:50:08 -0000 1.207
+++ src/org/eclipse/jdt/core/tests/model/ClasspathTests.java 2 Mar 2010 06:14:14 -0000
@@ -6116,5 +6116,316 @@
deleteExternalResource("lib.jar");
}
}
+/**
+ * @bug 252431:New API is needed to better identify referenced jars in the Class-Path: entry
+ * Test that 1) referenced libraries are added to the resolved classpath in the right order
+ * 2) referenced libraries are added to the appropriate referencing library in the correct order
+ * 3) referenced libraries and top-level libraries retain the source attachment and source attachment root path
+ * 4) referenced libraries point to the correct entry as their referencingEntry.
+ * 5) referenced libraries and their attributes are persisted in the .classpath file
+ *
+ * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=252431"
+ * @throws Exception
+ */
+public void testBug252341a() throws Exception {
+ try {
+ IJavaProject p = createJavaProject("P");
+ addLibrary(p, "lib1.jar", "abc.zip", new String[0],
+ new String[] {
+ "META-INF/MANIFEST.MF",
+ "Manifest-Version: 1.0\n" +
+ "Class-Path: lib2.jar lib3.jar\n",
+ },
+ JavaCore.VERSION_1_4);
+ createFile("/P/lib2.jar", "");
+ createFile("/P/lib3.jar", "");
+
+ // Test referenced entries are included in the right order in the resolved classpath
+ IClasspathEntry[] resolvedClasspath = p.getResolvedClasspath(true);
+ assertClasspathEquals(resolvedClasspath,
+ "/P[CPE_SOURCE][K_SOURCE][isExported:false]\n" +
+ ""+ getExternalJCLPathString() + "[CPE_LIBRARY][K_BINARY][isExported:false]\n" +
+ "/P/lib2.jar[CPE_LIBRARY][K_BINARY][isExported:true]\n" +
+ "/P/lib3.jar[CPE_LIBRARY][K_BINARY][isExported:true]\n" +
+ "/P/lib1.jar[CPE_LIBRARY][K_BINARY][sourcePath:/P/abc.zip][isExported:true]");
+
+ IClasspathEntry[] rawClasspath = p.getRawClasspath();
+ assertClasspathEquals(rawClasspath,
+ "/P[CPE_SOURCE][K_SOURCE][isExported:false]\n" +
+ "JCL_LIB[CPE_VARIABLE][K_SOURCE][isExported:false]\n" +
+ "/P/lib1.jar[CPE_LIBRARY][K_BINARY][sourcePath:/P/abc.zip][isExported:true]");
+
+ // Test referenced entries for a particular entry appear in the right order and the referencingEntry
+ // attribute has the correct value
+ IClasspathEntry[] chains = JavaCore.getReferencedClasspathEntries(rawClasspath[2], p);
+ assertClasspathEquals(chains,
+ "/P/lib2.jar[CPE_LIBRARY][K_BINARY][isExported:true]\n" +
+ "/P/lib3.jar[CPE_LIBRARY][K_BINARY][isExported:true]");
+
+ assertSame("Referencing Entry", rawClasspath[2], chains[0].getReferencingEntry());
+ assertSame("Referencing Entry", rawClasspath[2], chains[1].getReferencingEntry());
+
+ // Test a newly created library entry with similar attributes but without any referencing entry is equal to
+ // the original referenced entry
+ IClasspathEntry tempLibEntry = JavaCore.newLibraryEntry(chains[0].getPath(), chains[0].getSourceAttachmentPath(), chains[0].getSourceAttachmentRootPath(), true);
+ assertEquals("Library Entry", tempLibEntry, chains[0]);
+
+ // Test the source attachment and other attributes added to the referenced entries are stored and retrieved properly
+ assertEquals("source attachment", resolvedClasspath[4].getSourceAttachmentPath().toPortableString(), "/P/abc.zip");
+ assertNull("source attachment", chains[0].getSourceAttachmentPath());
+ assertNull("source attachment", chains[1].getSourceAttachmentPath());
+ assertNull("source attachment root", chains[0].getSourceAttachmentRootPath());
+ assertNull("source attachment root", chains[1].getSourceAttachmentRootPath());
+
+ ((ClasspathEntry)chains[0]).sourceAttachmentPath = new Path("/P/efg.zip");
+ ((ClasspathEntry)chains[1]).sourceAttachmentPath = new Path("/P/xyz.zip");
+ ((ClasspathEntry)chains[0]).sourceAttachmentRootPath = new Path("/src2");
+ ((ClasspathEntry)chains[1]).sourceAttachmentRootPath = new Path("/src3");
+
+ IClasspathAttribute javadocLoc = JavaCore.newClasspathAttribute("javadoc_location", "/P/efg.zip");
+ ((ClasspathEntry)chains[0]).extraAttributes = new IClasspathAttribute[]{javadocLoc};
+
+ p.setRawClasspath(rawClasspath, chains, p.getOutputLocation(), null);
+
+ // Test the .classpath file contains all the referenced entries and their attributes
+ String contents = new String (org.eclipse.jdt.internal.core.util.Util.getResourceContentsAsCharArray(getFile("/P/.classpath")));
+ assertSourceEquals(
+ "Unexpected content",
+ "\n" +
+ "