[565328] JSP translator must account for Jakarta EE 9 package change
diff --git a/web/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF b/web/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF
index ea21ef8..c41c331 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF
+++ b/web/bundles/org.eclipse.jst.jsp.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jst.jsp.core;singleton:=true
-Bundle-Version: 1.3.0.qualifier
+Bundle-Version: 1.3.100.qualifier
 Bundle-Activator: org.eclipse.jst.jsp.core.internal.JSPCorePlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/web/bundles/org.eclipse.jst.jsp.core/pom.xml b/web/bundles/org.eclipse.jst.jsp.core/pom.xml
index b56c470..7c11f9b 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/pom.xml
+++ b/web/bundles/org.eclipse.jst.jsp.core/pom.xml
@@ -21,6 +21,6 @@
 
   <groupId>org.eclipse.webtools.sourceediting</groupId>
   <artifactId>org.eclipse.jst.jsp.core</artifactId>
-  <version>1.3.0-SNAPSHOT</version>
+  <version>1.3.100-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyCache.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyCache.java
index bb5c124..e1bf45b 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyCache.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyCache.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 IBM Corporation and others.
+ * Copyright (c) 2007, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -39,6 +39,11 @@
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jst.jsp.core.internal.Logger;
 import org.eclipse.jst.jsp.core.internal.util.CommonXML;
 import org.eclipse.jst.jsp.core.internal.util.FacetModuleCoreSupport;
@@ -243,13 +248,13 @@
 					getInstance().deploymentDescriptorChanged(path);
 				}
 			}
-			else if (resource.getType() == IResource.PROJECT) {
+			else if (resource.getType() == IResource.PROJECT && (delta.getKind() == IResourceDelta.ADDED || delta.getKind() == IResourceDelta.REMOVED)) {
 				String name = resource.getName();
 				if (_debugResolutionCache) {
 					System.out.println("Removing DeploymentDescriptorPropertyCache resolution cache for project " + name); //$NON-NLS-1$
 				}
 				synchronized (LOCK) {
-					getInstance().resolvedMap.remove(name);
+					getInstance().invalidate(name);
 				}
 			}
 			return true;
@@ -646,6 +651,11 @@
 	 */
 	Map<String, Map<IPath, IPath>> resolvedMap = new HashMap<>();
 
+	/**
+	 * Map of project names to a structure representing the available Servlet API.
+	 */
+	Map<String, ServletAPIDescriptor> apiVersions = new HashMap<>();
+
 	final static Object LOCK = new Object();
 
 	private DeploymentDescriptorPropertyCache() {
@@ -745,6 +755,51 @@
 	}
 
 	/**
+	 * @param project
+	 * @return Descriptor for the Servlet API version found on the project's Java
+	 *         Build Path, <code>null</code> if none was discoverable.
+	 */
+	private ServletAPIDescriptor discoverServletAPIVersion(IProject project) {
+		IJavaProject javaProject = JavaCore.create(project);
+		if (!javaProject.exists()) {
+			return null;
+		}
+		try {
+			if (javaProject.findType("jakarta.servlet.GenericFilter") != null) {
+				return new ServletAPIDescriptor("jakarta.servlet", 4);
+			}
+			if (javaProject.findType("javax.servlet.GenericFilter") != null) {
+				return new ServletAPIDescriptor("javax.servlet", 4);
+			}
+			if (javaProject.findType("javax.servlet.ReadListener") != null) {
+				return new ServletAPIDescriptor("javax.servlet", 3.1f);
+			}
+			if (javaProject.findType("javax.servlet.SessionCookieConfig") != null) {
+				return new ServletAPIDescriptor("javax.servlet", 3);
+			}
+			IType servletRequestType = javaProject.findType("javax.servlet.http.HttpServletRequest");
+			if (servletRequestType != null) {
+				IMethod[] methods = servletRequestType.getMethods();
+				for (int i = 0; i < methods.length; i++) {
+					if ("getContextPath".equals(methods[i].getElementName())) {
+						return new ServletAPIDescriptor("javax.servlet", 2.5f);
+					}
+				}
+			}
+			if (javaProject.findType("javax.servlet.ServletRequestAttributeEvent") != null) {
+				return new ServletAPIDescriptor("javax.servlet", 2.4f);
+			}
+			if (javaProject.findType("javax.servlet.Filter") != null) {
+				return new ServletAPIDescriptor("javax.servlet", 2.3f);
+			}
+		}
+		catch (JavaModelException e) {
+			Logger.logException(e);
+		}
+		return null;
+	}
+
+	/**
 	 * parse the specified resource using Xerces, and if that fails, use the
 	 * SSE XML parser to find the property groups.
 	 */
@@ -874,7 +929,19 @@
 
 		/* check facet settings */
 		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(fullPath.segment(0));
-		version = FacetModuleCoreSupport.getDynamicWebProjectVersion(project);
+		float facetVersion = FacetModuleCoreSupport.getDynamicWebProjectVersion(project);
+
+		if (facetVersion > 0) {
+			// use it if set
+			version = facetVersion;
+		}
+		else {
+			// try to detect from classpath
+			ServletAPIDescriptor detected = getServletAPIVersion(project);
+			if (detected != null) {
+				return convertSpecVersions(detected.getAPIversion());
+			}
+		}
 
 		return convertSpecVersions(version);
 	}
@@ -908,6 +975,26 @@
 	}
 
 	/**
+	 * @param project
+	 * @return Descriptor for the Servlet API version found on the project's Java
+	 *         Build Path, <code>null</code> if none was discoverable.
+	 */
+	public ServletAPIDescriptor getServletAPIVersion(IProject project) {
+		ServletAPIDescriptor descriptor = apiVersions.get(project.getName());
+		if (descriptor == null) {
+			descriptor = discoverServletAPIVersion(project);
+			if (descriptor != null) {
+				apiVersions.put(project.getName(), descriptor);
+			}
+			else {
+				apiVersions.put(project.getName(), ServletAPIDescriptor.DEFAULT);
+				descriptor = ServletAPIDescriptor.DEFAULT;
+			}
+		}
+		return descriptor;
+	}
+
+	/**
 	 * @param fullPath
 	 *            the full path of the JSP file
 	 * @param reference
@@ -975,6 +1062,11 @@
 		return ResourcesPlugin.getWorkspace().getRoot().getFile(webxmlPath);
 	}
 
+	public void invalidate(String name) {
+		getInstance().resolvedMap.remove(name);
+		getInstance().apiVersions.remove(name);
+	}
+	
 	private void updateCacheEntry(IPath fullPath) {
 		/* don't update right now; remove and wait for another query to do that work */
 		fDeploymentDescriptors.remove(fullPath);
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/ServletAPIDescriptor.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/ServletAPIDescriptor.java
new file mode 100644
index 0000000..22927ce
--- /dev/null
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/ServletAPIDescriptor.java
@@ -0,0 +1,47 @@
+/*******************************************************************************

+ * Copyright (c) 2020 IBM Corporation and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License 2.0

+ * which accompanies this distribution, and is available at

+ * https://www.eclipse.org/legal/epl-2.0/

+ *

+ * SPDX-License-Identifier: EPL-2.0

+ *

+ * Contributors:

+ *     IBM Corporation - initial API and implementation

+ *     

+ *******************************************************************************/

+package org.eclipse.jst.jsp.core.internal.contenttype;

+

+/**

+ * Represents the root package (javax vs. jakarta) and API version for a

+ * project. Typically this will have been discovered against actual libraries.

+ */

+public class ServletAPIDescriptor {

+	public static ServletAPIDescriptor DEFAULT = new ServletAPIDescriptor("javax.servlet", 4);

+

+	public ServletAPIDescriptor(String rootPackage, float apiVersion) {

+		super();

+		this.fRootPackage = rootPackage;

+		this.fAPIversion = apiVersion;

+	}

+

+	String fRootPackage;

+	float fAPIversion;

+

+	public String getRootPackage() {

+		return fRootPackage;

+	}

+

+	public void setRootPackage(String packageRoot) {

+		fRootPackage = packageRoot;

+	}

+

+	public float getAPIversion() {

+		return fAPIversion;

+	}

+

+	public void setAPIversion(float aPIversion) {

+		fAPIversion = aPIversion;

+	}

+}

diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java
index 5ac4425..c081e99 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2018 IBM Corporation and others.
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.eclipse.core.resources.WorkspaceJob;
 import org.eclipse.core.runtime.CoreException;
@@ -74,8 +75,8 @@
 	/** the name of the class (w/out extension) **/
 	private String fClassname = ""; //$NON-NLS-1$
 	private IJavaProject fJavaProject = null;
-	private HashMap fJava2JspMap = null;
-	private HashMap fJsp2JavaMap = null;
+	private Map<Position, Position> fJava2JspMap = null;
+	private Map<Position, Position> fJsp2JavaMap = null;
 	private HashMap fJava2JspImportsMap = null;
 	private HashMap fJava2JspUseBeanMap = null;
 	private HashMap fJava2JspIndirectMap = null;
@@ -171,7 +172,7 @@
 				continue;
 
 			offsetInRange = jspOffset - jspPos.offset;
-			javaPos = (Position) fJsp2JavaMap.get(jspPos);
+			javaPos = fJsp2JavaMap.get(jspPos);
 			if(javaPos != null)
 				result = javaPos.offset + offsetInRange;
 			else  {
@@ -201,7 +202,7 @@
 				continue;
 
 			offsetInRange = javaOffset - javaPos.offset;
-			jspPos = (Position) fJava2JspMap.get(javaPos);
+			jspPos = fJava2JspMap.get(javaPos);
 			
 			if(jspPos != null)
 				result = jspPos.offset + offsetInRange;
@@ -222,7 +223,7 @@
 	 * 
 	 * @return a map of Positions in the Java document to corresponding Positions in the JSP document
 	 */
-	public HashMap getJava2JspMap() {
+	public Map<Position,Position> getJava2JspMap() {
 		return fJava2JspMap;
 	}
 
@@ -230,7 +231,7 @@
 	 * 
 	 * @return a map of Positions in the JSP document to corresponding Positions in the Java document
 	 */
-	public HashMap getJsp2JavaMap() {
+	public Map<Position,Position> getJsp2JavaMap() {
 		return fJsp2JavaMap;
 	}
 
@@ -264,12 +265,12 @@
 	 * @return <code>true</code> if the java code spans multiple JSP partitions, otherwise false.
 	 */
 	public boolean javaSpansMultipleJspPartitions(int javaOffset, int javaLength) {
-		HashMap java2jsp = getJava2JspMap();
+		Map<Position,Position> java2jsp = getJava2JspMap();
 		int count = 0;
-		Iterator it = java2jsp.keySet().iterator();
+		Iterator<Position> it = java2jsp.keySet().iterator();
 		Position javaRange = null;
 		while(it.hasNext()) {
-			javaRange = (Position)it.next();
+			javaRange = it.next();
 			if(javaRange.overlapsWith(javaOffset, javaLength))
 				count++;
 			if(count > 1)
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationExtension.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationExtension.java
index 737c3fc..2bacd6f 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationExtension.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationExtension.java
@@ -14,9 +14,9 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.jdt.core.IJavaProject;
@@ -151,7 +151,7 @@
 			// text
 			// mapping from java <-> jsp (eg. an import statement)
 			if (!isIndirect(javaPositions[i].offset))
-				jspPositions[i] = (Position) getJava2JspMap().get(javaPositions[i]);
+				jspPositions[i] = getJava2JspMap().get(javaPositions[i]);
 		}
 
 		if (DEBUG) {
@@ -399,11 +399,11 @@
 		// can be null if it's a NullJSPTranslation
 		if (getJavaDocument() != null && getJspDocument() != null) {
 
-			HashMap java2jsp = getJava2JspMap();
-			Iterator it = java2jsp.keySet().iterator();
+			Map<Position,Position> java2jsp = getJava2JspMap();
+			Iterator<Position> it = java2jsp.keySet().iterator();
 			Position javaPos = null;
 			while (it.hasNext()) {
-				javaPos = (Position) it.next();
+				javaPos = it.next();
 				try {
 
 					fJavaDocument.addPosition(javaPos);
@@ -421,12 +421,12 @@
 
 				try {
 
-					fJspDocument.addPosition((Position) java2jsp.get(javaPos));
+					fJspDocument.addPosition(java2jsp.get(javaPos));
 
 				}
 				catch (BadLocationException e) {
 					if (DEBUG) {
-						System.out.println("tyring to add JSP Position:[" + ((Position) java2jsp.get(javaPos)).offset + ":" + ((Position) java2jsp.get(javaPos)).length + "] to " + getJavaPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+						System.out.println("tyring to add JSP Position:[" + java2jsp.get(javaPos).offset + ":" + java2jsp.get(javaPos).length + "] to " + getJavaPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 						Logger.logException(e);
 					}
 				}
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java
index 877bbf9..a9ba4dc 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2018 IBM Corporation and others.
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -67,6 +67,7 @@
 import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.TLDElementDeclaration;
 import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache;
 import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache.PropertyGroup;
+import org.eclipse.jst.jsp.core.internal.contenttype.ServletAPIDescriptor;
 import org.eclipse.jst.jsp.core.internal.provisional.JSP11Namespace;
 import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace;
 import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts;
@@ -205,7 +206,10 @@
 
 	/** translated class service header */
 	String fServiceHeader = null;
-	
+
+	/** descriptor for the API available to build against */
+	ServletAPIDescriptor fServletAPIDescriptor = ServletAPIDescriptor.DEFAULT;
+
 	/** The context of the translation */
 	String fContext = null;
 
@@ -284,7 +288,7 @@
 	private int fOffsetInUserCode = 0;
 
 	/** correlates ranges (positions) in java to ranges in jsp */
-	private HashMap fJava2JspRanges = new HashMap();
+	private Map<Position,Position> fJava2JspRanges = new HashMap<>();
 
 	/**
 	 * map of ranges in fUserImports (relative to the start of the buffer) to
@@ -376,6 +380,9 @@
 
 		fStructuredDocument = fStructuredModel.getStructuredDocument();
 
+		fServletAPIDescriptor = DeploymentDescriptorPropertyCache.getInstance().getServletAPIVersion(ResourcesPlugin.getWorkspace().getRoot().getProject(new Path(baseLocation).segment(0)));
+		fSuperclass = fServletAPIDescriptor.getRootPackage() + ".http.HttpServlet"; //$NON-NLS-1$
+
 		String className = createClassname(node);
 		if (className.length() > 0) {
 			setClassname(className);
@@ -399,6 +406,9 @@
 
 		fELTranslatorID = getELTranslatorProperty(jspFile);
 
+		fServletAPIDescriptor = DeploymentDescriptorPropertyCache.getInstance().getServletAPIVersion(jspFile.getProject());
+		fSuperclass = fServletAPIDescriptor.getRootPackage() + ".http.HttpServlet"; //$NON-NLS-1$
+
 		String className = createClassname(jspFile);
 		if (className.length() > 0) {
 			setClassname(className);
@@ -743,7 +753,7 @@
 		javaOffset += fServiceHeader.length();
 		// session participant
 		if (fIsInASession) {
-			final String sessionVariableDeclaration = "javax.servlet.http.HttpSession session = "+ fSession + ENDL; //$NON-NLS-1$
+			final String sessionVariableDeclaration = fServletAPIDescriptor.getRootPackage() + ".http.HttpSession session = "+ fSession + ENDL; //$NON-NLS-1$
 			fResult.append(sessionVariableDeclaration);
 			javaOffset += sessionVariableDeclaration.length();
 		}
@@ -796,7 +806,7 @@
 	 * 
 	 * @return a map of java positions to jsp positions.
 	 */
-	public HashMap getJava2JspRanges() {
+	public Map<Position,Position> getJava2JspRanges() {
 		return fJava2JspRanges;
 	}
 
@@ -806,12 +816,12 @@
 	 * @return a map of jsp positions to java positions, or null if no
 	 *         translation has occured yet (the map hasn't been built).
 	 */
-	public HashMap getJsp2JavaRanges() {
+	public Map<Position,Position> getJsp2JavaRanges() {
 		if (fJava2JspRanges == null)
 			return null;
-		HashMap flipFlopped = new HashMap();
-		Iterator keys = fJava2JspRanges.keySet().iterator();
-		Object range = null;
+		Map<Position,Position> flipFlopped = new HashMap<>();
+		Iterator<Position> keys = fJava2JspRanges.keySet().iterator();
+		Position range = null;
 		while (keys.hasNext()) {
 			range = keys.next();
 			flipFlopped.put(fJava2JspRanges.get(range), range);
@@ -892,7 +902,7 @@
 					debugString.append("--------------------------------------------------------------\n"); //$NON-NLS-1$
 					debugString.append("|maps to...|\n"); //$NON-NLS-1$
 					debugString.append("==============================================================\n"); //$NON-NLS-1$
-					Position jsp = (Position) fJava2JspRanges.get(java);
+					Position jsp = fJava2JspRanges.get(java);
 					debugString.append("JSP range:[" + jsp.offset + ":" + jsp.length + "]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 					debugString.append("[" + fJspTextBuffer.toString().substring(jsp.offset, jsp.offset + jsp.length) + "]\n"); //$NON-NLS-1$ //$NON-NLS-2$
 					debugString.append("==============================================================\n"); //$NON-NLS-1$
@@ -1142,7 +1152,7 @@
 	private void doAfterBody(StringBuffer buffer, RegionTags regionTag) {
 		buffer.append("\tif ( (new "); //$NON-NLS-1$
 		buffer.append(regionTag.tag.getTagClassName());
-		buffer.append("()).doAfterBody() != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)\n\t\tbreak;\n"); //$NON-NLS-1$
+		buffer.append("()).doAfterBody() != " + fServletAPIDescriptor.getRootPackage() + ".jsp.tagext.BodyTag.EVAL_BODY_AGAIN)\n\t\tbreak;\n"); //$NON-NLS-1$
 	}
 
 	/**
@@ -1300,19 +1310,19 @@
 		fClassname = "_JSPServlet"; //$NON-NLS-1$
 		fClassHeader = "public class " + fClassname + " extends "; //$NON-NLS-1$ //$NON-NLS-2$
 		
-		fImplicitImports = "import javax.servlet.*;" + ENDL + //$NON-NLS-1$
-					"import javax.servlet.http.*;" + ENDL + //$NON-NLS-1$
-					"import javax.servlet.jsp.*;" + ENDL + ENDL; //$NON-NLS-1$
+		fImplicitImports = "import " + fServletAPIDescriptor.getRootPackage() + ".*;" + ENDL + //$NON-NLS-1$
+					"import "+ fServletAPIDescriptor.getRootPackage() + ".http.*;" + ENDL + //$NON-NLS-1$
+					"import " + fServletAPIDescriptor.getRootPackage() + ".jsp.*;" + ENDL + ENDL; //$NON-NLS-1$
 
-		fServiceHeader = "public void _jspService(javax.servlet.http.HttpServletRequest request," + //$NON-NLS-1$
-					" javax.servlet.http.HttpServletResponse response)" + ENDL + //$NON-NLS-1$
-					"\t\tthrows java.io.IOException, javax.servlet.ServletException {" + ENDL + //$NON-NLS-1$
-					"javax.servlet.jsp.PageContext pageContext = JspFactory.getDefaultFactory().getPageContext(this, request, response, null, true, JspWriter.DEFAULT_BUFFER, true);" + ENDL + //$NON-NLS-1$
-					"javax.servlet.ServletContext application = pageContext.getServletContext();" + ENDL + //$NON-NLS-1$
-					"javax.servlet.ServletConfig config = pageContext.getServletConfig();" + ENDL + //$NON-NLS-1$ 
-					"javax.servlet.jsp.JspWriter out = pageContext.getOut();" + ENDL + //$NON-NLS-1$
+		fServiceHeader = "public void _jspService(" + fServletAPIDescriptor.getRootPackage() + ".http.HttpServletRequest request," + //$NON-NLS-1$
+					" " + fServletAPIDescriptor.getRootPackage() + ".http.HttpServletResponse response)" + ENDL + //$NON-NLS-1$
+					"\t\tthrows java.io.IOException, " + fServletAPIDescriptor.getRootPackage() + ".ServletException {" + ENDL + //$NON-NLS-1$
+					fServletAPIDescriptor.getRootPackage() + ".jsp.PageContext pageContext = JspFactory.getDefaultFactory().getPageContext(this, request, response, null, true, JspWriter.DEFAULT_BUFFER, true);" + ENDL + //$NON-NLS-1$
+					fServletAPIDescriptor.getRootPackage() + ".ServletContext application = pageContext.getServletContext();" + ENDL + //$NON-NLS-1$
+					fServletAPIDescriptor.getRootPackage() + ".ServletConfig config = pageContext.getServletConfig();" + ENDL + //$NON-NLS-1$ 
+					fServletAPIDescriptor.getRootPackage() + ".jsp.JspWriter out = pageContext.getOut();" + ENDL + //$NON-NLS-1$
 					"Object page = this;" + ENDL; //$NON-NLS-1$
-		fSuperclass = "javax.servlet.http.HttpServlet"; //$NON-NLS-1$
+		fSuperclass = fServletAPIDescriptor.getRootPackage() + ".http.HttpServlet"; //$NON-NLS-1$
 		fContext = "pageContext"; //$NON-NLS-1$
 		fSession = fContext+".getSession();"; //$NON-NLS-1$
 	}
@@ -2168,7 +2178,7 @@
 		if (varName != null) {
 			if (isFragment) {
 				// 2.0:JSP.8.5.2
-				varType = "javax.servlet.jsp.tagext.JspFragment"; //$NON-NLS-1$
+				varType = fServletAPIDescriptor.getRootPackage() + ".jsp.tagext.JspFragment"; //$NON-NLS-1$
 			}
 			String declaration = new TaglibVariable(varType, varName, "", description).getDeclarationString(true, fContext, TaglibVariable.M_PRIVATE); //$NON-NLS-1$
 			appendToBuffer(declaration, fUserDeclarations, false, fCurrentNode);
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchDocument.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchDocument.java
index 4186bf3..e454194 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchDocument.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchDocument.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2009 IBM Corporation and others.
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -13,8 +13,8 @@
 package org.eclipse.jst.jsp.core.internal.java.search;
 
 import java.io.IOException;
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResource;
@@ -175,7 +175,7 @@
 		Position jspPos, javaPos = null;
 		JSPTranslation trans = getJSPTranslation();
 		if (trans != null) {
-			HashMap java2jspMap = trans.getJava2JspMap();
+			Map<Position,Position> java2jspMap = trans.getJava2JspMap();
 
 			// iterate all mapped java ranges
 			Iterator it = java2jspMap.keySet().iterator();
@@ -186,7 +186,7 @@
 					continue;
 
 				offsetInRange = javaOffset - javaPos.offset;
-				jspPos = (Position) java2jspMap.get(javaPos);
+				jspPos = java2jspMap.get(javaPos);
 
 				if (jspPos != null)
 					result = jspPos.offset + offsetInRange;
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperManager.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperManager.java
index 36b6e0b..8363a18 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperManager.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -31,6 +31,8 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jst.jsp.core.internal.JSPCoreMessages;
+import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache;
+import org.eclipse.jst.jsp.core.internal.java.JSPTranslatorPersister;
 import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP;
 
 /**
@@ -79,8 +81,9 @@
 			IJavaElementDelta[] changed = delta.getChangedChildren();
 			for (int i = 0; i < changed.length; i++) {
 				if ((changed[i].getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0 || (changed[i].getFlags() & IJavaElementDelta.F_REORDER) != 0 || (changed[i].getFlags() & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0 || (changed[i].getFlags() & IJavaElementDelta.F_PRIMARY_RESOURCE) != 0) {
-					IJavaElement proj = changed[i].getElement();
-					handleClasspathChange(changed, i, proj);
+					IJavaElement project = changed[i].getElement();
+					handleClasspathChange(changed, i, project);
+					DeploymentDescriptorPropertyCache.getInstance().invalidate(project.getJavaProject().getElementName());
 				}
 			}
 		}
@@ -119,7 +122,8 @@
 						project.accept(new IResourceProxyVisitor() {
 							public boolean visit(IResourceProxy proxy) throws CoreException {
 								if (!proxy.isDerived() && ContentTypeIdForJSP.indexOfJSPExtension(proxy.getName()) >= 0) {
-									proxy.requestResource().touch(null);
+									JSPTranslatorPersister.removePersistedTranslation(proxy.requestResource());
+//									proxy.requestResource().touch(null);
 								}
 								return !proxy.isDerived();
 							}
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/util/FacetModuleCoreSupport.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/util/FacetModuleCoreSupport.java
index a8009f1..bda96c5 100755
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/util/FacetModuleCoreSupport.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/util/FacetModuleCoreSupport.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 IBM Corporation and others.
+ * Copyright (c) 2007, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -69,12 +69,11 @@
 
 	/**
 	 * @param project
-	 * @return the version of the JST Web facet installed on the project, a default version otherwise
+	 * @return the version of the JST Web facet installed on the project, -1 otherwise
 	 * @throws org.eclipse.core.runtime.CoreException
 	 */
 	public static float getDynamicWebProjectVersion(IProject project) {
-		// In the absence of any facet information, assume the highest level
-		float version = DEFAULT_SERVLET_VERSION;
+		float version = -1;
 		try {
 			version = FacetModuleCoreSupportDelegate.getDynamicWebProjectVersion(project);
 		}
diff --git a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/validation/JSPJavaValidator.java b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/validation/JSPJavaValidator.java
index 6a8d283..5bf14ca 100644
--- a/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/validation/JSPJavaValidator.java
+++ b/web/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/validation/JSPJavaValidator.java
@@ -236,7 +236,7 @@
 						if (((problemID & IProblem.Internal) != 0) && ((problemID & IProblem.Syntax) != 0) && translation instanceof JSPTranslation) {
 							// Attach to the last code scripting section
 							JSPTranslation jspTranslation = ((JSPTranslation) translation);
-							Position[] jspPositions = (Position[]) jspTranslation.getJsp2JavaMap().keySet().toArray(new Position[jspTranslation.getJsp2JavaMap().size()]);
+							Position[] jspPositions = jspTranslation.getJsp2JavaMap().keySet().toArray(new Position[jspTranslation.getJsp2JavaMap().size()]);
 							for (int i = 0; i < jspPositions.length; i++) {
 								sourceStart = Math.max(sourceStart, jspPositions[i].getOffset());
 							}
diff --git a/web/bundles/org.eclipse.jst.jsp.ui/META-INF/MANIFEST.MF b/web/bundles/org.eclipse.jst.jsp.ui/META-INF/MANIFEST.MF
index 0191277..1b7005d 100755
--- a/web/bundles/org.eclipse.jst.jsp.ui/META-INF/MANIFEST.MF
+++ b/web/bundles/org.eclipse.jst.jsp.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jst.jsp.ui; singleton:=true
-Bundle-Version: 1.3.100.qualifier
+Bundle-Version: 1.3.200.qualifier
 Bundle-Activator: org.eclipse.jst.jsp.ui.internal.JSPUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
@@ -46,7 +46,7 @@
  org.eclipse.wst.html.ui;bundle-version="[1.1.0,1.2.0)",
  org.eclipse.wst.css.ui;bundle-version="[1.1.0,1.2.0)",
  org.eclipse.wst.xml.ui;bundle-version="[1.2.0,1.3.0)",
- org.eclipse.jst.jsp.core;bundle-version="[1.3.0,1.4.0)",
+ org.eclipse.jst.jsp.core;bundle-version="[1.3.100,1.4.0)",
  org.eclipse.wst.html.core;bundle-version="[1.3.0,1.4.0)",
  org.eclipse.wst.css.core;bundle-version="[1.2.0,1.3.0)",
  org.eclipse.wst.xml.core;bundle-version="[1.2.0,1.3.0)",
diff --git a/web/bundles/org.eclipse.jst.jsp.ui/pom.xml b/web/bundles/org.eclipse.jst.jsp.ui/pom.xml
index 1853cea..e03f542 100644
--- a/web/bundles/org.eclipse.jst.jsp.ui/pom.xml
+++ b/web/bundles/org.eclipse.jst.jsp.ui/pom.xml
@@ -21,6 +21,6 @@
 
   <groupId>org.eclipse.webtools.sourceediting</groupId>
   <artifactId>org.eclipse.jst.jsp.ui</artifactId>
-  <version>1.3.100-SNAPSHOT</version>
+  <version>1.3.200-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPCompletionProcessor.java b/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPCompletionProcessor.java
index e676272..c01e370 100644
--- a/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPCompletionProcessor.java
+++ b/web/bundles/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/contentassist/JSPCompletionProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -12,8 +12,8 @@
  *******************************************************************************/
 package org.eclipse.jst.jsp.ui.internal.contentassist;
 
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.Platform;
@@ -162,7 +162,7 @@
 	 */
 	private String debug(JSPTranslation translation) {
 		StringBuffer debugString = new StringBuffer();
-		HashMap jsp2java = translation.getJsp2JavaMap();
+		Map<Position,Position> jsp2java = translation.getJsp2JavaMap();
 		String javaText = translation.getJavaText();
 		String jspText = fViewer.getDocument().get();
 		debugString.append("[jsp2JavaMap in JSPCompletionProcessor]\r\n"); //$NON-NLS-1$
@@ -171,7 +171,7 @@
 		while (it.hasNext()) {
 			try {
 				Position jspPos = (Position) it.next();
-				Position javaPos = (Position) jsp2java.get(jspPos);
+				Position javaPos = jsp2java.get(jspPos);
 				debugString.append("jsp > " + jspPos.offset + ":" + jspPos.length + ":" + jspText.substring(jspPos.offset, jspPos.offset + jspPos.length) + ":\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 				debugString.append("java > " + javaPos.offset + ":" + javaPos.length + ":" + javaText.substring(javaPos.offset, javaPos.offset + javaPos.length) + ":\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 				debugString.append("-------------------------------------------------\n"); //$NON-NLS-1$
diff --git a/web/tests/org.eclipse.jst.jsp.core.tests/META-INF/MANIFEST.MF b/web/tests/org.eclipse.jst.jsp.core.tests/META-INF/MANIFEST.MF
index 39e1454..178c869 100644
--- a/web/tests/org.eclipse.jst.jsp.core.tests/META-INF/MANIFEST.MF
+++ b/web/tests/org.eclipse.jst.jsp.core.tests/META-INF/MANIFEST.MF
@@ -22,8 +22,8 @@
  org.eclipse.jst.jsp.css.core.tests.source,
  org.eclipse.jst.jsp.css.core.tests.testfiles,
  org.eclipse.jst.jsp.css.core.tests.testfiles.results
-Require-Bundle: javax.servlet,
- javax.servlet.jsp,
+Require-Bundle: javax.servlet;resolution:=optional,
+ javax.servlet.jsp;resolution:=optional,
  org.junit;bundle-version="[3.8.2,5.0.0)",
  org.eclipse.pde.core,
  org.eclipse.update.configurator,
@@ -42,6 +42,8 @@
  org.eclipse.wst.validation,
  org.eclipse.jdt.core,
  org.eclipse.wst.sse.ui
+Import-Package: jakarta.servlet; resolution:=optional,
+ jakarta.servlet.http; resolution:=optional
 Eclipse-LazyStart: true
 Bundle-ActivationPolicy: lazy
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
diff --git a/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/translation/JSPJavaTranslatorCoreTest.java b/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/translation/JSPJavaTranslatorCoreTest.java
index 700f945..0886e11 100644
--- a/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/translation/JSPJavaTranslatorCoreTest.java
+++ b/web/tests/org.eclipse.jst.jsp.core.tests/src/org/eclipse/jst/jsp/core/tests/translation/JSPJavaTranslatorCoreTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2018 IBM Corporation and others.
+ * Copyright (c) 2006, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -36,8 +36,12 @@
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jst.jsp.core.internal.JSPCorePlugin;
+import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache;
+import org.eclipse.jst.jsp.core.internal.contenttype.ServletAPIDescriptor;
 import org.eclipse.jst.jsp.core.internal.java.IJSPProblem;
 import org.eclipse.jst.jsp.core.internal.java.IJSPTranslation;
 import org.eclipse.jst.jsp.core.internal.java.JSPTranslation;
@@ -443,6 +447,55 @@
 				model.releaseFromEdit();
 		}
 	}
+	
+	public void testApiDetection1() throws Exception {
+		String testName = "testapidetection1";
+		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(testName);
+		synchronized (creationLock) {
+			if (!project.isAccessible()) {
+				// Create new project
+				project = BundleResourceUtil.createSimpleProject(testName, null, new String[] {JavaCore.NATURE_ID, "org.eclipse.pde.PluginNature"});
+				assertTrue(project.exists());
+				BundleResourceUtil.copyBundleEntriesIntoWorkspace("/testfiles/" + testName, "/" + testName);
+			}
+		}
+		ServletAPIDescriptor servletAPIVersion = DeploymentDescriptorPropertyCache.getInstance().getServletAPIVersion(project);
+		assertNotNull("no API version was detected", servletAPIVersion);
+		IClasspathEntry[] resolvedClasspath = JavaCore.create(project).getResolvedClasspath(true);
+		StringBuilder builder = new StringBuilder();
+		for (int i = 0; i < resolvedClasspath.length; i++) {
+			builder.append('\n');
+			builder.append(resolvedClasspath[i].getPath());
+		}
+		assertFalse("Default API version returned, nothing was detected\n" + builder, servletAPIVersion == ServletAPIDescriptor.DEFAULT);
+		assertEquals("Unexpected API version", 3.1f, servletAPIVersion.getAPIversion());
+		assertEquals("Unexpected root package", "javax.servlet", servletAPIVersion.getRootPackage());
+	}
+
+	// TODO: enable this test
+	public void testApiDetection2() throws Exception {
+		String testName = "testapidetection2";
+		IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(testName);
+		synchronized (creationLock) {
+			if (!project.isAccessible()) {
+				// Create new project
+				project = BundleResourceUtil.createSimpleProject(testName, null, new String[] {JavaCore.NATURE_ID, "org.eclipse.pde.PluginNature"});
+				assertTrue(project.exists());
+				BundleResourceUtil.copyBundleEntriesIntoWorkspace("/testfiles/" + testName, "/" + testName);
+			}
+		}
+		ServletAPIDescriptor servletAPIVersion = DeploymentDescriptorPropertyCache.getInstance().getServletAPIVersion(project);
+		assertNotNull("no API version was detected", servletAPIVersion);
+		IClasspathEntry[] resolvedClasspath = JavaCore.create(project).getResolvedClasspath(true);
+		StringBuilder builder = new StringBuilder();
+		for (int i = 0; i < resolvedClasspath.length; i++) {
+			builder.append('\n');
+			builder.append(resolvedClasspath[i].getPath());
+		}
+//		assertFalse("Default API version returned, nothing was detected\n" + builder, servletAPIVersion == ServletAPIDescriptor.DEFAULT);
+//		assertEquals("Unexpected API version", 3.1f, servletAPIVersion.getAPIversion());
+//		assertEquals("Unexpected root package", "javax.servlet", servletAPIVersion.getRootPackage());
+	}
 
 	public void test_codas() throws Exception {
 		String testName = "testPreludeAndCodas";
diff --git a/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testapidetection1/META-INF/MANIFEST.MF b/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testapidetection1/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..c613d16
--- /dev/null
+++ b/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testapidetection1/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: testapidetection1
+Bundle-SymbolicName: testapidetection1;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Import-Package: javax.servlet,
+ javax.servlet.http
+ 
\ No newline at end of file
diff --git a/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testapidetection2/META-INF/MANIFEST.MF b/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testapidetection2/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b00403b
--- /dev/null
+++ b/web/tests/org.eclipse.jst.jsp.core.tests/testfiles/testapidetection2/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: testapidetection1
+Bundle-SymbolicName: testapidetection1;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Import-Package: jakarta.servlet,
+ jakarta.servlet.http
+ 
\ No newline at end of file
diff --git a/web/tests/org.eclipse.jst.jsp.ui.tests/src/org/eclipse/jst/jsp/ui/tests/contentassist/JSPTranslationTest.java b/web/tests/org.eclipse.jst.jsp.ui.tests/src/org/eclipse/jst/jsp/ui/tests/contentassist/JSPTranslationTest.java
index 6f36788..8cd34cc 100644
--- a/web/tests/org.eclipse.jst.jsp.ui.tests/src/org/eclipse/jst/jsp/ui/tests/contentassist/JSPTranslationTest.java
+++ b/web/tests/org.eclipse.jst.jsp.ui.tests/src/org/eclipse/jst/jsp/ui/tests/contentassist/JSPTranslationTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2017 IBM Corporation and others.
+ * Copyright (c) 2006, 2020 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
@@ -17,6 +17,7 @@
 import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import junit.framework.TestCase;
 
@@ -174,10 +175,10 @@
 		JSPTranslationAdapter adapter = (JSPTranslationAdapter) model.getDocument().getAdapterFor(IJSPTranslation.class);
 		JSPTranslation translation = adapter.getJSPTranslation();
 		try {
-			HashMap java2jsp = translation.getJava2JspMap();
+			Map<Position, Position> java2jsp = translation.getJava2JspMap();
 			assertEquals("java2jsp map size:", 11, java2jsp.size());
 
-			HashMap jsp2java = translation.getJsp2JavaMap();
+			Map<Position, Position> jsp2java = translation.getJsp2JavaMap();
 			assertEquals("jsp2java map size:", 3, jsp2java.size());
 
 			// some test positions (out.print("" + | );)
@@ -304,13 +305,13 @@
 			JSPTranslationAdapter adapter = (JSPTranslationAdapter) sModel.getDocument().getAdapterFor(IJSPTranslation.class);
 			JSPTranslation translation = adapter.getJSPTranslation();
 			
-			HashMap jsp2java = translation.getJsp2JavaMap();
+			Map<Position, Position> jsp2java = translation.getJsp2JavaMap();
 			Object[] jspRanges = jsp2java.keySet().toArray();
 			Position jspPos = null;
 			Position javaPos = null;
 			for (int i = 0; i < jspRanges.length; i++) {
 				jspPos = (Position)jspRanges[i];
-				javaPos = (Position)jsp2java.get(jspPos);
+				javaPos = jsp2java.get(jspPos);
 				//System.out.println("jsp:" + printPos(jspPos) + " >> java:" + printPos(javaPos));
 				checkPosition(jspPos, javaPos);
 			}