Merge remote-tracking branch 'origin/R4_7_maintenance' into BETA_JUNIT5
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java
index 70b3842..7f6829e 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/JavaModelUtil.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
@@ -449,6 +449,19 @@
 	 * @throws JavaModelException thrown when the type can not be accessed
 	 */
 	public static String getResolvedTypeName(String refTypeSig, IType declaringType) throws JavaModelException {
+		return getResolvedTypeName(refTypeSig, declaringType, '.');
+	}
+
+	/**
+	 * Resolves a type name in the context of the declaring type.
+	 *
+	 * @param refTypeSig the type name in signature notation (for example 'QVector') this can also be an array type, but dimensions will be ignored.
+	 * @param declaringType the context for resolving (type where the reference was made in)
+	 * @param enclosingTypeSeparator the enclosing type separator used in the qualified type name 
+	 * @return returns the fully qualified type name or build-in-type name. if a unresolved type couldn't be resolved null is returned
+	 * @throws JavaModelException thrown when the type can not be accessed
+	 */
+	public static String getResolvedTypeName(String refTypeSig, IType declaringType, char enclosingTypeSeparator) throws JavaModelException {
 		int arrayCount= Signature.getArrayCount(refTypeSig);
 		char type= refTypeSig.charAt(arrayCount);
 		if (type == Signature.C_UNRESOLVED) {
@@ -465,7 +478,7 @@
 			}
 			String[][] resolvedNames= declaringType.resolveType(name);
 			if (resolvedNames != null && resolvedNames.length > 0) {
-				return JavaModelUtil.concatenateName(resolvedNames[0][0], resolvedNames[0][1]);
+				return JavaModelUtil.concatenateName(resolvedNames[0][0], resolvedNames[0][1].replace('.', enclosingTypeSeparator));
 			}
 			return null;
 		} else {
diff --git a/org.eclipse.jdt.junit.core/.settings/.api_filters b/org.eclipse.jdt.junit.core/.settings/.api_filters
new file mode 100644
index 0000000..6f01440
--- /dev/null
+++ b/org.eclipse.jdt.junit.core/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jdt.junit.core" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter comment="keep the same version as in 4.7.1 for now" id="924844039">
+            <message_arguments>
+                <message_argument value="3.9.0"/>
+                <message_argument value="3.9.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jdt.junit.core/plugin.properties b/org.eclipse.jdt.junit.core/plugin.properties
index 3949667..8ab213a 100644
--- a/org.eclipse.jdt.junit.core/plugin.properties
+++ b/org.eclipse.jdt.junit.core/plugin.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2009 IBM Corporation and others.
+# Copyright (c) 2000, 2016 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
@@ -67,6 +67,7 @@
 
 testKind.junit3 = JUnit 3
 testKind.junit4 = JUnit 4
+testKind.junit5 = JUnit 5
 
 JUnitContainerName = JUnit
 
diff --git a/org.eclipse.jdt.junit.core/plugin.xml b/org.eclipse.jdt.junit.core/plugin.xml
index 5352552..9c83c9b 100644
--- a/org.eclipse.jdt.junit.core/plugin.xml
+++ b/org.eclipse.jdt.junit.core/plugin.xml
@@ -93,7 +93,18 @@
          <runtimeClasspathEntry pluginId="org.eclipse.jdt.junit.runtime"/>     	
       </kind>
    </extension>
-   
+      <extension
+         point="org.eclipse.jdt.junit.internal_testKinds">
+      <kind
+            id="org.eclipse.jdt.junit.loader.junit5"
+            displayName="%testKind.junit5"
+            finderClass="org.eclipse.jdt.internal.junit.launcher.JUnit5TestFinder"
+            loaderPluginId="org.eclipse.jdt.junit5.runtime"
+            loaderClass="org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader">
+         <runtimeClasspathEntry pluginId="org.eclipse.jdt.junit5.runtime" />
+         <runtimeClasspathEntry pluginId="org.eclipse.jdt.junit.runtime" />
+      </kind>
+   </extension>
    <extension
          point="org.eclipse.core.contenttype.contentTypes">
       <content-type
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitCorePlugin.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitCorePlugin.java
index 60aab7a..372b279 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitCorePlugin.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitCorePlugin.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
@@ -61,6 +61,9 @@
 	public final static String TEST_SUPERCLASS_NAME= "junit.framework.TestCase"; //$NON-NLS-1$
 	public final static String TEST_INTERFACE_NAME= "junit.framework.Test"; //$NON-NLS-1$
 
+	public final static String JUNIT5_TESTABLE_ANNOTATION_NAME= "org.junit.platform.commons.annotation.Testable"; //$NON-NLS-1$
+	public final static String JUNIT5_JUPITER_TEST_ANNOTATION_NAME= "org.junit.jupiter.api.Test"; //$NON-NLS-1$
+
 	public final static String JUNIT4_ANNOTATION_NAME= "org.junit.Test"; //$NON-NLS-1$
 	public static final String SIMPLE_TEST_INTERFACE_NAME= "Test"; //$NON-NLS-1$
 
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.java
index 5574265..cc6876b 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -19,16 +19,22 @@
 
 	public static String JUnit4TestFinder_searching_description;
 
+	public static String JUnit5TestFinder_searching_description;
+
 	public static String JUnitContainerInitializer_description_initializer_junit3;
 
 	public static String JUnitContainerInitializer_description_initializer_junit4;
 
+	public static String JUnitContainerInitializer_description_initializer_junit5;
+
 	public static String JUnitContainerInitializer_description_initializer_unresolved;
 
 	public static String JUnitContainerInitializer_description_junit3;
 
 	public static String JUnitContainerInitializer_description_junit4;
 
+	public static String JUnitContainerInitializer_description_junit5;
+
 	public static String JUnitLaunchConfigurationDelegate_create_source_locator_description;
 
 	public static String JUnitLaunchConfigurationDelegate_error_input_element_deosn_not_exist;
@@ -37,6 +43,8 @@
 
 	public static String JUnitLaunchConfigurationDelegate_error_junit4notonpath;
 
+	public static String JUnitLaunchConfigurationDelegate_error_junit5notonpath;
+
 	public static String JUnitLaunchConfigurationDelegate_error_junitnotonpath;
 
 	public static String JUnitLaunchConfigurationDelegate_error_no_socket;
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.properties b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.properties
index 4824c19..ef93b3b 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.properties
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2013 IBM Corporation and others.
+# Copyright (c) 2000, 2016 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -10,10 +10,13 @@
 ###############################################################################
 TestSearchEngine_message_searching=Searching for tests and suites...
 JUnit4TestFinder_searching_description=Searching for JUnit 4 tests...
+JUnit5TestFinder_searching_description=Searching for JUnit 5 tests...
 JUnitContainerInitializer_description_junit3=JUnit 3
 JUnitContainerInitializer_description_junit4=JUnit 4
+JUnitContainerInitializer_description_junit5=JUnit 5
 JUnitContainerInitializer_description_initializer_junit3=JUnit 3
 JUnitContainerInitializer_description_initializer_junit4=JUnit 4
+JUnitContainerInitializer_description_initializer_junit5=JUnit 5
 JUnitContainerInitializer_description_initializer_unresolved=Unresolved JUnit container
 JUnitLaunchConfigurationDelegate_verifying_attriburtes_description=Verifying launch attributes...
 JUnitLaunchConfigurationDelegate_create_source_locator_description=Creating source locator...
@@ -21,6 +24,7 @@
 JUnitLaunchConfigurationDelegate_error_invalidproject=Invalid project specified.
 JUnitLaunchConfigurationDelegate_error_junitnotonpath=Cannot find 'junit.framework.TestCase' on project build path. JUnit 3 tests can only be run if JUnit is on the build path.
 JUnitLaunchConfigurationDelegate_error_junit4notonpath=Cannot find 'org.junit.Test' on project build path. JUnit 4 tests can only be run if JUnit 4 is on the build path.
+JUnitLaunchConfigurationDelegate_error_junit5notonpath=Cannot find ''{0}'' on project build path. JUnit 5 tests can only be run if JUnit 5 is on the build path.
 JUnitLaunchConfigurationDelegate_error_notests_kind=No tests found with test runner ''{0}''.
 JUnitLaunchConfigurationDelegate_error_wrong_input=Can only run types or single method
 JUnitLaunchConfigurationDelegate_error_input_element_deosn_not_exist=The input element of the launch configuration does not exist
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.java
index 7825603..55a028a 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.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
@@ -75,11 +75,71 @@
 	 * Javadoc location for org.hamcrest.core (JUnit 4)
 	 */
 	public static final String HAMCREST_CORE_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit4.hamcrest.core.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.jupiter.api (JUnit 5)
+	 */
+	public static final String JUNIT_JUPITER_API_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.jupiter.api.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.jupiter.engine (JUnit 5)
+	 */
+	public static final String JUNIT_JUPITER_ENGINE_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.jupiter.engine.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.jupiter.migrationsupport (JUnit 5)
+	 */
+	public static final String JUNIT_JUPITER_MIGRATIONSUPPORT_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.jupiter.migrationsupport.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.jupiter.params (JUnit 5)
+	 */
+	public static final String JUNIT_JUPITER_PARAMS_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.jupiter.params.javadoclocation"; //$NON-NLS-1$
 	
+	/**
+	 * Javadoc location for org.junit.platform.commons (JUnit 5)
+	 */
+	public static final String JUNIT_PLATFORM_COMMONS_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.platform.commons.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.platform.engine (JUnit 5)
+	 */
+	public static final String JUNIT_PLATFORM_ENGINE_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.platform.engine.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.platform.launcher (JUnit 5)
+	 */
+	public static final String JUNIT_PLATFORM_LAUNCHER_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.platform.launcher.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.platform.runner (JUnit 5)
+	 */
+	public static final String JUNIT_PLATFORM_RUNNER_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.platform.runner.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.platform.suite.api (JUnit 5)
+	 */
+	public static final String JUNIT_PLATFORM_SUITE_API_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.platform.suite.api.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.junit.vintage.engine (JUnit 5)
+	 */
+	public static final String JUNIT_VINTAGE_ENGINE_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.vintage.engine.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.opentest4j (JUnit 5)
+	 */
+	public static final String JUNIT_OPENTEST4J_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.opentest4j.javadoclocation"; //$NON-NLS-1$
+
+	/**
+	 * Javadoc location for org.apiguardian (JUnit 5)
+	 */
+	public static final String JUNIT_APIGUARDIAN_JAVADOC= JUnitCorePlugin.PLUGIN_ID + ".junit5.apiguardian.javadoclocation"; //$NON-NLS-1$
 
 	private static final String[] fgDefaultFilterPatterns= new String[] {
 		"org.eclipse.jdt.internal.junit.runner.*", //$NON-NLS-1$
 		"org.eclipse.jdt.internal.junit4.runner.*", //$NON-NLS-1$
+		"org.eclipse.jdt.internal.junit5.runner.*", //$NON-NLS-1$
 		"org.eclipse.jdt.internal.junit.ui.*", //$NON-NLS-1$
 		"junit.framework.TestCase", //$NON-NLS-1$
 		"junit.framework.TestResult", //$NON-NLS-1$
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java
index c4dfaf9..1e6ddd9 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java
@@ -13,12 +13,9 @@
 
 import java.util.List;
 
-import org.osgi.service.prefs.BackingStoreException;
-
 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
 import org.eclipse.core.runtime.preferences.DefaultScope;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.InstanceScope;
 
 /**
  * Default preference value initialization for the
@@ -46,25 +43,19 @@
 		prefs.put(JUnitPreferencesConstants.JUNIT3_JAVADOC, "http://junit.sourceforge.net/junit3.8.1/javadoc/"); //$NON-NLS-1$
 		prefs.put(JUnitPreferencesConstants.JUNIT4_JAVADOC, "http://junit.org/junit4/javadoc/latest/"); //$NON-NLS-1$
 		prefs.put(JUnitPreferencesConstants.HAMCREST_CORE_JAVADOC, "http://hamcrest.org/JavaHamcrest/javadoc/1.3/"); //$NON-NLS-1$
-		
-		// migrate old instance scope prefs
-		try {
-			IEclipsePreferences newInstancePrefs= InstanceScope.INSTANCE.getNode(JUnitCorePlugin.CORE_PLUGIN_ID);
-			
-			if (newInstancePrefs.keys().length == 0) {
-				IEclipsePreferences oldInstancePrefs= InstanceScope.INSTANCE.getNode(JUnitCorePlugin.PLUGIN_ID);
-				
-				String[] oldKeys= oldInstancePrefs.keys();
-				for (int i= 0; i < oldKeys.length; i++ ) {
-					String key= oldKeys[i];
-					newInstancePrefs.put(key, oldInstancePrefs.get(key, null));
-					oldInstancePrefs.remove(key);
-				}
-				newInstancePrefs.flush();
-				oldInstancePrefs.flush();
-			}
-		} catch (BackingStoreException e) {
-			JUnitCorePlugin.log(e);
-		}
+
+		String junit5JavadocLocation= "http://junit.org/junit5/docs/current/api/"; //$NON-NLS-1$
+		prefs.put(JUnitPreferencesConstants.JUNIT_JUPITER_API_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_JUPITER_ENGINE_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_JUPITER_MIGRATIONSUPPORT_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_JUPITER_PARAMS_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_PLATFORM_COMMONS_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_PLATFORM_ENGINE_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_PLATFORM_LAUNCHER_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_PLATFORM_RUNNER_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_PLATFORM_SUITE_API_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_VINTAGE_ENGINE_JAVADOC, junit5JavadocLocation);
+		prefs.put(JUnitPreferencesConstants.JUNIT_OPENTEST4J_JAVADOC, "http://ota4j-team.github.io/opentest4j/docs/current/api/"); //$NON-NLS-1$
+		prefs.put(JUnitPreferencesConstants.JUNIT_APIGUARDIAN_JAVADOC, "https://apiguardian-team.github.io/apiguardian/docs/current/api/"); //$NON-NLS-1$
 	}
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java
index ec56d12..f8f219b 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/BuildPathSupport.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
@@ -205,6 +205,54 @@
 	private static final JUnitPluginDescription HAMCREST_CORE_PLUGIN= new JUnitPluginDescription(
 			"org.hamcrest.core", new VersionRange("[1.1.0,2.0.0)"), null, "org.hamcrest.core_1.*.jar", "org.hamcrest.core.source", "source-bundle/", JUnitPreferencesConstants.HAMCREST_CORE_JAVADOC); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
 
+	public static final JUnitPluginDescription JUNIT_JUPITER_API_PLUGIN= new JUnitPluginDescription(
+			"org.junit.jupiter.api", new VersionRange("[5.0.0,6.0.0)"), "org.junit.jupiter.api.jar", "", "org.junit.jupiter.api.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_JUPITER_API_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_JUPITER_ENGINE_PLUGIN= new JUnitPluginDescription(
+			"org.junit.jupiter.engine", new VersionRange("[5.0.0,6.0.0)"), "org.junit.jupiter.engine.jar", "", "org.junit.jupiter.engine.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_JUPITER_ENGINE_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_JUPITER_MIGRATIONSUPPORT_PLUGIN= new JUnitPluginDescription(
+			"org.junit.jupiter.migrationsupport", new VersionRange("[5.0.0,6.0.0)"), "org.junit.jupiter.migrationsupport.jar", "", "org.junit.jupiter.migrationsupport.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_JUPITER_MIGRATIONSUPPORT_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_JUPITER_PARAMS_PLUGIN= new JUnitPluginDescription(
+			"org.junit.jupiter.params", new VersionRange("[5.0.0,6.0.0)"), "org.junit.jupiter.params.jar", "", "org.junit.jupiter.params.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_JUPITER_PARAMS_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_PLATFORM_COMMONS_PLUGIN= new JUnitPluginDescription(
+			"org.junit.platform.commons", new VersionRange("[1.0.0,2.0.0)"), "org.junit.platform.commons.jar", "", "org.junit.platform.commons.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_PLATFORM_COMMONS_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_PLATFORM_ENGINE_PLUGIN= new JUnitPluginDescription(
+			"org.junit.platform.engine", new VersionRange("[1.0.0,2.0.0)"), "org.junit.platform.engine.jar", "", "org.junit.platform.engine.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_PLATFORM_ENGINE_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_PLATFORM_LAUNCHER_PLUGIN= new JUnitPluginDescription(
+			"org.junit.platform.launcher", new VersionRange("[1.0.0,2.0.0)"), "org.junit.platform.launcher.jar", "", "org.junit.platform.launcher.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_PLATFORM_LAUNCHER_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_PLATFORM_RUNNER_PLUGIN= new JUnitPluginDescription(
+			"org.junit.platform.runner", new VersionRange("[1.0.0,2.0.0)"), "org.junit.platform.runner.jar", "", "org.junit.platform.runner.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_PLATFORM_RUNNER_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_PLATFORM_SUITE_API_PLUGIN= new JUnitPluginDescription(
+			"org.junit.platform.suite.api", new VersionRange("[1.0.0,2.0.0)"), "org.junit.platform.suite.api.jar", "", "org.junit.platform.suite.api.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_PLATFORM_SUITE_API_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_VINTAGE_ENGINE_PLUGIN= new JUnitPluginDescription(
+			"org.junit.vintage.engine", new VersionRange("[4.12.0,5.0.0)"), "org.junit.vintage.engine.jar", "", "org.junit.vintage.engine.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_VINTAGE_ENGINE_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_OPENTEST4J_PLUGIN= new JUnitPluginDescription(
+			"org.opentest4j", new VersionRange("[1.0.0,2.0.0)"), "org.opentest4j.jar", "", "org.opentest4j.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_OPENTEST4J_JAVADOC);
+
+	public static final JUnitPluginDescription JUNIT_APIGUARDIAN_PLUGIN= new JUnitPluginDescription(
+			"org.apiguardian", new VersionRange("[1.0.0,2.0.0)"), "org.apiguardian.jar", "", "org.apiguardian.source", "", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$
+			JUnitPreferencesConstants.JUNIT_APIGUARDIAN_JAVADOC);
+
 	public static final JUnitPluginDescription JUNIT4_AS_3_PLUGIN= new JUnitPluginDescription(
 			JUNIT4_PLUGIN.bundleId, JUNIT4_PLUGIN.versionRange, JUNIT4_PLUGIN.bundleRoot, JUNIT4_PLUGIN.binaryImportedRoot,
 			JUNIT4_PLUGIN.sourceBundleId, JUNIT4_PLUGIN.repositorySource, JUNIT3_PLUGIN.javadocPreferenceKey) {
@@ -232,6 +280,13 @@
 	}
 
 	/**
+	 * @return the JUnit5 classpath container
+	 */
+	public static IClasspathEntry getJUnit5ClasspathEntry() {
+		return JavaCore.newContainerEntry(JUnitCore.JUNIT5_CONTAINER_PATH);
+	}
+
+	/**
 	 * @return the org.junit version 3 library, or <code>null</code> if not available
 	 */
 	public static IClasspathEntry getJUnit3LibraryEntry() {
@@ -246,7 +301,8 @@
 	}
 
 	/**
-	 * @return the org.junit version 4 library with access rules for JUnit 3, or <code>null</code> if not available
+	 * @return the org.junit version 4 library with access rules for JUnit 3, or <code>null</code>
+	 *         if not available
 	 */
 	public static IClasspathEntry getJUnit4as3LibraryEntry() {
 		return JUNIT4_AS_3_PLUGIN.getLibraryEntry();
@@ -259,4 +315,87 @@
 		return HAMCREST_CORE_PLUGIN.getLibraryEntry();
 	}
 
+	/**
+	 * @return the org.junit.jupiter.api library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitJupiterApiLibraryEntry() {
+		return JUNIT_JUPITER_API_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.jupiter.engine library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitJupiterEngineLibraryEntry() {
+		return JUNIT_JUPITER_ENGINE_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.jupiter.migrationsupport library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitJupiterMigrationSupportLibraryEntry() {
+		return JUNIT_JUPITER_MIGRATIONSUPPORT_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.jupiter.params library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitJupiterParamsLibraryEntry() {
+		return JUNIT_JUPITER_PARAMS_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.platform.commons library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitPlatformCommonsLibraryEntry() {
+		return JUNIT_PLATFORM_COMMONS_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.platform.engine library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitPlatformEngineLibraryEntry() {
+		return JUNIT_PLATFORM_ENGINE_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.platform.launcher library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitPlatformLauncherLibraryEntry() {
+		return JUNIT_PLATFORM_LAUNCHER_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.platform.runner library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitPlatformRunnerLibraryEntry() {
+		return JUNIT_PLATFORM_RUNNER_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.platform.suite.api library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitPlatformSuiteApiLibraryEntry() {
+		return JUNIT_PLATFORM_SUITE_API_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.junit.vintage.engine library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitVintageEngineLibraryEntry() {
+		return JUNIT_VINTAGE_ENGINE_PLUGIN.getLibraryEntry();
+	}
+	
+	/**
+	 * @return the org.opentest4j library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitOpentest4jLibraryEntry() {
+		return JUNIT_OPENTEST4J_PLUGIN.getLibraryEntry();
+	}
+
+	/**
+	 * @return the org.apiguardian library, or <code>null</code> if not available
+	 */
+	public static IClasspathEntry getJUnitApiGuardianLibraryEntry() {
+		return JUNIT_APIGUARDIAN_PLUGIN.getLibraryEntry();
+	}
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerInitializer.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerInitializer.java
index 5c781aa..19ab84b 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerInitializer.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -11,6 +11,7 @@
 package org.eclipse.jdt.internal.junit.buildpath;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import org.eclipse.jdt.junit.JUnitCore;
 
@@ -47,6 +48,7 @@
 	private final static String JUNIT3_8_1= "3.8.1"; //$NON-NLS-1$
 	private final static String JUNIT3= "3"; //$NON-NLS-1$
 	private final static String JUNIT4= "4"; //$NON-NLS-1$
+	private final static String JUNIT5= "5"; //$NON-NLS-1$
 
 	private static class JUnitContainer implements IClasspathContainer {
 
@@ -65,6 +67,9 @@
 
 		@Override
 		public String getDescription() {
+			if (JUnitCore.JUNIT5_CONTAINER_PATH.equals(fPath)) {
+				return JUnitMessages.JUnitContainerInitializer_description_junit5;
+			}
 			if (JUnitCore.JUNIT4_CONTAINER_PATH.equals(fPath)) {
 				return JUnitMessages.JUnitContainerInitializer_description_junit4;
 			}
@@ -97,6 +102,7 @@
 	}
 
 	private static JUnitContainer getNewContainer(IPath containerPath) {
+		List<IClasspathEntry> entriesList= new ArrayList<>();
 		IClasspathEntry entry= null;
 		IClasspathEntry entry2= null;
 		String version= containerPath.segment(1);
@@ -108,9 +114,26 @@
 		} else if (JUNIT4.equals(version)) {
 			entry= BuildPathSupport.getJUnit4LibraryEntry();
 			entry2= BuildPathSupport.getHamcrestCoreLibraryEntry();
+		} else if (JUNIT5.equals(version)) {
+			entriesList.add(BuildPathSupport.getJUnitJupiterApiLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitJupiterEngineLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitJupiterMigrationSupportLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitJupiterParamsLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitPlatformCommonsLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitPlatformEngineLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitPlatformLauncherLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitPlatformRunnerLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitPlatformSuiteApiLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitVintageEngineLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitOpentest4jLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnitApiGuardianLibraryEntry());
+			entriesList.add(BuildPathSupport.getJUnit4LibraryEntry());
+			entriesList.add(BuildPathSupport.getHamcrestCoreLibraryEntry());
 		}
 		IClasspathEntry[] entries;
-		if (entry == null) {
+		if (!entriesList.isEmpty() ) {
+			entries= entriesList.toArray(new IClasspathEntry[entriesList.size()]);
+		} else if (entry == null) {
 			entries= new IClasspathEntry[] { };
 		} else if (entry2 == null) {
 			entries= new IClasspathEntry[] { entry };
@@ -195,11 +218,44 @@
 	private String getPreferenceKey(IClasspathEntry entry, String version) {
 		if (JUNIT3.equals(version)) {
 			return JUnitPreferencesConstants.JUNIT3_JAVADOC;
-		} else if (JUNIT4.equals(version)) {
-			if (entry.getPath().lastSegment().indexOf("junit") != -1) { //$NON-NLS-1$
-				return JUnitPreferencesConstants.JUNIT4_JAVADOC;
-			} else {
-				return JUnitPreferencesConstants.HAMCREST_CORE_JAVADOC;
+		} else {
+			String lastSegment= entry.getPath().lastSegment();
+			if (JUNIT4.equals(version)) {
+				if (lastSegment.indexOf("junit") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT4_JAVADOC;
+				} else {
+					return JUnitPreferencesConstants.HAMCREST_CORE_JAVADOC;
+				}
+			} else if (JUNIT5.equals(version)) {
+				if (lastSegment.indexOf("jupiter.api") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_JUPITER_API_JAVADOC;
+				} else if (lastSegment.indexOf("jupiter.engine") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_JUPITER_ENGINE_JAVADOC;
+				} else if (lastSegment.indexOf("jupiter.migrationsupport") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_JUPITER_MIGRATIONSUPPORT_JAVADOC;
+				} else if (lastSegment.indexOf("jupiter.params") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_JUPITER_PARAMS_JAVADOC;
+				} else if (lastSegment.indexOf("platform.commons") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_PLATFORM_COMMONS_JAVADOC;
+				} else if (lastSegment.indexOf("platform.engine") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_PLATFORM_ENGINE_JAVADOC;
+				} else if (lastSegment.indexOf("platform.launcher") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_PLATFORM_LAUNCHER_JAVADOC;
+				} else if (lastSegment.indexOf("platform.runner") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_PLATFORM_RUNNER_JAVADOC;
+				} else if (lastSegment.indexOf("platform.suite.api") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_PLATFORM_SUITE_API_JAVADOC;
+				} else if (lastSegment.indexOf("vintage.engine") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_VINTAGE_ENGINE_JAVADOC;
+				} else if (lastSegment.indexOf("opentest4j") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_OPENTEST4J_JAVADOC;
+				} else if (lastSegment.indexOf("apiguardian") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT_APIGUARDIAN_JAVADOC;
+				} else if (lastSegment.indexOf("junit") != -1) { //$NON-NLS-1$
+					return JUnitPreferencesConstants.JUNIT4_JAVADOC;
+				} else {
+					return JUnitPreferencesConstants.HAMCREST_CORE_JAVADOC;
+				}
 			}
 		}
 		return null;
@@ -240,6 +296,8 @@
 				return JUnitMessages.JUnitContainerInitializer_description_initializer_junit3;
 			} else if (JUNIT4.equals(version)) {
 				return JUnitMessages.JUnitContainerInitializer_description_initializer_junit4;
+			} else if (JUNIT5.equals(version)) {
+				return JUnitMessages.JUnitContainerInitializer_description_initializer_junit5;
 			}
 		}
 		return JUnitMessages.JUnitContainerInitializer_description_initializer_unresolved;
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnit5TestFinder.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnit5TestFinder.java
new file mode 100644
index 0000000..2c0eb93
--- /dev/null
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnit5TestFinder.java
@@ -0,0 +1,260 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.junit.launcher;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IRegion;
+import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.ITypeHierarchy;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IAnnotationBinding;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.Modifier;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
+
+import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
+import org.eclipse.jdt.internal.junit.JUnitMessages;
+import org.eclipse.jdt.internal.junit.util.CoreTestSearchEngine;
+
+public class JUnit5TestFinder implements ITestFinder {
+
+	private static class Annotation {
+
+		private static final Annotation RUN_WITH= new Annotation("org.junit.runner.RunWith"); //$NON-NLS-1$
+
+		private static final Annotation TEST_4= new Annotation("org.junit.Test"); //$NON-NLS-1$
+
+		private static final Annotation TESTABLE= new Annotation(JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME);
+
+		private final String fName;
+
+		private Annotation(String name) {
+			fName= name;
+		}
+
+		public String getName() {
+			return fName;
+		}
+
+		public boolean annotatesTypeOrSuperTypes(ITypeBinding type) {
+			while (type != null) {
+				if (annotates(type.getAnnotations())) {
+					return true;
+				}
+				type= type.getSuperclass();
+			}
+			return false;
+		}
+
+		public boolean annotatesAtLeastOneMethod(ITypeBinding type) {
+			if (type == null) {
+				return false;
+			}
+			if (annotatesDeclaredMethods(type)) {
+				return true;
+			}
+			ITypeBinding superClass= type.getSuperclass();
+			if (annotatesAtLeastOneMethod(superClass)) {
+				return true;
+			}
+			ITypeBinding[] interfaces= type.getInterfaces();
+			for (int i= 0; i < interfaces.length; i++) {
+				if (annotatesAtLeastOneMethod(interfaces[i])) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean annotatesDeclaredMethods(ITypeBinding type) {
+			IMethodBinding[] declaredMethods= type.getDeclaredMethods();
+			for (int i= 0; i < declaredMethods.length; i++) {
+				IMethodBinding curr= declaredMethods[i];
+				if (annotates(curr.getAnnotations())) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		// See JUnitLaunchConfigurationTab#isAnnotatedWithTestable also.
+		private boolean annotates(IAnnotationBinding[] annotations) {
+			for (IAnnotationBinding annotation : annotations) {
+				if (annotation == null) {
+					continue;
+				}
+				if (matchesName(annotation.getAnnotationType())) {
+					return true;
+				}
+				if (TESTABLE.getName().equals(fName)) {
+					Set<ITypeBinding> hierarchy= new HashSet<>();
+					if (matchesNameInAnnotationHierarchy(annotation, hierarchy)) {
+						return true;
+					}
+				}
+			}
+			return false;
+		}
+
+		private boolean matchesName(ITypeBinding annotationType) {
+			if (annotationType != null) {
+				String qualifiedName= annotationType.getQualifiedName();
+				if (qualifiedName.equals(fName)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		private boolean matchesNameInAnnotationHierarchy(IAnnotationBinding annotation, Set<ITypeBinding> hierarchy) {
+			ITypeBinding type= annotation.getAnnotationType();
+			if (type != null) {
+				for (IAnnotationBinding annotationBinding : type.getAnnotations()) {
+					if (annotationBinding != null) {
+						ITypeBinding annotationType= annotationBinding.getAnnotationType();
+						if (annotationType != null && hierarchy.add(annotationType)) {
+							if (matchesName(annotationType) || matchesNameInAnnotationHierarchy(annotationBinding, hierarchy)) {
+								return true;
+							}
+						}
+					}
+				}
+			}
+			return false;
+		}
+	}
+
+	@Override
+	public void findTestsInContainer(IJavaElement element, Set<IType> result, IProgressMonitor pm) throws CoreException {
+		if (element == null || result == null) {
+			throw new IllegalArgumentException();
+		}
+
+		if (element instanceof IType) {
+			IType type= (IType) element;
+			if (internalIsTest(type, pm)) {
+				result.add(type);
+				return;
+			}
+		}
+
+		if (pm == null)
+			pm= new NullProgressMonitor();
+
+		try {
+			pm.beginTask(JUnitMessages.JUnit5TestFinder_searching_description, 4);
+
+			IRegion region= CoreTestSearchEngine.getRegion(element);
+			ITypeHierarchy hierarchy= JavaCore.newTypeHierarchy(region, null, new SubProgressMonitor(pm, 1));
+			IType[] allClasses= hierarchy.getAllClasses();
+
+			// search for all types with references to RunWith and Test and all subclasses
+			for (IType type : allClasses) {
+				if (internalIsTest(type, pm) && region.contains(type)) {
+					addTypeAndSubtypes(type, result, hierarchy);
+				}
+			}
+
+			// add all classes implementing JUnit 3.8's Test interface in the region
+			IType testInterface= element.getJavaProject().findType(JUnitCorePlugin.TEST_INTERFACE_NAME);
+			if (testInterface != null) {
+				CoreTestSearchEngine.findTestImplementorClasses(hierarchy, testInterface, region, result);
+			}
+
+			//JUnit 4.3 can also run JUnit-3.8-style public static Test suite() methods:
+			CoreTestSearchEngine.findSuiteMethods(element, result, new SubProgressMonitor(pm, 1));
+		} finally {
+			pm.done();
+		}
+	}
+
+	private void addTypeAndSubtypes(IType type, Set<IType> result, ITypeHierarchy hierarchy) {
+		if (result.add(type)) {
+			IType[] subclasses= hierarchy.getSubclasses(type);
+			for (int i= 0; i < subclasses.length; i++) {
+				addTypeAndSubtypes(subclasses[i], result, hierarchy);
+			}
+		}
+	}
+
+	@Override
+	public boolean isTest(IType type) throws JavaModelException {
+		return internalIsTest(type, null);
+	}
+
+	private boolean internalIsTest(IType type, IProgressMonitor monitor) throws JavaModelException {
+		if (CoreTestSearchEngine.isAccessibleClass(type, TestKindRegistry.JUNIT5_TEST_KIND_ID)) {
+			if (CoreTestSearchEngine.hasSuiteMethod(type)) { // since JUnit 4.3.1
+				return true;
+			}
+			ASTParser parser= ASTParser.newParser(AST.JLS8);
+			if (type.getCompilationUnit() != null) {
+				parser.setSource(type.getCompilationUnit());
+			} else if (!isAvailable(type.getSourceRange())) { // class file with no source
+				parser.setProject(type.getJavaProject());
+				IBinding[] bindings= parser.createBindings(new IJavaElement[] { type }, monitor);
+				if (bindings.length == 1 && bindings[0] instanceof ITypeBinding) {
+					ITypeBinding binding= (ITypeBinding) bindings[0];
+					return isTest(binding);
+				}
+				return false;
+			} else {
+				parser.setSource(type.getClassFile());
+			}
+			parser.setFocalPosition(0);
+			parser.setResolveBindings(true);
+			CompilationUnit root= (CompilationUnit) parser.createAST(monitor);
+			ASTNode node= root.findDeclaringNode(type.getKey());
+			if (node instanceof TypeDeclaration) {
+				ITypeBinding binding= ((TypeDeclaration) node).resolveBinding();
+				if (binding != null) {
+					return isTest(binding);
+				}
+			}
+		}
+		return false;
+
+	}
+
+	private static boolean isAvailable(ISourceRange range) {
+		return range != null && range.getOffset() != -1;
+	}
+
+
+	private boolean isTest(ITypeBinding binding) {
+		if (Modifier.isAbstract(binding.getModifiers()))
+			return false;
+
+		if (Annotation.RUN_WITH.annotatesTypeOrSuperTypes(binding)
+				|| Annotation.TEST_4.annotatesAtLeastOneMethod(binding)
+				|| Annotation.TESTABLE.annotatesAtLeastOneMethod(binding)
+				|| Annotation.TESTABLE.annotatesTypeOrSuperTypes(binding)) {
+			return true;
+		}
+		return CoreTestSearchEngine.isTestImplementor(binding);
+	}
+}
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnitLaunchConfigurationConstants.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnitLaunchConfigurationConstants.java
index c96848c..6999617 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnitLaunchConfigurationConstants.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/JUnitLaunchConfigurationConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 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
@@ -40,7 +40,8 @@
 	public static final String ATTR_PORT= JUnitCorePlugin.PLUGIN_ID+".PORT"; //$NON-NLS-1$
 
 	/**
-	 * The test name, or "" iff running the whole test type.
+	 * The test method name (followed by a comma-separated list of fully qualified parameter type
+	 * names in parentheses, if exists), or "" iff running the whole test type.
 	 */
 	public static final String ATTR_TEST_NAME= JUnitCorePlugin.PLUGIN_ID + ".TESTNAME"; //$NON-NLS-1$
 
@@ -59,6 +60,11 @@
 
 	public static final String ATTR_TEST_RUNNER_KIND= JUnitCorePlugin.PLUGIN_ID+".TEST_KIND"; //$NON-NLS-1$
 
+	/**
+	 * The unique ID of test to run or "" if not available (applicable to JUnit 5 and above).
+	 */
+	public static final String ATTR_TEST_UNIQUE_ID= JUnitCorePlugin.PLUGIN_ID + ".TEST_UNIQUE_ID"; //$NON-NLS-1$
+
 	public static ITestKind getTestRunnerKind(ILaunchConfiguration launchConfiguration) {
 		try {
 			String loaderId = launchConfiguration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND, (String) null);
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/TestKindRegistry.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/TestKindRegistry.java
index 66d986b..70ff61d 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/TestKindRegistry.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/launcher/TestKindRegistry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2015 IBM Corporation and others.
+ * Copyright (c) 2006, 2016 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
@@ -33,6 +33,7 @@
 
 	public static final String JUNIT3_TEST_KIND_ID= "org.eclipse.jdt.junit.loader.junit3"; //$NON-NLS-1$
 	public static final String JUNIT4_TEST_KIND_ID= "org.eclipse.jdt.junit.loader.junit4"; //$NON-NLS-1$
+	public static final String JUNIT5_TEST_KIND_ID= "org.eclipse.jdt.junit.loader.junit5"; //$NON-NLS-1$
 
 	public static TestKindRegistry getDefault() {
 		if (fgRegistry != null)
@@ -107,8 +108,13 @@
 	public static String getContainerTestKindId(IJavaElement element) {
 		if (element != null) {
 			IJavaProject project= element.getJavaProject();
-			if (CoreTestSearchEngine.is50OrHigher(project) && CoreTestSearchEngine.hasTestAnnotation(project)) {
-				return JUNIT4_TEST_KIND_ID;
+			if (CoreTestSearchEngine.is50OrHigher(project)) {
+				if (CoreTestSearchEngine.is18OrHigher(project) && CoreTestSearchEngine.hasJUnit5TestAnnotation(project)) {
+					return JUNIT5_TEST_KIND_ID;
+				}
+				if (CoreTestSearchEngine.hasJUnit4TestAnnotation(project)) {
+					return JUNIT4_TEST_KIND_ID;
+				}
 			}
 		}
 		return JUNIT3_TEST_KIND_ID;
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/ITestRunListener2.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/ITestRunListener2.java
index a513ab0..63d1d06 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/ITestRunListener2.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/ITestRunListener2.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 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
@@ -69,18 +69,23 @@
 	public void testRunTerminated();
 
 	/**
-	 * Information about a member of the test suite that is about to be run. The
-	 * format of the string is:
+	 * Information about a member of the test suite that is about to be run. The format of the
+	 * string is:
 	 *
 	 * <pre>
-	 *  testId,testName,isSuite,testcount
+	 *  testId,testName,isSuite,testcount,isDynamicTest,parentId,displayName,parameterTypes,uniqueId
 	 *
 	 *  testId: a unique id for the test
 	 *  testName: the name of the test
 	 *  isSuite: true or false depending on whether the test is a suite
 	 *  testCount: an integer indicating the number of tests
-	 *
-	 *  Example: &quot;324968,testPass(junit.tests.MyTest),false,1&quot;
+	 *  isDynamicTest: true or false
+	 *  parentId: the unique testId of its parent if it is a dynamic test, otherwise can be "-1"
+	 *  displayName: the display name of the test
+	 *  parameterTypes: comma-separated list of method parameter types if applicable, otherwise an empty string
+	 *  uniqueId: the unique ID of the test provided by JUnit launcher, otherwise an empty string
+	 *  
+	 *  Example: 324968,testPass(junit.tests.MyTest),false,1,false,-1,A simple test case,&quot;&quot;,&quot;&quot;
 	 * </pre>
 	 *
 	 * @param description a string describing a tree entry
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/IXMLTags.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/IXMLTags.java
index 1d86125..a30acb0 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/IXMLTags.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/IXMLTags.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 IBM Corporation and others.
+ * Copyright (c) 2007, 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,5 +82,22 @@
 	 * value: String
 	 */
 	public static final String ATTR_MESSAGE= "message"; //$NON-NLS-1$
+	/**
+	 * value: String
+	 */
+	public static final String ATTR_DISPLAY_NAME= "displayname"; //$NON-NLS-1$
+	/**
+	 * value: Boolean
+	 */
+	public static final String ATTR_DYNAMIC_TEST= "dynamicTest"; //$NON-NLS-1$
+	/**
+	 * value: String
+	 */
+	public static final String ATTR_PARAMETER_TYPES= "parameters"; //$NON-NLS-1$
+	/**
+	 * value: String
+	 */
+	public static final String ATTR_UNIQUE_ID= "uniqueid"; //$NON-NLS-1$
+
 //	public static final String ATTR_TYPE= "type"; //$NON-NLS-1$
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/RemoteTestRunnerClient.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/RemoteTestRunnerClient.java
index 47fc3b0..8944da5 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/RemoteTestRunnerClient.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/RemoteTestRunnerClient.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java
index 99f3c10..ec3c5d6 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestCaseElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 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,10 +20,12 @@
 public class TestCaseElement extends TestElement implements ITestCaseElement {
 
 	private boolean fIgnored;
+	private boolean fIsDynamicTest;
 
-	public TestCaseElement(TestSuiteElement parent, String id, String testName) {
-		super(parent, id, testName);
+	public TestCaseElement(TestSuiteElement parent, String id, String testName, String displayName, boolean isDynamicTest, String[] parameterTypes, String uniqueId) {
+		super(parent, id, testName, displayName, parameterTypes, uniqueId);
 		Assert.isNotNull(parent);
+		fIsDynamicTest= isDynamicTest;
 	}
 
 	/**
@@ -77,4 +79,8 @@
 	public String toString() {
 		return "TestCase: " + getTestClassName() + "." + getTestMethodName() + " : " + super.toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	}
+
+	public boolean isDynamicTest() {
+		return fIsDynamicTest;
+	}
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestElement.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestElement.java
index 8e76d59..fb2ae31 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestElement.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 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,7 +20,6 @@
 
 import org.eclipse.core.runtime.Assert;
 
-
 public abstract class TestElement implements ITestElement {
 	public final static class Status {
 		public static final Status RUNNING_ERROR= new Status("RUNNING_ERROR", 5); //$NON-NLS-1$
@@ -169,6 +168,25 @@
 	private final String fId;
 	private String fTestName;
 
+	/**
+	 * The display name of the test element, can be <code>null</code>. In that case, use
+	 * {@link TestElement#fTestName fTestName}.
+	 */
+	private String fDisplayName;
+
+	/**
+	 * The array of method parameter types (as given by
+	 * org.junit.platform.engine.support.descriptor.MethodSource.getMethodParameterTypes()) if
+	 * applicable, otherwise <code>null</code>.
+	 */
+	private String[] fParameterTypes;
+
+	/**
+	 * The unique ID of the test element which can be <code>null</code> as it is applicable to JUnit 5
+	 * and above.
+	 */
+	private String fUniqueId;
+
 	private Status fStatus;
 	private String fTrace;
 	private String fExpected;
@@ -191,13 +209,22 @@
 	 * @param parent the parent, can be <code>null</code>
 	 * @param id the test id
 	 * @param testName the test name
+	 * @param displayName the test display name, can be <code>null</code>
+	 * @param parameterTypes the array of method parameter types (as given by
+	 *            org.junit.platform.engine.support.descriptor.MethodSource.getMethodParameterTypes())
+	 *            if applicable, otherwise <code>null</code>
+	 * @param uniqueId the unique ID of the test element, can be <code>null</code> as it is applicable
+	 *            to JUnit 5 and above
 	 */
-	public TestElement(TestSuiteElement parent, String id, String testName) {
+	public TestElement(TestSuiteElement parent, String id, String testName, String displayName, String[] parameterTypes, String uniqueId) {
 		Assert.isNotNull(id);
 		Assert.isNotNull(testName);
 		fParent= parent;
 		fId= id;
 		fTestName= testName;
+		fDisplayName= displayName;
+		fParameterTypes= parameterTypes;
+		fUniqueId= uniqueId;
 		fStatus= Status.NOT_RUN;
 		if (parent != null)
 			parent.addChild(this);
@@ -363,4 +390,34 @@
 	public String toString() {
 		return getProgressState() + " - " + getTestResult(true); //$NON-NLS-1$
 	}
+
+	/**
+	 * Returns the display name of the test. Can be <code>null</code>. In that case, use
+	 * {@link TestElement#getTestName() getTestName()}.
+	 * 
+	 * @return the test display name, can be <code>null</code>
+	 */
+	public String getDisplayName() {
+		return fDisplayName;
+	}
+
+	/**
+	 * @return the array of method parameter types (as given by
+	 *         org.junit.platform.engine.support.descriptor.MethodSource.getMethodParameterTypes()) if
+	 *         applicable, otherwise <code>null</code>
+	 */
+	public String[] getParameterTypes() {
+		return fParameterTypes;
+	}
+
+	/**
+	 * Returns the unique ID of the test element. Can be <code>null</code> as it is applicable to JUnit
+	 * 5 and above.
+	 * 
+	 * @return the unique ID of the test, can be <code>null</code>
+	 */
+	public String getUniqueId() {
+		return fUniqueId;
+	}
+
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRoot.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRoot.java
index 8b56ab2..8ff5a3b 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRoot.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 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
@@ -17,7 +17,7 @@
 	private final ITestRunSession fSession;
 
 	public TestRoot(ITestRunSession session) {
-		super(null, "-1", session.getTestRunName(), 1); //$NON-NLS-1$
+		super(null, "-1", session.getTestRunName(), 1, session.getTestRunName(), null, null); //$NON-NLS-1$
 		fSession= session;
 	}
 
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunHandler.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunHandler.java
index eebbef3..2a4abc9 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunHandler.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunHandler.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 IBM Corporation and others.
+ * Copyright (c) 2007, 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
@@ -14,6 +14,7 @@
 
 package org.eclipse.jdt.internal.junit.model;
 
+import java.util.Arrays;
 import java.util.Stack;
 
 import org.xml.sax.Attributes;
@@ -128,7 +129,20 @@
 
 			String pack= attributes.getValue(IXMLTags.ATTR_PACKAGE);
 			String suiteName= pack == null ? name : pack + "." + name; //$NON-NLS-1$
-			fTestSuite= (TestSuiteElement) fTestRunSession.createTestElement(fTestSuite, getNextId(), suiteName, true, 0);
+			String displayName= attributes.getValue(IXMLTags.ATTR_DISPLAY_NAME);
+			String paramTypesStr= attributes.getValue(IXMLTags.ATTR_PARAMETER_TYPES);
+			String[] paramTypes;
+			if (paramTypesStr != null && !paramTypesStr.trim().isEmpty()) {
+				paramTypes= paramTypesStr.split(","); //$NON-NLS-1$
+				Arrays.parallelSetAll(paramTypes, i -> paramTypes[i].trim());
+			} else {
+				paramTypes= null;
+			}
+			String uniqueId= attributes.getValue(IXMLTags.ATTR_UNIQUE_ID);
+			if (uniqueId != null && uniqueId.trim().isEmpty()) {
+				uniqueId= null;
+			}
+			fTestSuite= (TestSuiteElement) fTestRunSession.createTestElement(fTestSuite, getNextId(), suiteName, true, 0, false, displayName, paramTypes, uniqueId);
 			readTime(fTestSuite, attributes);
 			fNotRun.push(Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_INCOMPLETE)));
 
@@ -138,7 +152,22 @@
 		} else if (qName.equals(IXMLTags.NODE_TESTCASE)) {
 			String name= attributes.getValue(IXMLTags.ATTR_NAME);
 			String classname= attributes.getValue(IXMLTags.ATTR_CLASSNAME);
-			fTestCase= (TestCaseElement) fTestRunSession.createTestElement(fTestSuite, getNextId(), name + '(' + classname + ')', false, 0);
+			String testName= name + '(' + classname + ')';
+			boolean isDynamicTest= Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_DYNAMIC_TEST)).booleanValue();
+			String displayName= attributes.getValue(IXMLTags.ATTR_DISPLAY_NAME);
+			String paramTypesStr= attributes.getValue(IXMLTags.ATTR_PARAMETER_TYPES);
+			String[] paramTypes;
+			if (paramTypesStr != null && !paramTypesStr.trim().isEmpty()) {
+				paramTypes= paramTypesStr.split(","); //$NON-NLS-1$
+				Arrays.parallelSetAll(paramTypes, i -> paramTypes[i].trim());
+			} else {
+				paramTypes= null;
+			}
+			String uniqueId= attributes.getValue(IXMLTags.ATTR_UNIQUE_ID);
+			if (uniqueId != null && uniqueId.trim().isEmpty()) {
+				uniqueId= null;
+			}
+			fTestCase= (TestCaseElement) fTestRunSession.createTestElement(fTestSuite, getNextId(), testName, false, 0, isDynamicTest, displayName, paramTypes, uniqueId);
 			fNotRun.push(Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_INCOMPLETE)));
 			fTestCase.setIgnored(Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_IGNORED)).booleanValue());
 			readTime(fTestCase, attributes);
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSession.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSession.java
index 6c94785..2d359b6 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSession.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSession.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
@@ -90,6 +90,8 @@
 	 */
 	private List<IncompleteTestSuite> fIncompleteTestSuites;
 
+	private List<IncompleteTestSuite> fFactoryTestSuites;
+
 	/**
 	 * Suite for unrooted test case elements, or <code>null</code>.
 	 */
@@ -359,6 +361,7 @@
 			fTestRunnerClient= null;
 			fIdToTest= new HashMap<>();
 			fIncompleteTestSuites= null;
+			fFactoryTestSuites= null;
 			fUnrootedSuite= null;
 
 		} catch (IllegalStateException e) {
@@ -466,7 +469,7 @@
 	}
 
 	private TestElement addTreeEntry(String treeEntry) {
-		// format: testId","testName","isSuite","testcount
+		// format: testId","testName","isSuite","testcount","isDynamicTest","parentId","displayName","parameterTypes
 		int index0= treeEntry.indexOf(',');
 		String id= treeEntry.substring(0, index0);
 
@@ -477,29 +480,95 @@
 		int index2= treeEntry.indexOf(',', index1 + 1);
 		boolean isSuite= treeEntry.substring(index1 + 1, index2).equals("true"); //$NON-NLS-1$
 
-		int testCount= Integer.parseInt(treeEntry.substring(index2 + 1));
-
-		if (fIncompleteTestSuites.isEmpty()) {
-			return createTestElement(fTestRoot, id, testName, isSuite, testCount);
+		int testCount;
+		boolean isDynamicTest;
+		String parentId;
+		String displayName;
+		StringBuffer displayNameBuffer= new StringBuffer(100);
+		String[] parameterTypes;
+		StringBuffer parameterTypesBuffer= new StringBuffer(200);
+		String uniqueId;
+		StringBuffer uniqueIdBuffer= new StringBuffer(200);
+		int index3= treeEntry.indexOf(',', index2 + 1);
+		if (index3 == -1) {
+			testCount= Integer.parseInt(treeEntry.substring(index2 + 1));
+			isDynamicTest= false;
+			parentId= null;
+			displayName= null;
+			parameterTypes= null;
+			uniqueId= null;
 		} else {
-			int suiteIndex= fIncompleteTestSuites.size() - 1;
-			IncompleteTestSuite openSuite= fIncompleteTestSuites.get(suiteIndex);
-			openSuite.fOutstandingChildren--;
-			if (openSuite.fOutstandingChildren <= 0)
-				fIncompleteTestSuites.remove(suiteIndex);
-			return createTestElement(openSuite.fTestSuiteElement, id, testName, isSuite, testCount);
+			testCount= Integer.parseInt(treeEntry.substring(index2 + 1, index3));
+
+			int index4= treeEntry.indexOf(',', index3 + 1);
+			isDynamicTest= treeEntry.substring(index3 + 1, index4).equals("true"); //$NON-NLS-1$
+
+			int index5= treeEntry.indexOf(',', index4 + 1);
+			parentId= treeEntry.substring(index4 + 1, index5);
+			if (parentId.equals("-1")) { //$NON-NLS-1$
+				parentId= null;
+			}
+
+			int index6= scanTestName(treeEntry, index5 + 1, displayNameBuffer);
+			displayName= displayNameBuffer.toString().trim();
+			if (displayName.equals(testName)) {
+				displayName= null;
+			}
+
+			int index7= scanTestName(treeEntry, index6 + 1, parameterTypesBuffer);
+			String parameterTypesString= parameterTypesBuffer.toString().trim();
+			if (parameterTypesString.isEmpty()) {
+				parameterTypes= null;
+			} else {
+				parameterTypes= parameterTypesString.split(","); //$NON-NLS-1$
+				Arrays.parallelSetAll(parameterTypes, i -> parameterTypes[i].trim());
+			}
+
+			scanTestName(treeEntry, index7 + 1, uniqueIdBuffer);
+			uniqueId= uniqueIdBuffer.toString().trim();
+			if (uniqueId.isEmpty()) {
+				uniqueId= null;
+			}
+		}
+
+		if (isDynamicTest) {
+			if (parentId != null) {
+				for (IncompleteTestSuite suite : fFactoryTestSuites) {
+					if (parentId.equals(suite.fTestSuiteElement.getId())) {
+						return createTestElement(suite.fTestSuiteElement, id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId);
+					}
+				}
+			}
+			return createTestElement(getUnrootedSuite(), id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId); // should not reach here
+		} else {
+			if (fIncompleteTestSuites.isEmpty()) {
+				return createTestElement(fTestRoot, id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId);
+			} else {
+				int suiteIndex= fIncompleteTestSuites.size() - 1;
+				IncompleteTestSuite openSuite= fIncompleteTestSuites.get(suiteIndex);
+				openSuite.fOutstandingChildren--;
+				if (openSuite.fOutstandingChildren <= 0)
+					fIncompleteTestSuites.remove(suiteIndex);
+				return createTestElement(openSuite.fTestSuiteElement, id, testName, isSuite, testCount, isDynamicTest, displayName, parameterTypes, uniqueId);
+			}
 		}
 	}
 
-	public TestElement createTestElement(TestSuiteElement parent, String id, String testName, boolean isSuite, int testCount) {
+	public TestElement createTestElement(TestSuiteElement parent, String id, String testName, boolean isSuite, int testCount, boolean isDynamicTest, String displayName, String[] parameterTypes, String uniqueId) {
 		TestElement testElement;
+		if (parameterTypes != null && parameterTypes.length > 1) {
+			parameterTypes= Arrays.stream(parameterTypes).map(t -> t.trim()).toArray(String[]::new);
+		}
 		if (isSuite) {
-			TestSuiteElement testSuiteElement= new TestSuiteElement(parent, id, testName, testCount);
+			TestSuiteElement testSuiteElement= new TestSuiteElement(parent, id, testName, testCount, displayName, parameterTypes, uniqueId);
 			testElement= testSuiteElement;
-			if (testCount > 0)
+			if (testCount > 0) {
 				fIncompleteTestSuites.add(new IncompleteTestSuite(testSuiteElement, testCount));
+			} else if (fFactoryTestSuites != null) {
+				fFactoryTestSuites.add(new IncompleteTestSuite(testSuiteElement, testCount));
+			}
 		} else {
-			testElement= new TestCaseElement(parent, id, testName);
+			testElement= new TestCaseElement(parent, id, testName, displayName, isDynamicTest, parameterTypes, uniqueId);
 		}
 		fIdToTest.put(id, testElement);
 		return testElement;
@@ -533,6 +602,13 @@
 		return i;
 	}
 
+	private TestSuiteElement getUnrootedSuite() {
+		if (fUnrootedSuite == null) {
+			fUnrootedSuite= (TestSuiteElement) createTestElement(fTestRoot, "-2", JUnitMessages.TestRunSession_unrootedTests, true, 0, false, JUnitMessages.TestRunSession_unrootedTests, null, null); //$NON-NLS-1$
+		}
+		return fUnrootedSuite;
+	}
+
 	/**
 	 * An {@link ITestRunListener2} that listens to events from the
 	 * {@link RemoteTestRunnerClient} and translates them into high-level model
@@ -543,6 +619,7 @@
 		@Override
 		public void testRunStarted(int testCount) {
 			fIncompleteTestSuites= new ArrayList<>();
+			fFactoryTestSuites= new ArrayList<>();
 
 			fStartedCount= 0;
 			fIgnoredCount= 0;
@@ -599,7 +676,7 @@
 
 		private TestElement createUnrootedTestElement(String testId, String testName) {
 			TestSuiteElement unrootedSuite= getUnrootedSuite();
-			TestElement testElement= createTestElement(unrootedSuite, testId, testName, false, 1);
+			TestElement testElement= createTestElement(unrootedSuite, testId, testName, false, 1, false, testName, null, null);
 
 			for (ITestSessionListener listener : fSessionListeners) {
 				listener.testAdded(testElement);
@@ -608,13 +685,6 @@
 			return testElement;
 		}
 
-		private TestSuiteElement getUnrootedSuite() {
-			if (fUnrootedSuite == null) {
-				fUnrootedSuite= (TestSuiteElement) createTestElement(fTestRoot, "-2", JUnitMessages.TestRunSession_unrootedTests, true, 0);  //$NON-NLS-1$
-			}
-			return fUnrootedSuite;
-		}
-
 		@Override
 		public void testStarted(String testId, String testName) {
 			if (fStartedCount == 0) {
@@ -632,6 +702,10 @@
 			TestCaseElement testCaseElement= (TestCaseElement) testElement;
 			setStatus(testCaseElement, Status.RUNNING);
 
+			if (testCaseElement.isDynamicTest()) {
+				fTotalCount++;
+			}
+
 			fStartedCount++;
 
 			for (ITestSessionListener listener : fSessionListeners) {
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSessionSerializer.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSessionSerializer.java
index 9f70f7c..4f81a88 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSessionSerializer.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestRunSessionSerializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 IBM Corporation and others.
+ * Copyright (c) 2007, 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
@@ -17,7 +17,9 @@
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
+import java.util.Arrays;
 import java.util.Locale;
+import java.util.stream.Collectors;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
@@ -96,12 +98,23 @@
 			TestSuiteElement testSuiteElement= (TestSuiteElement) testElement;
 
 			AttributesImpl atts= new AttributesImpl();
-			addCDATA(atts, IXMLTags.ATTR_NAME, testSuiteElement.getSuiteTypeName());
+			// Need to store the full #getTestName instead of only the #getSuiteTypeName for test factory methods
+			addCDATA(atts, IXMLTags.ATTR_NAME, testSuiteElement.getTestName());
 			if (! Double.isNaN(testSuiteElement.getElapsedTimeInSeconds()))
 				addCDATA(atts, IXMLTags.ATTR_TIME, timeFormat.format(testSuiteElement.getElapsedTimeInSeconds()));
 			if (testElement.getProgressState() != ProgressState.COMPLETED || testElement.getTestResult(false) != Result.UNDEFINED)
 				addCDATA(atts, IXMLTags.ATTR_INCOMPLETE, Boolean.TRUE.toString());
-
+			if (testSuiteElement.getDisplayName() != null) {
+				addCDATA(atts, IXMLTags.ATTR_DISPLAY_NAME, testSuiteElement.getDisplayName());
+			}
+			String[] paramTypes= testSuiteElement.getParameterTypes();
+			if (paramTypes != null) {
+				String paramTypesStr= Arrays.stream(paramTypes).collect(Collectors.joining(",")); //$NON-NLS-1$
+				addCDATA(atts, IXMLTags.ATTR_PARAMETER_TYPES, paramTypesStr);
+			}
+			if (testSuiteElement.getUniqueId() != null) {
+				addCDATA(atts, IXMLTags.ATTR_UNIQUE_ID, testSuiteElement.getUniqueId());
+			}
 			startElement(IXMLTags.NODE_TESTSUITE, atts);
 			addFailure(testSuiteElement);
 
@@ -123,7 +136,20 @@
 				addCDATA(atts, IXMLTags.ATTR_INCOMPLETE, Boolean.TRUE.toString());
 			if (testCaseElement.isIgnored())
 				addCDATA(atts, IXMLTags.ATTR_IGNORED, Boolean.TRUE.toString());
-
+			if (testCaseElement.isDynamicTest()) {
+				addCDATA(atts, IXMLTags.ATTR_DYNAMIC_TEST, Boolean.TRUE.toString());
+			}
+			if (testCaseElement.getDisplayName() != null) {
+				addCDATA(atts, IXMLTags.ATTR_DISPLAY_NAME, testCaseElement.getDisplayName());
+			}
+			String[] paramTypes= testCaseElement.getParameterTypes();
+			if (paramTypes != null) {
+				String paramTypesStr= Arrays.stream(paramTypes).collect(Collectors.joining(",")); //$NON-NLS-1$
+				addCDATA(atts, IXMLTags.ATTR_PARAMETER_TYPES, paramTypesStr);
+			}
+			if (testCaseElement.getUniqueId() != null) {
+				addCDATA(atts, IXMLTags.ATTR_UNIQUE_ID, testCaseElement.getUniqueId());
+			}
 			startElement(IXMLTags.NODE_TESTCASE, atts);
 			addFailure(testCaseElement);
 
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestSuiteElement.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestSuiteElement.java
index 193839a..70e0d51 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestSuiteElement.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/model/TestSuiteElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 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
@@ -23,8 +23,8 @@
 	private List<TestElement> fChildren;
 	private Status fChildrenStatus;
 
-	public TestSuiteElement(TestSuiteElement parent, String id, String testName, int childrenCount) {
-		super(parent, id, testName);
+	public TestSuiteElement(TestSuiteElement parent, String id, String testName, int childrenCount, String displayName, String[] parameterTypes, String uniqueId) {
+		super(parent, id, testName, displayName, parameterTypes, uniqueId);
 		fChildren= new ArrayList<>(childrenCount);
 	}
 
@@ -51,6 +51,10 @@
 		fChildren.add(child);
 	}
 
+	public void removeChild(TestElement child) {
+		fChildren.remove(child);
+	}
+
 	@Override
 	public Status getStatus() {
 		Status suiteStatus= getSuiteStatus();
@@ -144,7 +148,7 @@
 
 	@Override
 	public String toString() {
-		return "TestSuite: " + getSuiteTypeName() + " : " + super.toString() + " (" + fChildren.size() + ")";   //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+		return "TestSuite: " + getTestName() + " : " + super.toString() + " (" + fChildren.size() + ")";   //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 	}
 
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/util/CoreTestSearchEngine.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/util/CoreTestSearchEngine.java
index 6601781..de62eb8 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/util/CoreTestSearchEngine.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/util/CoreTestSearchEngine.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
@@ -57,7 +57,7 @@
 		return testKind.getFinder().isTest(declaringType);
 	}
 
-	public static boolean isAccessibleClass(IType type) throws JavaModelException {
+	public static boolean isAccessibleClass(IType type, String testKindId) throws JavaModelException {
 		int flags= type.getFlags();
 		if (Flags.isInterface(flags)) {
 			return false;
@@ -67,7 +67,19 @@
 			if (parent instanceof ICompilationUnit || parent instanceof IClassFile) {
 				return true;
 			}
-			if (!(parent instanceof IType) || !Flags.isStatic(flags) || !Flags.isPublic(flags)) {
+			if (!(parent instanceof IType)) {
+				return false;
+			}
+			if (TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKindId)) {
+				// A nested/inner class need not be public in JUnit 5.
+				if (Flags.isPrivate(flags)) {
+					return false;
+				}
+				// If the inner class is non-static, it must be annotated with @Nested.
+				if (!Flags.isStatic(flags) && !type.getAnnotation("Nested").exists()) { //$NON-NLS-1$
+					return false;
+				}
+			} else if (!Flags.isStatic(flags) || !Flags.isPublic(flags)) {
 				return false;
 			}
 			flags= ((IType) parent).getFlags();
@@ -75,7 +87,11 @@
 		}
 	}
 
-	public static boolean isAccessibleClass(ITypeBinding type) {
+	public static boolean isAccessibleClass(IType type) throws JavaModelException {
+		return isAccessibleClass(type, null);
+	}
+
+	public static boolean isAccessibleClass(ITypeBinding type) { // not used
 		if (type.isInterface()) {
 			return false;
 		}
@@ -105,7 +121,7 @@
 		return false;
 	}
 
-	public static boolean hasTestAnnotation(IJavaProject project) {
+	public static boolean hasJUnit4TestAnnotation(IJavaProject project) {
 		try {
 			if (project != null) {
 				IType type= project.findType(JUnitCorePlugin.JUNIT4_ANNOTATION_NAME);
@@ -123,6 +139,24 @@
 		return false;
 	}
 
+	public static boolean hasJUnit5TestAnnotation(IJavaProject project) {
+		try {
+			if (project != null) {
+				IType type= project.findType(JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME);
+				if (type != null) {
+					// @Testable annotation is not accessible if the JUnit classpath container is set to JUnit 3 or JUnit 4
+					// (although it may resolve to a JUnit 5 JAR)
+					IPackageFragmentRoot root= (IPackageFragmentRoot) type.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+					IClasspathEntry cpEntry= root.getRawClasspathEntry();
+					return ! JUnitCore.JUNIT3_CONTAINER_PATH.equals(cpEntry.getPath()) && ! JUnitCore.JUNIT4_CONTAINER_PATH.equals(cpEntry.getPath());
+				}
+			}
+		} catch (JavaModelException e) {
+			// not available
+		}
+		return false;
+	}
+
 	public static boolean isTestImplementor(IType type) throws JavaModelException {
 		ITypeHierarchy typeHier= type.newSupertypeHierarchy(null);
 		IType[] superInterfaces= typeHier.getAllInterfaces();
@@ -263,6 +297,22 @@
 		String source= project != null ? project.getOption(JavaCore.COMPILER_SOURCE, true) : JavaCore.getOption(JavaCore.COMPILER_SOURCE);
 		return is50OrHigher(source);
 	}
+
+	public static boolean is18OrHigher(String compliance) {
+		return !isVersionLessThan(compliance, JavaCore.VERSION_1_8);
+	}
+
+	/**
+	 * Checks if the given project or workspace has source compliance 1.8 or greater.
+	 * 
+	 * @param project the project to test or <code>null</code> to test the workspace settings
+	 * @return <code>true</code> if the given project or workspace has source compliance 1.8 or
+	 *         greater.
+	 */
+	public static boolean is18OrHigher(IJavaProject project) {
+		String source= project != null ? project.getOption(JavaCore.COMPILER_SOURCE, true) : JavaCore.getOption(JavaCore.COMPILER_SOURCE);
+		return is18OrHigher(source);
+	}
 // ---
 
 }
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/JUnitCore.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/JUnitCore.java
index fa1138e..42d6b7b 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/JUnitCore.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/JUnitCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -61,6 +61,7 @@
 	 * 
 	 * @see #JUNIT3_CONTAINER_PATH
 	 * @see #JUNIT4_CONTAINER_PATH
+	 * @see #JUNIT5_CONTAINER_PATH
 	 * @since 3.6
 	 */
 	public static final String JUNIT_CONTAINER_ID= "org.eclipse.jdt.junit.JUNIT_CONTAINER"; //$NON-NLS-1$
@@ -80,6 +81,13 @@
 	public final static IPath JUNIT4_CONTAINER_PATH= new Path(JUNIT_CONTAINER_ID).append("4"); //$NON-NLS-1$
 
 	/**
+	 * Path of the JUnit 5 {@linkplain IClasspathContainer classpath container}.
+	 * 
+	 * @since 3.9
+	 */
+	public final static IPath JUNIT5_CONTAINER_PATH= new Path(JUNIT_CONTAINER_ID).append("5"); //$NON-NLS-1$
+
+	/**
 	 * Adds a listener for test runs.
 	 *
 	 * @param listener listener to be added
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java
index 911b3bd..6234d25 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java
@@ -27,6 +27,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.osgi.framework.Bundle;
 
@@ -49,8 +50,11 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
 
 import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
 import org.eclipse.jdt.internal.junit.JUnitMessages;
@@ -82,7 +86,7 @@
 
 	private boolean fKeepAlive= false;
 	private int fPort;
-	private IMember[] fTestElements;
+	private IJavaElement[] fTestElements;
 
 	@Override
 	public synchronized void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException {
@@ -122,7 +126,17 @@
 			fPort= evaluatePort();
 			launch.setAttribute(JUnitLaunchConfigurationConstants.ATTR_PORT, String.valueOf(fPort));
 
-			fTestElements= evaluateTests(configuration, new SubProgressMonitor(monitor, 1));
+			ITestKind testKind= getTestRunnerKind(configuration);
+			if (TestKindRegistry.JUNIT3_TEST_KIND_ID.equals(testKind.getId()) || TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId())) {
+				fTestElements= evaluateTests(configuration, new SubProgressMonitor(monitor, 1));
+			} else {
+				IJavaElement testTarget= getTestTarget(configuration, getJavaProject(configuration));
+				if (testTarget instanceof IPackageFragment || testTarget instanceof IPackageFragmentRoot || testTarget instanceof IJavaProject) {
+					fTestElements= new IJavaElement[] { testTarget };
+				} else {
+					fTestElements= evaluateTests(configuration, new SubProgressMonitor(monitor, 1));
+				}
+			}
 
 			String mainTypeName= verifyMainTypeName(configuration);
 			IVMRunner runner= getVMRunner(configuration, mode);
@@ -206,15 +220,19 @@
 			if ((javaProject == null) || !javaProject.exists()) {
 				abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_invalidproject, null, IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT);
 			}
-			if (!CoreTestSearchEngine.hasTestCaseType(javaProject)) {
-				abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_junitnotonpath, null, IJUnitStatusConstants.ERR_JUNIT_NOT_ON_PATH);
-			}
-
 			ITestKind testKind= getTestRunnerKind(configuration);
 			boolean isJUnit4Configuration= TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId());
-			if (isJUnit4Configuration && ! CoreTestSearchEngine.hasTestAnnotation(javaProject)) {
+			boolean isJUnit5Configuration= TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId());
+			if (!isJUnit5Configuration && !CoreTestSearchEngine.hasTestCaseType(javaProject)) {
+				abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_junitnotonpath, null, IJUnitStatusConstants.ERR_JUNIT_NOT_ON_PATH);
+			}
+			if (isJUnit4Configuration && !CoreTestSearchEngine.hasJUnit4TestAnnotation(javaProject)) {
 				abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_junit4notonpath, null, IJUnitStatusConstants.ERR_JUNIT_NOT_ON_PATH);
 			}
+			if (isJUnit5Configuration && !CoreTestSearchEngine.hasJUnit5TestAnnotation(javaProject)) {
+				String msg= Messages.format(JUnitMessages.JUnitLaunchConfigurationDelegate_error_junit5notonpath, JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME);
+				abort(msg, null, IJUnitStatusConstants.ERR_JUNIT_NOT_ON_PATH);
+			}
 		} finally {
 			monitor.done();
 		}
@@ -250,6 +268,8 @@
 		String testMethodName= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_NAME, ""); //$NON-NLS-1$
 		if (testMethodName.length() > 0) {
 			if (testTarget instanceof IType) {
+				// If parameters exist, testMethodName is followed by a comma-separated list of fully qualified parameter type names in parentheses.
+				// The testMethodName is required in this format by #collectExecutionArguments, hence it will be used as it is with the handle-only method IType#getMethod here.
 				return new IMember[] { ((IType) testTarget).getMethod(testMethodName, new String[0]) };
 			}
 		}
@@ -280,8 +300,6 @@
 		vmArguments.addAll(Arrays.asList(execArgs.getVMArgumentsArray()));
 		programArguments.addAll(Arrays.asList(execArgs.getProgramArgumentsArray()));
 
-		String testFailureNames= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_FAILURES_NAMES, ""); //$NON-NLS-1$
-		
 		/*
 		 * The "-version" "3" arguments don't make sense and should eventually be removed.
 		 * But we keep them for now, since users may want to run with older releases of
@@ -307,18 +325,22 @@
 		programArguments.add("-loaderpluginname"); //$NON-NLS-1$
 		programArguments.add(testRunnerKind.getLoaderPluginId());
 
-		IMember[] testElements = fTestElements;
+		IJavaElement[] testElements= fTestElements;
 
-		// a test name was specified just run the single test
-		if (testElements.length == 1) {
-			if (testElements[0] instanceof IMethod) {
-				IMethod method= (IMethod) testElements[0];
+		if (testElements.length == 1) { // a test name was specified just run the single test, or a test container was specified
+			IJavaElement testElement= testElements[0];
+			if (testElement instanceof IMethod) {
+				IMethod method= (IMethod) testElement;
 				programArguments.add("-test"); //$NON-NLS-1$
-				programArguments.add(method.getDeclaringType().getFullyQualifiedName()+':'+method.getElementName());
-			} else if (testElements[0] instanceof IType) {
-				IType type= (IType) testElements[0];
+				programArguments.add(method.getDeclaringType().getFullyQualifiedName() + ':' + method.getElementName());
+			} else if (testElement instanceof IType) {
+				IType type= (IType) testElement;
 				programArguments.add("-classNames"); //$NON-NLS-1$
 				programArguments.add(type.getFullyQualifiedName());
+			} else if (testElement instanceof IPackageFragment || testElement instanceof IPackageFragmentRoot || testElement instanceof IJavaProject) {
+				String fileName= createPackageNamesFile(testElement, testRunnerKind);
+				programArguments.add("-packageNameFile"); //$NON-NLS-1$
+				programArguments.add(fileName);
 			} else {
 				abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_wrong_input, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
 			}
@@ -327,13 +349,72 @@
 			programArguments.add("-testNameFile"); //$NON-NLS-1$
 			programArguments.add(fileName);
 		}
+
+		String testFailureNames= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_FAILURES_NAMES, ""); //$NON-NLS-1$
 		if (testFailureNames.length() > 0) {
 			programArguments.add("-testfailures"); //$NON-NLS-1$
 			programArguments.add(testFailureNames);
 		}
+
+		String uniqueId= configuration.getAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_UNIQUE_ID, ""); //$NON-NLS-1$
+		if (!uniqueId.trim().isEmpty()) {
+			programArguments.add("-uniqueId"); //$NON-NLS-1$
+			programArguments.add(uniqueId);
+		}
 	}
 
-	private String createTestNamesFile(IMember[] testElements) throws CoreException {
+	private String createPackageNamesFile(IJavaElement testContainer, ITestKind testRunnerKind) throws CoreException {
+		try {
+			File file= File.createTempFile("packageNames", ".txt"); //$NON-NLS-1$ //$NON-NLS-2$
+			file.deleteOnExit();
+			try (BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) { //$NON-NLS-1$) 
+				Set<String> pkgNames= new HashSet<>();
+				if (testContainer instanceof IPackageFragment) {
+					pkgNames.add(getPackageName(testContainer.getElementName()));
+				} else if (testContainer instanceof IPackageFragmentRoot) {
+					addAllPackageFragments((IPackageFragmentRoot) testContainer, pkgNames);
+				} else if (testContainer instanceof IJavaProject) {
+					for (IPackageFragmentRoot pkgFragmentRoot : ((IJavaProject) testContainer).getPackageFragmentRoots()) {
+						if (!pkgFragmentRoot.isExternal() && !pkgFragmentRoot.isArchive()) {
+							addAllPackageFragments(pkgFragmentRoot, pkgNames);
+						}
+					}
+				} else {
+					abort(JUnitMessages.JUnitLaunchConfigurationDelegate_error_wrong_input, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+				}
+				if (pkgNames.size() == 0) {
+					String msg= Messages.format(JUnitMessages.JUnitLaunchConfigurationDelegate_error_notests_kind, testRunnerKind.getDisplayName());
+					abort(msg, null, IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_MAIN_TYPE);
+				} else {
+					for (String pkgName : pkgNames) {
+						bw.write(pkgName);
+						bw.newLine();
+					}
+				}
+			}
+			return file.getAbsolutePath();
+		} catch (IOException | JavaModelException e) {
+			throw new CoreException(new Status(IStatus.ERROR, JUnitCorePlugin.CORE_PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+		}
+	}
+
+	private Set<String> addAllPackageFragments(IPackageFragmentRoot pkgFragmentRoot, Set<String> pkgNames) throws JavaModelException {
+		for (IJavaElement child : pkgFragmentRoot.getChildren()) {
+			if (child instanceof IPackageFragment && ((IPackageFragment) child).hasChildren()) {
+				pkgNames.add(getPackageName(child.getElementName()));
+			}
+		}
+		return pkgNames;
+	}
+
+	private String getPackageName(String elementName) {
+		if (elementName.isEmpty()) {
+			return "<default>"; //$NON-NLS-1$
+		}
+		return elementName;
+	}
+
+	private String createTestNamesFile(IJavaElement[] testElements) throws CoreException {
 		try {
 			File file= File.createTempFile("testNames", ".txt"); //$NON-NLS-1$ //$NON-NLS-2$
 			file.deleteOnExit();
diff --git a/org.eclipse.jdt.junit.runtime/META-INF/MANIFEST.MF b/org.eclipse.jdt.junit.runtime/META-INF/MANIFEST.MF
index 2ce195a..2337f9c 100644
--- a/org.eclipse.jdt.junit.runtime/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.junit.runtime/META-INF/MANIFEST.MF
@@ -5,7 +5,11 @@
 Bundle-Version: 3.4.600.qualifier
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
-Export-Package: org.eclipse.jdt.internal.junit.runner;x-friends:="org.eclipse.jdt.junit.core,org.eclipse.jdt.junit4.runtime,org.eclipse.pde.junit.runtime",
- org.eclipse.jdt.internal.junit.runner.junit3;x-friends:="org.eclipse.jdt.junit4.runtime"
+Export-Package: org.eclipse.jdt.internal.junit.runner;
+  x-friends:="org.eclipse.jdt.junit.core,
+   org.eclipse.jdt.junit4.runtime,
+   org.eclipse.pde.junit.runtime,
+   org.eclipse.jdt.junit5.runtime",
+ org.eclipse.jdt.internal.junit.runner.junit3;x-friends:="org.eclipse.jdt.junit4.runtime,org.eclipse.jdt.junit5.runtime"
 Require-Bundle: org.junit;bundle-version="3.8.2"
 Bundle-RequiredExecutionEnvironment: J2SE-1.4
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java
index c721a20..0ab831b 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/FirstRunExecutionListener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2016 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -56,7 +56,7 @@
 	}
 
 	private void sendMessage(ITestIdentifier test, String status) {
-		fSender.sendMessage(status + getTestId(test) + ',' + RemoteTestRunner.escapeTestName(test.getName()));
+		fSender.sendMessage(status + getTestId(test) + ',' + RemoteTestRunner.escapeText(test.getName()));
 	}
 
 }
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestIdentifier.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestIdentifier.java
index 3b8db0c..24ccc4f 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestIdentifier.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestIdentifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -17,4 +17,9 @@
 
 	String getName();
 
+	String getDisplayName();
+
+	String getParameterTypes();
+
+	String getUniqueId();
 }
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestLoader.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestLoader.java
index 2cd424f..0c59823 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestLoader.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/ITestLoader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -18,9 +18,12 @@
 	 * @param testClasses classes to be run
 	 * @param testName individual method to be run
 	 * @param failureNames may want to run these first, since they failed
+	 * @param packages packages containing tests to run
+	 * @param includeExcludeTags tags to be included and excluded in the test run
+	 * @param uniqueId unique ID of the test to run
 	 * @param listener to be notified if tests could not be loaded
 	 * @return the loaded test references
 	 */
-	public abstract ITestReference[] loadTests(Class[] testClasses, String testName, String[] failureNames, RemoteTestRunner listener);
+	public abstract ITestReference[] loadTests(Class[] testClasses, String testName, String[] failureNames, String[] packages, String[][] includeExcludeTags, String uniqueId, RemoteTestRunner listener);
 }
 
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/IVisitsTestTrees.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/IVisitsTestTrees.java
index 2ebc602..c292230 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/IVisitsTestTrees.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/IVisitsTestTrees.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -14,5 +14,5 @@
 package org.eclipse.jdt.internal.junit.runner;
 
 public interface IVisitsTestTrees {
-	public abstract void visitTreeEntry(ITestIdentifier identifier, boolean hasChildren, int testCount);
+	public abstract void visitTreeEntry(ITestIdentifier identifier, boolean hasChildren, int testCount, boolean isDynamicTest, String parentId);
 }
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/MessageIds.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/MessageIds.java
index 291f984..6564040 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/MessageIds.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/MessageIds.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
@@ -73,12 +73,12 @@
 	 */
 	public static final String TEST_START=  "%TESTS  ";		 //$NON-NLS-1$
 	/**
-	 * Notification that a test has started.
+	 * Notification that a test has ended.
 	 * TEST_END + testID + "," + testName
 	 */
 	public static final String TEST_END=    "%TESTE  ";		 //$NON-NLS-1$
 	/**
-	 * Notification that a test had a error.
+	 * Notification that a test had an error.
 	 * TEST_ERROR + testID + "," + testName.
 	 * After the notification follows the stack trace.
 	 */
@@ -104,12 +104,20 @@
 	 * Status = "OK" or "FAILURE".
 	 */
 	public static final String TEST_RERAN=  "%TSTRERN"; //$NON-NLS-1$
+
 	/**
-	 * Notification about a test inside the test suite.
-	 * TEST_TREE + testId + "," + testName + "," + isSuite + "," + testcount
-	 * isSuite = "true" or "false"
+	 * Notification about a test inside the test suite. <br>
+	 * TEST_TREE + testId + "," + testName + "," + isSuite + "," + testcount + "," +
+	 * isDynamicTest + "," + parentId + "," + displayName + "," + parameterTypes<br>
+	 * isSuite = "true" or "false" <br>
+	 * isDynamicTest = "true" or "false" <br>
+	 * parentId = the unique id of its parent if it is a dynamic test, otherwise can be "-1" <br>
+	 * displayName = the display name of the test <br>
+	 * parameterTypes = comma-separated list of method parameter types if applicable, otherwise an empty string <br>
+	 * See: ITestRunListener2#testTreeEntry
+	 * 
 	 */
-	public static final String TEST_TREE="%TSTTREE"; //$NON-NLS-1$
+	public static final String TEST_TREE= "%TSTTREE"; //$NON-NLS-1$
 	/**
 	 * Request to stop the current test run.
 	 */
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java
index 63acd41..05085fa 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/RemoteTestRunner.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
@@ -62,6 +62,19 @@
 	 */
 	private String fTestName;
 	/**
+	 * The names of the packages containing tests to run
+	 */
+	private String[] fPackageNames;
+	/**
+	 * The unique ID of test to run or "" if not available
+	 */
+	private String fUniqueId;
+	/**
+	 * Tags to be included and excluded in the test run
+	 */
+	private String[][] fIncludeExcludeTags= new String[2][];
+
+	/**
 	 * The current test result
 	 */
 	private TestExecution fExecution;
@@ -120,6 +133,8 @@
 
 	private boolean fConsoleMode = false;
 
+	public static final RemoteTestRunner fgTestRunServer= new RemoteTestRunner();
+
 	/**
 	 * Reader thread that processes messages from the client.
 	 */
@@ -180,6 +195,7 @@
 	 * <pre>-classnames: the name of the test suite class
 	 * -testfilename: the name of a file containing classnames of test suites
 	 * -test: the test method name (format classname testname)
+	 * -packagenamefile: the name of a file containing package names of tests
 	 * -host: the host to connect to default local host
 	 * -port: the port to connect to, mandatory argument
 	 * -keepalive: keep the process alive after a test run
@@ -187,9 +203,8 @@
      */
 	public static void main(String[] args) {
 		try {
-			RemoteTestRunner testRunServer= new RemoteTestRunner();
-			testRunServer.init(args);
-			testRunServer.run();
+			fgTestRunServer.init(args);
+			fgTestRunServer.run();
 		} catch (Throwable e) {
 			e.printStackTrace(); // don't allow System.exit(0) to swallow exceptions
 		} finally {
@@ -249,7 +264,16 @@
 				}
 				i++;
 
-			} else if(args[i].toLowerCase().equals("-testfailures")) { //$NON-NLS-1$
+			} else if (args[i].toLowerCase().equals("-packagenamefile")) { //$NON-NLS-1$
+				String pkgNameFile= args[i+1];
+				try {
+					readPackageNames(pkgNameFile);
+				} catch (IOException e) {
+					throw new IllegalArgumentException("Cannot read packagename file.");		 //$NON-NLS-1$
+				}
+				i++;
+
+			} else if (args[i].toLowerCase().equals("-testfailures")) { //$NON-NLS-1$
 				String testFailuresFile= args[i+1];
 				try {
 					readFailureNames(testFailuresFile);
@@ -282,14 +306,48 @@
 				String className = args[i + 1];
 				createLoader(className);
 				i++;
+			} else if(args[i].toLowerCase().equals("-uniqueid")) { //$NON-NLS-1$
+				fUniqueId= args[i+1];
+				i++;
+			} else if (args[i].toLowerCase().equals("--include-tag")) { //$NON-NLS-1$
+				String[] includeTags= fIncludeExcludeTags[0];
+				if (includeTags == null) {
+					includeTags= new String[1];
+					includeTags[0]= args[i + 1];
+				} else {
+					String[] tags= new String[includeTags.length + 1];
+					System.arraycopy(includeTags, 0, tags, 0, includeTags.length);
+					tags[includeTags.length]= args[i + 1];
+					includeTags= tags;
+				}
+				fIncludeExcludeTags[0]= includeTags;
+				i++;
+			} else if (args[i].toLowerCase().equals("--exclude-tag")) { //$NON-NLS-1$
+				String[] excludeTags= fIncludeExcludeTags[1];
+				if (excludeTags == null) {
+					excludeTags= new String[1];
+					excludeTags[0]= args[i + 1];
+				} else {
+					String[] tags= new String[excludeTags.length + 1];
+					System.arraycopy(excludeTags, 0, tags, 0, excludeTags.length);
+					tags[excludeTags.length]= args[i + 1];
+					excludeTags= tags;
+				}
+				fIncludeExcludeTags[1]= excludeTags;
+				i++;
 			}
 		}
 
 		if (getTestLoader() == null)
 			initDefaultLoader();
 
-		if(fTestClassNames == null || fTestClassNames.length == 0)
-			throw new IllegalArgumentException(JUnitMessages.getString("RemoteTestRunner.error.classnamemissing")); //$NON-NLS-1$
+		if(fTestClassNames == null || fTestClassNames.length == 0) {
+			if (fPackageNames == null || fPackageNames.length == 0) {
+				throw new IllegalArgumentException(JUnitMessages.getString("RemoteTestRunner.error.classnamemissing")); //$NON-NLS-1$
+			} else {
+				fTestClassNames= new String[0];
+			}
+		}
 
 		if (fPort == -1)
 			throw new IllegalArgumentException(JUnitMessages.getString("RemoteTestRunner.error.portmissing")); //$NON-NLS-1$
@@ -324,6 +382,27 @@
 		fLoader = newInstance;
 	}
 
+	private void readPackageNames(String pkgNameFile) throws IOException {
+		BufferedReader br= new BufferedReader(new InputStreamReader(new FileInputStream(new File(pkgNameFile)), "UTF-8")); //$NON-NLS-1$
+		try {
+			String line;
+			Vector list= new Vector();
+			while ((line= br.readLine()) != null) {
+				list.add(line);
+			}
+			fPackageNames= (String[]) list.toArray(new String[list.size()]);
+		}
+		finally {
+			br.close();
+		}
+		if (fDebugMode) {
+			System.out.println("Packages:"); //$NON-NLS-1$
+			for (int i= 0; i < fPackageNames.length; i++) {
+				System.out.println("    "+fPackageNames[i]); //$NON-NLS-1$
+			}
+		}
+	}
+	
 	private void readTestNames(String testNameFile) throws IOException {
 		BufferedReader br= new BufferedReader(new InputStreamReader(new FileInputStream(new File(testNameFile)), "UTF-8")); //$NON-NLS-1$
 		try {
@@ -441,17 +520,18 @@
 	 * @param execution executor
 	 */
 	public void runTests(String[] testClassNames, String testName, TestExecution execution) {
-		ITestReference[] suites= fLoader.loadTests(loadClasses(testClassNames), testName, fFailureNames, this);
+		ITestReference[] suites= fLoader.loadTests(loadClasses(testClassNames), testName, fFailureNames, fPackageNames, fIncludeExcludeTags, fUniqueId, this);
 
 		// count all testMethods and inform ITestRunListeners
 		int count= countTests(suites);
 
 		notifyTestRunStarted(count);
 
-		if (count == 0) {
+		// test count is 0 if only dynamic tests will be run (i.e. only @TestFactory methods are present), hence test run should continue.
+		/*if (count == 0) {
 			notifyTestRunEnded(0);
 			return;
-		}
+		}*/
 
 		sendTrees(suites);
 
@@ -488,7 +568,7 @@
 	 */
 	public void rerunTest(RerunRequest r) {
 		final Class[] classes= loadClasses(new String[] { r.fRerunClassName });
-		ITestReference rerunTest1= fLoader.loadTests(classes, r.fRerunTestName, null, this)[0];
+		ITestReference rerunTest1= fLoader.loadTests(classes, r.fRerunTestName, null, null, fIncludeExcludeTags, fUniqueId, this)[0];
 		RerunExecutionListener service= rerunExecutionListener();
 
 		TestExecution execution= new TestExecution(service, getClassifier());
@@ -506,11 +586,14 @@
 		return new DefaultClassifier();
 	}
 
-	public void visitTreeEntry(ITestIdentifier id, boolean b, int i) {
-		notifyTestTreeEntry(getTestId(id) + ',' + escapeTestName(id.getName()) + ',' + b + ',' + i);
+	public void visitTreeEntry(ITestIdentifier identifier, boolean hasChildren, int testCount, boolean isDynamicTest, String parentId) {
+		String treeEntry= getTestId(identifier) + ',' + escapeText(identifier.getName()) + ',' + hasChildren + ',' + testCount 
+				+ ',' + isDynamicTest + ',' + parentId + ',' + escapeText(identifier.getDisplayName()) + ',' + escapeText(identifier.getParameterTypes()) 
+				+ ',' + escapeText(identifier.getUniqueId());
+		notifyTestTreeEntry(treeEntry);
 	}
 
-	public static String escapeTestName(String s) {
+	public static String escapeText(String s) {
 		if ((s.indexOf(',') < 0) && (s.indexOf('\\') < 0) && (s.indexOf('\r') < 0) && (s.indexOf('\n') < 0))
 			return s;
 		StringBuffer sb= new StringBuffer(s.length()+10);
@@ -535,7 +618,7 @@
 	}
 
 	// WANT: work in bug fixes since RC2?
-	private String getTestId(ITestIdentifier id) {
+	public String getTestId(ITestIdentifier id) {
 		return fIds.getTestId(id);
 	}
 
@@ -676,7 +759,7 @@
 
 	public void runTests(TestExecution execution) {
 		runTests(fTestClassNames, fTestName, execution);
-		}
+	}
 
 	public ITestLoader getTestLoader() {
 		return fLoader;
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestIdMap.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestIdMap.java
index cd67239..3d8409c 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestIdMap.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestIdMap.java
@@ -29,7 +29,7 @@
 		return newId;
 	}
 
-	public String getTestId(ITestReference ref) {
+	public String getTestId(ITestReference ref) { // not used
 		return getTestId(ref.getIdentifier());
 	}
 }
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java
index 31e7640..295fb2e 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/TestReferenceFailure.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2016 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -38,7 +38,7 @@
 		fComparison = comparison;
 	}
 
-	public TestReferenceFailure(ITestReference reference, String status, String trace) {
+	public TestReferenceFailure(ITestReference reference, String status, String trace) { // not used
 		this(reference.getIdentifier(), status, trace);
 	}
 
@@ -55,7 +55,8 @@
 	}
 
 	public String toString() {
-		return fStatus + " " + RemoteTestRunner.escapeTestName(fTest.getName()); //$NON-NLS-1$
+		return fStatus + " " + RemoteTestRunner.escapeText(fTest.getName())  //$NON-NLS-1$
+			+ " " + RemoteTestRunner.escapeText(fTest.getParameterTypes()); //$NON-NLS-1$ 
 	}
 
 	public void setComparison(FailedComparison comparison) {
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3Identifier.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3Identifier.java
index def5c28..5673cb3 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3Identifier.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3Identifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -37,4 +37,16 @@
 	public int hashCode() {
 		return ref.hashCode();
 	}
+
+	public String getDisplayName() {
+		return getName();
+	}
+
+	public String getParameterTypes() {
+		return ""; //$NON-NLS-1$
+	}
+
+	public String getUniqueId() {
+		return ""; //$NON-NLS-1$
+	}
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestLoader.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestLoader.java
index 6ba4a0f..dcb975a 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestLoader.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestLoader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -36,7 +36,7 @@
 
 	// WANT: give test loaders a schema
 
-	public ITestReference[] loadTests(Class[] testClasses, String testName, String[] failureNames, RemoteTestRunner listener) {
+	public ITestReference[] loadTests(Class[] testClasses, String testName, String[] failureNames, String[] packages, String[][] includeExcludeTags, String uniqueId, RemoteTestRunner listener) {
 		// instantiate all tests
 		ITestReference[] suites= new ITestReference[testClasses.length];
 		ITestPrioritizer prioritizer;
diff --git a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestReference.java b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestReference.java
index 4cfa275..903d2c9 100644
--- a/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestReference.java
+++ b/org.eclipse.jdt.junit.runtime/src/org/eclipse/jdt/internal/junit/runner/junit3/JUnit3TestReference.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -22,12 +22,6 @@
 import java.util.Iterator;
 import java.util.List;
 
-import junit.extensions.TestDecorator;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestResult;
-import junit.framework.TestSuite;
-
 import org.eclipse.jdt.internal.junit.runner.FailedComparison;
 import org.eclipse.jdt.internal.junit.runner.IClassifiesThrowables;
 import org.eclipse.jdt.internal.junit.runner.IListensToTestExecutions;
@@ -39,6 +33,12 @@
 import org.eclipse.jdt.internal.junit.runner.TestExecution;
 import org.eclipse.jdt.internal.junit.runner.TestReferenceFailure;
 
+import junit.extensions.TestDecorator;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
 public class JUnit3TestReference implements ITestReference {
 
 	private final Test fTest;
@@ -124,22 +124,22 @@
 	public void sendTree(IVisitsTestTrees notified) {
 		if (fTest instanceof TestDecorator) {
 			TestDecorator decorator= (TestDecorator) fTest;
-			notified.visitTreeEntry(getIdentifier(), true, 1);
+			notified.visitTreeEntry(getIdentifier(), true, 1, false, "-1"); //$NON-NLS-1$
 			sendTreeOfChild(decorator.getTest(), notified);
 		} else if (fTest instanceof TestSuite) {
 			TestSuite suite= (TestSuite) fTest;
-			notified.visitTreeEntry(getIdentifier(), true, suite.testCount());
+			notified.visitTreeEntry(getIdentifier(), true, suite.testCount(), false, "-1"); //$NON-NLS-1$
 			for (int i= 0; i < suite.testCount(); i++) {
 				sendTreeOfChild(suite.testAt(i), notified);
 			}
 		} else if (isJUnit4TestSuiteAdapter(fTest)) {
 			List tests= (List) callJUnit4GetterMethod(fTest, "getTests"); //$NON-NLS-1$
-			notified.visitTreeEntry(getIdentifier(), true, tests.size());
+			notified.visitTreeEntry(getIdentifier(), true, tests.size(), false, "-1"); //$NON-NLS-1$
 			for (Iterator iter= tests.iterator(); iter.hasNext();) {
 				sendTreeOfChild((Test) iter.next(), notified);
 			}
 		} else {
-			notified.visitTreeEntry(getIdentifier(), false, fTest.countTestCases());
+			notified.visitTreeEntry(getIdentifier(), false, fTest.countTestCases(), false, "-1"); //$NON-NLS-1$
 		}
 	}
 
diff --git a/org.eclipse.jdt.junit/.settings/.api_filters b/org.eclipse.jdt.junit/.settings/.api_filters
new file mode 100644
index 0000000..c6a48b2
--- /dev/null
+++ b/org.eclipse.jdt.junit/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jdt.junit" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter comment="keep the same version as in 4.7.1 for now" id="924844039">
+            <message_arguments>
+                <message_argument value="3.10.0"/>
+                <message_argument value="3.10.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jdt.junit/plugin.xml b/org.eclipse.jdt.junit/plugin.xml
index 95e5c39..47e3688 100644
--- a/org.eclipse.jdt.junit/plugin.xml
+++ b/org.eclipse.jdt.junit/plugin.xml
@@ -224,9 +224,14 @@
                   <count value="1"/>
                	  <iterate>
                      <adapt type="org.eclipse.jdt.core.IJavaElement">
-		                <test property="org.eclipse.jdt.core.isInJavaProject"/>
-		                <test property="org.eclipse.jdt.core.hasTypeOnClasspath" value="junit.framework.Test"/>
-		                <test property="org.eclipse.jdt.junit.canLaunchAsJUnit" forcePluginActivation="true"/>
+                     	<and>
+		                	<test property="org.eclipse.jdt.core.isInJavaProject"/>
+		                	<or>
+		                	<test property="org.eclipse.jdt.core.hasTypeOnClasspath" value="junit.framework.Test"/>
+		                	<test property="org.eclipse.jdt.core.hasTypeOnClasspath" value="org.junit.platform.commons.annotation.Testable"/>
+		                	</or>
+		                	<test property="org.eclipse.jdt.junit.canLaunchAsJUnit" forcePluginActivation="true"/>
+                  		</and>
 		             </adapt>
 		          </iterate>
                </with>
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerWizardPage.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerWizardPage.java
index 3815217..c5ef299 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerWizardPage.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/buildpath/JUnitContainerWizardPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -36,6 +36,7 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 import org.eclipse.jdt.internal.junit.BasicElementLabels;
 import org.eclipse.jdt.internal.junit.ui.JUnitMessages;
 import org.eclipse.jdt.internal.junit.util.ExceptionHandler;
@@ -120,7 +121,8 @@
 		fVersionCombo= new Combo(composite, SWT.READ_ONLY);
 		fVersionCombo.setItems(new String[] {
 				JUnitMessages.JUnitContainerWizardPage_option_junit3,
-				JUnitMessages.JUnitContainerWizardPage_option_junit4
+				JUnitMessages.JUnitContainerWizardPage_option_junit4,
+				JUnitMessages.JUnitContainerWizardPage_option_junit5
 		});
 		fVersionCombo.setFont(composite.getFont());
 
@@ -130,8 +132,10 @@
 
 		if (fContainerEntryResult != null && JUnitCore.JUNIT3_CONTAINER_PATH.equals(fContainerEntryResult.getPath())) {
 			fVersionCombo.select(0);
-		} else {
+		} else if (fContainerEntryResult != null && JUnitCore.JUNIT4_CONTAINER_PATH.equals(fContainerEntryResult.getPath())) {
 			fVersionCombo.select(1);
+		} else {
+			fVersionCombo.select(2);
 		}
 		fVersionCombo.addModifyListener(new ModifyListener() {
 			@Override
@@ -182,7 +186,10 @@
 
 		IClasspathEntry libEntry;
 		IPath containerPath;
-		if (fVersionCombo != null && fVersionCombo.getSelectionIndex() == 1) {
+		if (fVersionCombo != null && fVersionCombo.getSelectionIndex() == 2) {
+			containerPath= JUnitCore.JUNIT5_CONTAINER_PATH;
+			libEntry= BuildPathSupport.getJUnitJupiterApiLibraryEntry();
+		} else if (fVersionCombo != null && fVersionCombo.getSelectionIndex() == 1) {
 			containerPath= JUnitCore.JUNIT4_CONTAINER_PATH;
 			libEntry= BuildPathSupport.getJUnit4LibraryEntry();
 		} else {
@@ -198,6 +205,10 @@
 			if (fProject != null && !JUnitStubUtility.is50OrHigher(fProject)) {
 				status.setWarning(JUnitMessages.JUnitContainerWizardPage_warning_java5_required);
 			}
+		} else if (JUnitCore.JUNIT5_CONTAINER_PATH.equals(containerPath)) {
+			if (fProject != null && !JavaModelUtil.is18OrHigher(fProject)) {
+				status.setWarning(JUnitMessages.JUnitContainerWizardPage_warning_java8_required);
+			}
 		}
 		fContainerEntryResult= JavaCore.newContainerEntry(containerPath);
 
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitClasspathFixProcessor.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitClasspathFixProcessor.java
index 76ee46b..4cb222f 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitClasspathFixProcessor.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitClasspathFixProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 IBM Corporation and others.
+ * Copyright (c) 2007, 2016 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
@@ -37,18 +37,21 @@
 
 	private static class JUnitClasspathFixProposal extends ClasspathFixProposal {
 
-		private final boolean fIsJunit4;
+		private final int fJunitVersion;
 		private final int fRelevance;
 		private final IJavaProject fProject;
-		public JUnitClasspathFixProposal(IJavaProject project, boolean isJunit4, int relevance) {
+		public JUnitClasspathFixProposal(IJavaProject project, int junitVersion, int relevance) {
 			fProject= project;
-			fIsJunit4= isJunit4;
+			fJunitVersion= junitVersion;
 			fRelevance= relevance;
 		}
 
 		@Override
 		public String getAdditionalProposalInfo() {
-			if (fIsJunit4) {
+			if (fJunitVersion == 5) {
+				return JUnitMessages.JUnitAddLibraryProposal_junit5_info;
+			}
+			if (fJunitVersion == 4) {
 				return JUnitMessages.JUnitAddLibraryProposal_junit4_info;
 			}
 			return JUnitMessages.JUnitAddLibraryProposal_info;
@@ -62,7 +65,9 @@
 			monitor.beginTask(JUnitMessages.JUnitClasspathFixProcessor_progress_desc, 1);
 			try {
 				IClasspathEntry entry= null;
-				if (fIsJunit4) {
+				if (fJunitVersion == 5) {
+					entry= BuildPathSupport.getJUnit5ClasspathEntry();
+				} else if (fJunitVersion == 4) {
 					entry= BuildPathSupport.getJUnit4ClasspathEntry();
 				} else {
 					entry= BuildPathSupport.getJUnit3ClasspathEntry();
@@ -116,7 +121,10 @@
 
 		@Override
 		public String getDisplayString() {
-			if (fIsJunit4) {
+			if (fJunitVersion == 5) {
+				return JUnitMessages.JUnitAddLibraryProposa_junit5_label;
+			}
+			if (fJunitVersion == 4) {
 				return JUnitMessages.JUnitAddLibraryProposa_junit4_label;
 			}
 			return JUnitMessages.JUnitAddLibraryProposal_label;
@@ -135,28 +143,36 @@
 
 	private static final int JUNIT3= 1;
 	private static final int JUNIT4= 2;
+	private static final int JUNIT5= 4;
 
 
 	@Override
 	public ClasspathFixProposal[] getFixImportProposals(IJavaProject project, String missingType) throws CoreException {
 		String s= missingType;
 		int res= 0;
-		if (s.startsWith("org.junit.")) { //$NON-NLS-1$
+		if (s.startsWith("org.junit.jupiter") || s.startsWith("org.junit.platform")) { //$NON-NLS-1$ //$NON-NLS-2$
+			res= JUNIT5;
+		} else if (s.startsWith("org.junit.")) { //$NON-NLS-1$
 			res= JUNIT4;
 		} else if (s.equals("TestCase") || s.equals("TestSuite") || s.startsWith("junit.")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 			res= JUNIT3;
 		} else if (s.equals("Test")) { //$NON-NLS-1$
-			res= JUNIT3 | JUNIT4;
+			res= JUNIT3 | JUNIT4 | JUNIT5;
+		} else if (s.equals("TestFactory") || s.equals("Testable") || s.equals("TestTemplate") || s.equals("ParameterizedTest") || s.equals("RepeatedTest")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+			res= JUNIT5;
 		} else if (s.equals("RunWith")) { //$NON-NLS-1$
 			res= JUNIT4;
 		}
 		if (res != 0) {
 			ArrayList<JUnitClasspathFixProposal> proposals= new ArrayList<>();
+			if ((res & JUNIT5) != 0 && JUnitStubUtility.is18OrHigher(project)) {
+				proposals.add(new JUnitClasspathFixProposal(project, 5, 15));
+			}
 			if ((res & JUNIT4) != 0 && JUnitStubUtility.is50OrHigher(project)) {
-				proposals.add(new JUnitClasspathFixProposal(project, true, 15));
+				proposals.add(new JUnitClasspathFixProposal(project, 4, 15));
 			}
 			if ((res & JUNIT3) != 0) {
-				proposals.add(new JUnitClasspathFixProposal(project, false, 15));
+				proposals.add(new JUnitClasspathFixProposal(project, 3, 15));
 			}
 			return proposals.toArray(new ClasspathFixProposal[proposals.size()]);
 		}
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.java
index 5fe2772..201de7f 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.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
@@ -57,12 +57,14 @@
 	public static String GotoReferencedTestAction_selectdialog_title;
 
 	public static String JUnitAddLibraryProposa_junit4_label;
+	public static String JUnitAddLibraryProposa_junit5_label;
 
 	public static String JUnitAddLibraryProposal_info;
 	public static String JUnitAddLibraryProposal_title;
 	public static String JUnitAddLibraryProposal_cannotAdd;
 
 	public static String JUnitAddLibraryProposal_junit4_info;
+	public static String JUnitAddLibraryProposal_junit5_info;
 	public static String JUnitAddLibraryProposal_label;
 
 	public static String JUnitContainerWizardPage_combo_label;
@@ -79,6 +81,8 @@
 
 	public static String JUnitContainerWizardPage_option_junit4;
 
+	public static String JUnitContainerWizardPage_option_junit5;
+
 	public static String JUnitClasspathFixProcessor_progress_desc;
 
 	public static String JUnitContainerWizardPage_resolved_label;
@@ -89,6 +93,8 @@
 
 	public static String JUnitContainerWizardPage_warning_java5_required;
 
+	public static String JUnitContainerWizardPage_warning_java8_required;
+
 	public static String JUnitContainerWizardPage_wizard_description;
 
 	public static String JUnitContainerWizardPage_wizard_title;
@@ -99,6 +105,8 @@
 
 	public static String JUnitLaunchConfigurationTab_error_JDK15_required;
 
+	public static String JUnitLaunchConfigurationTab_error_JDK18_required;
+
 	public static String JUnitLaunchConfigurationTab_error_noContainer;
 
 	public static String JUnitLaunchConfigurationTab_error_notJavaProject;
@@ -250,8 +258,12 @@
 	public static String TestRunnerViewPart_cannotrerun_title;
 	public static String TestRunnerViewPart_cannotrerurn_message;
 	public static String TestRunnerViewPart_configName;
+
+	public static String TestRunnerViewPart__error_cannotrun;
 	public static String TestRunnerViewPart_error_cannotrerun;
 
+	public static String TestRunnerViewPart_error_notests_kind;
+
 	public static String TestRunnerViewPart_ExportTestRunSessionAction_error_title;
 
 	public static String TestRunnerViewPart_ExportTestRunSessionAction_name;
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.properties b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.properties
index a3b12cd..083b628 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.properties
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitMessages.properties
@@ -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
@@ -23,9 +23,9 @@
 CounterPanel_label_failures=Failures: 
 CounterPanel_runcount= {0}/{1}
 CounterPanel_runcount_skipped= {0}/{1} ({2} skipped)
-CounterPanel_runcount_ignored= {0}/{1} ({2} ignored)
+CounterPanel_runcount_ignored= {0}/{1} ({2} disabled)
 CounterPanel_runcount_assumptionsFailed= {0}/{1} ({2} assumption failures)
-CounterPanel_runcount_ignored_assumptionsFailed= {0}/{1} ({2} ignored, {3} assumption failures)
+CounterPanel_runcount_ignored_assumptionsFailed= {0}/{1} ({2} disabled, {3} assumption failures)
 
 EnableStackFilterAction_action_label=Filter
 EnableStackFilterAction_action_description=Filter the stack trace
@@ -50,6 +50,7 @@
 JUnitPreferencePage_addtypedialog_message=&Select a class to filter in the failure stack trace:
 JUnitPreferencePage_addtypedialog_error_message=Could not open type selection dialog for stack filters.
 JUnitContainerWizardPage_warning_java5_required=JUnit 4 requires a Java 5 project
+JUnitContainerWizardPage_warning_java8_required=JUnit 5 requires a Java 8 project
 JUnitPreferencePage_addpackagedialog_title=Add Packages to Stack Filters
 JUnitPreferencePage_addpackagedialog_message=&Select a package to filter in the failure stack trace:
 JUnitPreferencePage_enableassertionscheckbox_label=Add '-ea' to VM arguments when creating a new &JUnit launch configuration
@@ -93,6 +94,7 @@
 TestRunnerViewPart_ExportTestRunSessionAction_title=Export Test Run
 TestRunnerViewPart_ExportTestRunSessionAction_error_title=Export Test Run
 TestRunnerViewPart_error_cannotrerun=Could not rerun test
+TestRunnerViewPart_error_notests_kind=No tests found with test runner ''{0}''.
 TestRunnerViewPart_message_terminated=Terminated
 TestRunnerViewPart_cannotrerun_title=Rerun Test
 TestRunnerViewPart_cannotrerurn_message=To rerun tests they must be launched under the debugger\nand \'Keep JUnit running\' must be set in the launch configuration.
@@ -104,6 +106,7 @@
 TestRunnerViewPart_message_stopping=Stopping...
 TestRunnerViewPart_message_started= {0} - {1}
 TestRunnerViewPart_configName=Rerun {0}
+TestRunnerViewPart__error_cannotrun=Could not run test
 TestRunnerViewPart_layout_menu=&Layout
 TestRunnerViewPart_Launching=Launching {0}...
 TestRunnerViewPart_test_runs=Test Runs
@@ -129,7 +132,7 @@
 JUnitLaunchConfigurationDelegate_dialog_title=Problems Launching JUnit Tests
 JUnitLaunchConfigurationTab_error_test_class_not_found=Can not find test class ''{0}'' in project ''{1}''
 JUnitLaunchConfigurationTab_error_test_method_not_found=Can not find test method {0}.{1} in project {2}
-JUnitLaunchConfigurationTab_error_testannotationnotonpath=Cannot find class 'org.junit.Test' on project build path.
+JUnitLaunchConfigurationTab_error_testannotationnotonpath=Cannot find class ''{0}'' on project build path.
 JUnitLaunchConfigurationTab_label_oneTest=Run a s&ingle test
 JUnitLaunchConfigurationTab_label_project=&Project:
 JUnitClasspathFixProcessor_progress_desc=Adding JUnit library
@@ -162,9 +165,11 @@
 JUnitContainerWizardPage_combo_label=&JUnit library version:
 JUnitLaunchConfigurationTab_error_invalidProjectName=''{0}'' is not a valid project name
 JUnitLaunchConfigurationTab_error_JDK15_required=JUnit 4 requires a JDK version of 1.5 or higher
+JUnitLaunchConfigurationTab_error_JDK18_required=JUnit 5 requires a JDK version of 1.8 or higher
 JUnitContainerWizardPage_wizard_title=JUnit Library
 JUnitContainerWizardPage_option_junit3=JUnit 3
 JUnitContainerWizardPage_option_junit4=JUnit 4
+JUnitContainerWizardPage_option_junit5=JUnit 5
 JUnitContainerWizardPage_resolved_label=Current location:
 JUnitLaunchShortcut_message_launchfailed=Launching of JUnit tests unexpectedly failed. Check log for details.
 JUnitLaunchConfigurationTab_error_noContainer=No project, source folder or package is specified
@@ -217,6 +222,8 @@
 JUnitQuickFixProcessor_apply_problem_title=JUnit Quick Fix
 JUnitQuickFixProcessor_add_assert_info=Adds a static import ''{0}''.
 
+JUnitAddLibraryProposa_junit5_label=Add JUnit 5 library to the build path
+JUnitAddLibraryProposal_junit5_info=Adds the JUnit 5 library to the build path.
 JUnitAddLibraryProposal_info=Adds the JUnit 3 library to the build path.
 JUnitAddLibraryProposa_junit4_label=Add JUnit 4 library to the build path
 JUnitAddLibraryProposal_junit4_info=Adds the JUnit 4 library to the build path.
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPlugin.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPlugin.java
index 8257678..2c95cca 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPlugin.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPlugin.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -16,7 +16,11 @@
 
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -46,6 +50,8 @@
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 
+import org.eclipse.jdt.ui.PreferenceConstants;
+
 /**
  * The plug-in runtime class for the JUnit plug-in.
  */
@@ -187,18 +193,56 @@
 		return null;
 	}
 
-	/**
-	 * @see AbstractUIPlugin#start(BundleContext)
-	 */
 	@Override
 	public void start(BundleContext context) throws Exception {
 		super.start(context);
 		fBundleContext= context;
+		setCodeassistFavoriteStaticMembers();
 	}
 
 	/**
-	 * @see AbstractUIPlugin#stop(BundleContext)
+	 * Add the new default static import favorites in old workspaces that already have non-default
+	 * favorites. Only do this once, so that users have a way to opt-out if they don't want the new
+	 * favorites.
 	 */
+	private void setCodeassistFavoriteStaticMembers() {
+		Set<String> favoritesToAdd= new LinkedHashSet<>();
+		favoritesToAdd.add("org.junit.Assert.*"); //$NON-NLS-1$
+		favoritesToAdd.add("org.junit.Assume.*"); //$NON-NLS-1$
+		favoritesToAdd.add("org.junit.jupiter.api.Assertions.*"); //$NON-NLS-1$
+		favoritesToAdd.add("org.junit.jupiter.api.Assumptions.*"); //$NON-NLS-1$
+		favoritesToAdd.add("org.junit.jupiter.api.DynamicContainer.*"); //$NON-NLS-1$
+		favoritesToAdd.add("org.junit.jupiter.api.DynamicTest.*"); //$NON-NLS-1$
+
+		// default value
+		Set<String> defaultFavorites= new LinkedHashSet<>();
+		String defaultPreferenceValue= PreferenceConstants.getPreferenceStore().getDefaultString(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS);
+		if (defaultPreferenceValue != null && defaultPreferenceValue.length() > 0) {
+			defaultFavorites.addAll(Arrays.asList(defaultPreferenceValue.split(";"))); //$NON-NLS-1$
+		}
+		defaultFavorites.addAll(favoritesToAdd);
+		String newDefaultPreferenceValue= defaultFavorites.stream().collect(Collectors.joining(";")); //$NON-NLS-1$
+		PreferenceConstants.getPreferenceStore().setDefault(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS, newDefaultPreferenceValue);
+
+		// current value
+		if (JUnitUIPreferencesConstants.isCodeassistFavoriteStaticMembersMigrated()) {
+			return;
+		}
+		Set<String> currentFavorites= new LinkedHashSet<>();
+		String currentPreferenceValue= PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS);
+		if (currentPreferenceValue != null && currentPreferenceValue.length() > 0) {
+			currentFavorites.addAll(Arrays.asList(currentPreferenceValue.split(";"))); //$NON-NLS-1$
+		}
+		favoritesToAdd.removeAll(currentFavorites);
+		if (!favoritesToAdd.isEmpty()) {
+			String newPreferenceValue= currentPreferenceValue + ";" + favoritesToAdd.stream().collect(Collectors.joining(";")); //$NON-NLS-1$ //$NON-NLS-2$
+			PreferenceConstants.getPreferenceStore().setValue(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS, newPreferenceValue);
+		}
+
+		// set as migrated
+		JUnitUIPreferencesConstants.setCodeassistFavoriteStaticMembersMigrated(true);
+	}
+
 	@Override
 	public void stop(BundleContext context) throws Exception {
 		fIsStopped= true;
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitQuickFixProcessor.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitQuickFixProcessor.java
index 53fbe0e..4077d4b 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitQuickFixProcessor.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitQuickFixProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 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
@@ -65,12 +65,13 @@
 import org.eclipse.jdt.ui.CodeStyleConfiguration;
 import org.eclipse.jdt.ui.ISharedImages;
 import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jdt.ui.PreferenceConstants;
 import org.eclipse.jdt.ui.text.java.ClasspathFixProcessor;
+import org.eclipse.jdt.ui.text.java.ClasspathFixProcessor.ClasspathFixProposal;
 import org.eclipse.jdt.ui.text.java.IInvocationContext;
 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
 import org.eclipse.jdt.ui.text.java.IProblemLocation;
 import org.eclipse.jdt.ui.text.java.IQuickFixProcessor;
-import org.eclipse.jdt.ui.text.java.ClasspathFixProcessor.ClasspathFixProposal;
 
 public class JUnitQuickFixProcessor implements IQuickFixProcessor {
 
@@ -103,7 +104,10 @@
 			if (IProblem.UndefinedType == id) {
 				res= getAddJUnitToBuildPathProposals(context, problem, res);
 			} else if (id == IProblem.UndefinedMethod) {
-				res= getAddAssertImportProposals(context, problem, res);
+				String currentPreferenceValue= PreferenceConstants.getPreferenceStore().getString(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS);
+				if (!currentPreferenceValue.contains("org.junit.Assert.*")) { //$NON-NLS-1$
+					res= getAddAssertImportProposals(context, problem, res);
+				}
 			}
 		}
 		if (res == null || res.isEmpty()) {
@@ -131,6 +135,7 @@
 		try {
 			ICompilationUnit unit= context.getCompilationUnit();
 			String qualifiedName= null;
+			String qualifiedName1= null;
 
 			String s= unit.getBuffer().getText(location.getOffset(), location.getLength());
 			if (s.equals("TestCase") || s.equals("TestSuite")) { //$NON-NLS-1$ //$NON-NLS-2$
@@ -141,21 +146,31 @@
 				ASTNode node= location.getCoveredNode(context.getASTRoot());
 				if (node != null && node.getLocationInParent() == MarkerAnnotation.TYPE_NAME_PROPERTY) {
 					qualifiedName= "org.junit.Test"; //$NON-NLS-1$
+					qualifiedName1= "org.junit.jupiter.api.Test"; //$NON-NLS-1$
 				} else {
 					qualifiedName= "junit.framework.Test"; //$NON-NLS-1$
 				}
+			} else if (s.equals("TestFactory")) { //$NON-NLS-1$
+				qualifiedName= "org.junit.jupiter.api.TestFactory"; //$NON-NLS-1$
+			} else if (s.equals("Testable")) { //$NON-NLS-1$
+				qualifiedName= "org.junit.platform.commons.annotation.Testable"; //$NON-NLS-1$				
+			} else if (s.equals("TestTemplate")) { //$NON-NLS-1$
+				qualifiedName= "org.junit.jupiter.api.TestTemplate"; //$NON-NLS-1$
+			} else if (s.equals("ParameterizedTest")) { //$NON-NLS-1$
+				qualifiedName= "org.junit.jupiter.params.ParameterizedTest"; //$NON-NLS-1$
+			} else if (s.equals("RepeatedTest")) { //$NON-NLS-1$
+				qualifiedName= "org.junit.jupiter.api.RepeatedTest"; //$NON-NLS-1$
 			}
-			if (qualifiedName != null) {
-				IJavaProject javaProject= unit.getJavaProject();
-				if (javaProject.findType(qualifiedName) != null) {
-					return proposals;
+			IJavaProject javaProject= unit.getJavaProject();
+			if (!(foundInProjectClasspath(javaProject, qualifiedName) && foundInProjectClasspath(javaProject, qualifiedName1))) {
+				if (qualifiedName != null) {
+					proposals= addProposal(context, proposals, qualifiedName, javaProject);
 				}
-				ClasspathFixProposal[] fixProposals= ClasspathFixProcessor.getContributedFixImportProposals(javaProject, qualifiedName, null);
-				for (ClasspathFixProposal fixProposal : fixProposals) {
-					if (proposals == null)
-						proposals= new ArrayList<>();
-					proposals.add(new JUnitClasspathFixCorrectionProposal(javaProject, fixProposal, getImportRewrite(context.getASTRoot(), qualifiedName)));
+				if (qualifiedName1 != null) {
+					proposals= addProposal(context, proposals, qualifiedName1, javaProject);
 				}
+			} else {
+				return proposals;
 			}
 		} catch (JavaModelException e) {
 		    JUnitPlugin.log(e.getStatus());
@@ -163,6 +178,20 @@
 		return proposals;
 	}
 
+	private ArrayList<IJavaCompletionProposal> addProposal(IInvocationContext context, ArrayList<IJavaCompletionProposal> proposals, String qualifiedName, IJavaProject javaProject) {
+		ClasspathFixProposal[] fixProposals= ClasspathFixProcessor.getContributedFixImportProposals(javaProject, qualifiedName, null);
+		for (ClasspathFixProposal fixProposal : fixProposals) {
+			if (proposals == null)
+				proposals= new ArrayList<>();
+			proposals.add(new JUnitClasspathFixCorrectionProposal(javaProject, fixProposal, getImportRewrite(context.getASTRoot(), qualifiedName)));
+		}
+		return proposals;
+	}
+
+	private boolean foundInProjectClasspath(IJavaProject javaProject, String qualifiedName) throws JavaModelException {
+		return qualifiedName != null && javaProject.findType(qualifiedName) != null;
+	}
+
 	private ImportRewrite getImportRewrite(CompilationUnit astRoot, String typeToImport) {
 		if (typeToImport != null) {
 			ImportRewrite importRewrite= CodeStyleConfiguration.createImportRewrite(astRoot, true);
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitUIPreferencesConstants.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitUIPreferencesConstants.java
index e107968..c730610 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitUIPreferencesConstants.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitUIPreferencesConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2016 IBM Corporation and others.
+ * Copyright (c) 2010, 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
@@ -30,6 +30,8 @@
 
 	public static final boolean SHOW_IN_ALL_VIEWS_DEFAULT= false; // would need a PreferenceInitializer if this was changed to true!
 
+	private static final String CODEASSIST_FAVORITE_STATIC_MEMBERS_MIGRATED= JUnitPlugin.PLUGIN_ID + ".content_assist_favorite_static_members_migrated"; //$NON-NLS-1$
+
 	private JUnitUIPreferencesConstants() {
 		// no instance
 	}
@@ -47,4 +49,18 @@
 			JUnitPlugin.log(e);
 		}
 	}
+
+	public static boolean isCodeassistFavoriteStaticMembersMigrated() {
+		return Platform.getPreferencesService().getBoolean(JUnitPlugin.PLUGIN_ID, CODEASSIST_FAVORITE_STATIC_MEMBERS_MIGRATED, false, null);
+	}
+
+	public static void setCodeassistFavoriteStaticMembersMigrated(boolean migrated) {
+		IEclipsePreferences preferences= InstanceScope.INSTANCE.getNode(JUnitPlugin.PLUGIN_ID);
+		preferences.putBoolean(CODEASSIST_FAVORITE_STATIC_MEMBERS_MIGRATED, migrated);
+		try {
+			preferences.flush();
+		} catch (BackingStoreException e) {
+			JUnitPlugin.log(e);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/OpenTestAction.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/OpenTestAction.java
index ad805f7..f78eae4 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/OpenTestAction.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/OpenTestAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 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
@@ -11,14 +11,21 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.junit.ui;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
 
 import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
 
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
@@ -27,7 +34,6 @@
 
 import org.eclipse.ui.texteditor.ITextEditor;
 
-import org.eclipse.jdt.core.IAnnotation;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IMethod;
@@ -37,6 +43,14 @@
 import org.eclipse.jdt.core.JavaConventions;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.core.search.SearchRequestor;
 
 import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
 import org.eclipse.jdt.internal.junit.BasicElementLabels;
@@ -52,11 +66,14 @@
 public class OpenTestAction extends OpenEditorAction {
 
 	private String fMethodName;
+	private String[] fMethodParamTypes;
 	private IMethod fMethod;
 	private int fLineNumber= -1;
 
-	public OpenTestAction(TestRunnerViewPart testRunnerPart, TestCaseElement testCase) {
-		this(testRunnerPart, testCase.getClassName(), extractRealMethodName(testCase), true);
+	private IType fType;
+
+	public OpenTestAction(TestRunnerViewPart testRunnerPart, TestCaseElement testCase, String[] methodParamTypes) {
+		this(testRunnerPart, testCase.getClassName(), extractRealMethodName(testCase), methodParamTypes, true);
 		String trace= testCase.getTrace();
 		if (trace != null) {
 			String rawClassName= TestElement.extractRawClassName(testCase.getTestName());
@@ -78,13 +95,14 @@
 	}
 
 	public OpenTestAction(TestRunnerViewPart testRunner, String className) {
-		this(testRunner, className, null, true);
+		this(testRunner, className, null, null, true);
 	}
 
-	private OpenTestAction(TestRunnerViewPart testRunner, String className, String method, boolean activate) {
+	public OpenTestAction(TestRunnerViewPart testRunner, String className, String method, String[] methodParamTypes, boolean activate) {
 		super(testRunner, className, activate);
 		PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJUnitHelpContextIds.OPENTEST_ACTION);
 		fMethodName= method;
+		fMethodParamTypes= methodParamTypes;
 	}
 
 	private static String extractRealMethodName(TestCaseElement testCase) {
@@ -109,23 +127,32 @@
 		if (type == null)
 			return null;
 
-		if (fMethodName == null)
+		if (fMethodName == null) {
+			fType= type;
 			return type;
+		}
 
-		IMethod method= findMethod(type);
-		if (method == null) {
-			ITypeHierarchy typeHierarchy= type.newSupertypeHierarchy(null);
-			IType[] supertypes= typeHierarchy.getAllSuperclasses(type);
-			for (IType supertype : supertypes) {
-				method= findMethod(supertype);
-				if (method != null)
-					break;
+		IMethod method= null;
+		try {
+			method= findMethod(type);
+			if (method == null) {
+				ITypeHierarchy typeHierarchy= type.newSupertypeHierarchy(null);
+				IType[] supertypes= typeHierarchy.getAllSupertypes(type);
+				for (IType supertype : supertypes) {
+					method= findMethod(supertype);
+					if (method != null)
+						break;
+				}
 			}
+		} catch (OperationCanceledException e) {
+			// user cancelled the selection dialog - ignore and proceed
 		}
 		if (method == null) {
-			String title= JUnitMessages.OpenTestAction_dialog_title;
-			String message= Messages.format(JUnitMessages.OpenTestAction_error_methodNoFound, BasicElementLabels.getJavaElementName(fMethodName));
-			MessageDialog.openInformation(getShell(), title, message);
+			if (fLineNumber < 0) {
+				String title= JUnitMessages.OpenTestAction_dialog_title;
+				String message= Messages.format(JUnitMessages.OpenTestAction_error_methodNoFound, BasicElementLabels.getJavaElementName(fMethodName));
+				MessageDialog.openInformation(getShell(), title, message);
+			}
 			return type;
 		}
 
@@ -137,34 +164,91 @@
 		IStatus status= JavaConventionsUtil.validateMethodName(fMethodName, type);
 		if (! status.isOK())
 			return null;
-		IMethod method= type.getMethod(fMethodName, new String[0]);
-		if (method != null && method.exists())
-			return method;
 
-		// search just by name, if method not found yet (for custom runner with test methods having parameters)
+		List<IMethod> foundMethods= new ArrayList<>();
 		try {
-			List<IMethod> foundMethods= new ArrayList<>();
-			for (IMethod method2 : type.getMethods()) {
-				String methodName= method2.getElementName();
-				IAnnotation methodAnnotation= method2.getAnnotation("Test"); //$NON-NLS-1$
+			PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
+				@Override
+				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+					String methodPattern= type.getFullyQualifiedName('.') + '.' + fMethodName;
+					if (fMethodParamTypes != null && fMethodParamTypes.length > 0) {
+						String paramTypes= Arrays.stream(fMethodParamTypes).map(paramType -> {
+							try {
+								return paramType= Signature.toString(paramType);
+							} catch (IllegalArgumentException e) {
+								// return the paramType as it is
+							}
+							return paramType.replace('$', '.'); // for nested classes... See OpenEditorAction#findType also.
+						}).collect(Collectors.joining(", ", "(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+						methodPattern+= paramTypes;
+					} else {
+						methodPattern+= "()"; //$NON-NLS-1$
+					}
+					int matchRule= SearchPattern.R_ERASURE_MATCH | SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
+					SearchPattern searchPattern= SearchPattern.createPattern(methodPattern, IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, matchRule);
+					if (searchPattern == null) {
+						return;
+					}
+					SearchRequestor requestor= new SearchRequestor() {
+						@Override
+						public void acceptSearchMatch(SearchMatch match) throws CoreException {
+							Object element= match.getElement();
+							if (element instanceof IMethod) {
+								foundMethods.add((IMethod) element);
+							}
+						}
+					};
+					SearchParticipant[] participants= new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
+					IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaElement[] { type });
+					try {
+						new SearchEngine().search(searchPattern, participants, scope, requestor, monitor);
+					} catch (CoreException e) {
+						JUnitPlugin.log(e);
+					}
+				}
+			});
+		} catch (InvocationTargetException e) {
+			JUnitPlugin.log(e);
+		} catch (InterruptedException e) {
+			// user cancelled
+		}
 
-				// JUnit3 test method starts with "test" or JUnit4 test method is annotated with "@Test"
-				if (!(methodName.startsWith("test") || (methodAnnotation != null && methodAnnotation.exists()))) //$NON-NLS-1$
-					continue;
-
-				if (fMethodName.equals(methodName))
-					foundMethods.add(method2);
+		if (foundMethods.size() == 1) {
+			return foundMethods.get(0);
+		} else if (foundMethods.size() > 1) {
+			IMethod method= openSelectionDialog(foundMethods);
+			if (method == null) {
+				throw new OperationCanceledException();
 			}
-			if (foundMethods.isEmpty())
-				return null;
-			else if (foundMethods.size() > 1) {
-				IMethod[] elements= foundMethods.toArray(new IMethod[foundMethods.size()]);
-				String title= JUnitMessages.OpenTestAction_dialog_title;
-				String message= JUnitMessages.OpenTestAction_select_element;
+			return method;
+		}
 
-				return (IMethod)SelectionConverter.selectJavaElement(elements, getShell(), title, message);
-			} else
+		// search just by name and number of parameters, if method not found yet
+		try {
+			for (IMethod method : type.getMethods()) {
+				String methodName= method.getElementName();
+				if (fMethodName.equals(methodName)) {
+					int numOfParams= method.getNumberOfParameters();
+					int requiredNumOfParams= 0;
+					if (fMethodParamTypes != null) {
+						requiredNumOfParams= fMethodParamTypes.length;
+					}
+					if (numOfParams == requiredNumOfParams) {
+						foundMethods.add(method);
+					}
+				}
+			}
+			if (foundMethods.isEmpty()) {
+				return null;
+			} else if (foundMethods.size() > 1) {
+				IMethod method= openSelectionDialog(foundMethods);
+				if (method == null) {
+					throw new OperationCanceledException();
+				}
+				return method;
+			} else {
 				return foundMethods.get(0);
+			}
 		} catch (JavaModelException e) {
 			// if type does not exist or if an exception occurs while accessing its resource => ignore (no method found)
 		}
@@ -172,6 +256,13 @@
 		return null;
 	}
 
+	private IMethod openSelectionDialog(List<IMethod> foundMethods) {
+		IMethod[] elements= foundMethods.toArray(new IMethod[foundMethods.size()]);
+		String title= JUnitMessages.OpenTestAction_dialog_title;
+		String message= JUnitMessages.OpenTestAction_select_element;
+		return (IMethod) SelectionConverter.selectJavaElement(elements, getShell(), title, message);
+	}
+
 	@Override
 	protected void reveal(ITextEditor textEditor) {
 		if (fLineNumber >= 0) {
@@ -202,6 +293,16 @@
 				ISourceRange range= fMethod.getNameRange();
 				if (range != null && range.getOffset() >= 0)
 					textEditor.selectAndReveal(range.getOffset(), range.getLength());
+				return;
+			} catch (JavaModelException e) {
+				// not a problem
+			}
+		}
+		if (fType != null) {
+			try {
+				ISourceRange range= fType.getNameRange();
+				if (range != null && range.getOffset() >= 0)
+					textEditor.selectAndReveal(range.getOffset(), range.getLength());
 			} catch (JavaModelException e) {
 				// not a problem
 			}
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/RerunAction.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/RerunAction.java
index 69c9d79..a50fb08 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/RerunAction.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/RerunAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 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
@@ -21,7 +21,9 @@
 	private String fTestId;
 	private String fClassName;
 	private String fTestName;
+	private String fTestDisplayName;
 	private TestRunnerViewPart fTestRunner;
+	private String fUniqueId;
 	private String fLaunchMode;
 
 	/**
@@ -31,24 +33,25 @@
 	 * @param testId the test id
 	 * @param className the class name containing the test
 	 * @param testName the method to run or <code>null</code>
+	 * @param testDisplayName the display name of the test to re-run or <code>null</code>
+	 * @param uniqueId the unique ID of the test to re-run or <code>null</code>
 	 * @param launchMode the launch mode
 	 */
 	public RerunAction(String actionName, TestRunnerViewPart runner, String testId, String className, String testName,
-			String launchMode) {
+			String testDisplayName, String uniqueId, String launchMode) {
 		super(actionName);
 		PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJUnitHelpContextIds.RERUN_ACTION);
 		fTestRunner= runner;
 		fTestId= testId;
 		fClassName= className;
 		fTestName= testName;
+		fTestDisplayName= testDisplayName;
+		fUniqueId= uniqueId;
 		fLaunchMode= launchMode;
 	}
 
-	/*
-	 * @see IAction#run()
-	 */
 	@Override
 	public void run() {
-		fTestRunner.rerunTest(fTestId, fClassName, fTestName, fLaunchMode);
+		fTestRunner.rerunTest(fTestId, fClassName, fTestName, fTestDisplayName, fUniqueId, fLaunchMode);
 	}
 }
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java
index aa0ae47..c2fd084 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestRunnerViewPart.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
@@ -141,6 +141,7 @@
 import org.eclipse.jdt.internal.junit.Messages;
 import org.eclipse.jdt.internal.junit.launcher.ITestKind;
 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
+import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
 import org.eclipse.jdt.internal.junit.model.ITestRunSessionListener;
 import org.eclipse.jdt.internal.junit.model.ITestSessionListener;
 import org.eclipse.jdt.internal.junit.model.JUnitModel;
@@ -758,6 +759,7 @@
 				}
 			});
 			stopUpdateJobs();
+			showMessageIfNoTests();
 		}
 
 		@Override
@@ -1456,6 +1458,19 @@
 			}
 		});
 		stopUpdateJobs();
+		showMessageIfNoTests();
+	}
+
+	private void showMessageIfNoTests() {
+		if (fTestRunSession != null && TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(fTestRunSession.getTestRunnerKind().getId()) && fTestRunSession.getTotalCount() == 0) {
+			Display.getDefault().asyncExec(new Runnable() {
+				@Override
+				public void run() {
+					String msg= Messages.format(JUnitMessages.TestRunnerViewPart_error_notests_kind, fTestRunSession.getTestRunnerKind().getDisplayName());
+					MessageDialog.openInformation(JUnitPlugin.getActiveWorkbenchShell(), JUnitMessages.TestRunnerViewPart__error_cannotrun, msg);
+				}
+			});
+		}
 	}
 
 	private void resetViewIcon() {
@@ -1583,9 +1598,16 @@
 	}
 
 	private void updateRerunFailedFirstAction() {
-		boolean state= hasErrorsOrFailures() && fTestRunSession.getLaunch() != null;
-	    fRerunFailedFirstAction.setEnabled(state);
-    }
+		boolean state= !isJUnit5() && hasErrorsOrFailures() && fTestRunSession.getLaunch() != null;
+		fRerunFailedFirstAction.setEnabled(state);
+	}
+
+	private boolean isJUnit5() {
+		if (fTestRunSession == null) {
+			return false;
+		}
+		return TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(fTestRunSession.getTestRunnerKind().getId());
+	}
 
     /**
      * @return the display name of the current test run sessions kind, or <code>null</code>
@@ -2135,7 +2157,7 @@
 			getDisplay().asyncExec(r);
 	}
 
-	public void rerunTest(String testId, String className, String testName, String launchMode) {
+	public void rerunTest(String testId, String className, String testName, String testDisplayName, String uniqueId, String launchMode) {
 		if (lastLaunchIsKeptAlive()) {
 			fTestRunSession.rerunTest(testId, className, testName);
 			TestCaseElement testCaseElement= (TestCaseElement) fTestRunSession.getTestElement(testId);
@@ -2152,18 +2174,22 @@
 				ILaunchConfiguration launchConfiguration= launch.getLaunchConfiguration();
 				if (launchConfiguration != null) {
 					try {
-						String name= className;
-						if (testName != null)
-							name+= "."+testName; //$NON-NLS-1$
+						String name;
+						if (testDisplayName != null) {
+							name= testDisplayName;
+						} else {
+							name= className;
+							if (testName != null)
+								name+= "."+testName; //$NON-NLS-1$
+						}
 						String configName= Messages.format(JUnitMessages.TestRunnerViewPart_configName, name);
 						ILaunchConfigurationWorkingCopy tmp = launchConfiguration.copy(configName);
 						// fix for bug: 64838  junit view run single test does not use correct class [JUnit]
 						tmp.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, className);
 						// reset the container
 						tmp.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, ""); //$NON-NLS-1$
-						if (testName != null) {
-							tmp.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_NAME, testName);
-						}
+						tmp.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_NAME, testName);
+						tmp.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_UNIQUE_ID, uniqueId);
 						relaunch(tmp, launchMode);
 						return;
 						} catch (CoreException e) {
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestSessionLabelProvider.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestSessionLabelProvider.java
index d5d27b6..4eec28a 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestSessionLabelProvider.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestSessionLabelProvider.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
@@ -15,25 +15,23 @@
 
 import java.text.NumberFormat;
 
-import org.eclipse.jdt.junit.model.ITestCaseElement;
 import org.eclipse.jdt.junit.model.ITestElement;
 import org.eclipse.jdt.junit.model.ITestRunSession;
-import org.eclipse.jdt.junit.model.ITestSuiteElement;
 
 import org.eclipse.swt.graphics.Image;
 
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
 import org.eclipse.jface.viewers.StyledCellLabelProvider;
 import org.eclipse.jface.viewers.StyledString;
-import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
 
 import org.eclipse.jdt.internal.junit.BasicElementLabels;
 import org.eclipse.jdt.internal.junit.Messages;
 import org.eclipse.jdt.internal.junit.model.TestCaseElement;
 import org.eclipse.jdt.internal.junit.model.TestElement;
-import org.eclipse.jdt.internal.junit.model.TestSuiteElement;
 import org.eclipse.jdt.internal.junit.model.TestElement.Status;
+import org.eclipse.jdt.internal.junit.model.TestSuiteElement;
 
 public class TestSessionLabelProvider extends LabelProvider implements IStyledLabelProvider {
 
@@ -74,15 +72,29 @@
 			}
 
 		} else {
-			if (element instanceof ITestCaseElement) {
-				String className= BasicElementLabels.getJavaElementName(((ITestCaseElement) element).getTestClassName());
-				String decorated= Messages.format(JUnitMessages.TestSessionLabelProvider_testMethodName_className, new Object[] { label, className });
+			if (element instanceof TestCaseElement) {
+				String decorated= getTextForFlatLayout((TestCaseElement) testElement, label);
 				text= StyledCellLabelProvider.styleDecoratedString(decorated, StyledString.QUALIFIER_STYLER, text);
 			}
 		}
 		return addElapsedTime(text, testElement.getElapsedTimeInSeconds());
 	}
 
+	private String getTextForFlatLayout(TestCaseElement testCaseElement, String label) {
+		String parentName;
+		String parentDisplayName= testCaseElement.getParent().getDisplayName();
+		if (parentDisplayName != null) {
+			parentName= parentDisplayName;
+		} else {
+			if (testCaseElement.isDynamicTest()) {
+				parentName= testCaseElement.getTestMethodName();
+			} else {
+				parentName= testCaseElement.getTestClassName();
+			}
+		}
+		return Messages.format(JUnitMessages.TestSessionLabelProvider_testMethodName_className, new Object[] { label, BasicElementLabels.getJavaElementName(parentName) });
+	}
+
 	private StyledString addElapsedTime(StyledString styledString, double time) {
 		String string= styledString.getString();
 		String decorated= addElapsedTime(string, time);
@@ -98,10 +110,14 @@
 	}
 
 	private String getSimpleLabel(Object element) {
-		if (element instanceof ITestCaseElement) {
-			return BasicElementLabels.getJavaElementName(((ITestCaseElement) element).getTestMethodName());
-		} else if (element instanceof ITestSuiteElement) {
-			return BasicElementLabels.getJavaElementName(((ITestSuiteElement) element).getSuiteTypeName());
+		if (element instanceof TestCaseElement) {
+			TestCaseElement testCaseElement= (TestCaseElement) element;
+			String displayName= testCaseElement.getDisplayName();
+			return BasicElementLabels.getJavaElementName(displayName != null ? displayName : testCaseElement.getTestMethodName());
+		} else if (element instanceof TestSuiteElement) {
+			TestSuiteElement testSuiteElement= (TestSuiteElement) element;
+			String displayName= testSuiteElement.getDisplayName();
+			return BasicElementLabels.getJavaElementName(displayName != null ? displayName : testSuiteElement.getSuiteTypeName());
 		}
 		return null;
 	}
@@ -121,9 +137,8 @@
 				}
 			}
 		} else {
-			if (element instanceof ITestCaseElement) {
-				String className=  BasicElementLabels.getJavaElementName(((ITestCaseElement) element).getTestClassName());
-				label= Messages.format(JUnitMessages.TestSessionLabelProvider_testMethodName_className, new Object[] { label, className });
+			if (element instanceof TestCaseElement) {
+				label= getTextForFlatLayout((TestCaseElement) testElement, label);
 			}
 		}
 		return addElapsedTime(label, testElement.getElapsedTimeInSeconds());
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java
index c966bd7..0a2dd4d 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/TestViewer.java
@@ -22,6 +22,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.stream.Collectors;
 
 import org.eclipse.jdt.junit.model.ITestElement;
 import org.eclipse.jdt.junit.model.ITestElement.Result;
@@ -266,32 +267,18 @@
 		if (! selection.isEmpty()) {
 			TestElement testElement= (TestElement) selection.getFirstElement();
 
-			String testLabel= testElement.getTestName();
-			String className= testElement.getClassName();
 			if (testElement instanceof TestSuiteElement) {
-				manager.add(new OpenTestAction(fTestRunnerPart, testLabel));
+				TestSuiteElement testSuiteElement= (TestSuiteElement) testElement;
+				manager.add(getOpenTestAction(testSuiteElement));
 				manager.add(new Separator());
 				if (!fTestRunnerPart.lastLaunchIsKeptAlive()) {
-					IType testType= findTestClass(testElement);
-					if (testType != null) {
-						String qualifiedName= testType.getFullyQualifiedName();
-						String testName= qualifiedName.equals(className) ? null : testElement.getTestName();
-						manager.add(new RerunAction(JUnitMessages.RerunAction_label_run, fTestRunnerPart, testElement.getId(), qualifiedName, testName, ILaunchManager.RUN_MODE));
-						manager.add(new RerunAction(JUnitMessages.RerunAction_label_debug, fTestRunnerPart, testElement.getId(), qualifiedName, testName, ILaunchManager.DEBUG_MODE));
-					}
+					addRerunActions(manager, testSuiteElement);
 				}
 			} else {
 				TestCaseElement testCaseElement= (TestCaseElement) testElement;
-				String testMethodName= testCaseElement.getTestMethodName();
-				manager.add(new OpenTestAction(fTestRunnerPart, testCaseElement));
+				manager.add(getOpenTestAction(testCaseElement));
 				manager.add(new Separator());
-				if (fTestRunnerPart.lastLaunchIsKeptAlive()) {
-					manager.add(new RerunAction(JUnitMessages.RerunAction_label_rerun, fTestRunnerPart, testElement.getId(), className, testMethodName, ILaunchManager.RUN_MODE));
-
-				} else {
-					manager.add(new RerunAction(JUnitMessages.RerunAction_label_run, fTestRunnerPart, testElement.getId(), className, testMethodName, ILaunchManager.RUN_MODE));
-					manager.add(new RerunAction(JUnitMessages.RerunAction_label_debug, fTestRunnerPart, testElement.getId(), className, testMethodName, ILaunchManager.DEBUG_MODE));
-				}
+				addRerunActions(manager, testCaseElement);
 			}
 			if (fLayoutMode == TestRunnerViewPart.LAYOUT_HIERARCHICAL) {
 				manager.add(new Separator());
@@ -308,10 +295,65 @@
 		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS + "-end")); //$NON-NLS-1$
 	}
 
+	private void addRerunActions(IMenuManager manager, TestCaseElement testCaseElement) {
+		String className= testCaseElement.getClassName();
+		String testMethodName= testCaseElement.getTestMethodName();
+		String[] parameterTypes= testCaseElement.getParameterTypes();
+		if (parameterTypes != null) {
+			String paramTypesStr= Arrays.stream(parameterTypes).collect(Collectors.joining(",")); //$NON-NLS-1$
+			testMethodName= testMethodName + "(" + paramTypesStr + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		if (fTestRunnerPart.lastLaunchIsKeptAlive()) {
+			manager.add(new RerunAction(JUnitMessages.RerunAction_label_rerun, fTestRunnerPart, testCaseElement.getId(), className, testMethodName, testCaseElement.getDisplayName(), testCaseElement.getUniqueId(), ILaunchManager.RUN_MODE));
+		} else {
+			manager.add(new RerunAction(JUnitMessages.RerunAction_label_run, fTestRunnerPart, testCaseElement.getId(), className, testMethodName, testCaseElement.getDisplayName(), testCaseElement.getUniqueId(), ILaunchManager.RUN_MODE));
+			manager.add(new RerunAction(JUnitMessages.RerunAction_label_debug, fTestRunnerPart, testCaseElement.getId(), className, testMethodName, testCaseElement.getDisplayName(), testCaseElement.getUniqueId(), ILaunchManager.DEBUG_MODE));
+		}
+	}
+
+	private void addRerunActions(IMenuManager manager, TestSuiteElement testSuiteElement) {
+		String qualifiedName= null;
+		String testMethodName= null; // test method name is null when re-running a regular test class
+
+		String testName= testSuiteElement.getTestName();
+
+		IType testType= findTestClass(testSuiteElement, true);
+		if (testType != null) {
+			qualifiedName= testType.getFullyQualifiedName();
+
+			if (!qualifiedName.equals(testName)) {
+				int index= testName.indexOf('(');
+				if (index > 0) { // test factory method
+					testMethodName= testName.substring(0, index);
+				}
+			}
+			String[] parameterTypes= testSuiteElement.getParameterTypes();
+			if (testMethodName != null && parameterTypes != null) {
+				String paramTypesStr= Arrays.stream(parameterTypes).collect(Collectors.joining(",")); //$NON-NLS-1$
+				testMethodName= testMethodName + "(" + paramTypesStr + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		} else {
+			// see bug 443498
+			testType= findTestClass(testSuiteElement.getParent(), false);
+			if (testType != null) {
+				qualifiedName= testType.getFullyQualifiedName();
+
+				String className= testSuiteElement.getSuiteTypeName();
+				if (!qualifiedName.equals(className)) {
+					testMethodName= testName;
+				}
+			}
+		}
+		if (qualifiedName != null) {
+			manager.add(new RerunAction(JUnitMessages.RerunAction_label_run, fTestRunnerPart, testSuiteElement.getId(), qualifiedName, testMethodName, testSuiteElement.getDisplayName(), testSuiteElement.getUniqueId(), ILaunchManager.RUN_MODE));
+			manager.add(new RerunAction(JUnitMessages.RerunAction_label_debug, fTestRunnerPart, testSuiteElement.getId(), qualifiedName, testMethodName, testSuiteElement.getDisplayName(), testSuiteElement.getUniqueId(), ILaunchManager.DEBUG_MODE));
+		}
+	}
+
 	/*
 	 * Returns the element's test class or the next container's test class, which exists, and for which ITestFinder.isTest() is true.
 	 */
-	private IType findTestClass(ITestElement element) {
+	private IType findTestClass(ITestElement element, boolean checkOnlyCurrentElement) {
 		ITestFinder finder= ((TestRunSession)element.getTestRunSession()).getTestRunnerKind().getFinder();
 		if (ITestFinder.NULL.equals(finder)) {
 			return null;
@@ -334,8 +376,11 @@
 				}
 				if (className != null) {
 					IType type= project.findType(className);
-					if (type != null && finder.isTest(type))
+					if (type != null && finder.isTest(type)) {
 						return type;
+					} else if (checkOnlyCurrentElement) {
+						return null;
+					}
 				}
 			} catch (JavaModelException e) {
 				// fall through
@@ -366,18 +411,9 @@
 
 		OpenTestAction action;
 		if (testElement instanceof TestSuiteElement) {
-			String testName= testElement.getTestName();
-			ITestElement[] children= ((TestSuiteElement) testElement).getChildren();
-			if (testName.startsWith("[") && testName.endsWith("]") //$NON-NLS-1$ //$NON-NLS-2$
-					&& children.length > 0 && children[0] instanceof TestCaseElement) {
-				// a group of parameterized tests
-				action= new OpenTestAction(fTestRunnerPart, (TestCaseElement) children[0]);
-			} else {
-				action= new OpenTestAction(fTestRunnerPart, testName);
-			}
+			action= getOpenTestAction((TestSuiteElement) testElement);
 		} else if (testElement instanceof TestCaseElement) {
-			TestCaseElement testCase= (TestCaseElement)testElement;
-			action= new OpenTestAction(fTestRunnerPart, testCase);
+			action= getOpenTestAction((TestCaseElement) testElement);
 		} else {
 			throw new IllegalStateException(String.valueOf(testElement));
 		}
@@ -386,6 +422,36 @@
 			action.run();
 	}
 
+	private OpenTestAction getOpenTestAction(TestCaseElement testCase) {
+		return new OpenTestAction(fTestRunnerPart, testCase, testCase.getParameterTypes());
+	}
+
+	private OpenTestAction getOpenTestAction(TestSuiteElement testSuite) {
+		String testName= testSuite.getTestName();
+		ITestElement[] children= testSuite.getChildren();
+
+		if (testName.startsWith("[") && testName.endsWith("]") && children.length > 0 && children[0] instanceof TestCaseElement) { //$NON-NLS-1$ //$NON-NLS-2$
+			// a group of parameterized tests
+			return new OpenTestAction(fTestRunnerPart, (TestCaseElement) children[0], null);
+		}
+
+		int index= testName.indexOf('(');
+		// test factory method
+		if (index > 0) {
+			if (children.length > 0 && children[0] instanceof TestCaseElement) {
+				// has dynamic test case as child
+				TestCaseElement testCase= (TestCaseElement) children[0];
+				return new OpenTestAction(fTestRunnerPart, testCase, testCase.getParameterTypes());
+			} else {
+				// has no child
+				return new OpenTestAction(fTestRunnerPart, testSuite.getSuiteTypeName(), testName.substring(0, index), testSuite.getParameterTypes(), true);
+			}
+		}
+
+		// regular test class
+		return new OpenTestAction(fTestRunnerPart, testName);
+	}
+
 	private void handleSelected() {
 		IStructuredSelection selection= (IStructuredSelection) fSelectionProvider.getSelection();
 		TestElement testElement= null;
@@ -675,7 +741,7 @@
 	}
 
 	public void selectFirstFailure() {
-		TestCaseElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true);
+		TestElement firstFailure= getNextChildFailure(fTestRunSession.getTestRoot(), true);
 		if (firstFailure != null)
 			getActiveViewer().setSelection(new StructuredSelection(firstFailure), true);
 	}
@@ -704,7 +770,7 @@
 		return getNextFailureSibling(selected, showNext);
 	}
 
-	private TestCaseElement getNextFailureSibling(TestElement current, boolean showNext) {
+	private TestElement getNextFailureSibling(TestElement current, boolean showNext) {
 		TestSuiteElement parent= current.getParent();
 		if (parent == null)
 			return null;
@@ -718,16 +784,20 @@
 			TestElement sibling= (TestElement) siblings.get(i);
 			if (sibling.getStatus().isErrorOrFailure()) {
 				if (sibling instanceof TestCaseElement) {
-					return (TestCaseElement) sibling;
+					return sibling;
 				} else {
-					return getNextChildFailure((TestSuiteElement) sibling, showNext);
+					TestSuiteElement testSuiteElement= (TestSuiteElement) sibling;
+					if (testSuiteElement.getChildren().length == 0) {
+						return testSuiteElement;
+					}
+					return getNextChildFailure(testSuiteElement, showNext);
 				}
 			}
 		}
 		return getNextFailureSibling(parent, showNext);
 	}
 
-	private TestCaseElement getNextChildFailure(TestSuiteElement root, boolean showNext) {
+	private TestElement getNextChildFailure(TestSuiteElement root, boolean showNext) {
 		List<ITestElement> children= Arrays.asList(root.getChildren());
 		if (! showNext)
 			children= new ReverseList<>(children);
@@ -735,9 +805,13 @@
 			TestElement child= (TestElement) children.get(i);
 			if (child.getStatus().isErrorOrFailure()) {
 				if (child instanceof TestCaseElement) {
-					return (TestCaseElement) child;
+					return child;
 				} else {
-					return getNextChildFailure((TestSuiteElement) child, showNext);
+					TestSuiteElement testSuiteElement= (TestSuiteElement) child;
+					if (testSuiteElement.getChildren().length == 0) {
+						return testSuiteElement;
+					}
+					return getNextChildFailure(testSuiteElement, showNext);
 				}
 			}
 		}
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/util/JUnitStubUtility.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/util/JUnitStubUtility.java
index 28d2e51..e0e8f08 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/util/JUnitStubUtility.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/util/JUnitStubUtility.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
@@ -10,6 +10,10 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.junit.util;
 
+import java.util.ArrayList;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import org.eclipse.core.runtime.CoreException;
 
 import org.eclipse.text.edits.MalformedTreeException;
@@ -264,6 +268,71 @@
 		return null;
 	}
 
+	/**
+	 * Returns a comma-separated list of method parameter type names in parentheses or "" if the method
+	 * has no parameters. If fully qualified type names are required, <code>$</code> is used as the
+	 * enclosing type separator in the qualified type name. Type erasure is performed on a parameterized
+	 * type, arrays use the square brackets and a type parameter is resolved while creating the return
+	 * value.
+	 * 
+	 * @param method the method whose parameter types are required
+	 * @param useSimpleNames <code>true</code> if the last segment of the type name should be used
+	 *            instead of the fully qualified type name
+	 * @return a comma-separated list of method parameter type names in parentheses
+	 */
+	public static String getParameterTypes(final IMethod method, final boolean useSimpleNames) {
+		String paramTypes= ""; //$NON-NLS-1$
+
+		int numOfParams= method.getNumberOfParameters();
+		if (numOfParams > 0) {
+			String[] parameterTypeSignatures= method.getParameterTypes();
+			ArrayList<String> parameterTypeNames= new ArrayList<>(numOfParams);
+
+			try {
+				String[] fullNames= null;
+				for (int i= 0; i < parameterTypeSignatures.length; i++) {
+					String paramTypeSign= parameterTypeSignatures[i];
+					StringBuffer buf= new StringBuffer();
+
+					String typeSign= Signature.getTypeErasure(paramTypeSign);
+					String fullName;
+					if (useSimpleNames) {
+						fullName= JavaModelUtil.getResolvedTypeName(typeSign, method.getDeclaringType(), '.');
+					} else {
+						fullName= JavaModelUtil.getResolvedTypeName(typeSign, method.getDeclaringType(), '$');
+					}
+					if (fullName == null) { // e.g. a type parameter "QE;"
+						if (fullNames == null) {
+							fullNames= JUnitStubUtility.getParameterTypeNamesForSeeTag(method);
+						}
+						fullName= fullNames[i];
+					}
+
+					if (fullName != null) {
+						buf.append(fullName);
+						int dim= Signature.getArrayCount(typeSign);
+						while (dim > 0) {
+							buf.append("[]"); //$NON-NLS-1$
+							dim--;
+						}
+					}
+
+					parameterTypeNames.add(buf.toString());
+				}
+			} catch (JavaModelException e) {
+				// ignore
+			}
+
+			Stream<String> stream= parameterTypeNames.stream();
+			if (useSimpleNames) {
+				stream= stream.map(paramTypeName -> paramTypeName.substring(paramTypeName.lastIndexOf('.') + 1));
+			}
+			paramTypes= stream.collect(Collectors.joining(", ", "(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$	
+		}
+
+		return paramTypes;
+	}
+
 	/*
 	 * Evaluates if a member (possible from another package) is visible from
 	 * elements in a package.
@@ -295,6 +364,14 @@
 		return CoreTestSearchEngine.is50OrHigher(compliance);
 	}
 
+	public static boolean is18OrHigher(IJavaProject project) {
+		return CoreTestSearchEngine.is18OrHigher(project);
+	}
+
+	public static boolean is18OrHigher(String compliance) {
+		return CoreTestSearchEngine.is18OrHigher(compliance);
+	}
+
 	public static String[] getParameterTypeNamesForSeeTag(IMethod overridden) {
 		try {
 			ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/NewTestCaseCreationWizard.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/NewTestCaseCreationWizard.java
index 8c29b09..276e41b 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/NewTestCaseCreationWizard.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/NewTestCaseCreationWizard.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 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
@@ -15,6 +15,7 @@
 import java.util.Map;
 
 import org.eclipse.jdt.junit.wizards.NewTestCaseWizardPageOne;
+import org.eclipse.jdt.junit.wizards.NewTestCaseWizardPageOne.JUnitVersion;
 import org.eclipse.jdt.junit.wizards.NewTestCaseWizardPageTwo;
 
 import org.eclipse.swt.SWT;
@@ -82,9 +83,6 @@
 		setDefaultPageImageDescriptor(JUnitPlugin.getImageDescriptor("wizban/newtest_wiz.png")); //$NON-NLS-1$
 	}
 
-	/*
-	 * @see Wizard#createPages
-	 */
 	@Override
 	public void addPages() {
 		super.addPages();
@@ -95,22 +93,29 @@
 		addPage(fPage2);
 	}
 
-	/*
-	 * @see Wizard#performFinish
-	 */
 	@Override
 	public boolean performFinish() {
 		IJavaProject project= fPage1.getJavaProject();
 		IRunnableWithProgress runnable= fPage1.getRunnable();
 		try {
-			if (fPage1.isJUnit4()) {
-				if (project.findType(JUnitCorePlugin.JUNIT4_ANNOTATION_NAME) == null) {
-					runnable= addJUnitToClasspath(project, runnable, true);
-				}
-			} else {
-				if (project.findType(JUnitCorePlugin.TEST_SUPERCLASS_NAME) == null) {
-					runnable= addJUnitToClasspath(project, runnable, false);
-				}
+			JUnitVersion jUnitVersion= fPage1.getJUnitVersion();
+			switch (jUnitVersion) {
+				case VERSION_5:
+					if (project.findType(JUnitCorePlugin.JUNIT5_JUPITER_TEST_ANNOTATION_NAME) == null) {
+						runnable= addJUnitToClasspath(project, runnable, jUnitVersion);
+					}
+					break;
+				case VERSION_4:
+					if (project.findType(JUnitCorePlugin.JUNIT4_ANNOTATION_NAME) == null) {
+						runnable= addJUnitToClasspath(project, runnable, jUnitVersion);
+					}
+					break;
+				case VERSION_3:
+				default:
+					if (project.findType(JUnitCorePlugin.TEST_SUPERCLASS_NAME) == null) {
+						runnable= addJUnitToClasspath(project, runnable, jUnitVersion);
+					}
+					break;
 			}
 		} catch (JavaModelException e) {
 			// ignore
@@ -130,11 +135,23 @@
 		return false;
 	}
 
-	private IRunnableWithProgress addJUnitToClasspath(IJavaProject project, final IRunnableWithProgress runnable, boolean isJUnit4) {
-		String typeToLookup= isJUnit4 ? "org.junit.*" : "junit.awtui.*";  //$NON-NLS-1$//$NON-NLS-2$
+	private IRunnableWithProgress addJUnitToClasspath(IJavaProject project, final IRunnableWithProgress runnable, JUnitVersion junitVersion) {
+		String typeToLookup;
+		switch (junitVersion) {
+			case VERSION_5:
+				typeToLookup= "org.junit.jupiter.*"; //$NON-NLS-1$
+				break;
+			case VERSION_4:
+				typeToLookup= "org.junit.*"; //$NON-NLS-1$
+				break;
+			case VERSION_3:
+			default:
+				typeToLookup= "junit.awtui.*"; //$NON-NLS-1$
+				break;
+		}
 		ClasspathFixProposal[] fixProposals= ClasspathFixProcessor.getContributedFixImportProposals(project, typeToLookup, null);
 
-		ClasspathFixSelectionDialog dialog= new ClasspathFixSelectionDialog(getShell(), isJUnit4, project, fixProposals);
+		ClasspathFixSelectionDialog dialog= new ClasspathFixSelectionDialog(getShell(), junitVersion, project, fixProposals);
 		if (dialog.open() != 0) {
 			throw new OperationCanceledException();
 		}
@@ -202,8 +219,8 @@
 
 		private ClasspathFixProposal fSelectedFix;
 
-		public ClasspathFixSelectionDialog(Shell parent, boolean isJUnit4, IJavaProject project, ClasspathFixProposal[] fixProposals) {
-			super(parent, WizardMessages.Wizard_title_new_testcase, null, getDialogMessage(isJUnit4), MessageDialog.QUESTION, new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
+		public ClasspathFixSelectionDialog(Shell parent, JUnitVersion junitVersion, IJavaProject project, ClasspathFixProposal[] fixProposals) {
+			super(parent, WizardMessages.Wizard_title_new_testcase, null, getDialogMessage(junitVersion), MessageDialog.QUESTION, new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
 			fProject= project;
 			fFixProposals= fixProposals;
 			fSelectedFix= null;
@@ -214,8 +231,16 @@
 			return true;
 		}
 
-		private static String getDialogMessage(boolean isJunit4) {
-			return isJunit4 ? WizardMessages.NewTestCaseCreationWizard_fix_selection_junit4_description : WizardMessages.NewTestCaseCreationWizard_fix_selection_junit3_description;
+		private static String getDialogMessage(JUnitVersion junitVersion) {
+			switch (junitVersion) {
+				case VERSION_5:
+					return WizardMessages.NewTestCaseCreationWizard_fix_selection_junit5_description;
+				case VERSION_4:
+					return WizardMessages.NewTestCaseCreationWizard_fix_selection_junit4_description;
+				case VERSION_3:
+				default:
+					return WizardMessages.NewTestCaseCreationWizard_fix_selection_junit3_description;
+			}
 		}
 
 		@Override
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/SuiteClassesContentProvider.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/SuiteClassesContentProvider.java
index 3c02da0..d796373 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/SuiteClassesContentProvider.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/SuiteClassesContentProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -64,7 +64,6 @@
 	public Set<IType> getTests(IPackageFragment pack) {
 		try {
 			HashSet<IType> result= new HashSet<>();
-			
 			if (isIncludeJunit4Tests()) {
 				new JUnit4TestFinder().findTestsInContainer(pack, result, null);
 			} else {
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.java
index 20add9c..8fa1333 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 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
@@ -22,10 +22,14 @@
 	}
 
 	public static String NewTestCaseWizardPageOne__error_junit4NotOnbuildpath;
+	public static String NewTestCaseWizardPageOne__error_junit5NotOnbuildpath;
 	public static String NewTestCaseWizardPageOne_error_java5required;
+	public static String NewTestCaseWizardPageOne_error_java8required;
 	public static String NewTestCaseWizardPageOne_junit3_radio_label;
 	public static String NewTestCaseWizardPageOne_junit4_radio_label;
+	public static String NewTestCaseWizardPageOne_junit5_radio_label;
 	public static String NewTestCaseWizardPageOne_linkedtext_java5required;
+	public static String NewTestCaseWizardPageOne_linkedtext_java8required;
 	public static String NewTestCaseWizardPageOne_methodStub_setUpBeforeClass;
 	public static String NewTestCaseWizardPageOne_methodStub_tearDownAfterClass;
 	public static String NewTestCaseWizardPageOne_not_yet_implemented_string;
@@ -53,6 +57,7 @@
 	public static String NewTestCaseWizardPageOne_warning_class_to_test_is_interface;
 	public static String NewTestCaseCreationWizard_fix_selection_junit3_description;
 	public static String NewTestCaseCreationWizard_fix_selection_junit4_description;
+	public static String NewTestCaseCreationWizard_fix_selection_junit5_description;
 	public static String NewTestCaseCreationWizard_fix_selection_open_build_path_dialog;
 	public static String NewTestCaseCreationWizard_fix_selection_invoke_fix;
 	public static String NewTestCaseCreationWizard_create_progress;
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.properties b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.properties
index 980857e..b775cd1 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.properties
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/wizards/WizardMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2010 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
@@ -38,10 +38,12 @@
 NewTestCaseWizardPageOne_class_to_test_dialog_message=Test stubs will be generated for class:
 NewTestCaseWizardPageOne_error_superclass_not_exist=Superclass does not exist.
 NewTestCaseWizardPageOne__error_junit4NotOnbuildpath=JUnit 4 library is not on the classpath
+NewTestCaseWizardPageOne__error_junit5NotOnbuildpath=JUnit 5 library is not on the classpath
 NewTestCaseWizardPageOne_error_superclass_is_interface=Superclass is an interface.
 NewTestCaseWizardPageOne_error_superclass_not_implementing_test_interface=Superclass does not implement the ''{0}'' interface.
 NewTestCaseWizardPageOne_error_superclass_empty=Super class name is empty.
-NewTestCaseWizardPageOne_error_java5required=JUnit 4 requires a project with 1.5 compliance or more. 
+NewTestCaseWizardPageOne_error_java5required=JUnit 4 requires a project with 1.5 compliance or more.
+NewTestCaseWizardPageOne_error_java8required=JUnit 5 requires a project with 1.8 compliance or more. 
 NewTestCaseWizardPageOne_error_class_to_test_not_valid=Class under test is not valid.
 NewTestCaseWizardPageOne_error_class_to_test_not_exist=Class under test does not exist in current project.
 NewTestCaseWizardPageOne_warning_class_to_test_is_interface=Warning: Class under test ''{0}'' is an interface.
@@ -50,6 +52,7 @@
 NewTestCaseCreationWizard_fix_selection_invoke_fix=&Perform the following action:
 NewTestCaseCreationWizard_fix_selection_junit3_description=JUnit 3 is not on the build path. Do you want to add it?
 NewTestCaseCreationWizard_fix_selection_junit4_description=JUnit 4 is not on the build path. Do you want to add it?
+NewTestCaseCreationWizard_fix_selection_junit5_description=JUnit 5 is not on the build path. Do you want to add it?
 NewTestCaseCreationWizard_create_progress=Creating JUnit test case...
 NewTestCaseCreationWizard_fix_selection_not_now=&Not now
 NewTestCaseCreationWizard_fix_selection_open_build_path_dialog=&Open the build path property page
@@ -132,6 +135,8 @@
 UpdateTestSuite_could_not_update=The test suite could not be updated
 
 NewTestCaseWizardPageOne_linkedtext_java5required=JUnit 4 requires a Java 5 project. <a href="c">Configure</a> project compliance and the project build path.
+NewTestCaseWizardPageOne_linkedtext_java8required=JUnit 5 requires a Java 8 project. <a href="c">Configure</a> project compliance and the project build path.
 NewTestCaseWizardPageOne_not_yet_implemented_string=Not yet implemented
 NewTestCaseWizardPageOne_junit3_radio_label=New JUnit &3 test
 NewTestCaseWizardPageOne_junit4_radio_label=New JUnit &4 test
+NewTestCaseWizardPageOne_junit5_radio_label=New JUnit &Jupiter test
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationTab.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationTab.java
index 23c86b9..c42b5c1 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationTab.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationTab.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
@@ -89,6 +89,7 @@
 import org.eclipse.jdt.core.search.SearchEngine;
 
 import org.eclipse.jdt.internal.junit.BasicElementLabels;
+import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
 import org.eclipse.jdt.internal.junit.Messages;
 import org.eclipse.jdt.internal.junit.launcher.ITestKind;
 import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
@@ -664,7 +665,8 @@
 		if (javaProject == null || type == null || testKind == null)
 			return Collections.emptySet();
 
-		String methodsCacheKey= javaProject.getElementName() + '\n' + type.getFullyQualifiedName() + '\n' + testKind.getId();
+		String testKindId= testKind.getId();
+		String methodsCacheKey= javaProject.getElementName() + '\n' + type.getFullyQualifiedName() + '\n' + testKindId;
 		if (methodsCacheKey.equals(fMethodsCacheKey))
 			return fMethodsCache;
 
@@ -672,42 +674,108 @@
 		fMethodsCache= methodNames;
 		fMethodsCacheKey= methodsCacheKey;
 
-		boolean isJUnit4= TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId());
+		collectMethodNames(type, javaProject, testKindId, methodNames);
 
-		while (type != null) {
-			IMethod[] methods= type.getMethods();
-			for (IMethod method : methods) {
-				int flags= method.getFlags();
-				// Only include public, non-static, no-arg methods that return void and start with "test":
-				if (Modifier.isPublic(flags) && !Modifier.isStatic(flags) &&
-						method.getNumberOfParameters() == 0 && Signature.SIG_VOID.equals(method.getReturnType()) &&
-						method.getElementName().startsWith("test")) { //$NON-NLS-1$
-					methodNames.add(method.getElementName());
-				}
-				if (isJUnit4) {
-					IAnnotation annotation= method.getAnnotation("Test"); //$NON-NLS-1$
-					if (annotation.exists()) {
-						methodNames.add(method.getElementName());
+		return methodNames;
+	}
+
+	private void collectMethodNames(IType type, IJavaProject javaProject, String testKindId, Set<String> methodNames) throws JavaModelException {
+		if (type == null) {
+			return;
+		}
+		collectDeclaredMethodNames(type, javaProject, testKindId, methodNames);
+
+		String superclassName= type.getSuperclassName();
+		IType superType= getResolvedType(superclassName, type, javaProject);
+		collectMethodNames(superType, javaProject, testKindId, methodNames);
+
+		String[] superInterfaceNames= type.getSuperInterfaceNames();
+		for (String interfaceName : superInterfaceNames) {
+			superType= getResolvedType(interfaceName, type, javaProject);
+			collectMethodNames(superType, javaProject, testKindId, methodNames);
+		}
+	}
+
+	private IType getResolvedType(String typeName, IType type, IJavaProject javaProject) throws JavaModelException {
+		IType resolvedType= null;
+		if (typeName != null) {
+			int pos= typeName.indexOf('<');
+			if (pos != -1) {
+				typeName= typeName.substring(0, pos);
+			}
+			String[][] resolvedTypeNames= type.resolveType(typeName);
+			if (resolvedTypeNames != null && resolvedTypeNames.length > 0) {
+				String[] resolvedTypeName= resolvedTypeNames[0];
+				resolvedType= javaProject.findType(resolvedTypeName[0], resolvedTypeName[1]); // secondary types not found by this API
+			}
+		}
+		return resolvedType;
+	}
+
+	private void collectDeclaredMethodNames(IType type, IJavaProject javaProject, String testKindId, Set<String> methodNames) throws JavaModelException {
+		IMethod[] methods= type.getMethods();
+		for (IMethod method : methods) {
+			String methodName= method.getElementName();
+			int flags= method.getFlags();
+			// Only include public, non-static, no-arg methods that return void and start with "test":
+			if (Modifier.isPublic(flags) && !Modifier.isStatic(flags) &&
+					method.getNumberOfParameters() == 0 && Signature.SIG_VOID.equals(method.getReturnType()) &&
+					methodName.startsWith("test")) { //$NON-NLS-1$
+				methodNames.add(methodName);
+			}
+			boolean isJUnit3= TestKindRegistry.JUNIT3_TEST_KIND_ID.equals(testKindId);
+			boolean isJUnit5= TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKindId);
+			if (!isJUnit3 && !Modifier.isPrivate(flags) && !Modifier.isStatic(flags)) {
+				IAnnotation annotation= method.getAnnotation("Test"); //$NON-NLS-1$
+				if (annotation.exists()) {
+					methodNames.add(methodName + JUnitStubUtility.getParameterTypes(method, false));
+				} else if (isJUnit5) {
+					boolean hasAnyTestAnnotation= method.getAnnotation("TestFactory").exists() //$NON-NLS-1$
+							|| method.getAnnotation("Testable").exists() //$NON-NLS-1$
+							|| method.getAnnotation("TestTemplate").exists() //$NON-NLS-1$
+							|| method.getAnnotation("ParameterizedTest").exists() //$NON-NLS-1$
+							|| method.getAnnotation("RepeatedTest").exists(); //$NON-NLS-1$
+					if (hasAnyTestAnnotation || isAnnotatedWithTestable(method, type, javaProject)) {
+						methodNames.add(methodName + JUnitStubUtility.getParameterTypes(method, false));
 					}
 				}
 			}
-			String superclassName= type.getSuperclassName();
-			if (superclassName != null) {
-				int pos= superclassName.indexOf('<');
-				if (pos != -1)
-					superclassName= superclassName.substring(0, pos);
-				String[][] resolvedSupertype= type.resolveType(superclassName);
-				if (resolvedSupertype != null && resolvedSupertype.length > 0) {
-					String[] superclass= resolvedSupertype[0];
-					type= javaProject.findType(superclass[0], superclass[1]);
-				} else {
-					type= null;
+		}
+	}
+
+	// See JUnit5TestFinder.Annotation#annotates also.
+	private boolean isAnnotatedWithTestable(IMethod method, IType declaringType, IJavaProject javaProject) throws JavaModelException {
+		for (IAnnotation annotation : method.getAnnotations()) {
+			IType annotationType= getResolvedType(annotation.getElementName(), declaringType, javaProject);
+			if (annotationType != null) {
+				if (matchesTestable(annotationType)) {
+					return true;
 				}
-			} else {
-				type= null;
+				Set<IType> hierarchy= new HashSet<>();
+				if (matchesTestableInAnnotationHierarchy(annotationType, javaProject, hierarchy)) {
+					return true;
+				}
 			}
 		}
-		return methodNames;
+		return false;
+	}
+
+	private boolean matchesTestable(IType annotationType) {
+		return annotationType != null && JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME.equals(annotationType.getFullyQualifiedName());
+	}
+
+	private boolean matchesTestableInAnnotationHierarchy(IType annotationType, IJavaProject javaProject, Set<IType> hierarchy) throws JavaModelException {
+		if (annotationType != null) {
+			for (IAnnotation annotation : annotationType.getAnnotations()) {
+				IType annType= getResolvedType(annotation.getElementName(), annotationType, javaProject);
+				if (annType != null && hierarchy.add(annType)) {
+					if (matchesTestable(annType) || matchesTestableInAnnotationHierarchy(annType, javaProject, hierarchy)) {
+						return true;
+					}
+				}
+			}
+		}
+		return false;
 	}
 
 	private String chooseMethodName(Set<String> methodNames) {
@@ -839,70 +907,74 @@
 				return;
 			}
 			validateJavaProject(fContainerElement.getJavaProject());
-			return;
-		}
 
-		String projectName= fProjText.getText().trim();
-		if (projectName.length() == 0) {
-			setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_projectnotdefined);
-			return;
-		}
-
-		IStatus status= ResourcesPlugin.getWorkspace().validatePath(IPath.SEPARATOR + projectName, IResource.PROJECT);
-		if (!status.isOK() || !Path.ROOT.isValidSegment(projectName)) {
-			setErrorMessage(Messages.format(JUnitMessages.JUnitLaunchConfigurationTab_error_invalidProjectName, BasicElementLabels.getResourceName(projectName)));
-			return;
-		}
-
-		IProject project= getWorkspaceRoot().getProject(projectName);
-		if (!project.exists()) {
-			setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_projectnotexists);
-			return;
-		}
-		IJavaProject javaProject= JavaCore.create(project);
-		validateJavaProject(javaProject);
-
-		try {
-			if (!project.hasNature(JavaCore.NATURE_ID)) {
-				setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_notJavaProject);
+		} else {
+			String projectName= fProjText.getText().trim();
+			if (projectName.length() == 0) {
+				setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_projectnotdefined);
 				return;
 			}
-			String className= fTestText.getText().trim();
-			if (className.length() == 0) {
-				setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testnotdefined);
+
+			IStatus status= ResourcesPlugin.getWorkspace().validatePath(IPath.SEPARATOR + projectName, IResource.PROJECT);
+			if (!status.isOK() || !Path.ROOT.isValidSegment(projectName)) {
+				setErrorMessage(Messages.format(JUnitMessages.JUnitLaunchConfigurationTab_error_invalidProjectName, BasicElementLabels.getResourceName(projectName)));
 				return;
 			}
-			IType type= javaProject.findType(className);
-			if (type == null) {
-				setErrorMessage(Messages.format(JUnitMessages.JUnitLaunchConfigurationTab_error_test_class_not_found, new String[] { className, projectName }));
+
+			IProject project= getWorkspaceRoot().getProject(projectName);
+			if (!project.exists()) {
+				setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_projectnotexists);
 				return;
 			}
-			String methodName = fTestMethodText.getText();
-			if (methodName.length() > 0) {
-				Set<String> methodsForType= getMethodsForType(javaProject, type, getSelectedTestKind());
-				if (!methodsForType.contains(methodName)) {
-					super.setErrorMessage(Messages.format(JUnitMessages.JUnitLaunchConfigurationTab_error_test_method_not_found, new String[] { className, methodName, projectName }));
+			IJavaProject javaProject= JavaCore.create(project);
+			validateJavaProject(javaProject);
+
+			try {
+				if (!project.hasNature(JavaCore.NATURE_ID)) {
+					setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_notJavaProject);
 					return;
 				}
+				String className= fTestText.getText().trim();
+				if (className.length() == 0) {
+					setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testnotdefined);
+					return;
+				}
+				IType type= javaProject.findType(className);
+				if (type == null) {
+					setErrorMessage(Messages.format(JUnitMessages.JUnitLaunchConfigurationTab_error_test_class_not_found, new String[] { className, projectName }));
+					return;
+				}
+				String methodName= fTestMethodText.getText();
+				if (methodName.length() > 0) {
+					Set<String> methodsForType= getMethodsForType(javaProject, type, getSelectedTestKind());
+					if (!methodsForType.contains(methodName)) {
+						super.setErrorMessage(Messages.format(JUnitMessages.JUnitLaunchConfigurationTab_error_test_method_not_found, new String[] { className, methodName, projectName }));
+						return;
+					}
+				}
+			} catch (CoreException e) {
+				JUnitPlugin.log(e);
 			}
-
-
-		} catch (CoreException e) {
-			JUnitPlugin.log(e);
 		}
 
 		validateTestLoaderJVM();
 	}
 
 	private void validateJavaProject(IJavaProject javaProject) {
-		if (! CoreTestSearchEngine.hasTestCaseType(javaProject)) {
-			setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testcasenotonpath);
-			return;
-		}
 		TestKind testKind = getSelectedTestKind();
-		if (testKind != null && TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId())) {
-			if (! CoreTestSearchEngine.hasTestAnnotation(javaProject)) {
-				setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testannotationnotonpath);
+		if (testKind != null) {
+			if (!TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId()) && !CoreTestSearchEngine.hasTestCaseType(javaProject)) {
+				setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_testcasenotonpath);
+				return;
+			}
+
+			String msg= JUnitMessages.JUnitLaunchConfigurationTab_error_testannotationnotonpath;
+			if (TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId()) && !CoreTestSearchEngine.hasJUnit4TestAnnotation(javaProject)) {
+				setErrorMessage(Messages.format(msg, JUnitCorePlugin.JUNIT4_ANNOTATION_NAME));
+				return;
+			}
+			if (TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId()) && !CoreTestSearchEngine.hasJUnit5TestAnnotation(javaProject)) {
+				setErrorMessage(Messages.format(msg, JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME));
 				return;
 			}
 		}
@@ -922,8 +994,13 @@
 				IVMInstall vm = JavaRuntime.getVMInstall(Path.fromPortableString(path));
 				if (vm instanceof AbstractVMInstall) {
 					String compliance= ((AbstractVMInstall)vm).getJavaVersion();
-					if (compliance != null && !JUnitStubUtility.is50OrHigher(compliance)) {
-						setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_JDK15_required);
+					if (compliance != null) {
+						String testKindId= testKind.getId();
+						if (TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKindId) && !JUnitStubUtility.is50OrHigher(compliance)) {
+							setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_JDK15_required);
+						} else if (TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKindId) && !JUnitStubUtility.is18OrHigher(compliance)) {
+							setErrorMessage(JUnitMessages.JUnitLaunchConfigurationTab_error_JDK18_required);
+						}
 					}
 				}
 			}
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchShortcut.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchShortcut.java
index 0d2fb47..cf432c2 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchShortcut.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/launcher/JUnitLaunchShortcut.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 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
@@ -52,6 +52,7 @@
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
@@ -68,6 +69,7 @@
 import org.eclipse.jdt.internal.junit.ui.JUnitMessages;
 import org.eclipse.jdt.internal.junit.ui.JUnitPlugin;
 import org.eclipse.jdt.internal.junit.util.ExceptionHandler;
+import org.eclipse.jdt.internal.junit.util.JUnitStubUtility;
 import org.eclipse.jdt.internal.junit.util.TestSearchEngine;
 
 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
@@ -105,9 +107,9 @@
 	public void launch(IEditorPart editor, String mode) {
 		ITypeRoot element= JavaUI.getEditorInputTypeRoot(editor.getEditorInput());
 		if (element != null) {
-			IMethod selectedMethod= resolveSelectedMethodName(editor, element);
-			if (selectedMethod != null) {
-				launch(new Object[] { selectedMethod }, mode);
+			IMember selectedMember= resolveSelectedMemberName(editor, element);
+			if (selectedMember != null) {
+				launch(new Object[] { selectedMember }, mode);
 			} else {
 				launch(new Object[] { element }, mode);
 			}
@@ -116,7 +118,7 @@
 		}
 	}
 
-	private IMethod resolveSelectedMethodName(IEditorPart editor, ITypeRoot element) {
+	private IMember resolveSelectedMemberName(IEditorPart editor, ITypeRoot element) {
 		try {
 			ISelectionProvider selectionProvider= editor.getSite().getSelectionProvider();
 			if (selectionProvider == null)
@@ -129,15 +131,15 @@
 			ITextSelection textSelection= (ITextSelection) selection;
 
 			IJavaElement elementAtOffset= SelectionConverter.getElementAtOffset(element, textSelection);
-			if (! (elementAtOffset instanceof IMethod))
+			if (!(elementAtOffset instanceof IMethod) && !(elementAtOffset instanceof IType))
 				return null;
 
-			IMethod method= (IMethod) elementAtOffset;
+			IMember member= (IMember) elementAtOffset;
 
-			ISourceRange nameRange= method.getNameRange();
+			ISourceRange nameRange= member.getNameRange();
 			if (nameRange.getOffset() <= textSelection.getOffset()
 					&& textSelection.getOffset() + textSelection.getLength() <= nameRange.getOffset() + nameRange.getLength())
-				return method;
+				return member;
 		} catch (JavaModelException e) {
 			// ignore
 		}
@@ -344,10 +346,12 @@
 				break;
 			}
 			case IJavaElement.METHOD: {
-				testName= element.getElementName(); // Test-names can not be specified when launching a Java method.
 				IMethod method= (IMethod)element;
+				testName= method.getElementName(); // Test-names can not be specified when launching a Java method.
+				testName+= JUnitStubUtility.getParameterTypes(method, false);
 				containerHandleId= EMPTY_STRING;
-				mainTypeQualifiedName= method.getDeclaringType().getFullyQualifiedName('.');
+				IType declaringType= method.getDeclaringType();
+				mainTypeQualifiedName= declaringType.getFullyQualifiedName('.');
 				break;
 			}
 			default:
@@ -405,7 +409,9 @@
 				return element.getElementName();
 			case IJavaElement.METHOD:
 				IMethod method= (IMethod)element;
-				return method.getDeclaringType().getElementName() + '.' + method.getElementName();
+				String methodName= method.getElementName();
+				methodName+= JUnitStubUtility.getParameterTypes(method, true); // use simple names of parameter types
+				return method.getDeclaringType().getElementName() + '.' + methodName;
 			default:
 				throw new IllegalArgumentException("Invalid element type to create a launch configuration: " + element.getClass().getName()); //$NON-NLS-1$
 		}
@@ -508,23 +514,23 @@
 	public ILaunchConfiguration[] getLaunchConfigurations(final IEditorPart editor) {
 		final ITypeRoot element= JavaUI.getEditorInputTypeRoot(editor.getEditorInput());
 		if (element != null) {
-			IMethod selectedMethod = null;
+			IMember selectedMember = null;
 			if (Display.getCurrent() == null) {
-				final IMethod[] temp = new IMethod[1];
+				final IMember[] temp = new IMember[1];
 				Runnable runnable= new Runnable() {
 					@Override
 					public void run() {
-						temp[0]= resolveSelectedMethodName(editor, element);
+						temp[0]= resolveSelectedMemberName(editor, element);
 					}
 				};
 				Display.getDefault().syncExec(runnable);
-				selectedMethod = temp[0];
+				selectedMember = temp[0];
 			} else {
-				selectedMethod= resolveSelectedMethodName(editor, element);
+				selectedMember= resolveSelectedMemberName(editor, element);
 			}
 			Object candidate = element;
-			if (selectedMethod != null) {
-				candidate = selectedMethod;
+			if (selectedMember != null) {
+				candidate = selectedMember;
 			}
 			return findExistingLaunchConfigurations(candidate);
 		}
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestCaseWizardPageOne.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestCaseWizardPageOne.java
index 29809de..b0f6c7f 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestCaseWizardPageOne.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestCaseWizardPageOne.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 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
@@ -110,7 +110,7 @@
 	public final static String CLASS_UNDER_TEST= PAGE_NAME + ".classundertest"; //$NON-NLS-1$
 
 	/**
-	 * Field ID of the Junit4 toggle
+	 * Field ID of the JUnit version radio buttons
 	 * @since 3.2
 	 */
 	public final static String JUNIT4TOGGLE= PAGE_NAME + ".junit4toggle"; //$NON-NLS-1$
@@ -154,13 +154,26 @@
 	private JavaTypeCompletionProcessor fClassToTestCompletionProcessor;
 
 
-	private Button fJUnit4Toggle;
-	private boolean fIsJunit4;
-	private IStatus fJunit4Status; // status
-	private boolean fIsJunit4Enabled;
+	private Button fJUnit3Button;
+	private Button fJUnit4Button;
+	private Button fJUnit5Button;
+
+	private IStatus fJUnitStatus; // status
+	private boolean fIsJUnitEnabled;
 	private Link fLink;
 	private Label fImage;
 
+	private JUnitVersion fJUnitVersion;
+
+	/**
+	 * Available JUnit versions.
+	 * 
+	 * @since 3.10
+	 */
+	public enum JUnitVersion {
+		VERSION_3, VERSION_4, VERSION_5
+	}
+
 	/**
 	 * Creates a new <code>NewTestCaseCreationWizardPage</code>.
 	 * @param page2 The second page
@@ -198,8 +211,8 @@
 
 		fClassUnderTestText= ""; //$NON-NLS-1$
 
-		fJunit4Status= new JUnitStatus();
-		fIsJunit4= false;
+		fJUnitStatus= new JUnitStatus();
+		setJUnitVersion(JUnitVersion.VERSION_3);
 	}
 
 	/**
@@ -249,38 +262,108 @@
 
 		restoreWidgetValues();
 
+		boolean isJunit5= false;
 		boolean isJunit4= false;
 		if (element != null && element.getElementType() != IJavaElement.JAVA_MODEL) {
 			IJavaProject project= element.getJavaProject();
-			isJunit4= CoreTestSearchEngine.hasTestAnnotation(project);
-			if (!isJunit4 && !CoreTestSearchEngine.hasTestCaseType(project) && JUnitStubUtility.is50OrHigher(project)) {
-				isJunit4= true;
+			isJunit5= CoreTestSearchEngine.hasJUnit5TestAnnotation(project);
+			if (!isJunit5) {
+				isJunit4= CoreTestSearchEngine.hasJUnit4TestAnnotation(project);
+				if (!isJunit4) {
+					if (!CoreTestSearchEngine.hasTestCaseType(project)) {
+						if (JUnitStubUtility.is18OrHigher(project)) {
+							isJunit5= true;
+						} else if (JUnitStubUtility.is50OrHigher(project)) {
+							isJunit4= true;
+						}
+					}
+				}
 			}
 		}
-		setJUnit4(isJunit4, true);
+		if (isJunit5) {
+			setJUnitVersion(JUnitVersion.VERSION_5);
+		} else if (isJunit4) {
+			setJUnitVersion(JUnitVersion.VERSION_4);
+		} else {
+			setJUnitVersion(JUnitVersion.VERSION_3);
+		}
+		setEnabled(true);
 		updateStatus(getStatusList());
 	}
 
-	private IStatus junit4Changed() {
+	private IStatus junitStatusChanged() {
 		JUnitStatus status= new JUnitStatus();
 		return status;
 	}
 
 	/**
 	 * Specifies if the test should be created as JUnit 4 test.
-	 * @param isJUnit4 If set, a Junit 4 test will be created
-	 * @param isEnabled if <code>true</code> the modifier fields are
-	 * editable; otherwise they are read-only
+	 * @param isJUnit4 if set, a JUnit 4 test will be created; otherwise a JUnit 3 test will be
+	 *            created
+	 * @param isEnabled if <code>true</code>, the modifier fields are editable; otherwise they are
+	 *            read-only
 	 *
 	 * @since 3.2
+	 * @deprecated use {@link #setJUnitVersion(JUnitVersion)} and {@link #setEnabled(boolean)}
+	 *             instead
 	 */
+	@Deprecated
 	public void setJUnit4(boolean isJUnit4, boolean isEnabled) {
-		fIsJunit4Enabled= isEnabled;
-		if (fJUnit4Toggle != null && !fJUnit4Toggle.isDisposed()) {
-			fJUnit4Toggle.setSelection(isJUnit4);
-			fJUnit4Toggle.setEnabled(isEnabled);
+		setEnabled(isEnabled);
+		if (isJUnit4) {
+			setJUnitVersion(JUnitVersion.VERSION_4);
+		} else {
+			setJUnitVersion(JUnitVersion.VERSION_3);
 		}
-		internalSetJUnit4(isJUnit4);
+	}
+
+	/**
+	 * Specifies the JUnit version to create the test.
+	 * 
+	 * @param version the JUnit version
+	 * @since 3.10
+	 */
+	public void setJUnitVersion(JUnitVersion version) {
+		internalSetJUnit(version);
+		switch (fJUnitVersion) {
+			case VERSION_5:
+				if (fJUnit5Button != null && !fJUnit5Button.isDisposed()) {
+					fJUnit5Button.setSelection(true);
+				}
+				break;
+			case VERSION_4:
+				if (fJUnit4Button != null && !fJUnit4Button.isDisposed()) {
+					fJUnit4Button.setSelection(true);
+				}
+				break;
+			case VERSION_3:
+				if (fJUnit3Button != null && !fJUnit3Button.isDisposed()) {
+					fJUnit3Button.setSelection(true);
+				}
+				break;
+			default:
+				break;
+		}
+	}
+
+	/**
+	 * Specifies if the JUnit version radio buttons are enabled.
+	 * 
+	 * @param enabled if <code>true</code>, the JUnit version radio buttons are enabled; otherwise
+	 *            they are read-only
+	 * @since 3.10
+	 */
+	public void setEnabled(boolean enabled) {
+		fIsJUnitEnabled= enabled;
+		if (fJUnit5Button != null && !fJUnit5Button.isDisposed()) {
+			fJUnit5Button.setEnabled(fIsJUnitEnabled);
+		}
+		if (fJUnit4Button != null && !fJUnit4Button.isDisposed()) {
+			fJUnit4Button.setEnabled(fIsJUnitEnabled);
+		}
+		if (fJUnit3Button != null && !fJUnit3Button.isDisposed()) {
+			fJUnit3Button.setEnabled(fIsJUnitEnabled);
+		}
 	}
 
 	/**
@@ -288,14 +371,26 @@
 	 * @return returns <code>true</code> if the test should be created as Junit 4 test
 	 *
 	 * @since 3.2
+	 * @deprecated use {@link #getJUnitVersion()} instead
 	 */
+	@Deprecated
 	public boolean isJUnit4() {
-		return fIsJunit4;
+		return getJUnitVersion() == JUnitVersion.VERSION_4;
 	}
 
-	private void internalSetJUnit4(boolean isJUnit4) {
-		fIsJunit4= isJUnit4;
-		fJunit4Status= junit4Changed();
+	/**
+	 * Returns the JUnit version to create the test.
+	 * 
+	 * @return the JUnit version to create the test
+	 * @since 3.10
+	 */
+	public JUnitVersion getJUnitVersion() {
+		return fJUnitVersion;
+	}
+
+	private void internalSetJUnit(JUnitVersion version) {
+		fJUnitVersion= version;
+		fJUnitStatus= junitStatusChanged();
 		if (isDefaultSuperClass() || getSuperClass().trim().equals("")) //$NON-NLS-1$
 			setSuperClass(getDefaultSuperClassName(), true);
 		fSuperClassStatus= superClassChanged(); //validate superclass field when toggled
@@ -322,14 +417,15 @@
 			if (fClassUnderTestButton != null && !fClassUnderTestButton.isDisposed()) {
 				fClassUnderTestButton.setEnabled(getPackageFragmentRoot() != null);
 			}
-			fJunit4Status= junit4Changed();
+			fJUnitStatus= junitStatusChanged();
 
 			updateBuildPathMessage();
 		} else if (fieldName.equals(JUNIT4TOGGLE)) {
 			updateBuildPathMessage();
-			fMethodStubsButtons.setEnabled(IDX_SETUP_CLASS, isJUnit4());
-			fMethodStubsButtons.setEnabled(IDX_TEARDOWN_CLASS, isJUnit4());
-			fMethodStubsButtons.setEnabled(IDX_CONSTRUCTOR, !isJUnit4());
+			boolean isJUnit3= getJUnitVersion() == JUnitVersion.VERSION_3;
+			fMethodStubsButtons.setEnabled(IDX_SETUP_CLASS, !isJUnit3);
+			fMethodStubsButtons.setEnabled(IDX_TEARDOWN_CLASS, !isJUnit3);
+			fMethodStubsButtons.setEnabled(IDX_CONSTRUCTOR, isJUnit3);
 		}
 		updateStatus(getStatusList());
 	}
@@ -346,7 +442,7 @@
 				fClassUnderTestStatus,
 				fModifierStatus,
 				fSuperClassStatus,
-				fJunit4Status
+				fJUnitStatus
 		};
 	}
 
@@ -454,7 +550,7 @@
 	}
 
 	/**
-	 * Creates the controls for the JUnit 4 toggle control. Expects a <code>GridLayout</code> with
+	 * Creates the controls for the JUnit version radio buttons. Expects a <code>GridLayout</code> with
 	 * at least 3 columns.
 	 *
 	 * @param composite the parent composite
@@ -465,31 +561,54 @@
 	protected void createJUnit4Controls(Composite composite, int nColumns) {
 		Composite inner= new Composite(composite, SWT.NONE);
 		inner.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, nColumns, 1));
-		GridLayout layout= new GridLayout(2, false);
+		GridLayout layout= new GridLayout(3, false);
 		layout.marginHeight= 0;
 		layout.marginWidth= 0;
 		inner.setLayout(layout);
 
-		SelectionAdapter listener= new SelectionAdapter() {
+		JUnitVersion version= getJUnitVersion();
+
+		fJUnit3Button= new Button(inner, SWT.RADIO);
+		fJUnit3Button.setText(WizardMessages.NewTestCaseWizardPageOne_junit3_radio_label);
+		fJUnit3Button.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 1, 1));
+		fJUnit3Button.setSelection(version == JUnitVersion.VERSION_3);
+		fJUnit3Button.setEnabled(fIsJUnitEnabled);
+		fJUnit3Button.addSelectionListener(new SelectionAdapter() {
 			@Override
 			public void widgetSelected(SelectionEvent e) {
-				boolean isSelected= ((Button) e.widget).getSelection();
-				internalSetJUnit4(isSelected);
+				if (((Button) e.widget).getSelection()) {
+					internalSetJUnit(JUnitVersion.VERSION_3);
+				}
 			}
-		};
+		});
 
-		Button junti3Toggle= new Button(inner, SWT.RADIO);
-		junti3Toggle.setText(WizardMessages.NewTestCaseWizardPageOne_junit3_radio_label);
-		junti3Toggle.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 1, 1));
-		junti3Toggle.setSelection(!fIsJunit4);
-		junti3Toggle.setEnabled(fIsJunit4Enabled);
+		fJUnit4Button= new Button(inner, SWT.RADIO);
+		fJUnit4Button.setText(WizardMessages.NewTestCaseWizardPageOne_junit4_radio_label);
+		fJUnit4Button.setSelection(version == JUnitVersion.VERSION_4);
+		fJUnit4Button.setEnabled(fIsJUnitEnabled);
+		fJUnit4Button.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 1, 1));
+		fJUnit4Button.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (((Button) e.widget).getSelection()) {
+					internalSetJUnit(JUnitVersion.VERSION_4);
+				}
+			}
+		});
 
-		fJUnit4Toggle= new Button(inner, SWT.RADIO);
-		fJUnit4Toggle.setText(WizardMessages.NewTestCaseWizardPageOne_junit4_radio_label);
-		fJUnit4Toggle.setSelection(fIsJunit4);
-		fJUnit4Toggle.setEnabled(fIsJunit4Enabled);
-		fJUnit4Toggle.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 1, 1));
-		fJUnit4Toggle.addSelectionListener(listener);
+		fJUnit5Button= new Button(inner, SWT.RADIO);
+		fJUnit5Button.setText(WizardMessages.NewTestCaseWizardPageOne_junit5_radio_label);
+		fJUnit5Button.setSelection(version == JUnitVersion.VERSION_5);
+		fJUnit5Button.setEnabled(fIsJUnitEnabled);
+		fJUnit5Button.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, false, false, 1, 1));
+		fJUnit5Button.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (((Button) e.widget).getSelection()) {
+					internalSetJUnit(JUnitVersion.VERSION_5);
+				}
+			}
+		});
 	}
 
 	/**
@@ -575,10 +694,14 @@
 		if (root != null) {
 			IJavaProject project= root.getJavaProject();
 			if (project.exists()) {
-				if (isJUnit4()) {
+				if (fJUnitVersion == JUnitVersion.VERSION_4) {
 					if (!JUnitStubUtility.is50OrHigher(project)) {
 						message= WizardMessages.NewTestCaseWizardPageOne_linkedtext_java5required;
 					}
+				} else if (fJUnitVersion == JUnitVersion.VERSION_5) {
+					if (!JUnitStubUtility.is18OrHigher(project)) {
+						message= WizardMessages.NewTestCaseWizardPageOne_linkedtext_java8required;
+					}
 				}
 			}
 		}
@@ -738,12 +861,14 @@
 			createTearDown(type, imports);
 		}
 
-		if (fClassUnderTest != null || isJUnit4()) {
+		if (fClassUnderTest != null || fJUnitVersion != JUnitVersion.VERSION_3) {
 			createTestMethodStubs(type, imports);
 		}
 
-		if (isJUnit4()) {
+		if (fJUnitVersion == JUnitVersion.VERSION_4) {
 			imports.addStaticImport("org.junit.Assert", "*", false); //$NON-NLS-1$ //$NON-NLS-2$
+		} else if (fJUnitVersion == JUnitVersion.VERSION_5) {
+			imports.addStaticImport("org.junit.jupiter.api.Assertions", "*", false); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 
 	}
@@ -779,12 +904,12 @@
 			buffer.append("public "); //$NON-NLS-1$
 			buffer.append(getTypeName());
 			buffer.append('(');
-			if (!isJUnit4()) {
+			if (fJUnitVersion == JUnitVersion.VERSION_3) {
 				buffer.append(imports.addImport("java.lang.String")).append(" name"); //$NON-NLS-1$ //$NON-NLS-2$
 			}
 			buffer.append(") {"); //$NON-NLS-1$
 			buffer.append(delimiter);
-			if (!isJUnit4()) {
+			if (fJUnitVersion == JUnitVersion.VERSION_3) {
 				buffer.append("super(name);").append(delimiter); //$NON-NLS-1$
 			}
 			buffer.append('}');
@@ -816,7 +941,7 @@
 		String content= null;
 		IMethod methodTemplate= findInHierarchy(type, methodName);
 		String annotation= null;
-		if (isJUnit4()) {
+		if (fJUnitVersion != JUnitVersion.VERSION_3) {
 			annotation= '@' + imports.addImport(annotationType);
 		}
 
@@ -841,9 +966,9 @@
 				buffer.append(annotation).append(delimiter);
 			}
 
-			if (isJUnit4()) {
+			if (fJUnitVersion == JUnitVersion.VERSION_4) {
 				buffer.append("public "); //$NON-NLS-1$
-			} else {
+			} else if (fJUnitVersion == JUnitVersion.VERSION_3) {
 				buffer.append("protected "); //$NON-NLS-1$
 			}
 			if (isStatic) {
@@ -863,25 +988,29 @@
 
 
 	private void createSetUp(IType type, ImportsManager imports) throws CoreException {
-		createSetupStubs(type, "setUp", false, "org.junit.Before", imports); //$NON-NLS-1$ //$NON-NLS-2$
+		String annotationType= fJUnitVersion == JUnitVersion.VERSION_4 ? "org.junit.Before" : "org.junit.jupiter.api.BeforeEach"; //$NON-NLS-1$ //$NON-NLS-2$
+		createSetupStubs(type, "setUp", false, annotationType, imports); //$NON-NLS-1$ 
 	}
 
 	private void createTearDown(IType type, ImportsManager imports) throws CoreException {
-		createSetupStubs(type, "tearDown", false, "org.junit.After", imports); //$NON-NLS-1$ //$NON-NLS-2$
+		String annotationType= fJUnitVersion == JUnitVersion.VERSION_4 ? "org.junit.After" : "org.junit.jupiter.api.AfterEach"; //$NON-NLS-1$ //$NON-NLS-2$
+		createSetupStubs(type, "tearDown", false, annotationType, imports); //$NON-NLS-1$ 
 	}
 
 	private void createSetUpClass(IType type, ImportsManager imports) throws CoreException {
-		createSetupStubs(type, "setUpBeforeClass", true, "org.junit.BeforeClass", imports); //$NON-NLS-1$ //$NON-NLS-2$
+		String annotationType= fJUnitVersion == JUnitVersion.VERSION_4 ? "org.junit.BeforeClass" : "org.junit.jupiter.api.BeforeAll"; //$NON-NLS-1$ //$NON-NLS-2$
+		createSetupStubs(type, "setUpBeforeClass", true, annotationType, imports); //$NON-NLS-1$ 
 	}
 
 	private void createTearDownClass(IType type, ImportsManager imports) throws CoreException {
-		createSetupStubs(type, "tearDownAfterClass", true, "org.junit.AfterClass", imports); //$NON-NLS-1$ //$NON-NLS-2$
+		String annotationType= fJUnitVersion == JUnitVersion.VERSION_4 ? "org.junit.AfterClass" : "org.junit.jupiter.api.AfterAll"; //$NON-NLS-1$ //$NON-NLS-2$
+		createSetupStubs(type, "tearDownAfterClass", true, annotationType, imports); //$NON-NLS-1$ 
 	}
 
 	private void createTestMethodStubs(IType type, ImportsManager imports) throws CoreException {
 		IMethod[] methods= fPage2.getCheckedMethods();
 		if (methods.length == 0) {
-			if (isJUnit4()) {
+			if (fJUnitVersion != JUnitVersion.VERSION_3) {
 				List<String> names= new ArrayList<>();
 				createTestMethod(type, imports, null, null, names);
 			}
@@ -949,13 +1078,19 @@
 		if (isAddComments() && method != null) {
 			appendMethodComment(buffer, method);
 		}
-		if (isJUnit4()) {
+		if (fJUnitVersion == JUnitVersion.VERSION_4) {
 			ISourceRange typeSourceRange= type.getSourceRange();
 			int pos= typeSourceRange.getOffset() + typeSourceRange.getLength() - 1;
 			buffer.append('@').append(imports.addImport(JUnitCorePlugin.JUNIT4_ANNOTATION_NAME, pos)).append(getLineDelimiter());
+		} else if (fJUnitVersion == JUnitVersion.VERSION_5) {
+			ISourceRange typeSourceRange= type.getSourceRange();
+			int pos= typeSourceRange.getOffset() + typeSourceRange.getLength() - 1;
+			buffer.append('@').append(imports.addImport(JUnitCorePlugin.JUNIT5_JUPITER_TEST_ANNOTATION_NAME, pos)).append(getLineDelimiter());
 		}
 
-		buffer.append("public ");//$NON-NLS-1$
+		if (fJUnitVersion != JUnitVersion.VERSION_5) {
+			buffer.append("public ");//$NON-NLS-1$
+		}
 		if (fPage2.getCreateFinalMethodStubsButtonSelection())
 			buffer.append("final "); //$NON-NLS-1$
 		buffer.append("void ");//$NON-NLS-1$
@@ -1103,7 +1238,16 @@
 			try {
 				IJavaProject project= root.getJavaProject();
 				if (project.exists()) {
-					if (isJUnit4()) {
+					if (fJUnitVersion == JUnitVersion.VERSION_5) {
+						if (!JUnitStubUtility.is18OrHigher(project)) {
+							status.setError(WizardMessages.NewTestCaseWizardPageOne_error_java8required);
+							return status;
+						}
+						if (project.findType(JUnitCorePlugin.JUNIT5_TESTABLE_ANNOTATION_NAME) == null) {
+							status.setWarning(WizardMessages.NewTestCaseWizardPageOne__error_junit5NotOnbuildpath);
+							return status;
+						}
+					} else if (fJUnitVersion == JUnitVersion.VERSION_4) {
 						if (!JUnitStubUtility.is50OrHigher(project)) {
 							status.setError(WizardMessages.NewTestCaseWizardPageOne_error_java5required);
 							return status;
@@ -1132,13 +1276,13 @@
 			return stat;
 		String superClassName= getSuperClass();
 		JUnitStatus status= new JUnitStatus();
-		boolean isJUnit4= isJUnit4();
+		boolean isJUnit3= fJUnitVersion == JUnitVersion.VERSION_3;
 		if (superClassName == null || superClassName.trim().equals("")) { //$NON-NLS-1$
-			if (!isJUnit4)
+			if (isJUnit3)
 				status.setError(WizardMessages.NewTestCaseWizardPageOne_error_superclass_empty);
 			return status;
 		}
-		if (isJUnit4 && superClassName.equals("java.lang.Object")) //$NON-NLS-1$
+		if (!isJUnit3 && superClassName.equals("java.lang.Object")) //$NON-NLS-1$
 			return status;
 		if (getPackageFragmentRoot() != null) {
 			try {
@@ -1151,7 +1295,7 @@
 					status.setError(WizardMessages.NewTestCaseWizardPageOne_error_superclass_is_interface);
 					return status;
 				}
-				if (!isJUnit4 && !CoreTestSearchEngine.isTestImplementor(type)) { // TODO: expensive!
+				if (isJUnit3 && !CoreTestSearchEngine.isTestImplementor(type)) { // TODO: expensive!
 					status.setError(Messages.format(WizardMessages.NewTestCaseWizardPageOne_error_superclass_not_implementing_test_interface, BasicElementLabels.getJavaElementName(JUnitCorePlugin.TEST_INTERFACE_NAME)));
 					return status;
 				}
@@ -1243,7 +1387,15 @@
 	 * @since 3.7
 	 */
 	private String getDefaultSuperClassName() {
-		return isJUnit4() ? "java.lang.Object" : getJUnit3TestSuperclassName(); //$NON-NLS-1$
+		return fJUnitVersion != JUnitVersion.VERSION_3 ? "java.lang.Object" : getJUnit3TestSuperclassName(); //$NON-NLS-1$
 	}
 
+	@Override
+	public int getModifiers() {
+		int modifiers= super.getModifiers();
+		if (fJUnitVersion == JUnitVersion.VERSION_5) {
+			modifiers&= ~F_PUBLIC;
+		}
+		return modifiers;
+	}
 }
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestSuiteWizardPage.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestSuiteWizardPage.java
index 7606a5d..ffecabe 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestSuiteWizardPage.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/junit/wizards/NewTestSuiteWizardPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -180,7 +180,7 @@
 		boolean isJunit4= false;
 		if (jelem != null && jelem.getElementType() != IJavaElement.JAVA_MODEL) {
 			IJavaProject project= jelem.getJavaProject();
-			isJunit4= CoreTestSearchEngine.hasTestAnnotation(project);
+			isJunit4= CoreTestSearchEngine.hasJUnit4TestAnnotation(project);
 			if (!isJunit4 && !CoreTestSearchEngine.hasTestCaseType(project) && JUnitStubUtility.is50OrHigher(project)) {
 				isJunit4= true;
 			}
diff --git a/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4Identifier.java b/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4Identifier.java
index 1252ecb..be50f91 100644
--- a/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4Identifier.java
+++ b/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4Identifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2008 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -41,4 +41,16 @@
 		return fPlan.equals(id.fPlan);
 	}
 
+	public String getDisplayName() {
+		return getName();
+	}
+
+	public String getParameterTypes() {
+		return ""; //$NON-NLS-1$
+	}
+
+	public String getUniqueId() {
+		return ""; //$NON-NLS-1$
+	}
+
 }
diff --git a/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestLoader.java b/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestLoader.java
index c077f2b..811f7ad 100644
--- a/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestLoader.java
+++ b/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestLoader.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2014 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -35,6 +35,9 @@
 			Class[] testClasses,
 			String testName,
 			String[] failureNames,
+			String[] packages,
+			String[][] includeExcludeTags,
+			String uniqueId,
 			RemoteTestRunner listener) {
 
 		ITestReference[] refs= new ITestReference[testClasses.length];
diff --git a/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestReference.java b/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestReference.java
index 8888de3..45c4957 100644
--- a/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestReference.java
+++ b/org.eclipse.jdt.junit4.runtime/src/org/eclipse/jdt/internal/junit4/runner/JUnit4TestReference.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2014 IBM Corporation and others.
+ * Copyright (c) 2006, 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
@@ -98,9 +98,9 @@
 
 	private void sendTree(final IVisitsTestTrees notified, Description description) {
 		if (description.isTest()) {
-			notified.visitTreeEntry(new JUnit4Identifier(description), false, 1);
+			notified.visitTreeEntry(new JUnit4Identifier(description), false, 1, false, "-1"); //$NON-NLS-1$
 		} else {
-			notified.visitTreeEntry(new JUnit4Identifier(description), true, description.getChildren().size());
+			notified.visitTreeEntry(new JUnit4Identifier(description), true, description.getChildren().size(), false, "-1"); //$NON-NLS-1$
 			for (Description child : description.getChildren()) {
 				sendTree(notified, child);
 			}
diff --git a/org.eclipse.jdt.junit5.runtime/.classpath b/org.eclipse.jdt.junit5.runtime/.classpath
new file mode 100644
index 0000000..6d4f69f
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src/"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.junit5.runtime/.project b/org.eclipse.jdt.junit5.runtime/.project
new file mode 100644
index 0000000..2dd2428
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.jdt.junit5.runtime</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..6617ba5
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,422 @@
+eclipse.preferences.version=1

+org.eclipse.jdt.core.builder.cleanOutputFolder=clean

+org.eclipse.jdt.core.builder.duplicateResourceTask=warning

+org.eclipse.jdt.core.builder.invalidClasspath=abort

+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore

+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch

+org.eclipse.jdt.core.circularClasspath=error

+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled

+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled

+org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource=error

+org.eclipse.jdt.core.codeComplete.argumentPrefixes=

+org.eclipse.jdt.core.codeComplete.argumentSuffixes=

+org.eclipse.jdt.core.codeComplete.fieldPrefixes=f

+org.eclipse.jdt.core.codeComplete.fieldSuffixes=

+org.eclipse.jdt.core.codeComplete.localPrefixes=

+org.eclipse.jdt.core.codeComplete.localSuffixes=

+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=fg

+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=

+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=

+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=

+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled

+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore

+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull

+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault

+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable

+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled

+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled

+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate

+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8

+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve

+org.eclipse.jdt.core.compiler.compliance=1.8

+org.eclipse.jdt.core.compiler.debug.lineNumber=generate

+org.eclipse.jdt.core.compiler.debug.localVariable=generate

+org.eclipse.jdt.core.compiler.debug.sourceFile=generate

+org.eclipse.jdt.core.compiler.doc.comment.support=enabled

+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100

+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning

+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

+org.eclipse.jdt.core.compiler.problem.autoboxing=info

+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning

+org.eclipse.jdt.core.compiler.problem.deadCode=error

+org.eclipse.jdt.core.compiler.problem.deprecation=warning

+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled

+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled

+org.eclipse.jdt.core.compiler.problem.discouragedReference=error

+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning

+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error

+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning

+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning

+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled

+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning

+org.eclipse.jdt.core.compiler.problem.finalParameterBound=error

+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning

+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error

+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error

+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled

+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=error

+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error

+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning

+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled

+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private

+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning

+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error

+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=info

+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning

+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=enabled

+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error

+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore

+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled

+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags

+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled

+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private

+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning

+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled

+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning

+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=error

+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error

+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error

+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning

+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning

+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error

+org.eclipse.jdt.core.compiler.problem.nullReference=error

+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error

+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning

+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error

+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore

+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error

+org.eclipse.jdt.core.compiler.problem.potentialNullReference=info

+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=info

+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning

+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning

+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning

+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning

+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=info

+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore

+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore

+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled

+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error

+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled

+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled

+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled

+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore

+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning

+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled

+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning

+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning

+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=info

+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning

+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore

+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error

+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled

+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled

+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore

+org.eclipse.jdt.core.compiler.problem.unusedImport=error

+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning

+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning

+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=info

+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning

+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled

+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled

+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled

+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning

+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning

+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning

+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning

+org.eclipse.jdt.core.compiler.source=1.8

+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16

+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16

+org.eclipse.jdt.core.formatter.alignment_for_assignment=0

+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16

+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16

+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=48

+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0

+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16

+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0

+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16

+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80

+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16

+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16

+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16

+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1

+org.eclipse.jdt.core.formatter.blank_lines_after_package=1

+org.eclipse.jdt.core.formatter.blank_lines_before_field=1

+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0

+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1

+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1

+org.eclipse.jdt.core.formatter.blank_lines_before_method=1

+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1

+org.eclipse.jdt.core.formatter.blank_lines_before_package=0

+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1

+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1

+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line

+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line

+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false

+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false

+org.eclipse.jdt.core.formatter.comment.format_block_comments=false

+org.eclipse.jdt.core.formatter.comment.format_header=false

+org.eclipse.jdt.core.formatter.comment.format_html=true

+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true

+org.eclipse.jdt.core.formatter.comment.format_line_comments=false

+org.eclipse.jdt.core.formatter.comment.format_source_code=true

+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true

+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true

+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert

+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert

+org.eclipse.jdt.core.formatter.comment.line_length=100

+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true

+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true

+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false

+org.eclipse.jdt.core.formatter.compact_else_if=true

+org.eclipse.jdt.core.formatter.continuation_indentation=2

+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2

+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off

+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on

+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false

+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true

+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true

+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true

+org.eclipse.jdt.core.formatter.indent_empty_lines=false

+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true

+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true

+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true

+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true

+org.eclipse.jdt.core.formatter.indentation.size=4

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert

+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert

+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert

+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert

+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert

+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert

+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert

+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert

+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert

+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert

+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert

+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert

+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert

+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert

+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert

+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert

+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert

+org.eclipse.jdt.core.formatter.join_lines_in_comments=true

+org.eclipse.jdt.core.formatter.join_wrapped_lines=false

+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false

+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false

+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false

+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false

+org.eclipse.jdt.core.formatter.lineSplit=200

+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=true

+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true

+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0

+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=3

+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true

+org.eclipse.jdt.core.formatter.tabulation.char=tab

+org.eclipse.jdt.core.formatter.tabulation.size=4

+org.eclipse.jdt.core.formatter.use_on_off_tags=false

+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false

+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true

+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true

+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true

+org.eclipse.jdt.core.incompatibleJDKLevel=ignore

+org.eclipse.jdt.core.incompleteClasspath=error

+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter

diff --git a/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..b73bfac
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+formatter_profile=_JDT UI Code Style Conventions
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;sun;com;org;org.apache;org.w3c;org.eclipse;org.eclipse.swt;org.eclipse.core;org.eclipse.core.runtime;org.eclipse.core.resources;org.eclipse.core.filebuffers;org.eclipse.text;org.eclipse.jface;org.eclipse.jface.text;org.eclipse.ui;org.eclipse.ui.workbench.texteditor;org.eclipse.ui.texteditor;org.eclipse.ui.editors;org.eclipse.compare;org.eclipse.debug;org.eclipse.debug.ui;org.eclipse.search;org.eclipse.search2;org.eclipse.ltk;org.eclipse.jdt.core;org.eclipse.jdt.internal;org.eclipse.jdt.launching;org.eclipse.jdt.ui;org.eclipse.jdt.internal.ui;
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
diff --git a/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.pde.prefs b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..d1046a8
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,33 @@
+compilers.f.unresolved-features=1
+compilers.f.unresolved-plugins=1
+compilers.incompatible-environment=0
+compilers.p.build=1
+compilers.p.build.bin.includes=1
+compilers.p.build.encodings=2
+compilers.p.build.java.compiler=2
+compilers.p.build.java.compliance=1
+compilers.p.build.missing.output=2
+compilers.p.build.output.library=1
+compilers.p.build.source.library=1
+compilers.p.build.src.includes=1
+compilers.p.deprecated=1
+compilers.p.discouraged-class=1
+compilers.p.internal=1
+compilers.p.missing-packages=0
+compilers.p.missing-version-export-package=2
+compilers.p.missing-version-import-package=2
+compilers.p.missing-version-require-bundle=1
+compilers.p.no-required-att=0
+compilers.p.not-externalized-att=1
+compilers.p.unknown-attribute=0
+compilers.p.unknown-class=0
+compilers.p.unknown-element=0
+compilers.p.unknown-identifier=0
+compilers.p.unknown-resource=0
+compilers.p.unresolved-ex-points=0
+compilers.p.unresolved-import=0
+compilers.s.create-docs=false
+compilers.s.doc-folder=doc
+compilers.s.open-tags=1
+compilers.use-project=true
+eclipse.preferences.version=1
diff --git a/org.eclipse.jdt.junit5.runtime/META-INF/MANIFEST.MF b/org.eclipse.jdt.junit5.runtime/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..cf1ccb9
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-Vendor: %providerName
+Bundle-SymbolicName: org.eclipse.jdt.junit5.runtime;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Localization: plugin
+Export-Package: org.eclipse.jdt.internal.junit5.runner;x-internal:=true
+Require-Bundle: org.eclipse.jdt.junit.runtime;bundle-version="[3.4.600,4.0.0)",
+ org.junit.jupiter.api;bundle-version="5.0.0",
+ org.junit.jupiter.engine;bundle-version="5.0.0",
+ org.junit.jupiter.migrationsupport;bundle-version="5.0.0",
+ org.junit.jupiter.params;bundle-version="5.0.0",
+ org.junit.vintage.engine;bundle-version="4.12.0",
+ org.opentest4j;bundle-version="1.0.0",
+ org.junit.platform.commons;bundle-version="1.0.0",
+ org.junit.platform.engine;bundle-version="1.0.0",
+ org.junit.platform.launcher;bundle-version="1.0.0",
+ org.junit.platform.runner;bundle-version="1.0.0",
+ org.junit.platform.suite.api;bundle-version="1.0.0",
+ org.apiguardian;bundle-version="1.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/org.eclipse.jdt.junit5.runtime/about.html b/org.eclipse.jdt.junit5.runtime/about.html
new file mode 100644
index 0000000..4602330
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p>June 2, 2006</p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;).  A copy of the EPL is available 
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/org.eclipse.jdt.junit5.runtime/build.properties b/org.eclipse.jdt.junit5.runtime/build.properties
new file mode 100644
index 0000000..0058117
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/build.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2016 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
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+
+source.. = src/
+src.includes = about.html
+bin.includes = about.html,\
+               plugin.properties,\
+               .,\
+               META-INF/
diff --git a/org.eclipse.jdt.junit5.runtime/plugin.properties b/org.eclipse.jdt.junit5.runtime/plugin.properties
new file mode 100644
index 0000000..3ab5d2d
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/plugin.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2016 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
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+pluginName=Java Development Tools JUnit5 Runtime Support
+providerName=Eclipse.org
\ No newline at end of file
diff --git a/org.eclipse.jdt.junit5.runtime/pom.xml b/org.eclipse.jdt.junit5.runtime/pom.xml
new file mode 100644
index 0000000..dadecc8
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright (c) 2016 Eclipse Foundation and others.
+  All rights reserved. This program and the accompanying materials
+  are made available under the terms of the Eclipse Distribution License v1.0
+  which accompanies this distribution, and is available at
+  http://www.eclipse.org/org/documents/edl-v10.php
+ 
+  Contributors:
+     IBM Corporation - initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>eclipse.jdt.ui</artifactId>
+    <groupId>eclipse.jdt.ui</groupId>
+    <version>4.7.1-SNAPSHOT</version>
+  </parent>
+  <groupId>org.eclipse.jdt</groupId>
+  <artifactId>org.eclipse.jdt.junit5.runtime</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/org.eclipse.jdt.junit5.runtime/scripts/exportplugin.xml b/org.eclipse.jdt.junit5.runtime/scripts/exportplugin.xml
new file mode 100644
index 0000000..9c4124c
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/scripts/exportplugin.xml
@@ -0,0 +1,54 @@
+<project name="org.eclipse.jdt.junit5.runtime" default="export" basedir="..">
+<!-- build script to create a plugin from org.eclipse.jdt.ui -->
+
+	<target name="init">
+		<tstamp/>
+		<property name="destdir"	value="../../plugin-export" />
+		<property name="plugin"		value="org.eclipse.jdt.junit5.runtime" />
+		<property name="qualifier" value="zzz${DSTAMP}-${TSTAMP}" />
+		
+		<!-- define property ${plugin_version} by reading version from MANIFEST.MF: -->
+		<tempfile property="plugin_version_file" suffix=".plugin_version.tmp" destdir="${destdir}"/>
+		<copy file="META-INF/MANIFEST.MF" tofile="${plugin_version_file}"/>
+		<replaceregexp file="${plugin_version_file}" match=".*Bundle-Version: ((\d)+\.(\d)+\.(\d)+\.)qualifier.*" replace="plugin_version=_\1${qualifier}" flags="s" />
+		<property file="${plugin_version_file}"/>
+		<delete file="${plugin_version_file}" />
+		
+		<property name="dest"		value="${destdir}/${plugin}${plugin_version}" />
+		<property name="destjar"	value="${destdir}/${plugin}${plugin_version}.jar" />
+	</target>
+
+	<target name="build" depends="init">
+    	<eclipse.incrementalBuild project="${plugin}" kind="incr"/>
+	</target>
+
+	<target name="export" depends="build">
+		<mkdir dir="${destdir}" />
+		<delete dir="${dest}" />
+		<mkdir dir="${dest}" />
+		
+		<copy todir="${dest}/META-INF">
+			<fileset dir="META-INF" />
+		</copy>		
+		
+		<replaceregexp file="${dest}/META-INF/MANIFEST.MF" match="Bundle-Version: ((\d)+\.(\d)+\.(\d)+\.)qualifier" replace="Bundle-Version: \1${qualifier}" byline="true" />
+		
+		<delete file="${destjar}" />
+		<zip zipfile="${destjar}">
+			<fileset dir=".">
+			  <include name="plugin.xml" />
+			  <include name="plugin.properties" />
+			</fileset>
+			<fileset dir="bin" />
+			
+		    <zipfileset dir="src" prefix="src" />
+		    
+			<fileset dir="${dest}">
+			  <include name="META-INF/**" />
+			</fileset>
+		</zip>
+		
+		<delete dir="${dest}" />
+		
+	</target>
+</project>
diff --git a/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5Identifier.java b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5Identifier.java
new file mode 100644
index 0000000..48a8218
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5Identifier.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.junit5.runner;
+
+import java.text.MessageFormat;
+import java.util.function.Function;
+
+import org.junit.platform.engine.TestSource;
+import org.junit.platform.engine.support.descriptor.ClassSource;
+import org.junit.platform.engine.support.descriptor.MethodSource;
+import org.junit.platform.launcher.TestIdentifier;
+
+import org.eclipse.jdt.internal.junit.runner.ITestIdentifier;
+import org.eclipse.jdt.internal.junit.runner.MessageIds;
+
+public class JUnit5Identifier implements ITestIdentifier {
+
+	private TestIdentifier fTestIdentifier;
+
+	public JUnit5Identifier(TestIdentifier testIdentifier) {
+		fTestIdentifier= testIdentifier;
+	}
+
+	@Override
+	public String getName() {
+		return fTestIdentifier.getSource().map(this::getName).orElse(fTestIdentifier.getDisplayName());
+	}
+
+	private String getName(TestSource testSource) {
+		if (testSource instanceof ClassSource) {
+			return ((ClassSource) testSource).getJavaClass().getName();
+		}
+		if (testSource instanceof MethodSource) {
+			MethodSource methodSource= (MethodSource) testSource;
+			return MessageFormat.format(MessageIds.TEST_IDENTIFIER_MESSAGE_FORMAT, methodSource.getMethodName(), methodSource.getClassName());
+		}
+		return null;
+	}
+
+	@Override
+	public String getDisplayName() {
+		return fTestIdentifier.getDisplayName();
+	}
+
+	@Override
+	public int hashCode() {
+		return fTestIdentifier.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof JUnit5Identifier))
+			return false;
+
+		JUnit5Identifier id= (JUnit5Identifier) obj;
+		return fTestIdentifier.equals(id.fTestIdentifier);
+	}
+
+	@Override
+	public String getParameterTypes() {
+		Function<TestSource, String> getParameterTypes= (TestSource source) -> {
+			return source instanceof MethodSource ? ((MethodSource) source).getMethodParameterTypes() : null;
+		};
+		return fTestIdentifier.getSource().map(getParameterTypes).orElse(""); //$NON-NLS-1$
+	}
+
+	@Override
+	public String getUniqueId() {
+		return fTestIdentifier.getUniqueId();
+	}
+}
diff --git a/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestListener.java b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestListener.java
new file mode 100644
index 0000000..d25236c
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestListener.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.junit5.runner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.jdt.internal.junit.runner.FailedComparison;
+import org.eclipse.jdt.internal.junit.runner.IListensToTestExecutions;
+import org.eclipse.jdt.internal.junit.runner.ITestIdentifier;
+import org.eclipse.jdt.internal.junit.runner.MessageIds;
+import org.eclipse.jdt.internal.junit.runner.RemoteTestRunner;
+import org.eclipse.jdt.internal.junit.runner.TestReferenceFailure;
+import org.junit.platform.engine.TestExecutionResult;
+import org.junit.platform.engine.TestExecutionResult.Status;
+import org.junit.platform.launcher.TestExecutionListener;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.TestPlan;
+import org.opentest4j.AssertionFailedError;
+import org.opentest4j.MultipleFailuresError;
+import org.opentest4j.ValueWrapper;
+
+public class JUnit5TestListener implements TestExecutionListener {
+
+	private final IListensToTestExecutions fNotified;
+
+	private TestPlan fTestPlan;
+
+	public JUnit5TestListener(IListensToTestExecutions notified) {
+		fNotified= notified;
+	}
+
+	@Override
+	public void testPlanExecutionStarted(TestPlan testPlan) {
+		fTestPlan= testPlan;
+	}
+
+	@Override
+	public void testPlanExecutionFinished(TestPlan testPlan) {
+		fTestPlan= null;
+	}
+
+	@Override
+	public void executionStarted(TestIdentifier testIdentifier) {
+		if (testIdentifier.isTest()) {
+			fNotified.notifyTestStarted(getIdentifier(testIdentifier, false, false));
+		}
+	}
+
+	@Override
+	public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
+		Status result= testExecutionResult.getStatus();
+		if (testIdentifier.isTest()) {
+			if (result != Status.SUCCESSFUL) {
+				String trace= ""; //$NON-NLS-1$
+				FailedComparison comparison= null;
+				String status= MessageIds.TEST_FAILED;
+
+				boolean assumptionFailed= result == Status.ABORTED;
+				Optional<Throwable> throwableOp= testExecutionResult.getThrowable();
+				if (throwableOp.isPresent()) {
+					Throwable exception= throwableOp.get();
+					trace= getTrace(exception);
+					comparison= getFailedComparison(exception);
+					status= (assumptionFailed || exception instanceof AssertionError) ? MessageIds.TEST_FAILED : MessageIds.TEST_ERROR;
+				}
+
+				ITestIdentifier identifier= getIdentifier(testIdentifier, false, assumptionFailed);
+				fNotified.notifyTestFailed(new TestReferenceFailure(identifier, status, trace, comparison));
+			}
+
+			fNotified.notifyTestEnded(getIdentifier(testIdentifier, false, false));
+
+		} else { // container
+			if (result != Status.SUCCESSFUL) {
+				Optional<Throwable> throwableOp= testExecutionResult.getThrowable();
+				String trace= ""; //$NON-NLS-1$
+				if (throwableOp.isPresent()) {
+					trace= getTrace(throwableOp.get());
+				}
+				ITestIdentifier identifier= getIdentifier(testIdentifier, false, false);
+				fNotified.notifyTestFailed(new TestReferenceFailure(identifier, MessageIds.TEST_ERROR, trace));
+			}
+		}
+	}
+
+	private String getTrace(Throwable exception) {
+		StringWriter stringWriter= new StringWriter();
+		exception.printStackTrace(new PrintWriter(stringWriter));
+		return stringWriter.getBuffer().toString();
+	}
+
+	private FailedComparison getFailedComparison(Throwable exception) {
+		if (exception instanceof AssertionFailedError) {
+			AssertionFailedError assertionFailedError= (AssertionFailedError) exception;
+			ValueWrapper expected= assertionFailedError.getExpected();
+			ValueWrapper actual= assertionFailedError.getActual();
+			if (expected == null || actual == null) {
+				return null;
+			}
+			return new FailedComparison(expected.getStringRepresentation(), actual.getStringRepresentation());
+		} else if (exception instanceof MultipleFailuresError) {
+			String expectedStr= ""; //$NON-NLS-1$
+			String actualStr= ""; //$NON-NLS-1$
+			String delimiter= "\n\n"; //$NON-NLS-1$
+			List<Throwable> failures= ((MultipleFailuresError) exception).getFailures();
+			for (Throwable assertionError : failures) {
+				if (assertionError instanceof AssertionFailedError) {
+					AssertionFailedError assertionFailedError= (AssertionFailedError) assertionError;
+					ValueWrapper expected= assertionFailedError.getExpected();
+					ValueWrapper actual= assertionFailedError.getActual();
+					if (expected == null || actual == null) {
+						return null;
+					}
+					expectedStr+= expected.getStringRepresentation() + delimiter;
+					actualStr+= actual.getStringRepresentation() + delimiter;
+				} else {
+					return null;
+				}
+			}
+			return new FailedComparison(expectedStr, actualStr);
+		}
+		return null;
+	}
+
+	@Override
+	public void executionSkipped(TestIdentifier testIdentifier, String reason) {
+		if (testIdentifier.isContainer() && fTestPlan != null) {
+			fTestPlan.getDescendants(testIdentifier).stream().filter(t -> t.isTest()).forEachOrdered(t -> notifySkipped(t));
+		} else {
+			notifySkipped(testIdentifier);
+		}
+	}
+
+	private void notifySkipped(TestIdentifier testIdentifier) {
+		// Send message to listeners which would be stale otherwise
+		ITestIdentifier identifier= getIdentifier(testIdentifier, true, false);
+		fNotified.notifyTestStarted(identifier);
+		fNotified.notifyTestEnded(identifier);
+	}
+
+
+	@Override
+	public void dynamicTestRegistered(TestIdentifier testIdentifier) {
+		if (fTestPlan != null) {
+			JUnit5Identifier dynamicTestIdentifier= new JUnit5Identifier(testIdentifier);
+			boolean hasChildren;
+			int testCount;
+			if (testIdentifier.isContainer()) {
+				hasChildren= true;
+				testCount= fTestPlan.getChildren(testIdentifier).size();
+			} else {
+				hasChildren= false;
+				testCount= 1;
+			}
+			String parentId= JUnit5TestReference.getParentId(testIdentifier, fTestPlan);
+			RemoteTestRunner.fgTestRunServer.visitTreeEntry(dynamicTestIdentifier, hasChildren, testCount, true, parentId);
+		}
+	}
+
+	private ITestIdentifier getIdentifier(TestIdentifier testIdentifier, boolean ignored, boolean assumptionFailed) {
+		if (ignored) {
+			return new IgnoredTestIdentifier(testIdentifier);
+		}
+		if (assumptionFailed) {
+			return new AssumptionFailedTestIdentifier(testIdentifier);
+		}
+		return new JUnit5Identifier(testIdentifier);
+	}
+
+	private class IgnoredTestIdentifier extends JUnit5Identifier {
+		public IgnoredTestIdentifier(TestIdentifier description) {
+			super(description);
+		}
+
+		@Override
+		public String getName() {
+			String name= super.getName();
+			if (name != null)
+				return MessageIds.IGNORED_TEST_PREFIX + name;
+			return null;
+		}
+	}
+
+	private class AssumptionFailedTestIdentifier extends JUnit5Identifier {
+		public AssumptionFailedTestIdentifier(TestIdentifier description) {
+			super(description);
+		}
+
+		@Override
+		public String getName() {
+			String name= super.getName();
+			if (name != null)
+				return MessageIds.ASSUMPTION_FAILED_TEST_PREFIX + name;
+			return null;
+		}
+	}
+}
diff --git a/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestLoader.java b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestLoader.java
new file mode 100644
index 0000000..1ac0e05
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestLoader.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.junit5.runner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.platform.engine.Filter;
+import org.junit.platform.engine.discovery.ClassNameFilter;
+import org.junit.platform.engine.discovery.DiscoverySelectors;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.TagFilter;
+import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
+import org.junit.platform.launcher.core.LauncherFactory;
+
+import org.eclipse.jdt.internal.junit.runner.ITestLoader;
+import org.eclipse.jdt.internal.junit.runner.ITestReference;
+import org.eclipse.jdt.internal.junit.runner.RemoteTestRunner;
+
+public class JUnit5TestLoader implements ITestLoader {
+
+	private Launcher fLauncher= LauncherFactory.create();
+
+	@Override
+	public ITestReference[] loadTests(Class[] testClasses, String testName, String[] failureNames, String[] packages, String[][] includeExcludeTags, String uniqueId, RemoteTestRunner listener) {
+		ITestReference[] refs= new ITestReference[0];
+		if (uniqueId != null && !uniqueId.trim().isEmpty()) {
+			refs= new ITestReference[1];
+			refs[0]= createUniqueIdTest(uniqueId, includeExcludeTags);
+		} else if (packages != null) {
+			refs= new ITestReference[packages.length];
+			for (int i= 0; i < packages.length; i++) {
+				refs[i]= createTest(packages[i], includeExcludeTags);
+			}
+		} else {
+			refs= new ITestReference[testClasses.length];
+			for (int i= 0; i < testClasses.length; i++) {
+				refs[i]= createTest(testClasses[i], testName, includeExcludeTags);
+			}
+		}
+		return refs;
+	}
+
+	private ITestReference createTest(Class<?> clazz, String testName, String[][] includeExcludeTags) {
+		if (clazz == null) {
+			return null;
+		}
+		if (testName != null) {
+			return createFilteredTest(clazz, testName, includeExcludeTags);
+		}
+		return createUnfilteredTest(clazz, includeExcludeTags);
+	}
+
+	private ITestReference createFilteredTest(Class<?> clazz, String testName, String[][] includeExcludeTags) {
+		LauncherDiscoveryRequest request= LauncherDiscoveryRequestBuilder.request().selectors(DiscoverySelectors.selectMethod(clazz.getName() + "#" + testName)).filters(getTagFilters(includeExcludeTags)).build(); //$NON-NLS-1$
+		return new JUnit5TestReference(request, fLauncher);
+	}
+
+	private ITestReference createUnfilteredTest(Class<?> clazz, String[][] includeExcludeTags) {
+		LauncherDiscoveryRequest request= LauncherDiscoveryRequestBuilder.request().selectors(DiscoverySelectors.selectClass(clazz)).filters(getTagFilters(includeExcludeTags)).build();
+		return new JUnit5TestReference(request, fLauncher);
+	}
+
+	private ITestReference createTest(String pkg, String[][] includeExcludeTags) {
+		if (pkg == null) {
+			return null;
+		}
+		String pattern;
+		if (pkg.equals("<default>")) { //$NON-NLS-1$
+			pkg= ""; //$NON-NLS-1$
+			pattern= "^[^.]+$"; //$NON-NLS-1$
+		} else {
+			pattern= "^" + pkg + "\\.[^.]+$"; //$NON-NLS-1$//$NON-NLS-2$
+		}
+		LauncherDiscoveryRequest request= LauncherDiscoveryRequestBuilder.request()
+				.selectors(DiscoverySelectors.selectPackage(pkg))
+				.filters(ClassNameFilter.includeClassNamePatterns(pattern))
+				.filters(getTagFilters(includeExcludeTags))
+				.build();
+
+		return new JUnit5TestReference(request, fLauncher);
+	}
+
+	private ITestReference createUniqueIdTest(String uniqueId, String[][] includeExcludeTags) {
+		LauncherDiscoveryRequest request= LauncherDiscoveryRequestBuilder.request().selectors(DiscoverySelectors.selectUniqueId(uniqueId)).filters(getTagFilters(includeExcludeTags)).build();
+		return new JUnit5TestReference(request, fLauncher);
+	}
+
+	private Filter<?>[] getTagFilters(String[][] includeExcludeTags) {
+		String[] includeTags= includeExcludeTags[0];
+		String[] excludeTags= includeExcludeTags[1];
+		List<Filter<?>> tagFilters= new ArrayList<>();
+		if (includeTags != null) {
+			tagFilters.add(TagFilter.includeTags(includeTags));
+		}
+		if (excludeTags != null) {
+			tagFilters.add(TagFilter.excludeTags(excludeTags));
+		}
+		return tagFilters.toArray(new Filter[tagFilters.size()]);
+	}
+}
diff --git a/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestReference.java b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestReference.java
new file mode 100644
index 0000000..6db1102
--- /dev/null
+++ b/org.eclipse.jdt.junit5.runtime/src/org/eclipse/jdt/internal/junit5/runner/JUnit5TestReference.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.junit5.runner;
+
+import java.util.Set;
+
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.TestPlan;
+
+import org.eclipse.jdt.internal.junit.runner.ITestIdentifier;
+import org.eclipse.jdt.internal.junit.runner.ITestReference;
+import org.eclipse.jdt.internal.junit.runner.IVisitsTestTrees;
+import org.eclipse.jdt.internal.junit.runner.RemoteTestRunner;
+import org.eclipse.jdt.internal.junit.runner.TestExecution;
+import org.eclipse.jdt.internal.junit.runner.TestIdMap;
+
+public class JUnit5TestReference implements ITestReference {
+
+	private LauncherDiscoveryRequest fRequest;
+
+	private Launcher fLauncher;
+
+	private TestPlan fTestPlan;
+
+	public JUnit5TestReference(LauncherDiscoveryRequest request, Launcher launcher) {
+		fRequest= request;
+		fLauncher= launcher;
+		fTestPlan= fLauncher.discover(fRequest);
+	}
+
+	@Override
+	public int countTestCases() {
+		return (int) fTestPlan.countTestIdentifiers(TestIdentifier::isTest);
+	}
+
+	@Override
+	public void sendTree(IVisitsTestTrees notified) {
+		for (TestIdentifier root : fTestPlan.getRoots()) {
+			for (TestIdentifier child : fTestPlan.getChildren(root)) {
+				sendTree(notified, child);
+			}
+		}
+	}
+
+	void sendTree(IVisitsTestTrees notified, TestIdentifier testIdentifier) {
+		JUnit5Identifier identifier= new JUnit5Identifier(testIdentifier);
+		String parentId= getParentId(testIdentifier, fTestPlan);
+		if (testIdentifier.isTest()) {
+			notified.visitTreeEntry(identifier, false, 1, false, parentId);
+		} else {
+			Set<TestIdentifier> children= fTestPlan.getChildren(testIdentifier);
+			notified.visitTreeEntry(identifier, true, children.size(), false, parentId);
+			for (TestIdentifier child : children) {
+				sendTree(notified, child);
+			}
+		}
+	}
+
+	/**
+	 * @param testIdentifier the test identifier whose parent id is required
+	 * @param testPlan the test plan containing the test
+	 * @return the parent id from {@link TestIdMap} if the parent is present, otherwise
+	 *         <code>"-1"</code>
+	 */
+	static String getParentId(TestIdentifier testIdentifier, TestPlan testPlan) {
+		return testPlan.getParent(testIdentifier).map(parent -> RemoteTestRunner.fgTestRunServer.getTestId(new JUnit5Identifier(parent))).orElse("-1"); //$NON-NLS-1$
+	}
+
+	@Override
+	public void run(TestExecution execution) {
+		fLauncher.execute(fRequest, new JUnit5TestListener(execution.getListener()));
+	}
+
+	@Override
+	public ITestIdentifier getIdentifier() { // not used
+		return new JUnit5Identifier(fTestPlan.getRoots().iterator().next());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (!(obj instanceof JUnit5TestReference))
+			return false;
+
+		JUnit5TestReference ref= (JUnit5TestReference) obj;
+		return (ref.fRequest.equals(fRequest));
+	}
+
+	@Override
+	public int hashCode() {
+		return fRequest.hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return fRequest.toString();
+	}
+
+}
diff --git a/org.eclipse.jdt.ui.tests/testresources/JUnitWorkspace/JUnitTests/xml/FailingSuite.xml b/org.eclipse.jdt.ui.tests/testresources/JUnitWorkspace/JUnitTests/xml/FailingSuite.xml
index 4efef4a..dfb75d4 100644
--- a/org.eclipse.jdt.ui.tests/testresources/JUnitWorkspace/JUnitTests/xml/FailingSuite.xml
+++ b/org.eclipse.jdt.ui.tests/testresources/JUnitWorkspace/JUnitTests/xml/FailingSuite.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <testrun name="FailingSuite" project="JUnitTests" tests="1" started="0" failures="1" errors="0" ignored="0">
-  <testsuite name="pack.FailingSuite.MySetup" incomplete="true">
+  <testsuite name="pack.FailingSuite$MySetup" incomplete="true">
     <failure>junit.framework.AssertionFailedError: failure in setUp
 	at junit.framework.Assert.fail(Assert.java:47)
 	at pack.FailingSuite$MySetup.setUp(FailingSuite.java:15)
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility.java
index 97e3b5c..cea8de8 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2014 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
diff --git a/org.eclipse.jdt.ui/templates/default-templates.properties b/org.eclipse.jdt.ui/templates/default-templates.properties
index 17ddf98..926b01e 100644
--- a/org.eclipse.jdt.ui/templates/default-templates.properties
+++ b/org.eclipse.jdt.ui/templates/default-templates.properties
@@ -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
@@ -41,6 +41,8 @@
 Templates.toarray=convert collection to array
 Templates.test=test method (JUnit 3)
 Templates.test_junit4=test method (JUnit 4)
+Templates.test_junit5=test method (JUnit 5)
+Templates.testfactory_junit5=test factory method (JUnit Jupiter)
 Templates.systrace=print current method to standard out
 Templates.sysout=print to standard out
 Templates.syserr=print to standard error
diff --git a/org.eclipse.jdt.ui/templates/default-templates.xml b/org.eclipse.jdt.ui/templates/default-templates.xml
index a21516b..6a05971 100644
--- a/org.eclipse.jdt.ui/templates/default-templates.xml
+++ b/org.eclipse.jdt.ui/templates/default-templates.xml
@@ -2,7 +2,7 @@
 
 <!--
 /*******************************************************************************
- * 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
@@ -176,11 +176,22 @@
 	${cursor}
 }</template>
 
-<template name="test" description="%Templates.test_junit4" id="org.eclipse.jdt.ui.templates.test_junit4" context="java-members" enabled="true" autoinsert="false">@${testType:newType(org.junit.Test)}
+<template name="test4" description="%Templates.test_junit4" id="org.eclipse.jdt.ui.templates.test_junit4" context="java-members" enabled="true" autoinsert="false">@${testType:newType(org.junit.Test)}
 public void ${testName}() throws Exception {
 	${staticImport:importStatic('org.junit.Assert.*')}${cursor}
 }</template>
 
+<template name="test_jupiter" description="%Templates.test_junit5" id="org.eclipse.jdt.ui.templates.test_junit5" context="java-members" enabled="true" autoinsert="false">@${testType:newType(org.junit.jupiter.api.Test)}
+void ${testName}() throws Exception {
+	${staticImport:importStatic('org.junit.jupiter.api.Assertions.*')}${cursor}
+}</template>
+
+<template name="test_factory" description="%Templates.testfactory_junit5" id="org.eclipse.jdt.ui.templates.testfactory_junit5" context="java-members" enabled="true" autoinsert="false">@${testfactoryType:newType(org.junit.jupiter.api.TestFactory)}
+${returnType:link('Stream&lt;DynamicNode&gt;', 'Collection&lt;DynamicNode&gt;', 'Iterable&lt;DynamicNode&gt;', 'Iterator&lt;DynamicNode&gt;')} ${testFactoryName}() throws Exception {
+	// ${todo}: generate dynamic test cases
+	${cursor}return null;${typeImports:import('org.junit.jupiter.api.DynamicNode')}${staticImports:importStatic('org.junit.jupiter.api.Assertions.*', 'org.junit.jupiter.api.DynamicContainer.*', 'org.junit.jupiter.api.DynamicTest.*')}
+}</template>
+
 <template name="nls" description="%Templates.non-nls" id="org.eclipse.jdt.ui.templates.non-nls" context="java" enabled="true" autoinsert="false">//$$NON-NLS-${N}$$</template>
 
 <template name="fall-through" description="%Templates.fall-through" id="org.eclipse.jdt.ui.templates.fall-through" context="java-statements" enabled="true" autoinsert="false">//$$FALL-THROUGH$$</template>
diff --git a/pom.xml b/pom.xml
index 79778e9..ddea54f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,5 +65,6 @@
     <module>org.eclipse.jdt.junit.core</module>
     <module>org.eclipse.jdt.junit.runtime</module>
     <module>org.eclipse.jdt.junit4.runtime</module>
+    <module>org.eclipse.jdt.junit5.runtime</module>
   </modules>
 </project>