From 18cb8c18a0ece00d59fe97c8d820c8be6145f1c5 Mon Sep 17 00:00:00 2001 From: Jay Arthanareeswaran Date: Tue, 24 Apr 2018 12:49:58 +0530 Subject: Bug 509985 - [9] Support multi-release JAR files Change-Id: I5f370677dd238aabd52566a49f93c7a8ce707e2d Signed-off-by: Jay Arthanareeswaran --- .../jdt/compiler/apt/tests/Java8ElementsTests.java | 2 +- .../compiler/apt/util/EclipseFileManager.java | 14 +- .../compiler/tool/EclipseCompilerImpl.java | 12 +- .../internal/compiler/tool/EclipseFileManager.java | 14 +- .../compiler/regression/MultiReleaseJarTests.java | 220 +++++++++++++++++++++ .../workspace/multi.jar | Bin 0 -> 6523 bytes .../internal/compiler/batch/ClasspathJep247.java | 99 +++++++--- .../jdt/internal/compiler/batch/ClasspathJrt.java | 2 +- .../compiler/batch/ClasspathMultiReleaseJar.java | 172 ++++++++++++++++ .../jdt/internal/compiler/batch/FileSystem.java | 17 +- .../eclipse/jdt/internal/compiler/batch/Main.java | 18 +- .../jdt/internal/compiler/batch/ModuleFinder.java | 33 ++-- .../eclipse/jdt/internal/compiler/util/Util.java | 4 +- .../jdt/internal/core/JarPackageFragmentRoot.java | 45 ++++- .../internal/core/JarPackageFragmentRootInfo.java | 6 +- .../jdt/internal/core/builder/ClasspathJar.java | 5 + .../jdt/internal/core/builder/ClasspathJrt.java | 25 +-- .../internal/core/builder/ClasspathLocation.java | 25 ++- .../core/builder/ClasspathMultiReleaseJar.java | 186 +++++++++++++++++ .../jdt/internal/core/builder/NameEnvironment.java | 12 +- .../eclipse/jdt/internal/core/builder/State.java | 33 ++-- .../core/nd/java/model/BinaryTypeFactory.java | 9 +- .../search/matching/JavaSearchNameEnvironment.java | 9 +- 23 files changed, 850 insertions(+), 112 deletions(-) create mode 100644 org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MultiReleaseJarTests.java create mode 100644 org.eclipse.jdt.core.tests.compiler/workspace/multi.jar create mode 100644 org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java create mode 100644 org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java diff --git a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/Java8ElementsTests.java b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/Java8ElementsTests.java index 3c36c6d1ca..3706f40651 100644 --- a/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/Java8ElementsTests.java +++ b/org.eclipse.jdt.compiler.apt.tests/src/org/eclipse/jdt/compiler/apt/tests/Java8ElementsTests.java @@ -320,7 +320,7 @@ public class Java8ElementsTests extends TestCase { internalTest(compiler, JAVA8_ANNOTATION_PROC, "testPackageAnnotations", null, "filer8", "9"); } // See Java8ElementProcessor.testPackageAnnotations() - public void _testPackageAnnotationsWithJavac() throws Exception { + public void testPackageAnnotationsWithJavac() throws Exception { if (!canRunJava9()) return; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java index ec9051533e..38ce78b664 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java @@ -87,6 +87,7 @@ public class EclipseFileManager implements StandardJavaFileManager { File jrtHome; JrtFileSystem jrtSystem; public ResourceBundle bundle; + String releaseVersion; public EclipseFileManager(Locale locale, Charset charset) { this.locale = locale == null ? Locale.getDefault() : locale; @@ -814,6 +815,13 @@ public class EclipseFileManager implements StandardJavaFileManager { } else { throw new IllegalArgumentException(); } + case "--relese": //$NON-NLS-1$ + if (remaining.hasNext()) { + this.releaseVersion = remaining.next(); + return true; + } else { + throw new IllegalArgumentException(); + } } } catch (IOException e) { // ignore @@ -1206,7 +1214,9 @@ public class EclipseFileManager implements StandardJavaFileManager { customEncoding, isSourceOnly, accessRuleSet, - destPath, null); + destPath, + null, + this.releaseVersion); if (currentClasspath != null) { paths.add(currentClasspath); } @@ -1336,7 +1346,7 @@ public class EclipseFileManager implements StandardJavaFileManager { new DefaultProblemFactory()); for (Path path : paths) { List mp = ModuleFinder.findModules(path.toFile(), null, - new Parser(problemReporter, true), null, true); + new Parser(problemReporter, true), null, true, this.releaseVersion); for (Classpath cp : mp) { Collection moduleNames = cp.getModuleNames(null); for (String string : moduleNames) { diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java index c547b22ec8..4e1f2dee80 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java @@ -515,7 +515,9 @@ public class EclipseCompilerImpl extends Main { Classpath classpath = FileSystem.getClasspath( file.getAbsolutePath(), null, - null, this.options); + null, + this.options, + this.releaseVersion); if (classpath != null) { fileSystemClasspaths.add(classpath); havePlatformPaths = true; @@ -559,7 +561,9 @@ public class EclipseCompilerImpl extends Main { Classpath classpath = FileSystem.getClasspath( file.getAbsolutePath(), null, - null, this.options); + null, + this.options, + this.releaseVersion); if (classpath != null) { fileSystemClasspaths.add(classpath); } @@ -571,7 +575,9 @@ public class EclipseCompilerImpl extends Main { Classpath classpath = FileSystem.getClasspath( file.getAbsolutePath(), null, - null, this.options); + null, + this.options, + this.releaseVersion); if (classpath != null) { fileSystemClasspaths.add(classpath); haveClassPaths = true; diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java index 4aa0201692..1a9420c4b5 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java @@ -87,6 +87,7 @@ public class EclipseFileManager implements StandardJavaFileManager { File jrtHome; JrtFileSystem jrtSystem; public ResourceBundle bundle; + private String releaseVersion; public EclipseFileManager(Locale locale, Charset charset) { this.locale = locale == null ? Locale.getDefault() : locale; @@ -814,6 +815,13 @@ public class EclipseFileManager implements StandardJavaFileManager { } else { throw new IllegalArgumentException(); } + case "--relese": //$NON-NLS-1$ + if (remaining.hasNext()) { + this.releaseVersion = remaining.next(); + return true; + } else { + throw new IllegalArgumentException(); + } } } catch (IOException e) { // ignore @@ -1231,7 +1239,9 @@ public class EclipseFileManager implements StandardJavaFileManager { customEncoding, isSourceOnly, accessRuleSet, - destPath, null); + destPath, + null, + this.releaseVersion); if (currentClasspath != null) { paths.add(currentClasspath); } @@ -1362,7 +1372,7 @@ public class EclipseFileManager implements StandardJavaFileManager { new DefaultProblemFactory()); for (Path path : paths) { List mp = ModuleFinder.findModules(path.toFile(), null, - new Parser(problemReporter, true), null, true); + new Parser(problemReporter, true), null, true, this.releaseVersion); for (Classpath cp : mp) { Collection moduleNames = cp.getModuleNames(null); for (String string : moduleNames) { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MultiReleaseJarTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MultiReleaseJarTests.java new file mode 100644 index 0000000000..fa0dbd44f1 --- /dev/null +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MultiReleaseJarTests.java @@ -0,0 +1,220 @@ +package org.eclipse.jdt.core.tests.compiler.regression; + +import java.io.File; + +import javax.lang.model.SourceVersion; + +import org.eclipse.jdt.core.tests.util.Util; + +import junit.framework.Test; + +public class MultiReleaseJarTests extends AbstractBatchCompilerTest { + + static { +// TESTS_NAMES = new String[] { "test001" }; + // TESTS_NUMBERS = new int[] { 1 }; + // TESTS_RANGE = new int[] { 298, -1 }; + } + + private boolean isJRE10 = false; + public MultiReleaseJarTests(String name) { + super(name); + try { + SourceVersion valueOf = SourceVersion.valueOf("RELEASE_10"); + if (valueOf != null) this.isJRE10 = true; + } catch(Exception e) { + + } + } + + public static Test suite() { + return buildMinimalComplianceTestSuite(testClass(), F_9); + } + + public static Class testClass() { + return MultiReleaseJarTests.class; + } + public void test001() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "multi.jar"; + String[] libs = new String[1]; + libs[0] = path; + runNegativeTest( + new String[] { + "src/X.java", + "import a.b.c.MultiVersion1.Inner;\n" + + "import p.q.r.MultiVersion2.Inner;\n" + + "public class X {\n" + + "}\n"}, + "\"" + OUTPUT_DIR + File.separator + "src/X.java\"" + + " -classpath " + path + " --release 8 ", + "", + "----------\n" + + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/X.java (at line 1)\n" + + " import a.b.c.MultiVersion1.Inner;\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "The import a.b.c.MultiVersion1.Inner cannot be resolved\n" + + "----------\n" + + "2. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/X.java (at line 2)\n" + + " import p.q.r.MultiVersion2.Inner;\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "The import p.q.r.MultiVersion2.Inner cannot be resolved\n" + + "----------\n" + + "2 problems (2 errors)\n", + false + ); + } + public void test002() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "multi.jar"; + String[] libs = new String[1]; + libs[0] = path; + runNegativeTest( + new String[] { + "src/X.java", + "import a.b.c.MultiVersion1.Inner;\n" + + "import p.q.r.MultiVersion2.Inner;\n" + + "public class X {\n" + + "}\n"}, + "\"" + OUTPUT_DIR + File.separator + "src/X.java\"" + + " -classpath " + path + " --release 9 ", + "", + "----------\n" + + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/X.java (at line 1)\n" + + " import a.b.c.MultiVersion1.Inner;\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "The type a.b.c.MultiVersion1.Inner is not visible\n" + + "----------\n" + + "1 problem (1 error)\n", + false + ); + } + public void test003() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "multi.jar"; + String[] libs = new String[1]; + libs[0] = path; + runConformTest( + new String[] { + "src/X.java", + "import p.q.r.MultiVersion3.Inner;\n" + + "public class X {\n" + + " Inner i = null;\n" + + " p.q.r.MultiVersion2.Inner i2 = null;\n" + + "}\n"}, + "\"" + OUTPUT_DIR + File.separator + "src/X.java\"" + + " -classpath " + path + " --release 9 ", + "", + "", + false + ); + } + public void test004() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "multi.jar"; + String[] libs = new String[1]; + libs[0] = path; + runNegativeTest( + new String[] { + "src/X.java", + "import p.q.r.MultiVersion3.Inner;\n" + + "import p.q.r.MultiVersion2.Inner;\n" + + "public class X {\n" + + " Inner i = null;\n" + + "}\n"}, + "\"" + OUTPUT_DIR + File.separator + "src/X.java\"" + + " -classpath " + path + " --release 9 ", + "", + "----------\n" + + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/X.java (at line 2)\n" + + " import p.q.r.MultiVersion2.Inner;\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "The import p.q.r.MultiVersion2.Inner collides with another import statement\n" + + "----------\n" + + "1 problem (1 error)\n", + false + ); + } + public void test005() { + Util.flushDirectoryContent(new File(OUTPUT_DIR)); + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "multi.jar"; + String[] libs = new String[1]; + libs[0] = path; + File directory = new File(OUTPUT_DIR + File.separator + "src" + File.separator + "MyModule" ); + File out = new File(OUTPUT_DIR + File.separator + "out" ); + if (!directory.exists()) { + if (!directory.mkdirs()) { + System.out.println("Could not create " + directory.toString()); + return; + } + } + if (!out.exists()) { + if (!out.mkdirs()) { + System.out.println("Could not create " + directory.toString()); + return; + } + } + runNegativeTest( + new String[] { + "src/MyModule/module-info.java", + "module MyModule {\n" + + " requires Version9;\n" + + "}", + "src/MyModule/p/X.java", + "package p;\n" + + "public class X {\n" + + " java.sql.Connection con = null;\n" + + "}\n"}, + " -d \"" + out.toString() + "\" " + + " --module-source-path \"" + directory.toString() + "\" " + + " \"" + OUTPUT_DIR + File.separator + "src" + File.separator + "MyModule" + File.separator + "module-info.java\"" + + " \"" + OUTPUT_DIR + File.separator + "src" + File.separator + "MyModule" + File.separator + "p" + File.separator + "X.java\" " + + " --module-path " + path + " --release 9 ", + "", + "----------\n" + + "1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/src/MyModule/p/X.java (at line 3)\n" + + " java.sql.Connection con = null;\n" + + " ^^^^^^^^^^^^^^^^^^^\n" + + "The type java.sql.Connection is not accessible\n" + + "----------\n" + + "1 problem (1 error)\n", + false + ); + } + public void test006() { + if (!this.isJRE10) return; + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "multi.jar"; + String[] libs = new String[1]; + libs[0] = path; + File directory = new File(OUTPUT_DIR + File.separator + "src" + File.separator + "MyModule" ); + File out = new File(OUTPUT_DIR + File.separator + "out" ); + if (!directory.exists()) { + if (!directory.mkdirs()) { + System.out.println("Could not create " + directory.toString()); + return; + } + } + if (!out.exists()) { + if (!directory.mkdirs()) { + System.out.println("Could not create " + directory.toString()); + return; + } + } + runConformTest( + new String[] { + "src/MyModule/module-info.java", + "module MyModule {\n" + + " requires Version10;\n" + + "}", + "src/MyModule/p/X.java", + "package p;\n" + + "public class X {\n" + + " java.sql.Connection con = null;\n" + + "}\n"}, + " -d \"" + out.toString() + "\" " + + " --module-source-path \"" + directory.toString() + "\" " + + " \"" + OUTPUT_DIR + File.separator + "src" + File.separator + "MyModule" + File.separator + "module-info.java\"" + + " \"" + OUTPUT_DIR + File.separator + "src" + File.separator + "MyModule" + File.separator + "p" + File.separator + "X.java\" " + + " --module-path " + path + " --release 10 ", + "", + "", + false + ); + } +} diff --git a/org.eclipse.jdt.core.tests.compiler/workspace/multi.jar b/org.eclipse.jdt.core.tests.compiler/workspace/multi.jar new file mode 100644 index 0000000000..c28b088a36 Binary files /dev/null and b/org.eclipse.jdt.core.tests.compiler/workspace/multi.jar differ diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java index 37bb0a0564..6e1eb3af8e 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java @@ -15,32 +15,37 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.Util; -public class ClasspathJep247 extends ClasspathLocation { +public class ClasspathJep247 extends ClasspathJrt { private java.nio.file.FileSystem fs = null; private String compliance = null; private String releaseInHex = null; private String[] subReleases = null; private Path releasePath = null; - private File file = null; private Set packageCache; + File jdkHome; + String modulePath = null; public ClasspathJep247(File jdkHome, String release, AccessRuleSet accessRuleSet) { - super(accessRuleSet, null); + super(jdkHome, false, accessRuleSet, null); this.compliance = release; - this.file = jdkHome; + this.jdkHome = jdkHome; + this.file = new File(new File(jdkHome, "lib"), "jrt-fs.jar"); //$NON-NLS-1$ //$NON-NLS-2$ } @Override public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { @@ -83,15 +88,6 @@ public class ClasspathJep247 extends ClasspathLocation { } return null; } - @Override - public boolean hasAnnotationFileFor(String qualifiedTypeName) { - return false; - } - @Override - public char[][][] findTypeNames(final String qualifiedPackageName, String moduleName) { - // TODO: Revisit - return null; - } @Override public void initialize() throws IOException { @@ -99,7 +95,7 @@ public class ClasspathJep247 extends ClasspathLocation { return; } this.releaseInHex = Integer.toHexString(Integer.parseInt(this.compliance)); - Path filePath = this.file.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ + Path filePath = this.jdkHome.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ URI t = filePath.toUri(); if (!Files.exists(filePath)) { return; @@ -118,9 +114,73 @@ public class ClasspathJep247 extends ClasspathLocation { if (!Files.exists(this.fs.getPath(this.releaseInHex))) { throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ } + super.initialize(); + } + @Override + public void loadModules() { + if (CompilerOptions.releaseToJDKLevel(this.compliance) <= ClassFileConstants.JDK1_8) { + return; + } + final Path modPath = this.fs.getPath(this.releaseInHex + "-modules"); //$NON-NLS-1$ + if (!Files.exists(modPath)) { + throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ + } + this.modulePath = this.file.getPath() + "|" + modPath.toString(); //$NON-NLS-1$ + Map cache = ModulesCache.get(this.modulePath); + if (cache == null) { + try (DirectoryStream stream = Files.newDirectoryStream(modPath)) { + for (final java.nio.file.Path subdir: stream) { + Files.walkFileTree(subdir, new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { + byte[] content = null; + if (Files.exists(f)) { + content = JRTUtil.safeReadBytes(f); + if (content == null) + return FileVisitResult.CONTINUE; + ClasspathJep247.this.acceptModule(content); + ClasspathJep247.this.moduleNamesCache.add(f.getFileName().toString()); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } catch (IOException e) { + e.printStackTrace(); + } + } else { + this.moduleNamesCache.addAll(cache.keySet()); + } } + @Override void acceptModule(ClassFileReader reader) { - // Nothing to do + if (reader != null) { + IModule moduleDecl = reader.getModuleDeclaration(); + if (moduleDecl != null) { + Map cache = ModulesCache.get(this.modulePath); + if (cache == null) { + ModulesCache.put(this.modulePath, cache = new HashMap()); + } + cache.put(String.valueOf(moduleDecl.name()), moduleDecl); + } + } } protected void addToPackageCache(String packageName, boolean endsWithSep) { if (this.packageCache.contains(packageName)) @@ -178,11 +238,6 @@ public class ClasspathJep247 extends ClasspathLocation { return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); } @Override - public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { - // TOOD: Revisit - return false; - } - @Override public void reset() { try { super.reset(); @@ -224,8 +279,4 @@ public class ClasspathJep247 extends ClasspathLocation { return BINARY; } - @Override - public IModule getModule() { - return null; - } } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java index d7de9a9b43..64e28bb6e6 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java @@ -45,7 +45,7 @@ public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry public File file; protected ZipFile annotationZipFile; protected boolean closeZipFileAtEnd; - private static HashMap> ModulesCache = new HashMap<>(); + protected static HashMap> ModulesCache = new HashMap<>(); public final Set moduleNamesCache; //private Set packageCache; protected List annotationPaths; diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java new file mode 100644 index 0000000000..41756884ec --- /dev/null +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java @@ -0,0 +1,172 @@ +package org.eclipse.jdt.internal.compiler.batch; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.zip.ZipEntry; + +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class ClasspathMultiReleaseJar extends ClasspathJar { + private java.nio.file.FileSystem fs = null; + Path releasePath = null; + String compliance = null; + + public ClasspathMultiReleaseJar(File file, boolean closeZipFileAtEnd, + AccessRuleSet accessRuleSet, String destinationPath, String compliance) { + super(file, closeZipFileAtEnd, accessRuleSet, destinationPath); + this.compliance = compliance; + } + @Override + public void initialize() throws IOException { + super.initialize(); + URI t = this.file.toURI(); + if (this.file.exists()) { + URI uri = URI.create("jar:file:" + t.getRawPath()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + } catch(FileSystemNotFoundException fne) { + // Ignore and move on + } + if (this.fs == null) { + HashMap env = new HashMap<>(); + try { + this.fs = FileSystems.newFileSystem(uri, env); + } catch (IOException e) { + // return + } + } + this.releasePath = this.fs.getPath("/", "META-INF", "versions", this.compliance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (!Files.exists(this.releasePath)) { + this.releasePath = null; + } + } + } + @SuppressWarnings("rawtypes") + @Override + public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { + if (this.releasePath == null) { + return super.getModulesDeclaringPackage(qualifiedPackageName, moduleName); + } + if (this.packageCache != null) + return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); + + this.packageCache = new HashSet<>(41); + this.packageCache.add(Util.EMPTY_STRING); + + for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { + String fileName = ((ZipEntry) e.nextElement()).getName(); + addToPackageCache(fileName, false); + } + try { + if (this.releasePath != null && Files.exists(this.releasePath)) { + // go through the packages + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + Files.walkFileTree(subdir, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) + throws IOException { + Path p = ClasspathMultiReleaseJar.this.releasePath.relativize(f); + addToPackageCache(p.toString(), false); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) + throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + // move on; + } + return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); + } + @Override + public NameEnvironmentAnswer findClass(char[] binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { + if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case + if (this.releasePath != null) { + try { + Path p = this.releasePath.resolve(qualifiedBinaryFileName); + byte[] content = Files.readAllBytes(p); + IBinaryType reader = null; + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + } + if (reader != null) { + char[] modName = this.module == null ? null : this.module.name(); + if (reader instanceof ClassFileReader) { + ClassFileReader classReader = (ClassFileReader) reader; + if (classReader.moduleName == null) + classReader.moduleName = modName; + else + modName = classReader.moduleName; + } + String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); + searchPaths: + if (this.annotationPaths != null) { + String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1); + for (String annotationPath : this.annotationPaths) { + try { + if (this.annotationZipFile == null) { + this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(annotationPath, null); + } + reader = ExternalAnnotationDecorator.create(reader, annotationPath, qualifiedClassName, this.annotationZipFile); + + if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.TYPE_IS_ANNOTATED) { + break searchPaths; + } + } catch (IOException e) { + // don't let error on annotations fail class reading + } + } + // location is configured for external annotations, but no .eea found, decorate in order to answer NO_EEA_FILE: + reader = new ExternalAnnotationDecorator(reader, null); + } + if (this.accessRuleSet == null) + return new NameEnvironmentAnswer(reader, null, modName); + return new NameEnvironmentAnswer(reader, + this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), + modName); + } + } catch (IOException | ClassFormatException e) { + // treat as if class file is missing + } + } + return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, asBinaryOnly); + } +} diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java index ae2c63a02a..492067b88c 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java @@ -179,7 +179,7 @@ protected FileSystem(String[] classpathNames, String[] initialFileNames, String this.classpaths = new Classpath[classpathSize]; int counter = 0; for (int i = 0; i < classpathSize; i++) { - Classpath classpath = getClasspath(classpathNames[i], encoding, null, null); + Classpath classpath = getClasspath(classpathNames[i], encoding, null, null, null); try { classpath.initialize(); for (String moduleName : classpath.getModuleNames(limitModules)) @@ -244,10 +244,10 @@ protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annot this(paths, initialFileNames, annotationsFromClasspath, null); } public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet) { - return getClasspath(classpathName, encoding, false, accessRuleSet, null, null); + return getClasspath(classpathName, encoding, false, accessRuleSet, null, null, null); } -public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet, Map options) { - return getClasspath(classpathName, encoding, false, accessRuleSet, null, options); +public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet, Map options, String release) { + return getClasspath(classpathName, encoding, false, accessRuleSet, null, options, release); } public static Classpath getJrtClasspath(String jdkHome, String encoding, AccessRuleSet accessRuleSet, Map options) { return new ClasspathJrt(new File(convertPathSeparators(jdkHome)), true, accessRuleSet, null); @@ -257,7 +257,7 @@ public static Classpath getOlderSystemRelease(String jdkHome, String release, Ac } public static Classpath getClasspath(String classpathName, String encoding, boolean isSourceOnly, AccessRuleSet accessRuleSet, - String destinationPath, Map options) { + String destinationPath, Map options, String release) { Classpath result = null; File file = new File(convertPathSeparators(classpathName)); if (file.isDirectory()) { @@ -298,7 +298,10 @@ public static Classpath getClasspath(String classpathName, String encoding, JRT_CLASSPATH_CACHE.put(file, result); } } else { - result = new ClasspathJar(file, true, accessRuleSet, null); + result = + (release == null) ? + new ClasspathJar(file, true, accessRuleSet, null) : + new ClasspathMultiReleaseJar(file, true, accessRuleSet, destinationPath, release); } } } else if (format == Util.JMOD_FILE) { @@ -370,7 +373,7 @@ private void initializeKnownFileNames(String[] initialFileNames) { public void scanForModules(Parser parser) { for (int i = 0, max = this.classpaths.length; i < max; i++) { File file = new File(this.classpaths[i].getPath()); - IModule iModule = ModuleFinder.scanForModule(this.classpaths[i], file, parser, false); + IModule iModule = ModuleFinder.scanForModule(this.classpaths[i], file, parser, false, null); if (iModule != null) this.moduleLocations.put(String.valueOf(iModule.name()), this.classpaths[i]); } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java index d65835471d..b2b6c5e932 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -1632,7 +1632,9 @@ protected void addNewEntry(ArrayList paths, String current customEncoding, isSourceOnly, accessRuleSet, - destPath, this.options); + destPath, + this.options, + this.releaseVersion); if (currentClasspath != null) { paths.add(currentClasspath); } else if (currentClasspathName.length() != 0) { @@ -3531,9 +3533,9 @@ protected ArrayList handleModulepath(String arg) { File file = new File(path); if (file.isDirectory()) { result.addAll( - ModuleFinder.findModules(file, null, getNewParser(), this.options, true)); + ModuleFinder.findModules(file, null, getNewParser(), this.options, true, this.releaseVersion)); } else { - Classpath modulePath = ModuleFinder.findModule(file, null, getNewParser(), this.options, true); + Classpath modulePath = ModuleFinder.findModule(file, null, getNewParser(), this.options, true, this.releaseVersion); if (modulePath != null) result.add(modulePath); } @@ -3559,7 +3561,7 @@ protected ArrayList handleModuleSourcepath(String arg) { // 1. Create FileSystem.Classpath for each module // 2. Iterator each module in case of directory for source files and add to this.fileNames - List modules = ModuleFinder.findModules(dir, this.destinationPath, getNewParser(), this.options, false); + List modules = ModuleFinder.findModules(dir, this.destinationPath, getNewParser(), this.options, false, this.releaseVersion); for (Classpath classpath : modules) { result.add(classpath); Path modLocation = Paths.get(classpath.getPath()).toAbsolutePath(); @@ -3607,7 +3609,7 @@ protected ArrayList handleClasspath(ArrayList clas String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$ if ((classProp == null) || (classProp.length() == 0)) { addPendingErrors(this.bind("configure.noClasspath")); //$NON-NLS-1$ - final Classpath classpath = FileSystem.getClasspath(System.getProperty("user.dir"), customEncoding, null, this.options);//$NON-NLS-1$ + final Classpath classpath = FileSystem.getClasspath(System.getProperty("user.dir"), customEncoding, null, this.options, this.releaseVersion);//$NON-NLS-1$ if (classpath != null) { initial.add(classpath); } @@ -3617,7 +3619,7 @@ protected ArrayList handleClasspath(ArrayList clas while (tokenizer.hasMoreTokens()) { token = tokenizer.nextToken(); FileSystem.Classpath currentClasspath = FileSystem - .getClasspath(token, customEncoding, null, this.options); + .getClasspath(token, customEncoding, null, this.options, this.releaseVersion); if (currentClasspath != null) { initial.add(currentClasspath); } else if (token.length() != 0) { @@ -3697,7 +3699,7 @@ protected ArrayList handleEndorseddirs(ArrayList e FileSystem.Classpath classpath = FileSystem.getClasspath( current[j].getAbsolutePath(), - null, null, this.options); + null, null, this.options, this.releaseVersion); if (classpath != null) { result.add(classpath); } @@ -3758,7 +3760,7 @@ protected ArrayList handleExtdirs(ArrayList extdir FileSystem.Classpath classpath = FileSystem.getClasspath( current[j].getAbsolutePath(), - null, null, this.options); + null, null, this.options, this.releaseVersion); if (classpath != null) { result.add(classpath); } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java index 0ef53adfc0..1d48b3d0b2 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.StringTokenizer; import java.util.jar.JarFile; import java.util.jar.Manifest; +import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.jdt.internal.compiler.CompilationResult; @@ -35,45 +36,46 @@ import org.eclipse.jdt.internal.compiler.util.Util; public class ModuleFinder { - public static List findModules(File f, String destinationPath, Parser parser, Map options, boolean isModulepath) { + public static List findModules(File f, String destinationPath, Parser parser, Map options, boolean isModulepath, String release) { List collector = new ArrayList<>(); - scanForModules(destinationPath, parser, options, isModulepath, false, collector, f); + scanForModules(destinationPath, parser, options, isModulepath, false, collector, f, release); return collector; } protected static FileSystem.Classpath findModule(final File file, String destinationPath, Parser parser, - Map options, boolean isModulepath) { + Map options, boolean isModulepath, String release) { FileSystem.Classpath modulePath = FileSystem.getClasspath(file.getAbsolutePath(), null, !isModulepath, null, - destinationPath == null ? null : (destinationPath + File.separator + file.getName()), options); + destinationPath == null ? null : (destinationPath + File.separator + file.getName()), options, release); if (modulePath != null) { - scanForModule(modulePath, file, parser, isModulepath); + scanForModule(modulePath, file, parser, isModulepath, release); } return modulePath; } protected static void scanForModules(String destinationPath, Parser parser, Map options, boolean isModulepath, - boolean thisAnAutomodule, List collector, final File file) { + boolean thisAnAutomodule, List collector, final File file, String release) { FileSystem.Classpath entry = FileSystem.getClasspath( file.getAbsolutePath(), null, !isModulepath, null, destinationPath == null ? null : (destinationPath + File.separator + file.getName()), - options); + options, + release); if (entry != null) { - IModule module = scanForModule(entry, file, parser, thisAnAutomodule); + IModule module = scanForModule(entry, file, parser, thisAnAutomodule, release); if (module != null) { collector.add(entry); } else { if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { - scanForModules(destinationPath, parser, options, isModulepath, isModulepath, collector, f); + scanForModules(destinationPath, parser, options, isModulepath, isModulepath, collector, f, release); } } } } } - protected static IModule scanForModule(FileSystem.Classpath modulePath, final File file, Parser parser, boolean considerAutoModules) { + protected static IModule scanForModule(FileSystem.Classpath modulePath, final File file, Parser parser, boolean considerAutoModules, String release) { IModule module = null; if (file.isDirectory()) { String[] list = file.list(new FilenameFilter() { @@ -106,7 +108,7 @@ public class ModuleFinder { } else { String moduleDescPath = getModulePathForArchive(file); if (moduleDescPath != null) { - module = extractModuleFromArchive(file, modulePath, moduleDescPath); + module = extractModuleFromArchive(file, modulePath, moduleDescPath, release); } } if (considerAutoModules && module == null && !(modulePath instanceof ClasspathJrt)) { @@ -224,10 +226,17 @@ public class ModuleFinder { } return null; } - private static IModule extractModuleFromArchive(File file, Classpath pathEntry, String path) { + private static IModule extractModuleFromArchive(File file, Classpath pathEntry, String path, String release) { ZipFile zipFile = null; try { zipFile = new ZipFile(file); + if (release != null) { + String releasePath = "META-INF/versions/" + release + "/" + path; //$NON-NLS-1$ //$NON-NLS-2$ + ZipEntry entry = zipFile.getEntry(releasePath); + if (entry != null) { + path = releasePath; + } + } ClassFileReader reader = ClassFileReader.read(zipFile, path); IModule module = getModule(reader); if (module != null) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java index b7683aad29..fd4432b075 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2018 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 @@ -1242,7 +1242,7 @@ public class Util implements SuffixConstants { } List classpaths = new ArrayList<>(); for (String filePath : filePaths) { - FileSystem.Classpath currentClasspath = FileSystem.getClasspath(filePath, null, null, null); + FileSystem.Classpath currentClasspath = FileSystem.getClasspath(filePath, null, null, null, null); if (currentClasspath != null) { classpaths.add(currentClasspath); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java index 33136eb339..561c6084a6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java @@ -14,6 +14,8 @@ import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipException; @@ -27,8 +29,10 @@ import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IModuleDescription; import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.core.nd.IReader; @@ -63,6 +67,9 @@ public class JarPackageFragmentRoot extends PackageFragmentRoot { boolean knownToBeModuleLess; + private boolean multiVersion; + public String versionPath; + /** * Constructs a package fragment root which is the root of the Java package directory hierarchy * based on a JAR file that is not contained in a IJavaProject and @@ -89,6 +96,7 @@ public class JarPackageFragmentRoot extends PackageFragmentRoot { @Override protected boolean computeChildren(OpenableElementInfo info, IResource underlyingResource) throws JavaModelException { final HashtableOfArrayToObject rawPackageInfo = new HashtableOfArrayToObject(); + final Set overridden = new HashSet<>(); IJavaElement[] children; try { // always create the default package @@ -125,15 +133,28 @@ public class JarPackageFragmentRoot extends PackageFragmentRoot { // contain an up-to-date entry for this .jar) then fetch it directly from the .jar if (!usedIndex) { Object file = JavaModel.getTarget(getPath(), true); - long level = Util.getJdkLevel(file); - String compliance = CompilerOptions.versionFromJdkLevel(level); + long classLevel = Util.getJdkLevel(file); + String projectCompliance = this.getJavaProject().getOption(JavaCore.COMPILER_COMPLIANCE, true); + long projectLevel = CompilerOptions.versionToJdkLevel(projectCompliance); ZipFile jar = null; try { jar = getJar(); - + String version = "META-INF/versions/" + projectCompliance + "/"; //$NON-NLS-1$//$NON-NLS-2$ + int versionPathLength = version.length(); + if (projectLevel >= ClassFileConstants.JDK9 && jar.getEntry(version) != null) { + this.multiVersion = true; + this.versionPath = version; + } for (Enumeration e= jar.entries(); e.hasMoreElements();) { ZipEntry member= (ZipEntry) e.nextElement(); - initRawPackageInfo(rawPackageInfo, member.getName(), member.isDirectory(), compliance); + String name = member.getName(); + if (this.multiVersion && name.length() > versionPathLength && name.startsWith(version)) { + name = name.substring(version.length()); + if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) { + overridden.add(name); + } + } + initRawPackageInfo(rawPackageInfo, name, member.isDirectory(), CompilerOptions.versionFromJdkLevel(classLevel)); } } finally { JavaModelManager.getJavaModelManager().closeZipFile(jar); @@ -162,6 +183,7 @@ public class JarPackageFragmentRoot extends PackageFragmentRoot { info.setChildren(children); ((JarPackageFragmentRootInfo) info).rawPackageInfo = rawPackageInfo; + ((JarPackageFragmentRootInfo) info).overriddenClasses = overridden; return true; } protected IJavaElement[] createChildren(final HashtableOfArrayToObject rawPackageInfo) { @@ -257,6 +279,21 @@ public class JarPackageFragmentRoot extends PackageFragmentRoot { return new JarPackageFragment(this, pkgName); // Overridden in JImageModuleFragmentBridge } + @Override + public String getClassFilePath(String classname) { + if (this.multiVersion) { + JarPackageFragmentRootInfo elementInfo; + try { + elementInfo = (JarPackageFragmentRootInfo) getElementInfo(); + if (elementInfo.overriddenClasses.contains(classname)) { + return this.versionPath == null ? classname : this.versionPath + classname; + } + } catch (JavaModelException e) { + // move on + } + } + return classname; + } @Override public IModuleDescription getModuleDescription() { if (this.knownToBeModuleLess) diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java index 7955b082ed..113c5bfb37 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2018 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 @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core; +import java.util.Set; + import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject; /** @@ -18,4 +20,6 @@ import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject; class JarPackageFragmentRootInfo extends PackageFragmentRootInfo { // a map from package name (String[]) to a size-2 array of Array, the first element being the .class file names, and the second element being the non-Java resource names HashtableOfArrayToObject rawPackageInfo; + Set overriddenClasses; + } 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 2e2ebaf7d2..39c1ee10e0 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 @@ -136,6 +136,8 @@ boolean closeZipFileAtEnd; private SimpleSet knownPackageNames; AccessRuleSet accessRuleSet; String externalAnnotationPath; +// Meant for ClasspathMultiReleaseJar, not used in here +String compliance; ClasspathJar(IFile resource, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath) { this.resource = resource; @@ -228,6 +230,9 @@ public boolean equals(Object o) { if (this.accessRuleSet != jar.accessRuleSet) if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet)) return false; + if (!Util.equalOrNull(this.compliance, jar.compliance)) { + return false; + } return this.zipFilename.equals(jar.zipFilename) && lastModified() == jar.lastModified() && this.isOnModulePath == jar.isOnModulePath diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java index f87c28e9bc..94c0ce3462 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java @@ -58,7 +58,7 @@ String externalAnnotationPath; private ZipFile annotationZipFile; String zipFilename; // keep for equals AccessRuleSet accessRuleSet; -String compliance = null; +String release = null; String releaseInHex = null; private Path releasePath = null; private String[] subReleases = null; @@ -66,15 +66,15 @@ private java.nio.file.FileSystem fs = null; static final Set NO_LIMIT_MODULES = new HashSet<>(); -public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, String compliance) { +public ClasspathJrt(String zipFilename, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, String release) { this.zipFilename = zipFilename; this.accessRuleSet = accessRuleSet; if (externalAnnotationPath != null) this.externalAnnotationPath = externalAnnotationPath.toString(); - if (compliance != null && compliance.length() == 0) { - this.compliance = null; + if (release != null && release.length() == 0) { + this.release = null; } else { - this.compliance = compliance; + this.release = release; } initialize(); loadModules(this); @@ -172,11 +172,11 @@ public static void loadModules(final ClasspathJrt jrt) { } } public void initialize() { - if (this.compliance == null) { + if (this.release == null) { return; } - this.compliance = getReleaseOptionFromCompliance(this.compliance); - this.releaseInHex = Integer.toHexString(Integer.parseInt(this.compliance)); + this.release = getReleaseOptionFromCompliance(this.release); + this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)); Path lib = Paths.get(this.zipFilename).getParent(); Path filePath = Paths.get(lib.toString(), "ct.sym"); //$NON-NLS-1$ URI t = filePath.toUri(); @@ -194,16 +194,16 @@ public void initialize() { try { this.fs = FileSystems.newFileSystem(uri, env); } catch (IOException e) { - this.compliance = null; + this.release = null; return; } } this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ if (!Files.exists(this.fs.getPath(this.releaseInHex)) || Files.exists(this.fs.getPath(this.releaseInHex, "system-modules"))) { //$NON-NLS-1$ - this.compliance = null; + this.release = null; } - if (this.compliance != null) { + if (this.release != null) { List sub = new ArrayList<>(); try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { for (final java.nio.file.Path subdir: stream) { @@ -262,6 +262,7 @@ public void cleanup() { } this.annotationZipFile = null; } + this.fs = null; } @Override @@ -269,7 +270,7 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ClasspathJrt)) return false; ClasspathJrt jar = (ClasspathJrt) o; - if (!Util.equalOrNull(this.compliance, jar.compliance)) { + if (!Util.equalOrNull(this.release, jar.release)) { return false; } if (this.accessRuleSet != jar.accessRuleSet) diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java index f524946a9e..6f1748cc5a 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java @@ -16,15 +16,18 @@ import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.env.IUpdatableModule; import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; import org.eclipse.jdt.internal.compiler.util.Util; @@ -128,15 +131,15 @@ static ClasspathLocation forLibrary(String libraryPathname, IPath annotationsPath, boolean autoModule, String compliance) { - return Util.isJrt(libraryPathname) ? - new ClasspathJrt(libraryPathname, accessRuleSet, annotationsPath, compliance) : - Util.archiveFormat(libraryPathname) == Util.JMOD_FILE ? + return Util.archiveFormat(libraryPathname) == Util.JMOD_FILE ? new ClasspathJMod(libraryPathname, lastModified, accessRuleSet, annotationsPath) : - new ClasspathJar(libraryPathname, lastModified, accessRuleSet, annotationsPath, autoModule); + (compliance == null || (CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK9) ? + new ClasspathJar(libraryPathname, lastModified, accessRuleSet, annotationsPath, autoModule) : + new ClasspathMultiReleaseJar(libraryPathname, lastModified, accessRuleSet, annotationsPath, autoModule, compliance)); } -static ClasspathJrt forJrtSystem(String jdkHome, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) { - return new ClasspathJrt(jdkHome, accessRuleSet, annotationsPath, release); +static ClasspathJrt forJrtSystem(String jrtPath, AccessRuleSet accessRuleSet, IPath annotationsPath, String release) { + return new ClasspathJrt(jrtPath, accessRuleSet, annotationsPath, release); } public static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRuleSet, IPath annotationsPath, @@ -145,8 +148,14 @@ public static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet } static ClasspathLocation forLibrary(IFile library, AccessRuleSet accessRuleSet, IPath annotationsPath, - boolean autoModule) { - return new ClasspathJar(library, accessRuleSet, annotationsPath, autoModule); + boolean autoModule, String compliance) { + return compliance == null ? new ClasspathJar(library, accessRuleSet, annotationsPath, autoModule) : + new ClasspathMultiReleaseJar(library, accessRuleSet, annotationsPath, autoModule, compliance); +} +public static ClasspathLocation forLibrary(ZipFile zipFile, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) { + return (CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK9) ? + new ClasspathJar(zipFile, accessRuleSet, externalAnnotationPath, isOnModulePath) : + new ClasspathMultiReleaseJar(zipFile, accessRuleSet, externalAnnotationPath, isOnModulePath, compliance); } public abstract IPath getProjectRelativePath(); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java new file mode 100644 index 0000000000..d5954151de --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiReleaseJar.java @@ -0,0 +1,186 @@ +package org.eclipse.jdt.internal.core.builder; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.ProviderNotFoundException; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.function.Predicate; +import java.util.zip.ZipFile; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; +import org.eclipse.jdt.internal.compiler.util.SimpleSet; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; + +public class ClasspathMultiReleaseJar extends ClasspathJar { + private java.nio.file.FileSystem fs = null; + Path releasePath = null; + + ClasspathMultiReleaseJar(IFile resource, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) { + super(resource, accessRuleSet, externalAnnotationPath, isOnModulePath); + this.compliance = compliance; + initializeVersions(); + } + + ClasspathMultiReleaseJar(String zipFilename, long lastModified, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) { + super(zipFilename, lastModified, accessRuleSet, externalAnnotationPath, isOnModulePath); + this.compliance = compliance; + initializeVersions(); + } + + public ClasspathMultiReleaseJar(ZipFile zipFile, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) { + this(zipFile.getName(), accessRuleSet, externalAnnotationPath, isOnModulePath, compliance); + this.zipFile = zipFile; + this.closeZipFileAtEnd = true; + } + + public ClasspathMultiReleaseJar(String fileName, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean isOnModulePath, String compliance) { + this(fileName, 0, accessRuleSet, externalAnnotationPath, isOnModulePath, compliance); + if (externalAnnotationPath != null) + this.externalAnnotationPath = externalAnnotationPath.toString(); + } + private void initializeVersions() { + Path filePath = Paths.get(this.zipFilename); + if (Files.exists(filePath)) { + URI uri = URI.create("jar:" + filePath.toUri()); //$NON-NLS-1$ + try { + this.fs = FileSystems.getFileSystem(uri); + if (this.fs == null) { + HashMap env = new HashMap<>(); + this.fs = FileSystems.newFileSystem(uri, env); + } + } catch (FileSystemNotFoundException | ProviderNotFoundException e) { + // move on + } catch (IOException e) { + // move on + } + if (this.fs == null) { + this.releasePath = null; + } else { + this.releasePath = this.fs.getPath("/", "META-INF", "versions", this.compliance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (!Files.exists(this.releasePath)) { + this.releasePath = null; + try { + this.fs.close(); + } catch (IOException e) { + // ignore + } + } + } + } + } + @Override + protected String readJarContent(final SimpleSet packageSet) { + String[] modInfo = new String[1]; + modInfo[0] = super.readJarContent(packageSet); + try { + if (this.releasePath != null && Files.exists(this.releasePath)) { + // go through the packages + try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { + for (final java.nio.file.Path subdir: stream) { + Files.walkFileTree(subdir, new FileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult visitFile(java.nio.file.Path file, BasicFileAttributes attrs) + throws IOException { + Path p = ClasspathMultiReleaseJar.this.releasePath.relativize(file); + addToPackageSet(packageSet, p.toString(), false); + if (modInfo[0] == null) { + if (p.getFileName().toString().equalsIgnoreCase(IModule.MODULE_INFO_CLASS)) { + modInfo[0] = ClasspathMultiReleaseJar.this.releasePath.relativize(file).toString(); + } + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(java.nio.file.Path file, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) + throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } + } + } + } catch (Exception e) { + // move on; + } + return modInfo[0]; + } + @Override + public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly, Predicate moduleNameFilter) { + if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case + if (this.releasePath != null) { + try { + Path path = this.releasePath.resolve(qualifiedPackageName).resolve(binaryFileName); + byte[] content = Files.readAllBytes(path); + IBinaryType reader = null; + if (content != null) { + reader = new ClassFileReader(content, qualifiedBinaryFileName.toCharArray()); + } + if (reader != null) { + char[] modName = this.module == null ? null : this.module.name(); + if (reader instanceof ClassFileReader) { + ClassFileReader classReader = (ClassFileReader) reader; + if (classReader.moduleName == null) + classReader.moduleName = modName; + else + modName = classReader.moduleName; + } + String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); + if (this.externalAnnotationPath != null) { + try { + if (this.annotationZipFile == null) { + this.annotationZipFile = ExternalAnnotationDecorator + .getAnnotationZipFile(this.externalAnnotationPath, null); + } + + reader = ExternalAnnotationDecorator.create(reader, this.externalAnnotationPath, + fileNameWithoutExtension, this.annotationZipFile); + } catch (IOException e) { + // don't let error on annotations fail class reading + } + if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.NOT_EEA_CONFIGURED) { + // ensure a reader that answers NO_EEA_FILE + reader = new ExternalAnnotationDecorator(reader, null); + } + } + if (this.accessRuleSet == null) + return new NameEnvironmentAnswer(reader, null, modName); + return new NameEnvironmentAnswer(reader, + this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), + modName); + } + } catch (IOException | ClassFormatException e) { + // treat as if class file is missing + } + } + return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, asBinaryOnly, moduleNameFilter); + } +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java index d0137019b3..7111f9401c 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java @@ -268,7 +268,7 @@ private void computeClasspathLocations( && JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true))) ? null : entry.getAccessRuleSet(); - bLocation = ClasspathLocation.forLibrary((IFile) resource, accessRuleSet, externalAnnotationPath, isOnModulePath); + bLocation = ClasspathLocation.forLibrary((IFile) resource, accessRuleSet, externalAnnotationPath, isOnModulePath, compliance); } else if (resource instanceof IContainer) { AccessRuleSet accessRuleSet = (JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true)) @@ -302,10 +302,14 @@ private void computeClasspathLocations( && JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true))) ? null : entry.getAccessRuleSet(); - if (JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.COMPILER_RELEASE, true))) { - compliance = null; + String release = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.COMPILER_RELEASE, true)) ? null : compliance; + ClasspathLocation bLocation = null; + String libPath = path.toOSString(); + if (Util.isJrt(libPath)) { + bLocation = ClasspathLocation.forJrtSystem(path.toOSString(), accessRuleSet, externalAnnotationPath, release); + } else { + bLocation = ClasspathLocation.forLibrary(path.toOSString(), accessRuleSet, externalAnnotationPath, isOnModulePath, compliance); } - ClasspathLocation bLocation = ClasspathLocation.forLibrary(path.toOSString(), accessRuleSet, externalAnnotationPath, isOnModulePath, compliance); bLocations.add(bLocation); if (moduleEntries != null) { Set libraryLimitModules = (limitModules == null && projectModule != null) ? ClasspathJrt.NO_LIMIT_MODULES : limitModules; diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java index ab7d9c5b08..959aa62932 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java @@ -54,7 +54,7 @@ private long previousStructuralBuildTime; private StringSet structurallyChangedTypes; public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed -public static final byte VERSION = 0x0020; +public static final byte VERSION = 0x0021; static final byte SOURCE_FOLDER = 1; static final byte BINARY_FOLDER = 2; @@ -282,13 +282,16 @@ static State read(IProject project, DataInputStream in) throws IOException { break; case EXTERNAL_JAR : String jarPath = in.readUTF(); - boolean jrt = Util.isJrt(jarPath); - newState.binaryLocations[i] = ClasspathLocation.forLibrary(jarPath, in.readLong(), - readRestriction(in), new Path(in.readUTF()), jrt ? false : in.readBoolean(), jrt ? in.readUTF() : ""); //$NON-NLS-1$ + if (Util.isJrt(jarPath)) { + newState.binaryLocations[i] = ClasspathLocation.forJrtSystem(jarPath, readRestriction(in), new Path(in.readUTF()), in.readUTF()); + } else { + newState.binaryLocations[i] = ClasspathLocation.forLibrary(jarPath, in.readLong(), + readRestriction(in), new Path(in.readUTF()), in.readBoolean(), in.readUTF()); + } break; case INTERNAL_JAR : newState.binaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())), - readRestriction(in), new Path(in.readUTF()), in.readBoolean()); + readRestriction(in), new Path(in.readUTF()), in.readBoolean(), in.readUTF()); break; } ClasspathLocation loc = newState.binaryLocations[i]; @@ -356,13 +359,16 @@ static State read(IProject project, DataInputStream in) throws IOException { break; case EXTERNAL_JAR : String jarPath = in.readUTF(); - boolean jrt = Util.isJrt(jarPath); - newState.testBinaryLocations[i] = ClasspathLocation.forLibrary(jarPath, in.readLong(), - readRestriction(in), new Path(in.readUTF()), jrt ? false : in.readBoolean(), jrt ? in.readUTF() : ""); //$NON-NLS-1$ + if (Util.isJrt(jarPath)) { + newState.testBinaryLocations[i] = ClasspathLocation.forJrtSystem(jarPath, readRestriction(in), new Path(in.readUTF()), in.readUTF()); + } else { + newState.testBinaryLocations[i] = ClasspathLocation.forLibrary(jarPath, in.readLong(), + readRestriction(in), new Path(in.readUTF()), in.readBoolean(), in.readUTF()); + } break; case INTERNAL_JAR : newState.testBinaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())), - readRestriction(in), new Path(in.readUTF()), in.readBoolean()); + readRestriction(in), new Path(in.readUTF()), in.readBoolean(), in.readUTF()); break; } } @@ -558,14 +564,15 @@ void write(DataOutputStream out) throws IOException { writeRestriction(jar.accessRuleSet, out); out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$ out.writeBoolean(jar.isOnModulePath); + out.writeUTF(jar.compliance == null ? "" : jar.compliance); //$NON-NLS-1$ + } else { ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); - out.writeLong(-1); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.compliance != null ? jrt.compliance : ""); //$NON-NLS-1$ + out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ } char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray(); writeName(patchName, out); @@ -670,14 +677,14 @@ void write(DataOutputStream out) throws IOException { writeRestriction(jar.accessRuleSet, out); out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$ out.writeBoolean(jar.isOnModulePath); + out.writeUTF(jar.compliance != null ? jar.compliance : ""); //$NON-NLS-1$ } else { ClasspathJrt jrt = (ClasspathJrt) c; out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); - out.writeLong(-1); writeRestriction(jrt.accessRuleSet, out); out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ - out.writeUTF(jrt.compliance != null ? jrt.compliance : ""); //$NON-NLS-1$ + out.writeUTF(jrt.release != null ? jrt.release : ""); //$NON-NLS-1$ } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java index 46f5035e8b..d5e26b9bda 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java @@ -64,21 +64,24 @@ public class BinaryTypeFactory { * a location on the filesystem. */ private static BinaryTypeDescriptor createDescriptor(PackageFragment pkg, ClassFile classFile) { - String name = classFile.getName(); PackageFragmentRoot root = (PackageFragmentRoot) pkg.getParent(); IPath location = JavaIndex.getLocationForElement(root); if (location == null) { return null; } - name = root.getClassFilePath(Util.concatWith(pkg.names, name, '/')); String entryName = Util.concatWith(pkg.names, classFile.getElementName(), '/'); + String name = Util.concatWith(pkg.names, classFile.getName(), '/'); + String overridePath = root.getClassFilePath(entryName); + if (overridePath != entryName) { + entryName = overridePath; + name = ((JarPackageFragmentRoot) root).versionPath + name; + } char[] fieldDescriptor = CharArrayUtils.concat(new char[] { 'L' }, name.toCharArray(), new char[] { ';' }); IPath workspacePath = root.getPath(); String indexPath; if (root instanceof JarPackageFragmentRoot) { - entryName = ((JarPackageFragmentRoot) root).getClassFilePath(entryName); // The old version returned this, but it doesn't conform to the spec on IBinaryType.getFileName(): indexPath = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName; // Version that conforms to the JavaDoc spec on IBinaryType.getFileName() -- note that this breaks diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java index 480bb6e640..dd2bd66985 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java @@ -46,7 +46,6 @@ import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot; import org.eclipse.jdt.internal.core.NameLookup; import org.eclipse.jdt.internal.core.PackageFragmentRoot; -import org.eclipse.jdt.internal.core.builder.ClasspathJar; import org.eclipse.jdt.internal.core.builder.ClasspathJrt; import org.eclipse.jdt.internal.core.builder.ClasspathLocation; import org.eclipse.jdt.internal.core.util.Util; @@ -162,10 +161,10 @@ private ClasspathLocation mapToClassPathLocation(JavaModelManager manager, Packa cp = (root instanceof JrtPackageFragmentRoot) ? new ClasspathJrt(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, project.getProject(), true), compliance) : - new ClasspathJar(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), - ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, - ((IJavaProject) root.getParent()).getProject(), true), - rawClasspathEntry.isModular()); + ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(), + ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, + ((IJavaProject) root.getParent()).getProject(), true), + rawClasspathEntry.isModular(), compliance) ; } else { Object target = JavaModel.getTarget(path, true); if (target != null) { -- cgit v1.2.3