Bug 490103 - [1.9] JREContainer should work without any physical
libraries

Change-Id: I985a734512187ef4b39c9a2ebe1fa03506065b28
Signed-off-by: Jay Arthanareeswaran <jarthana@in.ibm.com>

diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java
index 86a3ee2..5df235e 100644
--- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -20,6 +20,7 @@
 
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.core.ClasspathEntry;
+import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.JavaProject;
 import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
 
@@ -296,7 +297,11 @@
 	public void addExternalJars(IPath projectPath, String[] jars, boolean isExported) throws JavaModelException {
 		for (int i = 0, max = jars.length; i < max; i++) {
 			String jar = jars[i];
-			addEntry(projectPath, JavaCore.newLibraryEntry(new Path(jar), null, null, isExported));
+			if (JavaModelManager.isJrtInstallation(jar) || jar.endsWith("jrt-fs.jar")) {
+				addEntry(projectPath, JavaCore.newJrtEntry(new Path(jar), null, null, null, null, isExported));
+			} else {
+				addEntry(projectPath, JavaCore.newLibraryEntry(new Path(jar), null, null, isExported));
+			}
 		}
 	}
 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java
index cc37982..8a39b6c 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter9Test.java
@@ -281,7 +281,7 @@
 			element = element.getParent();
 			assertNotNull(element);
 			assertEquals("Incorrect element type", IJavaElement.PACKAGE_FRAGMENT_ROOT, element.getElementType());
-			assertTrue("incorrect root type", (element instanceof JrtPackageFragmentRoot));
+			assertEquals("incorrect root type", element.getClass().toString(), JrtPackageFragmentRoot.class.toString());
 			JrtPackageFragmentRoot root = (JrtPackageFragmentRoot) element;
 			assertEquals("incorrect module name", "java.base", root.getElementName());
 		} finally {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
index fc1801e..9af91da 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
@@ -1328,15 +1328,22 @@
 		return createJava9ProjectWithJREAttributes(name, srcFolders, null);
 	}
 	protected IJavaProject createJava9ProjectWithJREAttributes(String name, String[] srcFolders, IClasspathAttribute[] attributes) throws CoreException {
-		String javaHome = System.getProperty("java.home") + File.separator;
-		Path bootModPath = new Path(javaHome +"/lib/jrt-fs.jar");
-		Path sourceAttachment = new Path(javaHome +"/lib/src.zip");
-		IClasspathEntry jrtEntry = JavaCore.newLibraryEntry(bootModPath, sourceAttachment, null, null, attributes, false);
+		String javaHome = System.getProperty("java.home");
+		Path bootModPath = new Path(javaHome);
+		Path sourceAttachment = new Path(javaHome + File.separator + "lib" + File.separator + "src.zip");
+		IClasspathEntry jrtEntry = JavaCore.newJrtEntry(bootModPath, sourceAttachment, null, null, attributes, false);
 		IJavaProject project = this.createJavaProject(name, srcFolders, new String[0],
 				new String[0], "bin", "9");
 		IClasspathEntry[] old = project.getRawClasspath();
-		IClasspathEntry[] newPath = new IClasspathEntry[old.length +1];
-		System.arraycopy(old, 0, newPath, 0, old.length);
+		List<IClasspathEntry> list = new ArrayList<>();
+		for (IClasspathEntry iClasspathEntry : old) {
+			if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE
+					|| iClasspathEntry.getContentKind() == ClasspathEntry.K_OUTPUT) {
+				list.add(iClasspathEntry);
+			}
+		}
+		list.add(jrtEntry);
+		IClasspathEntry[] newPath = list.toArray(new IClasspathEntry[list.size()]);
 		newPath[old.length] = jrtEntry;
 		project.setRawClasspath(newPath, null);
 		return project;
@@ -1764,6 +1771,14 @@
 								ClasspathEntry.getAccessRules(accessibleFiles, nonAccessibleFiles),
 								new IClasspathAttribute[0],
 								false);
+					} else if (JavaModelManager.isJrtInstallation((new Path(lib)).toString()) || lib.endsWith("jrt-fs.jar")) {
+						entries[sourceLength+i] = JavaCore.newJrtEntry(
+								new Path(lib),
+								null,
+								null,
+								ClasspathEntry.getAccessRules(accessibleFiles, nonAccessibleFiles),
+								new IClasspathAttribute[0],
+								false);
 					} else {
 						IPath libPath = new Path(lib);
 						if (!libPath.isAbsolute() && libPath.segmentCount() > 0 && libPath.getFileExtension() == null) {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
index f85115a..7c750e2 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
@@ -61,6 +61,7 @@
 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
 import org.eclipse.jdt.internal.core.ClasspathAttribute;
 import org.eclipse.jdt.internal.core.ClasspathEntry;
+import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.osgi.framework.Bundle;
 
 @SuppressWarnings({"rawtypes", "unchecked"})
@@ -83,7 +84,7 @@
 				this.entries = entries;
 			}
 			public IPath getPath() { return this.path; }
-			public IClasspathEntry[] getClasspathEntries() { return this.entries;	}
+			public IClasspathEntry[] getClasspathEntries() { return this.entries; }
 			public String getDescription() { return this.path.toString(); 	}
 			public int getKind() { return 0; }
 		}
@@ -91,15 +92,29 @@
 		public void initialize(IPath containerPath, IJavaProject project) throws CoreException {
 			String[] jars = Util.getJavaClassLibs();
 			IClasspathEntry[] entries = new IClasspathEntry[jars.length];
-			for (int i = 0; i < jars.length; i++) {
-				IClasspathAttribute[] extraAttributes;
-				if (RT_JAR_ANNOTATION_PATH != null && jars[i].endsWith("rt.jar"))
+			IClasspathAttribute[] extraAttributes;
+			if (jars.length == 1 && 
+					(jars[0].endsWith("jrt-fs.jar") || JavaModelManager.isJrtInstallation(jars[0]))) {
+				if (RT_JAR_ANNOTATION_PATH != null) {
 					extraAttributes = externalAnnotationExtraAttributes(RT_JAR_ANNOTATION_PATH);
-				else
+				} else {
 					extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
-				entries[i] = JavaCore.newLibraryEntry(new Path(jars[i]), null, null,
+				}
+				extraAttributes = externalAnnotationExtraAttributes(RT_JAR_ANNOTATION_PATH);
+				entries[0] = JavaCore.newJrtEntry((new Path(jars[0])).removeLastSegments(2), null, null,
 						ClasspathEntry.NO_ACCESS_RULES, extraAttributes, false/*not exported*/);
+			} else {
+				for (int i = 0; i < jars.length; i++) {
+					if (RT_JAR_ANNOTATION_PATH != null && jars[i].endsWith("rt.jar")) {
+						extraAttributes = externalAnnotationExtraAttributes(RT_JAR_ANNOTATION_PATH);
+					} else {
+						extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
+					}
+					entries[i] = JavaCore.newLibraryEntry(new Path(jars[i]), null, null,
+							ClasspathEntry.NO_ACCESS_RULES, extraAttributes, false/*not exported*/);
+				}
 			}
+			
 			JavaCore.setClasspathContainer(
 					new Path(TEST_CONTAINER_NAME),
 					new IJavaProject[]{ project },
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java
index bbe21fb..d4f9ce2 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java
@@ -789,9 +789,8 @@
 			project1.open(null);
 			IClasspathEntry[] rawClasspath = project1.getRawClasspath();
 			for (int i = 0; i < rawClasspath.length; i++) {
-				IPath path = rawClasspath[i].getPath();
-				if (path.lastSegment().equals("jrt-fs.jar")) {
-					path = path.removeLastSegments(2).append("jmods").append("java.base.jmod");
+				if (rawClasspath[i].getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
+					IPath path = rawClasspath[i].getPath().append("jmods").append("java.base.jmod");
 					IClasspathEntry newEntry = JavaCore.newLibraryEntry(path, rawClasspath[i].getSourceAttachmentPath(), new Path("java.base"));
 					rawClasspath[i] = newEntry;
 				}
@@ -845,8 +844,8 @@
 			IClasspathEntry[] rawClasspath = project1.getRawClasspath();
 			for (int i = 0; i < rawClasspath.length; i++) {
 				IPath path = rawClasspath[i].getPath();
-				if (path.lastSegment().equals("jrt-fs.jar")) {
-					path = path.removeLastSegments(2).append("jmods").append("java.base.jmod");
+				if (rawClasspath[i].getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
+					path = path.append("jmods").append("java.base.jmod");
 					IClasspathEntry newEntry = JavaCore.newLibraryEntry(path, rawClasspath[i].getSourceAttachmentPath(), new Path("java.base"));
 					rawClasspath[i] = newEntry;
 				}
@@ -1410,11 +1409,11 @@
 		IClasspathEntry[] newClasspath = new IClasspathEntry[rawClasspath.length + 1];
 		for (int i = 0; i < rawClasspath.length; i++) {
 			IPath path = rawClasspath[i].getPath();
-			if (path.lastSegment().equals("jrt-fs.jar")) {
-				path = path.removeLastSegments(2).append("jmods").append("java.base.jmod");
+			if (rawClasspath[i].getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
+				path = path.append("jmods").append("java.base.jmod");
 				IClasspathEntry newEntry = JavaCore.newLibraryEntry(path, rawClasspath[i].getSourceAttachmentPath(), new Path("java.base"));
 				newClasspath[i] = newEntry;
-				path = path.removeLastSegments(2).append("jmods").append("java.sql.jmod");
+				path = path.append("jmods").append("java.sql.jmod");
 				newEntry = JavaCore.newLibraryEntry(path, rawClasspath[i].getSourceAttachmentPath(), new Path("java.sql"));
 				newClasspath[rawClasspath.length] = newEntry;
 			} else {
@@ -1612,6 +1611,37 @@
 			deleteProject("Java9Elements");
 		}
 	}
+	/*
+	 * Tests that a binary type from JRT system is found on the project's classpath
+	 * For now, disabled since it kicks off indexing eventually timing out.
+	 */
+	public void testIsOnClasspath1() throws CoreException {
+		try {
+			IJavaProject project1 = createJava9Project("Java9Elements", new String[] {"src"});
+			project1.open(null);
+			String fileContent =
+					"module first {\n" +
+							"    requires second;\n" +
+							"    uses pack11.X11;\n" +
+							"}\n";
+			createFile("/Java9Elements/src/module-info.java", fileContent);
+			createFolder("/Java9Elements/src/pack11");
+			createFile("/Java9Elements/src/pack11/X11.java",
+					"package pack11;\n" +
+					"public interface X11 extends Serializable {}\n");
+
+			project1.close(); // sync
+			project1.open(null);
+			waitUntilIndexesReady();
+			IType type = project1.findType("java.io.Serializable");
+			assertNotNull("type not found", type);
+			assertTrue("should be a binary type", type.isBinary());
+			assertTrue("Not found in the classpath", project1.isOnClasspath(type));
+		}
+		finally {
+			deleteProject("Java9Elements");
+		}
+	}
 	public void testBug530402() throws CoreException {
 		try {
 			IJavaProject project = createJavaProject("Java9Elements", new String[] {"src"}, new String[] {"JCL19_LIB"}, "bin", "9");
@@ -1665,6 +1695,31 @@
 		finally {
 			deleteProject("Java9Elements");
 		}
+		}
+	public void testIsOnClasspath2() throws CoreException {
+		try {
+			IJavaProject project1 = createJavaProject("Java9Elements", new String[] {"src"}, new String[] {"JCL19_LIB"}, "bin", "9");
+			project1.open(null);
+			String fileContent =
+					"module first {\n" +
+							"    requires second;\n" +
+							"    uses pack11.X11;\n" +
+							"}\n";
+			createFile("/Java9Elements/src/module-info.java", fileContent);
+			createFolder("/Java9Elements/src/pack11");
+			createFile("/Java9Elements/src/pack11/X11.java",
+					"package pack11;\n" +
+					"public interface X11 extends Serializable {}\n");
+
+			project1.close(); // sync
+			project1.open(null);
+
+			ICompilationUnit unit = getCompilationUnit("/Java9Elements/src/module-info.java");
+			assertTrue("Not found in the classpath", project1.isOnClasspath(unit));
+		}
+		finally {
+			deleteProject("Java9Elements");
+		}
 	}
 	public void test530653() throws CoreException, IOException {
 		try {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
index c3c7911..1fa7b72 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
@@ -3040,4 +3040,80 @@
 			deleteProject(prj);
 	}
 }
+// module patching
+public void testBug522554_4() throws CoreException {
+	if (!isJRE9) return;
+	IJavaProject prj = null;
+	try {
+		IClasspathAttribute[] jreAttributes = {
+			JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "java.activation"),
+			JavaCore.newClasspathAttribute(IClasspathAttribute.LIMIT_MODULES, "java.se,jdk.security.auth,jdk.security.jgss,jdk.net,java.activation")
+		};
+		prj = createJava9ProjectWithJREAttributes("mod1", new String[] {"src" }, jreAttributes);
+		createFolder("/mod1/src/modify");
+		createFile("/mod1/src/modify/Test.java",
+				"package modify;\n" + 
+				"\n" + 
+				"import com.sun.activation.registries.*; \n" + 
+				"\n" + 
+				"public class Test {\n" + 
+				"	LogSupport logger;\n" + 
+				"}\n");
+		prj.getProject().getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+		IMarker[] markers = prj.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+		assertMarkers("Unexpected markers", "",  markers);
+
+		IClasspathEntry systemLibrary = prj.getRawClasspath()[1];
+		assertEquals("Should be system library", getJRE9Path(), systemLibrary.getPath());
+		String argLine = JavaModelAccess.getModuleCLIOptions(prj, systemLibrary);
+		String projectLoc = prj.getProject().getLocation().toOSString();
+		assertEquals("Unexpected CLI options",
+				"--patch-module java.activation="+projectLoc+File.separator+"bin " +
+				"--limit-modules java.activation,java.se,jdk.net,jdk.security.auth,jdk.security.jgss",
+				argLine);
+	} finally {
+		if (prj != null)
+			deleteProject(prj);
+	}
+}
+// module patching - multiple output locations
+public void testBug522554_5() throws CoreException {
+	if (!isJRE9) return;
+	IJavaProject prj = null;
+	try {
+		IClasspathAttribute[] jreAttributes = {
+			JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "java.activation"),
+		};
+		prj = createJava9ProjectWithJREAttributes("mod1", new String[] {"src" }, jreAttributes);
+		createFolder("/mod1/src2");
+		createFolder("/mod1/bin2");
+		addClasspathEntry(prj, JavaCore.newSourceEntry(new Path("/mod1/src2"), null, new Path("/mod1/bin2")));
+		createFolder("/mod1/src/modify");
+		createFile("/mod1/src/modify/Test.java",
+				"package modify;\n" + 
+				"\n" + 
+				"import com.sun.activation.registries.*; \n" + 
+				"\n" + 
+				"public class Test {\n" + 
+				"	LogSupport logger;\n" + 
+				"}\n");
+		prj.getProject().getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+		IMarker[] markers = prj.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+		assertMarkers("Unexpected markers", "",  markers);
+
+		IClasspathEntry systemLibrary = prj.getRawClasspath()[1];
+		assertEquals("Should be system library", getJRE9Path(), systemLibrary.getPath());
+		String argLine = JavaModelAccess.getModuleCLIOptions(prj, systemLibrary);
+		String projectLoc = prj.getProject().getLocation().toOSString();
+		assertEquals("Unexpected CLI options",
+				"--patch-module java.activation="+projectLoc+File.separator+"bin"+File.pathSeparator+projectLoc+File.separator+"bin2",
+				argLine);
+	} finally {
+		if (prj != null)
+			deleteProject(prj);
+	}
+}
+protected IPath getJRE9Path() {
+	return new Path(System.getProperty("java.home"));
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
index 7b63883..e9d814e 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
@@ -57,7 +57,7 @@
 	}
 
 	static {
-		// TESTS_NAMES = new String[] { "testBug528467" };
+//		 TESTS_NAMES = new String[] { "testPatch2" };
 	}
 	private String sourceWorkspacePath = null;
 	protected ProblemRequestor problemRequestor;
@@ -2636,9 +2636,8 @@
 			IJavaProject project = createJava9Project("Test01", new String[]{"src"});
 			IClasspathEntry[] rawClasspath = project.getRawClasspath();
 			for (int i = 0; i < rawClasspath.length; i++) {
-				IPath path = rawClasspath[i].getPath();
-				if (path.lastSegment().equals("jrt-fs.jar")) {
-					path = path.removeLastSegments(2).append("jmods").append("java.base.jmod");
+				if (rawClasspath[i].getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
+					IPath path = rawClasspath[i].getPath().append("jmods").append("java.base.jmod");
 					IClasspathEntry newEntry = JavaCore.newLibraryEntry(path, rawClasspath[i].getSourceAttachmentPath(), new Path("java.base"));
 					rawClasspath[i] = newEntry;
 				}
@@ -6429,12 +6428,11 @@
 			String jrtPath = null;
 			for (int i = 0; i < rawClasspath.length; i++) {
 				IClasspathEntry iClasspathEntry = rawClasspath[i];
-				if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY &&
-						iClasspathEntry.getPath().toString().endsWith("jrt-fs.jar")) {
+				if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
 					jrtPath = iClasspathEntry.getPath().toOSString();
 					IAccessRule[] pathRules = new IAccessRule[1];
 					pathRules[0] = JavaCore.newAccessRule(new Path("java/awt/**"), IAccessRule.K_NON_ACCESSIBLE);
-					IClasspathEntry newEntry = JavaCore.newLibraryEntry(iClasspathEntry.getPath(), 
+					IClasspathEntry newEntry = JavaCore.newJrtEntry(iClasspathEntry.getPath(), 
 							iClasspathEntry.getSourceAttachmentPath(), 
 							iClasspathEntry.getSourceAttachmentRootPath(), 
 								pathRules, 
@@ -6476,12 +6474,11 @@
 			String jrtPath = null;
 			for (int i = 0; i < rawClasspath.length; i++) {
 				IClasspathEntry iClasspathEntry = rawClasspath[i];
-				if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY &&
-						iClasspathEntry.getPath().toString().endsWith("jrt-fs.jar")) {
+				if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
 					jrtPath = iClasspathEntry.getPath().toOSString();
 					IAccessRule[] pathRules = new IAccessRule[1];
 					pathRules[0] = JavaCore.newAccessRule(new Path("java/awt/Image"), IAccessRule.K_NON_ACCESSIBLE);
-					IClasspathEntry newEntry = JavaCore.newLibraryEntry(iClasspathEntry.getPath(), 
+					IClasspathEntry newEntry = JavaCore.newJrtEntry(iClasspathEntry.getPath(), 
 							iClasspathEntry.getSourceAttachmentPath(), 
 							iClasspathEntry.getSourceAttachmentRootPath(), 
 								pathRules, 
@@ -6529,12 +6526,11 @@
 			String jrtPath = null;
 			for (int i = 0; i < rawClasspath.length; i++) {
 				IClasspathEntry iClasspathEntry = rawClasspath[i];
-				if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY &&
-						iClasspathEntry.getPath().toString().endsWith("jrt-fs.jar")) {
+				if (iClasspathEntry.getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
 					jrtPath = iClasspathEntry.getPath().toOSString();
 					IAccessRule[] pathRules = new IAccessRule[1];
 					pathRules[0] = JavaCore.newAccessRule(new Path("java/awt/**"), IAccessRule.K_NON_ACCESSIBLE);
-					IClasspathEntry newEntry = JavaCore.newLibraryEntry(iClasspathEntry.getPath(), 
+					IClasspathEntry newEntry = JavaCore.newJrtEntry(iClasspathEntry.getPath(), 
 							iClasspathEntry.getSourceAttachmentPath(), 
 							iClasspathEntry.getSourceAttachmentRootPath(), 
 								pathRules, 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java
index 573dae8..4ba351a 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -158,7 +158,7 @@
 //	JavaModelManager.VERBOSE = true;
 //	org.eclipse.jdt.internal.core.search.BasicSearchEngine.VERBOSE = true;
 //	TESTS_PREFIX = "testIgnoreIfBetterNonAccessibleRule";
-//	TESTS_NAMES = new String[] { "testBug374176" };
+//	TESTS_NAMES = new String[] { "testConvertPrimitiveTypeArrayTypeArgument" };
 //	TESTS_NUMBERS = new int[] { 118823 };
 //	TESTS_RANGE = new int[] { 16, -1 };
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java
index d779122..dba5861 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2017 IBM Corporation and others.
+ * Copyright (c) 2016, 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
@@ -11,7 +11,6 @@
 
 package org.eclipse.jdt.core.tests.model;
 
-import java.io.File;
 import java.io.IOException;
 
 import org.eclipse.core.resources.IFile;
@@ -59,7 +58,7 @@
 	
 		IJavaProject project = setUpJavaProject("Resolve", "9", true);
 	
-		String bootModPath = System.getProperty("java.home") + File.separator +"jrt-fs.jar";
+		String bootModPath = System.getProperty("java.home");
 		IClasspathEntry jrtEntry = JavaCore.newLibraryEntry(new Path(bootModPath), null, null, null, null, false);
 		IClasspathEntry[] old = project.getRawClasspath();
 		IClasspathEntry[] newPath = new IClasspathEntry[old.length +1];
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 b7683aa..93c1a7b 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
@@ -902,14 +902,6 @@
 		return true;
 	}
 
-	/**
-	 * Returns true iff str.toLowerCase().endsWith("jrt-fs.jar")
-	 * implementation is not creating extra strings.
-	 */
-	public final static boolean isJrt(String name) {
-		return name.endsWith(JRTUtil.JRT_FS_JAR);
-	}
-
 	public static void reverseQuickSort(char[][] list, int left, int right) {
 		int original_left= left;
 		int original_right= right;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
index 5b862f6..1ff8d89 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 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
@@ -25,8 +25,12 @@
  * <ul>
  * <li> library entries (<code>CPE_LIBRARY</code>) </li>
  * <li> project entries (<code>CPE_PROJECT</code>) </li>
+ * <li> Module based Java Runtime entries (<code>CPE_JRT_SYSTEM</code>) </li>
  * </ul>
  * In particular, a classpath container can neither reference further classpath containers or classpath variables.
+ * <p>
+ * Note: Even though it is allowed for containers to have multiple entries of kind <code>CPE_JRT_SYSTEM</code>
+ * typically, there will be only one such entry.
  * <p> 
  * A library entry can reference other libraries through the Class-Path section of the JAR's MANIFEST.MF file. If the
  * container wants such referenced entries to be part of the classpath, the container must explicitly add them to the
@@ -64,6 +68,7 @@
 	 * <ul>
 	 * <li> library entries (<code>CPE_LIBRARY</code>) </li>
 	 * <li> project entries (<code>CPE_PROJECT</code>) </li>
+	 * <li> Module based Java Runtime entries (<code>CPE_JRT_SYSTEM</code>) </li>
 	 * </ul>
 	 * A classpath container can neither reference further classpath containers
 	 * or classpath variables.
@@ -84,6 +89,7 @@
 	 * only the following Java model APIs:
 	 * <ul>
 	 * <li>{@link JavaCore#newLibraryEntry(IPath, IPath, IPath, boolean)} and variants</li>
+	 * <li>{@link JavaCore#newJrtEntry(IPath, IPath, IPath, IAccessRule[], IClasspathAttribute[], boolean)}</li>
 	 * <li>{@link JavaCore#newProjectEntry(IPath, boolean)} and variants</li>
 	 * <li>{@link JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot)}</li>
 	 * <li>{@link JavaCore#create(org.eclipse.core.resources.IProject)}</li>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
index d4e4d46..199fbd2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -148,6 +148,13 @@
 	 * @since 2.0
 	 */
 	int CPE_CONTAINER = 5;
+	/**
+	 * Entry kind constant describing a classpath entry representing
+	 * a modularized Java run time system.
+	 * 
+	 * @since 3.14
+	 */
+	int CPE_JRT_SYSTEM = 6;
 
 	/**
 	 * Returns whether the access rules of the project's exported entries should be combined with this entry's access rules.
@@ -181,7 +188,7 @@
 	/**
 	 * Returns the kind of this classpath entry.
 	 *
-	 * @return one of:
+	 * @return one of but not limited to:
 	 * <ul>
 	 * <li>{@link #CPE_SOURCE} - this entry describes a source root in
 	 		its project
@@ -191,9 +198,12 @@
 	 *
 	 * <li>{@link #CPE_VARIABLE} - this entry describes a project or library
 	 *  	indirectly via a classpath variable in the first segment of the path
-	 * *
+	 *
 	 * <li>{@link #CPE_CONTAINER} - this entry describes set of entries
 	 *  	referenced indirectly via a classpath container
+	 *
+	 * <li>{@link #CPE_JRT_SYSTEM} - this entry describes an installation of module based 
+	 * Java Runtime system.
 	 * </ul>
 	 */
 	int getEntryKind();
@@ -383,6 +393,9 @@
 	 *     extra segments that can be used as additional hints for resolving this container
 	 * 	reference (also see {@link IClasspathContainer}).
 	 * </li>
+	 *  <li> A module based Java Runtime (JRT) ({@link #CPE_JRT_SYSTEM}) - the path is the absolute
+	 *  path to the Java Runtime installation.
+	 * </li>
 	 * </ul>
 	 *
 	 * @return the path of this classpath entry
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index 6c8bf76..5c5f5b0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.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
@@ -4627,6 +4627,41 @@
 	}
 
 	/**
+	 * Creates and returns a new classpath entry representing a modularized Java runtime system.
+	 * The entry is of kind <code>CPE_JRT_SYSTEM</code> and the given path points to the 
+	 * Java run time installation.
+	 *
+	 * @param javaHome the path where the Java Runtime is located
+	 * @return a new JRT classpath entry
+	 * @since 3.14
+	 */
+	public static IClasspathEntry newJrtEntry(IPath javaHome, 
+			IPath sourceAttachmentPath,
+			IPath sourceAttachmentRootPath,
+			IAccessRule[] accessRules,
+			IClasspathAttribute[] extraAttributes,
+			boolean isExported) {
+		if (accessRules == null || accessRules.length==0) {
+			accessRules = ClasspathEntry.NO_ACCESS_RULES;
+		}
+		if (extraAttributes == null || extraAttributes.length==0) {
+			extraAttributes = ClasspathEntry.NO_EXTRA_ATTRIBUTES;
+		}
+		return new ClasspathEntry(
+				IPackageFragmentRoot.K_BINARY,
+				IClasspathEntry.CPE_JRT_SYSTEM,
+				javaHome,
+				ClasspathEntry.INCLUDE_ALL, // inclusion patterns
+				ClasspathEntry.EXCLUDE_NONE, // exclusion patterns
+				sourceAttachmentPath, // source attachment
+				sourceAttachmentRootPath, // source attachment root
+				null, // specific output folder
+				isExported,
+				accessRules,
+				true, // combine access rules
+				extraAttributes);
+	}
+	/**
 	 * Creates and returns a new classpath entry of kind <code>CPE_CONTAINER</code>
 	 * for the given path. This method is fully equivalent to calling
 	 * {@link #newContainerEntry(IPath, IAccessRule[], IClasspathAttribute[], boolean)
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java
index 8a34601..4923abd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java
@@ -185,7 +185,7 @@
 	protected byte[] getClassFileContent(JarPackageFragmentRoot root, String className) throws CoreException, IOException {
 		byte[] contents = null;
 		String rootPath = root.getPath().toOSString();
-		if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(rootPath)) {
+		if (root instanceof JrtPackageFragmentRoot) {
 				try {
 					contents = org.eclipse.jdt.internal.compiler.util.JRTUtil.getClassfileContent(
 							new File(rootPath),
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 4227b67..93c925c 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
@@ -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
@@ -219,17 +219,17 @@
 	}
 	IBinaryType result = null;
 	IPackageFragmentRoot root = getPackageFragmentRoot();
-	if (getPackageFragmentRoot() instanceof JarPackageFragmentRoot) {
+	if (root instanceof JarPackageFragmentRoot) {
 		if (root instanceof JrtPackageFragmentRoot || this.name.equals(IModule.MODULE_INFO)) {
 			PackageFragment pkg = (PackageFragment) getParent();
-			JarPackageFragmentRoot jarRoot = (JarPackageFragmentRoot) getPackageFragmentRoot();
+			JarPackageFragmentRoot jarRoot = (JarPackageFragmentRoot) root;
 			String entryName = jarRoot.getClassFilePath(Util.concatWith(pkg.names, getElementName(), '/'));
 			byte[] contents = getClassFileContent(jarRoot, entryName);
 			if (contents != null) {
 				String fileName;
-				String rootPath = root.getPath().toOSString();
+				char[] mod = null;
 				String rootIdentifier = root.getHandleIdentifier();
-				if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(rootPath)) {
+				if (root instanceof JrtPackageFragmentRoot) {
 					int slash = rootIdentifier.lastIndexOf('/');
 					if (slash != -1) {
 						StringBuilder extract = new StringBuilder();
@@ -241,7 +241,9 @@
 					}
 				}
 				fileName = rootIdentifier + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName;
-				result = new ClassFileReader(contents, fileName.toCharArray(), false);
+				ClassFileReader reader = new ClassFileReader(contents, fileName.toCharArray(), false);
+				reader.moduleName = mod;
+				result = reader;
 			}
 		} else {
 			result = BinaryTypeFactory.readType(descriptor, null);
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 f47326f..b9ef295 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
@@ -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
@@ -119,7 +119,7 @@
 
 	/**
 	 * Describes the kind of classpath entry - one of
-	 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
+	 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE, CPE_CONTAINER or CPE_JRT_SYSTEM
 	 */
 	public int entryKind;
 
@@ -131,27 +131,12 @@
 	public int contentKind;
 
 	/**
-	 * The meaning of the path of a classpath entry depends on its entry kind:<ul>
-	 *	<li>Source code in the current project (<code>CPE_SOURCE</code>) -
-	 *      The path associated with this entry is the absolute path to the root folder. </li>
-	 *	<li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
-	 *		associated with this entry is the absolute path to the JAR (or root folder), and
-	 *		in case it refers to an external JAR, then there is no associated resource in
-	 *		the workbench.
-	 *	<li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
-	 *		path to the corresponding project resource.</li>
-	 *  <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
-	 *      is the name of a classpath variable. If this classpath variable
-	 *		is bound to the path <it>P</it>, the path of the corresponding classpath entry
-	 *		is computed by appending to <it>P</it> the segments of the returned
-	 *		path without the variable.</li>
-	 *  <li> A container entry (<code>CPE_CONTAINER</code>) - the first segment of the path is denoting
-	 *     the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
-	 * 	registered), and the remaining segments are used as additional hints for resolving the container entry to
-	 * 	an actual <code>IClasspathContainer</code>.</li>
+	 * The meaning of the path of a classpath entry depends on its entry kind. For
+	 * more details, see {@link IClasspathEntry#getPath()}.
 	 */
 	public IPath path;
 
+	
 	/**
 	 * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
 	 */
@@ -817,6 +802,18 @@
 												extraAttributes,
 												isExported);
 				break;
+			case IClasspathEntry.CPE_JRT_SYSTEM :
+				// Caveat: This is meant to be a resolved classpath entry.
+				// Only required for tests that will put a CPE_JRT_SYSTEM in the raw classpath.
+				// But this also allows anyone to use this in the .classpath directly instead of JRE_CONTAINER
+				entry = JavaCore.newJrtEntry(
+											path,
+											sourceAttachmentPath,
+											sourceAttachmentRootPath,
+											accessRules,
+											extraAttributes,
+											isExported);
+				break;
 			case IClasspathEntry.CPE_SOURCE :
 				// must be an entry in this project or specify another project
 				String projSegment = path.segment(0);
@@ -1489,6 +1486,8 @@
 			return IClasspathEntry.CPE_LIBRARY;
 		if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
 			return ClasspathEntry.K_OUTPUT;
+		if (kindStr.equalsIgnoreCase("jrt")) //$NON-NLS-1$
+			return IClasspathEntry.CPE_JRT_SYSTEM;
 		return -1;
 	}
 
@@ -1508,6 +1507,8 @@
 				return "var"; //$NON-NLS-1$
 			case IClasspathEntry.CPE_CONTAINER :
 				return "con"; //$NON-NLS-1$
+			case IClasspathEntry.CPE_JRT_SYSTEM :
+				return "jrt"; //$NON-NLS-1$
 			case ClasspathEntry.K_OUTPUT :
 				return "output"; //$NON-NLS-1$
 			default :
@@ -1561,6 +1562,8 @@
 			case IClasspathEntry.CPE_CONTAINER :
 				buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
 				break;
+			case IClasspathEntry.CPE_JRT_SYSTEM :
+				buffer.append("CPE_JRT_SYSTEM"); //$NON-NLS-1$
 		}
 		buffer.append("]["); //$NON-NLS-1$
 		switch (getContentKind()) {
@@ -1712,6 +1715,9 @@
 				case IClasspathEntry.CPE_CONTAINER :
 					this.rootID = "[CON]"+this.path;  //$NON-NLS-1$
 					break;
+				case IClasspathEntry.CPE_JRT_SYSTEM :
+					this.rootID = "[JRT]"+this.path; //$NON-NLS-1$
+					break;
 				default :
 					this.rootID = "";  //$NON-NLS-1$
 					break;
@@ -1738,6 +1744,7 @@
 		switch(getEntryKind()) {
 			case IClasspathEntry.CPE_LIBRARY :
 			case IClasspathEntry.CPE_VARIABLE :
+			case IClasspathEntry.CPE_JRT_SYSTEM :
 				break;
 			default :
 				return null;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
index 57130cf..4ff2194 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarEntryFile.java
@@ -48,7 +48,7 @@
 	@Override
 	public InputStream getContents() throws CoreException {
 		IPackageFragmentRoot root = getPackageFragmentRoot();
-		if (Util.isJrt(root.getPath().toOSString())) {
+		if (root instanceof JrtPackageFragmentRoot) {
 			try {
 				IPath rootPath = root.getPath();
 				Object target = JavaModel.getTarget(rootPath, false);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
index f31982a..c5e7785 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
@@ -742,6 +742,7 @@
 			
 			entry= root.getRawClasspathEntry();
 			switch (entry.getEntryKind()) {
+				case IClasspathEntry.CPE_JRT_SYSTEM:
 				case IClasspathEntry.CPE_LIBRARY:
 				case IClasspathEntry.CPE_VARIABLE:
 					return getLibraryJavadocLocation(entry);
@@ -754,6 +755,7 @@
 
 	protected static URL getLibraryJavadocLocation(IClasspathEntry entry) throws JavaModelException {
 		switch(entry.getEntryKind()) {
+			case IClasspathEntry.CPE_JRT_SYSTEM :
 			case IClasspathEntry.CPE_LIBRARY :
 			case IClasspathEntry.CPE_VARIABLE :
 				break;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
index 1222069..b82ef1b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModel.java
@@ -383,9 +383,6 @@
 	return false;
 }
 
-public static boolean isJimage(File file) {
-	return JavaModelManager.isJrt(file.getPath());
-}
 public static boolean isJmod(File file) {
 	IPath path = Path.fromOSString(file.getPath());
 	if (path.getFileExtension().equalsIgnoreCase(SuffixConstants.EXTENSION_jmod)) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index 74cbf5c..b5c04af 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -32,6 +32,8 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -42,7 +44,9 @@
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Map.Entry;
+import java.util.stream.Stream;
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.util.zip.ZipException;
@@ -127,7 +131,6 @@
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
-import org.eclipse.jdt.internal.compiler.util.JRTUtil;
 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
 import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
@@ -180,6 +183,8 @@
 	private static final String NON_CHAINING_JARS_CACHE = "nonChainingJarsCache"; //$NON-NLS-1$
 	private static final String EXTERNAL_FILES_CACHE = "externalFilesCache";  //$NON-NLS-1$
 	private static final String ASSUMED_EXTERNAL_FILES_CACHE = "assumedExternalFilesCache";  //$NON-NLS-1$
+	private static final String RELEASE_FILE = "release"; //$NON-NLS-1$
+	private static final String JAVA_VERSION = "JAVA_VERSION"; //$NON-NLS-1$
 
 	public static enum ArchiveValidity {
 		BAD_FORMAT, UNABLE_TO_READ, FILE_NOT_FOUND, VALID;
@@ -2845,19 +2850,25 @@
 		return this.workspaceScope;
 	}
 
-	public static boolean isJrt(IPath path) {
-		return path.toString().endsWith(JRTUtil.JRT_FS_JAR);
-	}
-
-	public static boolean isJrt(String path) {
-		return isJrt(new Path(path));
+	public static boolean isJrtInstallation(String path) {
+		java.nio.file.Path releasePath = Paths.get(path, RELEASE_FILE);
+		if (!Files.exists(releasePath)) 
+			return false;
+		try (Stream<String> lines = Files.lines(releasePath).filter(s -> s.contains(JAVA_VERSION))) {
+			Optional<String> hasVersion = lines.findFirst();
+			if (hasVersion.isPresent()) {
+				String line = hasVersion.get();
+				String version = line.substring(14, line.length() - 1); // length of JAVA_VERSION + 2 in JAVA_VERSION="9"
+				return JavaCore.compareJavaVersions(version, JavaCore.VERSION_1_8) > 0;
+			}
+		}
+		catch (IOException e) {
+			// Just return false;
+		} 
+		return false;
 	}
 
 	public void verifyArchiveContent(IPath path) throws CoreException {
-		// TODO: we haven't finalized what path the JRT is represented by. Don't attempt to validate it.
-		if (isJrt(path)) {
-			return;
-		}
 		throwExceptionIfArchiveInvalid(path);
 		// Check if we can determine the archive's validity by examining the index
 		if (JavaIndex.isEnabled()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index ab9df20..b7906da 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.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
@@ -663,6 +663,31 @@
 		IPackageFragmentRoot root = null;
 
 		switch(resolvedEntry.getEntryKind()){
+			case IClasspathEntry.CPE_JRT_SYSTEM :
+				PerProjectInfo info = getPerProjectInfo();
+				ObjectVector imageRoots;
+				if (info.jrtRoots == null || !info.jrtRoots.containsKey(entryPath)) {
+					imageRoots = new ObjectVector();
+					loadModulesInJrt(entryPath, imageRoots, rootToResolvedEntries, resolvedEntry, referringEntry);
+					info.setJrtPackageRoots(entryPath, imageRoots); // unfiltered
+					rootIDs.add(rootID);
+				} else {
+					imageRoots = info.jrtRoots.get(entryPath);
+				}
+				if (filterModuleRoots) {
+					List<String> rootModules = null;
+					String limitModules = ClasspathEntry.getExtraAttribute(resolvedEntry, IClasspathAttribute.LIMIT_MODULES);
+					if (limitModules != null) {
+						rootModules = Arrays.asList(limitModules.split(",")); //$NON-NLS-1$
+					} else if (isUnNamedModule()) {
+						rootModules = defaultRootModules((Iterable) imageRoots);
+					}
+					if (rootModules != null) {
+						imageRoots = filterLimitedModules(entryPath, imageRoots, rootModules);
+					}
+				}
+				accumulatedRoots.addAll(imageRoots);
+				break;
 			// source folder
 			case IClasspathEntry.CPE_SOURCE :
 
@@ -690,31 +715,7 @@
 				} else if (target instanceof File) {
 					// external target
 					if (JavaModel.isFile(target)) {
-						if (JavaModel.isJimage((File) target)) {
-							PerProjectInfo info = getPerProjectInfo();
-							ObjectVector imageRoots;
-							if (info.jrtRoots == null || !info.jrtRoots.containsKey(entryPath)) {
-								imageRoots = new ObjectVector();
-								loadModulesInJimage(entryPath, imageRoots, rootToResolvedEntries, resolvedEntry, referringEntry);
-								info.setJrtPackageRoots(entryPath, imageRoots); // unfiltered
-								rootIDs.add(rootID);
-							} else {
-								imageRoots = info.jrtRoots.get(entryPath);
-							}
-							if (filterModuleRoots) {
-								List<String> rootModules = null;
-								String limitModules = ClasspathEntry.getExtraAttribute(resolvedEntry, IClasspathAttribute.LIMIT_MODULES);
-								if (limitModules != null) {
-									rootModules = Arrays.asList(limitModules.split(",")); //$NON-NLS-1$
-								} else if (isUnNamedModule()) {
-									rootModules = defaultRootModules((Iterable) imageRoots);
-								}
-								if (rootModules != null) {
-									imageRoots = filterLimitedModules(entryPath, imageRoots, rootModules);
-								}
-							}
-							accumulatedRoots.addAll(imageRoots);
-						} else if (JavaModel.isJmod((File) target)) {
+						if (JavaModel.isJmod((File) target)) {
 							root = new JModPackageFragmentRoot(entryPath, this);
 						}
 						else {
@@ -892,7 +893,7 @@
 		}
 	}
 
-	private void loadModulesInJimage(final IPath imagePath, final ObjectVector roots, final Map rootToResolvedEntries, 
+	private void loadModulesInJrt(final IPath imagePath, final ObjectVector roots, final Map rootToResolvedEntries, 
 				final IClasspathEntry resolvedEntry, final IClasspathEntry referringEntry) {
 		try {
 			org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imagePath.toFile(),
@@ -2203,7 +2204,7 @@
 		IFolder linkedFolder = JavaModelManager.getExternalManager().getFolder(externalLibraryPath);
 		if (linkedFolder != null)
 			return new ExternalPackageFragmentRoot(linkedFolder, externalLibraryPath, this);
-		if (JavaModelManager.isJrt(externalLibraryPath)) {
+		if (JavaModelManager.isJrtInstallation(externalLibraryPath.toOSString())) {
 			return this.new JImageModuleFragmentBridge(externalLibraryPath);
 		}
 		Object target = JavaModel.getTarget(externalLibraryPath, true/*check existency*/);
@@ -2594,6 +2595,7 @@
 			IClasspathEntry entry = rawClasspath[i];
 			switch (entry.getEntryKind()) {
 				case IClasspathEntry.CPE_LIBRARY:
+				case IClasspathEntry.CPE_JRT_SYSTEM:
 				case IClasspathEntry.CPE_PROJECT:
 				case IClasspathEntry.CPE_SOURCE:
 					if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, entry))
@@ -3687,6 +3689,7 @@
 						break;
 					case IClasspathEntry.CPE_LIBRARY:
 					case IClasspathEntry.CPE_CONTAINER:
+					case IClasspathEntry.CPE_JRT_SYSTEM:
 						for (IPackageFragmentRoot root : findPackageFragmentRoots(entry)) {
 							module = root.getModuleDescription();
 							if (module != null && module.getElementName().equals(mainModule))
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java
index bca2552..d0962f5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java
@@ -121,6 +121,11 @@
 		return new JarPackageFragment(this, pkgName);
 	}
 	@Override
+	protected IStatus validateExistence(IResource underlyingResource) {
+		// check whether this pkg fragment root can be opened
+		return validateOnClasspath();
+	}
+	@Override
 	public int hashCode() {
 		return this.jarPath.hashCode() + this.moduleName.hashCode();
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java
index 0f00d8a..eabf217 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java
@@ -168,9 +168,8 @@
 				byte[] contents = getClassFileContent(jarRoot, entryName);
 				if (contents != null) {
 					String fileName;
-					String rootPath = root.getPath().toOSString();
 					String rootIdentifier = root.getHandleIdentifier();
-					if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(rootPath)) {
+					if (root instanceof JrtPackageFragmentRoot) {
 						int slash = rootIdentifier.lastIndexOf('/');
 						if (slash != -1)
 							rootIdentifier = rootIdentifier.substring(0, slash);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
index 93b4ca0..d4a3c4e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.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
@@ -494,7 +494,7 @@
 	((JavaElement)getParent()).getHandleMemento(buff);
 	buff.append(getHandleMementoDelimiter());
 	escapeMementoName(buff, path.toString());
-	if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(path.toOSString())) {
+	if (this instanceof JrtPackageFragmentRoot) {
 		buff.append(JavaElement.JEM_MODULE);
 		escapeMementoName(buff, getElementName());
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
index 1c4f3ac..6268832 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.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
@@ -549,22 +549,8 @@
 
 		String sourceLevel = null;
 		String complianceLevel = null;
-		if (Util.isJrt(pkgFragmentRootPath.toOSString())) {
-			try {
-				JrtPackageNamesAdderVisitor jrtPackageNamesAdderVisitor = new JrtPackageNamesAdderVisitor(firstLevelPackageNames, 
-						sourceLevel, complianceLevel, containsADefaultPackage, containsJavaSource, root);
-				org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(root.getPath().toFile(), jrtPackageNamesAdderVisitor, JRTUtil.NOTIFY_FILES);
-				sourceLevel = jrtPackageNamesAdderVisitor.sourceLevel;
-				complianceLevel = jrtPackageNamesAdderVisitor.complianceLevel;
-				containsADefaultPackage = jrtPackageNamesAdderVisitor.containsADefaultPackage;
-				containsJavaSource = jrtPackageNamesAdderVisitor.containsJavaSource;
-			} catch (IOException e) {
-				// We are not reading any specific file, so, move on for now
-				if (VERBOSE) {
-					e.printStackTrace();
-				}
-			}
-		} else if (root.isArchive()) {
+
+		if (root.isArchive()) {
 			JavaModelManager manager = JavaModelManager.getJavaModelManager();
 			ZipFile zip = null;
 			try {
@@ -603,7 +589,24 @@
 			}
 		} else {
 			Object target = JavaModel.getTarget(root.getPath(), true);
-			if (target instanceof IResource) {
+			if (target == null) {
+				if (root instanceof JrtPackageFragmentRoot) {
+					try {
+						JrtPackageNamesAdderVisitor jrtPackageNamesAdderVisitor = new JrtPackageNamesAdderVisitor(firstLevelPackageNames, 
+								sourceLevel, complianceLevel, containsADefaultPackage, containsJavaSource, root);
+						org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(root.getPath().toFile(), jrtPackageNamesAdderVisitor, JRTUtil.NOTIFY_FILES);
+						sourceLevel = jrtPackageNamesAdderVisitor.sourceLevel;
+						complianceLevel = jrtPackageNamesAdderVisitor.complianceLevel;
+						containsADefaultPackage = jrtPackageNamesAdderVisitor.containsADefaultPackage;
+						containsJavaSource = jrtPackageNamesAdderVisitor.containsJavaSource;
+					} catch (IOException e) {
+						// We are not reading any specific file, so, move on for now
+						if (VERBOSE) {
+							e.printStackTrace();
+						}
+					}
+				}
+			} else if (target instanceof IResource) {
 				IResource resource = (IResource) target;
 				if (resource instanceof IContainer) {
 					try {
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 0f43c83..b95c7e7 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
@@ -124,13 +124,14 @@
 										AccessRuleSet accessRuleSet, 
 										IPath annotationsPath,
 										boolean autoModule) {
-	return Util.isJrt(libraryPathname) ?
-			new ClasspathJrt(libraryPathname, accessRuleSet, annotationsPath) :
-				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);
 
 }
+static ClasspathJrt forJrtSystem(String jdkHome, AccessRuleSet accessRuleSet, IPath annotationsPath) {
+	return new ClasspathJrt(jdkHome, accessRuleSet, annotationsPath);
+}
 
 public static ClasspathLocation forLibrary(String libraryPathname, AccessRuleSet accessRuleSet, IPath annotationsPath,
 											boolean autoModule) {
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 d7090e8..909332d 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
@@ -137,7 +137,8 @@
 		IPath path = entry.getPath();
 		Object target = JavaModel.getTarget(path, true);
 		IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, javaProject.getProject(), true);
-		if (target == null) continue nextEntry;
+		if (target == null && entry.getEntryKind() != IClasspathEntry.CPE_JRT_SYSTEM)
+			continue nextEntry;
 		boolean isOnModulePath = isOnModulePath(entry);
 
 		Set<String> limitModules = ModuleEntryProcessor.computeLimitModules(entry);
@@ -150,6 +151,23 @@
 			this.moduleUpdater.computeModuleUpdates(entry);
 
 		switch(entry.getEntryKind()) {
+			case IClasspathEntry.CPE_JRT_SYSTEM :
+				//TODO: Some of the code in case CPE_LIBRARY is handled here. Revisit when confirmed
+				// a CPE_LIBRARY need not handle multi module entry.
+				ClasspathJrt jrtClasspath = 
+				ClasspathLocation.forJrtSystem(entry.getPath().toOSString(), entry.getAccessRuleSet(), externalAnnotationPath);
+				AccessRuleSet accessRuleSet =
+						(JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
+							&& JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
+								? null
+								: entry.getAccessRuleSet();
+				bLocations.add(jrtClasspath);
+				if (moduleEntries != null) {
+					Set<String> libraryLimitModules = (limitModules == null && projectModule != null) ? ClasspathJrt.NO_LIMIT_MODULES : limitModules;
+					patchedModule = collectModuleEntries(jrtClasspath, path, isOnModulePath,
+							libraryLimitModules, patchedModuleName, patchedModule, moduleEntries);
+				}
+				break;
 			case IClasspathEntry.CPE_SOURCE :
 				if (!(target instanceof IContainer)) continue nextEntry;
 				IPath outputPath = entry.getOutputLocation() != null
@@ -262,14 +280,14 @@
 					IResource resource = (IResource) target;
 					ClasspathLocation bLocation = null;
 					if (resource instanceof IFile) {
-						AccessRuleSet accessRuleSet =
+						accessRuleSet =
 							(JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
 							&& JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
 								? null
 								: entry.getAccessRuleSet();
 						bLocation = ClasspathLocation.forLibrary((IFile) resource, accessRuleSet, externalAnnotationPath, isOnModulePath);
 					} else if (resource instanceof IContainer) {
-						AccessRuleSet accessRuleSet =
+						accessRuleSet =
 							(JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
 							&& JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
 								? null
@@ -296,7 +314,7 @@
 						binaryLocationsPerProject.put(p, existingLocations);
 					}
 				} else if (target instanceof File) {
-					AccessRuleSet accessRuleSet =
+					accessRuleSet =
 						(JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
 							&& JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
 								? null
@@ -304,9 +322,8 @@
 					ClasspathLocation bLocation = ClasspathLocation.forLibrary(path.toOSString(), accessRuleSet, externalAnnotationPath, isOnModulePath);
 					bLocations.add(bLocation);
 					if (moduleEntries != null) {
-						Set<String> libraryLimitModules = (limitModules == null && projectModule != null) ? ClasspathJrt.NO_LIMIT_MODULES : limitModules;
 						patchedModule = collectModuleEntries(bLocation, path, isOnModulePath,
-											libraryLimitModules, patchedModuleName, patchedModule, moduleEntries);
+											limitModules, patchedModuleName, patchedModule, moduleEntries);
 					}
 				}
 				continue nextEntry;
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 ae3c904..849a053 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
@@ -21,7 +21,6 @@
 import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.*;
 import org.eclipse.jdt.internal.compiler.env.AccessRule;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
-import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jdt.internal.core.ClasspathAccessRule;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 
@@ -60,6 +59,7 @@
 static final byte BINARY_FOLDER = 2;
 static final byte EXTERNAL_JAR = 3;
 static final byte INTERNAL_JAR = 4;
+static final byte JRT_SYSTEM = 5;
 
 State() {
 	// constructor with no argument
@@ -283,11 +283,16 @@
 			case EXTERNAL_JAR :
 				String jarPath = in.readUTF();
 				newState.binaryLocations[i] = ClasspathLocation.forLibrary(jarPath, in.readLong(),
-							readRestriction(in), new Path(in.readUTF()), Util.isJrt(jarPath) ? false : in.readBoolean());
+							readRestriction(in), new Path(in.readUTF()), in.readBoolean());
 				break;
 			case INTERNAL_JAR :
 					newState.binaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())),
 							readRestriction(in), new Path(in.readUTF()), in.readBoolean());
+					break;
+			case JRT_SYSTEM :
+				jarPath = in.readUTF();
+				newState.binaryLocations[i] = ClasspathLocation.forJrtSystem(jarPath, readRestriction(in), new Path(in.readUTF()));
+				break;
 		}
 		ClasspathLocation loc = newState.binaryLocations[i];
 		char[] patchName = readName(in);
@@ -355,11 +360,16 @@
 			case EXTERNAL_JAR :
 				String jarPath = in.readUTF();
 				newState.testBinaryLocations[i] = ClasspathLocation.forLibrary(jarPath, in.readLong(),
-							readRestriction(in), new Path(in.readUTF()), Util.isJrt(jarPath) ? false : in.readBoolean());
+							readRestriction(in), new Path(in.readUTF()), in.readBoolean());
 				break;
 			case INTERNAL_JAR :
 					newState.testBinaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())),
 							readRestriction(in), new Path(in.readUTF()), in.readBoolean());
+					break;
+			case JRT_SYSTEM :
+				jarPath = in.readUTF();
+				newState.binaryLocations[i] = ClasspathLocation.forJrtSystem(jarPath, readRestriction(in), new Path(in.readUTF()));
+				break;
 		}
 	}
 
@@ -556,10 +566,10 @@
 			out.writeBoolean(jar.isOnModulePath);
 		} else {
 			ClasspathJrt jrt = (ClasspathJrt) c;
-			out.writeByte(EXTERNAL_JAR);
+			out.writeByte(JRT_SYSTEM);
 			out.writeUTF(jrt.zipFilename);
 			out.writeLong(-1);
-			writeRestriction(null, out);
+			writeRestriction(jrt.accessRuleSet, out);
 			out.writeUTF(""); //$NON-NLS-1$
 		}
 		char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
index 352d19a..28f97a3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
@@ -98,8 +98,7 @@
 			}
 			// create handle
 			String module = null;
-			String rootPath = this.lastPkgFragmentRoot.getPath().toOSString();
-			if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(rootPath)) {
+			if (this.lastPkgFragmentRoot instanceof JrtPackageFragmentRoot) {
 				module = resourcePath.substring(separatorIndex + 1, 
 						(separatorIndex = resourcePath.lastIndexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR)));
 			}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
index 47e44ed..178971a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
@@ -846,7 +846,8 @@
 						}
 					}
 					if (path != null) {
-						if (JavaModelManager.isJrt(path)) {
+						if (JavaModelManager.isJrtInstallation(path.toOSString())) {
+							// TODO: This should be taken care of by the clients.
 							return ClassFileConstants.JDK9;
 						} else {
 							jar = JavaModelManager.getJavaModelManager().getZipFile(path);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
index 74269ef..057c140 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 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
@@ -141,6 +141,7 @@
 		access = cpEntry.getAccessRuleSet();
 		switch (entry.getEntryKind()) {
 			case IClasspathEntry.CPE_LIBRARY:
+			case IClasspathEntry.CPE_JRT_SYSTEM:
 				IClasspathEntry rawEntry = null;
 				Map rootPathToRawEntries = perProjectInfo.rootPathToRawEntries;
 				if (rootPathToRawEntries != null) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
index aec5bec..c772028 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -96,7 +96,7 @@
 			IClasspathEntry[] entries = javaProject.getResolvedClasspath();
 			for (int j = 0, eLength = entries.length; j < eLength; j++) {
 				IClasspathEntry entry = entries[j];
-				if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+				if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY || entry.getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
 					IPath path = entry.getPath();
 					Object target = JavaModel.getTarget(path, false/*don't check existence*/);
 					if (target instanceof IFolder) // case of an external folder
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java
index 41f9392..d22459a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016 IBM Corporation and others.
+ * Copyright (c) 2016, 2017 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
@@ -46,12 +46,6 @@
 		DELETED
 	}
 
-	public AddJrtToIndex(IFile resource, IndexLocation indexFile, IndexManager manager, final boolean updateIndex) {
-		super(resource.getFullPath(), manager);
-		this.resource = resource;
-		this.indexFileURL = indexFile;
-		this.forceIndexUpdate = updateIndex;
-	}
 	public AddJrtToIndex(IPath jrtPath, IndexLocation indexFile, IndexManager manager, final boolean updateIndex) {
 		// external JAR scenario - no resource
 		super(jrtPath, manager);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
index 91ac2cc..889d526 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -82,6 +82,8 @@
 						// ensure a job exists to index it as a binary folder
 						this.manager.indexLibrary(projectPath, this.project, ((ClasspathEntry)entry).getLibraryIndexLocation());
 						return true;
+					} else if (entry.getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
+						this.manager.indexJrtSystem(entry.getPath(), this.project, ((ClasspathEntry)entry).getLibraryIndexLocation());
 					}
 				}
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index f499b83..ea0d892 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 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
@@ -42,7 +42,6 @@
 import org.eclipse.jdt.internal.compiler.SourceElementParser;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
-import org.eclipse.jdt.internal.compiler.util.JRTUtil;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
 import org.eclipse.jdt.internal.core.ClasspathEntry;
@@ -578,8 +577,11 @@
 		IClasspathEntry[] entries = javaProject.getResolvedClasspath();
 		for (int i = 0; i < entries.length; i++) {
 			IClasspathEntry entry= entries[i];
-			if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
+			if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
 				indexLibrary(entry.getPath(), project, ((ClasspathEntry)entry).getLibraryIndexLocation());
+			} else if (entry.getEntryKind() == IClasspathEntry.CPE_JRT_SYSTEM) {
+				indexJrtSystem(entry.getPath(), project, ((ClasspathEntry)entry).getLibraryIndexLocation());
+			}
 		}
 	} catch(JavaModelException e){ // cannot retrieve classpath info
 	}
@@ -589,18 +591,40 @@
 	if (!isJobWaiting(request))
 		request(request);
 }
+public void indexJrtSystem(IPath path, IProject requestingProject, URL indexURL) {
+	this.indexer.makeWorkspacePathDirty(path);
+	// requestingProject is no longer used to cancel jobs but leave it here just in case
+	IndexLocation indexFile = null;
+	boolean forceIndexUpdate = false;
+	if(indexURL != null) {
+		if(IS_MANAGING_PRODUCT_INDEXES_PROPERTY) {
+			indexFile = computeIndexLocation(path, indexURL);
+		}
+		else {
+			indexFile = IndexLocation.createIndexLocation(indexURL);
+		}
+	}
+	if (JavaCore.getPlugin() == null) return;
+	IndexRequest request = new AddJrtToIndex(path, indexFile, this, forceIndexUpdate);
+
+	if (!isJobWaiting(request))
+		request(request);
+}
 public void indexLibrary(IPath path, IProject requestingProject, URL indexURL) {
 	this.indexLibrary(path, requestingProject, indexURL, false);
 }
 
 private IndexRequest getRequest(Object target, IPath jPath, IndexLocation indexFile, IndexManager manager, boolean updateIndex) {
-	return isJrt(((File) target).getName()) ? new AddJrtToIndex(jPath, indexFile, this, updateIndex) :
-		new AddJarFileToIndex(jPath, indexFile, this, updateIndex);
+	if (target instanceof File) {
+		return new AddJarFileToIndex(jPath, indexFile, this, updateIndex);
+	} else if (target == null) {
+		if (JavaModelManager.isJrtInstallation(jPath.toOSString())) {
+			return new AddJrtToIndex(jPath, indexFile, this, updateIndex);
+		}
+	}
+	return null;
 }
 
-private boolean isJrt(String fileName) {
-	return fileName != null && fileName.endsWith(JRTUtil.JRT_FS_JAR);
-}
 /**
  * Trigger addition of a library to an index
  * Note: the actual operation is performed in background
@@ -628,19 +652,15 @@
 	IndexRequest request = null;
 	Object target = JavaModel.getTarget(path, true);
 	if (target instanceof IFile) {
-		request = isJrt(((IFile) target).getFullPath().toOSString()) ? 
-				new AddJrtToIndex((IFile) target, indexFile, this, forceIndexUpdate) :
-					new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate);
-	} else if (target instanceof File) {
-		request = getRequest(target, path, indexFile, this, forceIndexUpdate);
+		request = new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate);
 	} else if (target instanceof IContainer) {
 		request = new IndexBinaryFolder((IContainer) target, this);
 	} else {
-		return;
+		request = getRequest(target, path, indexFile, this, forceIndexUpdate);
 	}
 
 	// check if the same request is not already in the queue
-	if (!isJobWaiting(request))
+	if (request != null && !isJobWaiting(request))
 		request(request);
 }
 
@@ -727,7 +747,6 @@
 private void rebuildIndex(IndexLocation indexLocation, IPath containerPath, final boolean updateIndex) {
 	this.indexer.makeWorkspacePathDirty(containerPath);
 	Object target = JavaModel.getTarget(containerPath, true);
-	if (target == null) return;
 
 	if (VERBOSE)
 		Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath); //$NON-NLS-1$ //$NON-NLS-2$
@@ -741,10 +760,8 @@
 	} else if (target instanceof IFolder) {
 		request = new IndexBinaryFolder((IFolder) target, this);
 	} else if (target instanceof IFile) {
-		request = isJrt(((IFile) target).getFullPath().toOSString()) ? 
-				new AddJrtToIndex((IFile) target, null, this, updateIndex) :
-					new AddJarFileToIndex((IFile) target, null, this, updateIndex);
-	} else if (target instanceof File) {
+		request = new AddJarFileToIndex((IFile) target, null, this, updateIndex);
+	} else {
 		request = getRequest(target, containerPath, null, this, updateIndex);
 	}
 	if (request != null)
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 babf866..fc368cc 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
@@ -43,6 +43,7 @@
 import org.eclipse.jdt.internal.core.JavaModel;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 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;
@@ -156,7 +157,7 @@
 	try {
 		if (root.isArchive()) {
 			ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
-			cp = JavaModelManager.isJrt(path) ? 
+			cp = (root instanceof JrtPackageFragmentRoot) ? 
 					new ClasspathJrt(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), 
 							ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true)) :
 						new ClasspathJar(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(),
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index 2eb1b04..111021e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -74,6 +74,7 @@
 import org.eclipse.jdt.internal.core.JavaElement;
 import org.eclipse.jdt.internal.core.JavaModelManager;
 import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.JrtPackageFragmentRoot;
 import org.eclipse.jdt.internal.core.LambdaFactory;
 import org.eclipse.jdt.internal.core.LocalVariable;
 import org.eclipse.jdt.internal.core.ModularClassFile;
@@ -260,7 +261,7 @@
 			return Util.newClassFileReader(((JavaElement) type).resource());
 
 		String rootPath = root.getPath().toOSString();
-		if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(rootPath)) {
+		if (root instanceof JrtPackageFragmentRoot) {
 			String classFileName = classFile.getElementName();
 			String path = Util.concatWith(pkg.names, classFileName, '/');
 			return ClassFileReader.readFromJrt(new File(rootPath), null, path);