Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2015-01-31 01:01:14 +0000
committerStephan Herrmann2015-01-31 01:34:27 +0000
commit201cf9c2eb11ce7ae348436cd3a3b55863b9eb2f (patch)
tree5d93752b2517faad3f0cc003ed92c73d1fba785d
parent2117d348df3fc8f7646ee8f84473f25f24d25460 (diff)
downloadeclipse.jdt.core-201cf9c2eb11ce7ae348436cd3a3b55863b9eb2f.tar.gz
eclipse.jdt.core-201cf9c2eb11ce7ae348436cd3a3b55863b9eb2f.tar.xz
eclipse.jdt.core-201cf9c2eb11ce7ae348436cd3a3b55863b9eb2f.zip
Bug 440477 - [null] Infrastructure for feeding external annotations into
compilation - further improvements in change propagation - hook into classpath change analysis - fine tune resource change listener - make eea reading more robust against white space
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java62
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java3
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java51
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java16
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java70
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java8
7 files changed, 122 insertions, 96 deletions
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
index 9318036c7b..181ad0e8bb 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java
@@ -104,9 +104,11 @@ public NameEnvironmentAnswer findClass(char[] typeName, String qualifiedPackageN
if (reader != null) {
if (this.annotationPath != null) {
String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1);
- ZipFile[] zipFileInOut = new ZipFile[] { this.annotationZipFile };
- reader.setExternalAnnotationProvider(this.annotationPath, qualifiedClassName, zipFileInOut, null);
- this.annotationZipFile = zipFileInOut[0];
+ try {
+ this.annotationZipFile = reader.setExternalAnnotationProvider(this.annotationPath, qualifiedClassName, this.annotationZipFile, null);
+ } catch (IOException e) {
+ // don't let error on annotations fail class reading
+ }
}
return new NameEnvironmentAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName));
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index cb4a203fc5..c58a627ebf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -22,7 +22,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -406,51 +405,46 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
}
}
-/** Auxiliary interface for {@link #setExternalAnnotationProvider(String,String,ZipFile[],ZipFileProducer)}. */
-public interface ZipFileProducer { ZipFile produce(); }
+/** Auxiliary interface for {@link #setExternalAnnotationProvider(String,String,ZipFile,ZipFileProducer)}. */
+public interface ZipFileProducer { ZipFile produce() throws IOException; }
/**
* Create and remember a provider for external annotations using the given basePath,
* which is either a directory holding .eea text files, or a zip file of entries of the same format.
* @param basePath resolved filesystem path of either directory or zip file
* @param qualifiedBinaryTypeName slash-separated type name
- * @param zipFileInOut Input: an existing zip file for the same basePath, or null.
- * Output: will be filled with a fresh new ZipFile when appropriate, to let clients cache it, if desired.
+ * @param zipFile an existing zip file for the same basePath, or null.
+ * Output: wl be filled with
* @param producer an optional helper to produce the zipFile when needed.
- * @return true if external annotations could be found for the given basePath and type name.
+ * @return the client provided zip file;
+ * or else a fresh new zip file, to let clients cache it, if desired;
+ * or null to signal that basePath is not a zip file, but a directory.
+ * @throws IOException any unexpected errors during file access. File not found while
+ * accessing an individual file if basePath is a directory <em>is</em> expected,
+ * and simply answered with null. If basePath is neither a directory nor a zip file,
+ * this is unexpected.
*/
-public boolean setExternalAnnotationProvider(String basePath, String qualifiedBinaryTypeName, ZipFile[] zipFileInOut, ZipFileProducer producer) {
+public ZipFile setExternalAnnotationProvider(String basePath, String qualifiedBinaryTypeName, ZipFile zipFile, ZipFileProducer producer) throws IOException {
String qualifiedBinaryFileName = qualifiedBinaryTypeName + ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX;
- try {
- ZipFile zipFile = zipFileInOut[0];
- if (zipFile == null) {
- File annotationBase = new File(basePath);
- if (annotationBase.isDirectory()) {
- try {
- setExternalAnnotationProvider(new FileInputStream(annotationBase.getAbsolutePath()+'/'+qualifiedBinaryFileName));
- } catch (FileNotFoundException e) {
- return false; // expected, no need to report an error here
- }
- return true;
+ if (zipFile == null) {
+ File annotationBase = new File(basePath);
+ if (annotationBase.isDirectory()) {
+ try {
+ String filePath = annotationBase.getAbsolutePath()+'/'+qualifiedBinaryFileName;
+ this.annotationProvider = new ExternalAnnotationProvider(new FileInputStream(filePath), String.valueOf(getName()));
+ } catch (FileNotFoundException e) {
+ // expected, no need to report an error here
}
- zipFileInOut[0] = zipFile = (producer != null ? producer.produce() : new ZipFile(annotationBase));
- if (zipFile == null)
- return false;
+ return null; // no zipFile
}
- ZipEntry entry = zipFile.getEntry(qualifiedBinaryFileName);
- if (entry != null)
- return setExternalAnnotationProvider(zipFile.getInputStream(entry));
- } catch (ZipException e) {
- // treat as missing, FIXME: error reporting
- } catch (IOException e) {
- // treat as missing, FIXME: error reporting
+ if (!annotationBase.exists())
+ return null; // no zipFile, treat as not-yet-created directory
+ zipFile = (producer != null ? producer.produce() : new ZipFile(annotationBase));
}
- return false;
-}
-
-boolean setExternalAnnotationProvider(InputStream inputStream) throws IOException {
- this.annotationProvider = new ExternalAnnotationProvider(inputStream, String.valueOf(getName()));
- return true;
+ ZipEntry entry = zipFile.getEntry(qualifiedBinaryFileName);
+ if (entry != null)
+ this.annotationProvider = new ExternalAnnotationProvider(zipFile.getInputStream(entry), String.valueOf(getName()));
+ return zipFile;
}
/** If a provider for external annotations has been registered try to retrieve an annotation walker for type parameters of the current type. */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
index ce03b603d4..2bd85ff75c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
@@ -78,10 +78,11 @@ public class ExternalAnnotationProvider {
if (line.startsWith(TYPE_PARAMETER_PREFIX)) {
this.typeParameterAnnotationSource = line.substring(TYPE_PARAMETER_PREFIX.length());
if ((line = reader.readLine()) == null)
- return;
+ return;
}
}
do {
+ line = line.trim();
if (line.isEmpty()) continue;
String rawSig = null, annotSig = null;
// selector:
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index 2247da8ecf..6611749034 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -36,6 +36,7 @@ import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
+import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.IDependent;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
@@ -52,7 +53,6 @@ public class ClassFile extends Openable implements IClassFile, SuffixConstants {
protected String name;
protected BinaryType binaryType = null;
- private boolean hasExternalAnnotations = false;
/*
* Creates a handle to a class file.
*/
@@ -389,30 +389,33 @@ private void setupExternalAnnotationProvider(IProject project, final IPath exter
String resolvedPath = resource.exists()
? resource.getLocation().toString() // workspace lookup succeeded -> resolve it
: externalAnnotationPath.toString(); // not in workspace, use as is
- ZipFile[] zipFileInOut = new ZipFile[] { annotationZip };
- if (reader.setExternalAnnotationProvider(resolvedPath, typeName, zipFileInOut, new ClassFileReader.ZipFileProducer() {
- @Override public ZipFile produce() {
- try {
- return JavaModelManager.getJavaModelManager().getZipFile(externalAnnotationPath); // use (absolute, but) unresolved path here
- } catch (CoreException e) {
- Util.log(e, "Failed to read annotation file for "+typeName+" from "+externalAnnotationPath.toString()); //$NON-NLS-1$ //$NON-NLS-2$
- return null;
- }
- }}))
- {
- annotationZip = zipFileInOut[0];
- this.hasExternalAnnotations = true;
+ try {
+ annotationZip = reader.setExternalAnnotationProvider(resolvedPath, typeName, annotationZip, new ClassFileReader.ZipFileProducer() {
+ @Override public ZipFile produce() throws IOException {
+ try {
+ return JavaModelManager.getJavaModelManager().getZipFile(externalAnnotationPath); // use (absolute, but) unresolved path here
+ } catch (CoreException e) {
+ throw new IOException("Failed to read annotation file for "+typeName+" from "+externalAnnotationPath.toString(), e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }});
+ } catch (IOException e) {
+ Util.log(e);
+ return;
}
- if (this.hasExternalAnnotations && annotationZip == null) {
- // additional change listening for individual types only when annotations are in individual files:
+ if (annotationZip == null) {
+ // Additional change listening for individual types only when annotations are in individual files.
+ // Note that we also listen for classes that don't yet have an annotation file, to detect its creation
+ final IPath workspaceFilePath = externalAnnotationPath
+ .append(new Path(typeName))
+ .addFileExtension(ExternalAnnotationProvider.ANNOTION_FILE_EXTENSION);
final IWorkspace workspace = project.getWorkspace();
workspace.addResourceChangeListener(new IResourceChangeListener() {
@Override
public void resourceChanged(IResourceChangeEvent event) {
- if (event.getDelta().findMember(externalAnnotationPath) != null) {
+ if (event.getDelta().findMember(workspaceFilePath) != null) {
workspace.removeResourceChangeListener(this);
try {
- ClassFile.this.close();
+ ClassFile.this.closeAndRemoveFromJarTypeCache();
} catch (JavaModelException e) {
Util.log(e, "Failed to close ClassFile "+ClassFile.this.name); //$NON-NLS-1$
}
@@ -422,6 +425,11 @@ private void setupExternalAnnotationProvider(IProject project, final IPath exter
IResourceChangeEvent.POST_CHANGE);
}
}
+void closeAndRemoveFromJarTypeCache() throws JavaModelException {
+ close();
+ // triggered when external annotations have changed we need to recreate this class file
+ JavaModelManager.getJavaModelManager().removeFromJarTypeCache(this.binaryType);
+}
public IBuffer getBuffer() throws JavaModelException {
IStatus status = validateClassFile();
if (status.isOK()) {
@@ -901,11 +909,4 @@ protected IStatus validateExistence(IResource underlyingResource) {
public ISourceRange getNameRange() {
return null;
}
-@Override
-public void close() throws JavaModelException {
- super.close();
- if (this.binaryType != null && this.hasExternalAnnotations)
- // triggered when external annotations have changed we need to recreate this class file
- JavaModelManager.getJavaModelManager().removeFromJarTypeCache(this.binaryType);
-}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java
index 247a132bf8..7d1df251b4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 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
@@ -7,6 +7,8 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for
+ * Bug 440477 - [null] Infrastructure for feeding external annotations into compilation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -27,6 +29,7 @@ import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
import org.eclipse.jdt.internal.core.DeltaProcessor.RootInfo;
@@ -122,6 +125,17 @@ public class ClasspathChange {
continue nextEntry;
}
}
+ if (JavaCore.ENABLED.equals(this.project.getOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, true))) {
+ // if null annotations are enabled, also check for changes in external annotation attachment
+ String annotationPath = ClasspathEntry.getRawExternalAnnotationPath(entry);
+ String otherAnnotationPath = ClasspathEntry.getRawExternalAnnotationPath(other);
+ if (annotationPath != null && otherAnnotationPath != null) {
+ if (!annotationPath.equals(otherAnnotationPath))
+ continue;
+ } else if (annotationPath != otherAnnotationPath) {
+ continue; // null and not-null
+ }
+ }
return i;
}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
index f024ca491f..b5acca9628 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -1275,43 +1275,55 @@ public class ClasspathEntry implements IClasspathEntry {
* @return a path (in the workspace or filesystem-absolute) or null
*/
public static IPath getExternalAnnotationPath(IClasspathEntry entry, IProject project, boolean resolve) {
+ String rawAnnotationPath = getRawExternalAnnotationPath(entry);
+ if (rawAnnotationPath != null) {
+ IPath annotationPath = new Path(rawAnnotationPath);
+ if (annotationPath.isAbsolute()) {
+ if (!resolve)
+ return annotationPath;
+
+ if (annotationPath.segmentCount() > 1) {
+ // try Workspace-absolute:
+ IProject targetProject = project.getWorkspace().getRoot().getProject(annotationPath.segment(0));
+ if (targetProject.exists())
+ return targetProject.getLocation().append(annotationPath.removeFirstSegments(1));
+ }
+ // absolute, not in workspace, must be Filesystem-absolute:
+ return annotationPath;
+ } else {
+ // try Variable (always resolved):
+ IPath resolved = JavaCore.getResolvedVariablePath(annotationPath);
+ if (resolved != null)
+ return resolved;
+
+ // Project-relative:
+ if (project != null) {
+ if (resolve)
+ return project.getLocation().append(annotationPath);
+ else
+ return new Path(project.getName()).append(annotationPath).makeAbsolute();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answer the raw external annotation path as specified in .classpath, or null.
+ * @param entry where to look
+ * @return the attached external annotation path, or null.
+ */
+ static String getRawExternalAnnotationPath(IClasspathEntry entry) {
IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
for (int i = 0, length = extraAttributes.length; i < length; i++) {
IClasspathAttribute attribute = extraAttributes[i];
if (IClasspathAttribute.EXTERNAL_ANNOTATION_PATH.equals(attribute.getName())) {
- IPath annotationPath = new Path(attribute.getValue());
-
- if (annotationPath.isAbsolute()) {
- if (!resolve)
- return annotationPath;
-
- if (annotationPath.segmentCount() > 1) {
- // try Workspace-absolute:
- IProject targetProject = project.getWorkspace().getRoot().getProject(annotationPath.segment(0));
- if (targetProject.exists())
- return targetProject.getLocation().append(annotationPath.removeFirstSegments(1));
- }
- // absolute, not in workspace, must be Filesystem-absolute:
- return annotationPath;
- } else {
- // try Variable (always resolved):
- IPath resolved = JavaCore.getResolvedVariablePath(annotationPath);
- if (resolved != null)
- return resolved;
-
- // Project-relative:
- if (project != null) {
- if (resolve)
- return project.getLocation().append(annotationPath);
- else
- return new Path(project.getName()).append(annotationPath).makeAbsolute();
- }
- }
+ return attribute.getValue();
}
}
return null;
}
-
+
public IClasspathEntry getReferencingEntry() {
return this.referencingEntry;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
index ce869209dc..1bda5fb27a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
@@ -169,9 +169,11 @@ public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPa
if (reader != null) {
String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
if (this.externalAnnotationPath != null) {
- ZipFile[] zipFileInOut = new ZipFile[] { this.annotationZipFile };
- reader.setExternalAnnotationProvider(this.externalAnnotationPath, fileNameWithoutExtension, zipFileInOut, null);
- this.annotationZipFile = zipFileInOut[0];
+ try {
+ this.annotationZipFile = reader.setExternalAnnotationProvider(this.externalAnnotationPath, fileNameWithoutExtension, this.annotationZipFile, null);
+ } catch (IOException e) {
+ // don't let error on annotations fail class reading
+ }
}
if (this.accessRuleSet == null)
return new NameEnvironmentAnswer(reader, null);

Back to the top