Merge remote-tracking branch 'origin/master' into BETA_JAVA14

Change-Id: I5a984068daa2d0347f0a4aef0d070bb3e9e80514
diff --git a/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/AbstractJDITest.java b/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/AbstractJDITest.java
index d442fed..8667fe0 100644
--- a/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/AbstractJDITest.java
+++ b/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/AbstractJDITest.java
@@ -23,9 +23,6 @@
 import java.util.StringTokenizer;
 import java.util.Vector;
 
-import junit.framework.Test;
-import junit.framework.TestCase;
-
 import org.eclipse.jdi.Bootstrap;
 
 import com.sun.jdi.AbsentInformationException;
@@ -62,6 +59,9 @@
 import com.sun.jdi.request.ModificationWatchpointRequest;
 import com.sun.jdi.request.StepRequest;
 
+import junit.framework.Test;
+import junit.framework.TestCase;
+
 /**
  * Tests for com.sun.jdi.* and JDWP commands.
  * These tests assume that the target program is
@@ -145,8 +145,9 @@
 			if (parameters.length == 0 && name.startsWith(match)) {
 				if (!isExcludedTest(name)) {
 					result.add(name);
-				} else
+				} else {
 					System.out.println(name + " is excluded.");
+				}
 			}
 		}
 		return result;
@@ -359,8 +360,9 @@
 	 */
 	protected ClassType getClass(String name) {
 		List<?> classes = fVM.classesByName(name);
-		if (classes.size() == 0)
+		if (classes.size() == 0) {
 			return null;
+		}
 
 		return (ClassType) classes.get(0);
 	}
@@ -398,8 +400,9 @@
 
 		// Get field
 		Field result = type.fieldByName(fieldName);
-		if (result == null)
+		if (result == null) {
 			throw new Error("Unknown field: " + fieldName);
+		}
 
 		return result;
 	}
@@ -488,8 +491,9 @@
 				break;
 			}
 		}
-		if (method == null)
+		if (method == null) {
 			throw new Error("Unknown method: " + name + signature);
+		}
 
 		return method;
 	}
@@ -562,8 +566,9 @@
 	 */
 	protected ClassType getSystemType() {
 		List<ReferenceType> classes = fVM.classesByName("java.lang.Object");
-		if (classes.size() == 0)
+		if (classes.size() == 0) {
 			return null;
+		}
 
 		return (ClassType) classes.get(0);
 	}
@@ -581,8 +586,9 @@
 
 	private ThreadReference getThread(String fieldName) {
 		ClassType type = getMainClass();
-		if (type == null)
+		if (type == null) {
 			return null;
+		}
 
 		// Get static field "fThread"
 		List<Field> fields = type.fields();
@@ -590,14 +596,16 @@
 		Field field = null;
 		while (iterator.hasNext()) {
 			field = iterator.next();
-			if (field.name().equals(fieldName))
+			if (field.name().equals(fieldName)) {
 				break;
+			}
 		}
 
 		// Get value of "fThread"
 		Value value = type.getValue(field);
-		if (value == null)
+		if (value == null) {
 			return null;
+		}
 
 		return (ThreadReference) value;
 	}
@@ -617,11 +625,14 @@
 	 */
 	private boolean isExcludedTest(String testName) {
 		String[] excludedTests = excludedTests();
-		if (excludedTests == null)
+		if (excludedTests == null) {
 			return false;
-		for (int i = 0; i < excludedTests.length; i++)
-			if (testName.equals(excludedTests[i]))
+		}
+		for (int i = 0; i < excludedTests.length; i++) {
+			if (testName.equals(excludedTests[i])) {
 				return true;
+			}
+		}
 		return false;
 	}
 
@@ -636,8 +647,9 @@
 	protected boolean vmIsRunning() {
 		boolean isRunning = false;
 		try {
-			if (fLaunchedVM != null)
+			if (fLaunchedVM != null) {
 				fLaunchedVM.exitValue();
+			}
 		} catch (IllegalThreadStateException e) {
 			isRunning = true;
 		}
@@ -645,14 +657,15 @@
 	}
 
 	protected void launchTarget() {
-		if (fVmCmd != null)
+		if (fVmCmd != null) {
 			launchCommandLineTarget();
-		else if (fVMLauncherName.equals("SunVMLauncher"))
+		} else if (fVMLauncherName.equals("SunVMLauncher")) {
 			launchSunTarget();
-		else if (fVMLauncherName.equals("IBMVMLauncher"))
+		} else if (fVMLauncherName.equals("IBMVMLauncher")) {
 			launchIBMTarget();
-		else
+		} else {
 			launchJ9Target();
+		}
 	}
 
 	/**
@@ -700,9 +713,9 @@
 			int index = 0;
 			String binDirectory =
 				fTargetAddress
-					+ System.getProperty("file.separator")
+					+ File.separatorChar
 					+ "bin"
-					+ System.getProperty("file.separator");
+					+ File.separatorChar;
 
 			proxyString[index++] = binDirectory + "j9proxy";
 			proxyString[index++] = "localhost:" + (fBackEndPort - 1);
@@ -719,8 +732,9 @@
 			}
 			commandLine.add(launcher);
 
-			if (fBootPath.length() > 0)
+			if (fBootPath.length() > 0) {
 				commandLine.add("-bp:" + fBootPath);
+			}
 			commandLine.add("-cp:" + fClassPath);
 			commandLine.add("-debug:" + (fBackEndPort - 1));
 			injectVMArgs(commandLine);
@@ -745,8 +759,8 @@
 			} else {
 				binDirectory.append(fTargetAddress);
 			}
-			binDirectory.append(System.getProperty("file.separator"));
-			binDirectory.append("bin").append(System.getProperty("file.separator"));
+			binDirectory.append(File.separatorChar);
+			binDirectory.append("bin").append(File.separatorChar);
 
 			Vector<String> commandLine = new Vector<>();
 
@@ -784,9 +798,9 @@
 			// Launch target VM
 			String binDirectory =
 				fTargetAddress
-					+ System.getProperty("file.separator")
+					+ File.separatorChar
 					+ "bin"
-					+ System.getProperty("file.separator");
+					+ File.separatorChar;
 
 			Vector<String> commandLine = new Vector<>();
 
@@ -860,16 +874,18 @@
 			try {
 				VirtualMachineManager manager = Bootstrap.virtualMachineManager();
 				List<AttachingConnector> connectors = manager.attachingConnectors();
-				if (connectors.size() == 0)
+				if (connectors.size() == 0) {
 					break;
+				}
 				AttachingConnector connector = connectors.get(0);
 				Map<String, Argument> args = connector.defaultArguments();
 				args.get("port").setValue(String.valueOf(fBackEndPort));
 				args.get("hostname").setValue("localhost");
 
 				fVM = connector.attach(args);
-				if (fVMTraceFlags != com.sun.jdi.VirtualMachine.TRACE_NONE)
+				if (fVMTraceFlags != com.sun.jdi.VirtualMachine.TRACE_NONE) {
 					fVM.setDebugTraceMode(fVMTraceFlags);
+				}
 				break;
 			} catch (IllegalConnectorArgumentsException e) {
 			} catch (IOException e) {
@@ -893,8 +909,9 @@
 						int read;
 						do {
 							read = in.read();
-							if (read != -1)
+							if (read != -1) {
 								System.out.print((char) read);
+							}
 						} while (read != -1);
 					}
 				} catch (IOException e) {
@@ -1055,8 +1072,9 @@
 	 */
 	protected void runSuite(String[] args) {
 		// Check args
-		if (!parseArgs(args))
+		if (!parseArgs(args)) {
 			return;
+		}
 
 		// Run test
 		System.out.println(new java.util.Date());
@@ -1131,8 +1149,9 @@
 
 		// We want subsequent connections to use different ports, unless a
 		// VM exec sting is given.
-		if (fVmCmd == null)
+		if (fVmCmd == null) {
 			fBackEndPort += 2;
+		}
 	}
 	/**
 	 * Starts the threads that reads from the VM and proxy input and error streams
@@ -1164,8 +1183,9 @@
 		}
 		fConsoleErrorReader.start();
 
-		if (fLaunchedProxy == null)
+		if (fLaunchedProxy == null) {
 			return;
+		}
 
 		if (fProxyoutFile != null) {
 			fProxyReader =
@@ -1199,14 +1219,18 @@
 	 * Stops the console reader.
 	 */
 	private void stopConsoleReaders() {
-		if (fConsoleReader != null)
+		if (fConsoleReader != null) {
 			fConsoleReader.stop();
-		if (fConsoleErrorReader != null)
+		}
+		if (fConsoleErrorReader != null) {
 			fConsoleErrorReader.stop();
-		if (fProxyReader != null)
+		}
+		if (fProxyReader != null) {
 			fProxyReader.stop();
-		if (fProxyErrorReader != null)
+		}
+		if (fProxyErrorReader != null) {
 			fProxyErrorReader.stop();
+		}
 	}
 	/**
 	 * Starts event reader.
@@ -1222,10 +1246,12 @@
 		fEventReader.stop();
 	}
 	protected void killVM() {
-		if (fLaunchedVM != null)
+		if (fLaunchedVM != null) {
 			fLaunchedVM.destroy();
-		if (fLaunchedProxy != null)
+		}
+		if (fLaunchedProxy != null) {
 			fLaunchedProxy.destroy();
+		}
 	}
 	/**
 	 * Starts the target program.
@@ -1328,9 +1354,10 @@
 		String eventType,
 		boolean shouldGo) {
 		Event event = triggerAndWait(request, eventType, shouldGo, TIMEOUT);
-		if (event == null)
+		if (event == null) {
 			throw new Error(
 				"Event for " + request + " didn't come in after " + TIMEOUT + "ms");
+		}
 
 		return event;
 	}
@@ -1346,10 +1373,11 @@
 		boolean shouldGo,
 		long time) {
 		// Suspend only if asked
-		if (shouldGo)
+		if (shouldGo) {
 			request.setSuspendPolicy(EventRequest.SUSPEND_NONE);
-		else
+		} else {
 			request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+		}
 
 		// Enable request
 		request.enable();
@@ -1397,8 +1425,9 @@
 		// Resume the test thread
 		ThreadReference thread = getThread();
 		int suspendCount = thread.suspendCount();
-		for (int i = 0; i < suspendCount; i++)
+		for (int i = 0; i < suspendCount; i++) {
 			thread.resume();
+		}
 	}
 	/**
 	 * Triggers a step event and waits for it to come in.
@@ -1434,14 +1463,16 @@
 
 		// Trigger step event
 		int suspendCount = thread.suspendCount();
-		for (int i = 0; i < suspendCount; i++)
+		for (int i = 0; i < suspendCount; i++) {
 			thread.resume();
+		}
 
 		// Wait for the event to come in
 		StepEvent event = (StepEvent) waitForEvent(waiter, timeout);
 		fEventReader.removeEventListener(waiter);
-		if (event == null)
+		if (event == null) {
 			throw new Error("StepEvent didn't come in after " + timeout + "ms");
+		}
 
 		// Stop getting step events
 		fVM.eventRequestManager().deleteEventRequest(eventRequest);
@@ -1455,8 +1486,9 @@
 	 * Output verbose string if asked for.
 	 */
 	protected void verbose(String verboseString) {
-		if (fVerbose)
+		if (fVerbose) {
 			System.out.println(verboseString);
+		}
 	}
 	/**
 	 * Waits for an event to come in using the given waiter.
@@ -1500,15 +1532,17 @@
 			ExceptionEvent event = (ExceptionEvent) waitForEvent(waiter, TIMEOUT);
 
 			// Throw error if event is null
-			if (event == null)
+			if (event == null) {
 				throw new Error("Target program was not ready after " + TIMEOUT + "ms");
+			}
 
 			// Get the method where the exception was thrown
 			Method meth = event.location().method();
-			if (meth == null || !meth.name().equals("printAndSignal"))
+			if (meth == null || !meth.name().equals("printAndSignal")) {
 				fVM.resume();
-			else
+			} else {
 				break;
+			}
 		}
 
 		// Disable request
diff --git a/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/program/MainClass.java b/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/program/MainClass.java
index fbd0024..93d8c23 100644
--- a/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/program/MainClass.java
+++ b/org.eclipse.jdt.debug.jdi.tests/tests/org/eclipse/debug/jdi/tests/program/MainClass.java
@@ -388,7 +388,7 @@
 		fEventType = "";
 
 		/* Trigger event according to the field fEventType */
-		if (eventType.equals("")) {
+		if (eventType.isEmpty()) {
 			return;
 		} else if(eventType.equals("refclassload")) {
 			new RefClass();
diff --git a/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceConsoleTest.java b/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceConsoleTest.java
index d11b319..924dcda 100644
--- a/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceConsoleTest.java
+++ b/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/JavaStackTraceConsoleTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2019 SAP SE and others.
+ * Copyright (c) 2014, 2020 SAP SE and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -12,10 +12,12 @@
  *     SAP SE - initial API and implementation
  *     Paul Pazderski - Bug 546900: Tests to check initial console content and content persistence
  *     Paul Pazderski - Bug 343023: Tests for 'clear initial content on first edit'
+ *     Paul Pazderski - Bug 304219: Tests for formatting
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests.console;
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotEquals;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -24,6 +26,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
@@ -35,6 +39,7 @@
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.BadPositionCategoryException;
 import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.Position;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.ST;
@@ -57,6 +62,9 @@
  */
 public class JavaStackTraceConsoleTest extends AbstractDebugTest {
 
+	private final static Pattern LEFT_INDENT = Pattern.compile("^[ \\t]*");
+	private final static Pattern RIGHT_INDENT = Pattern.compile("\\s+$");
+
 	private final JavaStackTraceConsoleFactory fConsoleFactory = new JavaStackTraceConsoleFactory();
 	private JavaStackTraceConsole fConsole;
 
@@ -269,6 +277,223 @@
 		});
 	}
 
+	/** Test formatting of a plain simple stack trace. */
+	public void testFormatSimple() {
+		IDocument doc = consoleDocumentFormatted("java.lang.AssertionError: expected:5 but was:7\n\n"
+				+ "at org.junit.Ass\nert.fail(Assert.java:88) \n" + "at\norg.junit.   \nAssert.failNotEquals(Assert.java:834)\n"
+				+ "at org.junit.Assert.assertEquals(Assert.java:118)\n" + "at \norg.junit.Assert.assertEquals\n(Assert.java:144)");
+		assertEquals("java.lang.AssertionError: expected:5 but was:7", getLine(doc, 0));
+		assertEquals("at org.junit.Assert.fail(Assert.java:88)", getLine(doc, 1).trim());
+		assertEquals("at org.junit.Assert.failNotEquals(Assert.java:834)", getLine(doc, 2).trim());
+		assertEquals("at org.junit.Assert.assertEquals(Assert.java:118)", getLine(doc, 3).trim());
+		assertEquals("at org.junit.Assert.assertEquals(Assert.java:144)", getLine(doc, 4).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting of a stack trace including thread name. */
+	public void testFormatThreadName() {
+		IDocument doc = consoleDocumentFormatted("Exception in thread \"ma\nin\" java.lang.NullPointerException\n"
+				+ "at \nStacktrace.main(Stacktrace.java:4)");
+		assertEquals("Exception in thread \"main\" java.lang.NullPointerException", getLine(doc, 0));
+		assertEquals("at Stacktrace.main(Stacktrace.java:4)", getLine(doc, 1).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting with some less common method names. */
+	public void testFormatUncommonMethods() {
+		IDocument doc = consoleDocumentFormatted("Stack Trace\n" + "  at org.eclipse.core.runtime.SafeRunner.run\n(SafeRunner.java:43)\n"
+				+ "      at org.eclipse.ui.internal.JFaceUtil.lambda$0(JFaceUtil.java:47)\n"
+				+ "    at org.eclipse.ui.internal.JFaceUtil$$Lambda$107/0x00000   \n008013c5c40.run(Unknown Source)\n"
+				+ "\tat org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)\n"
+				+ "         at java.base@12/java.lang.reflect.Method.invoke(Method.java:567)\n"
+				+ " \n at app/\n/org.eclipse.equinox.launcher.Main.main(Main.java:1438)");
+		assertEquals("Stack Trace", getLine(doc, 0));
+		assertEquals("at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:43)", getLine(doc, 1).trim());
+		assertEquals("at org.eclipse.ui.internal.JFaceUtil.lambda$0(JFaceUtil.java:47)", getLine(doc, 2).trim());
+		assertEquals("at org.eclipse.ui.internal.JFaceUtil$$Lambda$107/0x00000008013c5c40.run(Unknown Source)", getLine(doc, 3).trim());
+		assertEquals("at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)", getLine(doc, 4).trim());
+		assertEquals("at java.base@12/java.lang.reflect.Method.invoke(Method.java:567)", getLine(doc, 5).trim());
+		assertEquals("at app//org.eclipse.equinox.launcher.Main.main(Main.java:1438)", getLine(doc, 6).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting with a 'locked' entry. */
+	public void testFormatLocked() {
+		IDocument doc = consoleDocumentFormatted("java.lang.Thread.State: RUNNABLE\n"
+				+ " at java.net.PlainSocketImpl.socketAccept(Native Method)\n\n\n"
+				+ "at java.net.PlainSocketImpl\n.accept(PlainSocketImpl.java:408)\n" + "\t - locked <0x911d3c30>   (a java.net.SocksSocketImpl)\n"
+				+ "    at java.net.ServerSocket.implAccept(ServerSocket.java:462)\n" + "at java.net.ServerSocket.accept(ServerSocket.java:430)");
+		assertEquals("java.lang.Thread.State: RUNNABLE", getLine(doc, 0));
+		assertEquals("at java.net.PlainSocketImpl.socketAccept(Native Method)", getLine(doc, 1).trim());
+		assertEquals("at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)", getLine(doc, 2).trim());
+		assertEquals("- locked <0x911d3c30> (a java.net.SocksSocketImpl)", getLine(doc, 3).trim());
+		assertEquals("at java.net.ServerSocket.implAccept(ServerSocket.java:462)", getLine(doc, 4).trim());
+		assertEquals("at java.net.ServerSocket.accept(ServerSocket.java:430)", getLine(doc, 5).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting with a ... more entry. */
+	public void testFormatMore() {
+		// additional this one is missing the 'header' line and starting with an 'at' line
+		IDocument doc = consoleDocumentFormatted(" at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:470)\n"
+				+ "    at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.afterPropertiesSet(DefaultPersistenceUnitManager.java:424)\n"
+				+ "at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:310)\n"
+				+ "          at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)\n\n"
+				+ "  \t\t    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)\n"
+				+ "   \t \tat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)\n"
+				+ "  ... 53 more\n" + "");
+		assertEquals("at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.preparePersistenceUnitInfos(DefaultPersistenceUnitManager.java:470)", getLine(doc, 1).trim());
+		assertEquals("at org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager.afterPropertiesSet(DefaultPersistenceUnitManager.java:424)", getLine(doc, 2).trim());
+		assertEquals("at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:310)", getLine(doc, 3).trim());
+		assertEquals("at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)", getLine(doc, 4).trim());
+		assertEquals("at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)", getLine(doc, 5).trim());
+		assertEquals("at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)", getLine(doc, 6).trim());
+		assertEquals("... 53 more", getLine(doc, 7).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting stack trace with cause. */
+	public void testFormatCause() {
+		IDocument doc = consoleDocumentFormatted("HighLevelException:\n LowLevelException\n" + "\tat Junk.a(Junk.java:13)\n"
+				+ "         at Junk.main(Junk.java:4)\n" + "     Caused by: LowLevelException\n" + " at Junk.e(Junk.java:30)\n"
+				+ "    at Junk.d\n(Junk.java:27)\n" + "at Junk.c(Junk.java:21)");
+		assertEquals("HighLevelException: LowLevelException", getLine(doc, 0));
+		assertEquals("at Junk.a(Junk.java:13)", getLine(doc, 1).trim());
+		assertEquals("at Junk.main(Junk.java:4)", getLine(doc, 2).trim());
+		assertEquals("Caused by: LowLevelException", getLine(doc, 3));
+		assertEquals("at Junk.e(Junk.java:30)", getLine(doc, 4).trim());
+		assertEquals("at Junk.d(Junk.java:27)", getLine(doc, 5).trim());
+		assertEquals("at Junk.c(Junk.java:21)", getLine(doc, 6).trim());
+		checkIndentationConsistency(doc, 0);
+
+		// nested causes
+		doc = consoleDocumentFormatted("HighLevelException:\t MidLevelException:\n LowLevelException\n" + "\tat Junk.a(Junk.java:13)\n"
+				+ "    at Junk.main(Junk.java:4)\n" + " Caused by: MidLevelException: LowLevelException\n" + "    at Junk.c(Junk.java:23)\n"
+				+ "      at Junk.b(Junk.java:17)\n" + "      at Junk.a(Junk.java:11)\n" + "... 1 more\n" + " Caused by: LowLevelException\n"
+				+ "     at Junk.e(Junk.java:30)\n" + "at Junk.d(Junk.java:27)\n" + "   at Junk.c(Junk.java:21)\n" + "         ... 3 more\n");
+		assertEquals("HighLevelException: MidLevelException: LowLevelException", getLine(doc, 0));
+		assertEquals("at Junk.a(Junk.java:13)", getLine(doc, 1).trim());
+		assertEquals("at Junk.main(Junk.java:4)", getLine(doc, 2).trim());
+		assertEquals("Caused by: MidLevelException: LowLevelException", getLine(doc, 3));
+		assertEquals("at Junk.c(Junk.java:23)", getLine(doc, 4).trim());
+		assertEquals("at Junk.b(Junk.java:17)", getLine(doc, 5).trim());
+		assertEquals("at Junk.a(Junk.java:11)", getLine(doc, 6).trim());
+		assertEquals("... 1 more", getLine(doc, 7).trim());
+		assertEquals("Caused by: LowLevelException", getLine(doc, 8));
+		assertEquals("at Junk.e(Junk.java:30)", getLine(doc, 9).trim());
+		assertEquals("at Junk.d(Junk.java:27)", getLine(doc, 10).trim());
+		assertEquals("at Junk.c(Junk.java:21)", getLine(doc, 11).trim());
+		assertEquals("... 3 more", getLine(doc, 12).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting stack trace with suppressed exceptions. */
+	public void testFormatSuppressed() {
+		IDocument doc = consoleDocumentFormatted("Exception in thread \"main\" java.lang.Exception: Something happened\n" + "at Foo.bar(Native)\n"
+				+ "  at Foo.main(Foo.java:5)\n" + "  Suppressed: Resource$CloseFailException: Resource ID = 0\n"
+				+ "    at Resource.close(Resource\n.java:26)\n" + "      at Foo.bar(Foo.java)\n" + "         ... 1 more\n" + "");
+		assertEquals("Exception in thread \"main\" java.lang.Exception: Something happened", getLine(doc, 0));
+		assertEquals("at Foo.bar(Native)", getLine(doc, 1).trim());
+		assertEquals("at Foo.main(Foo.java:5)", getLine(doc, 2).trim());
+		assertEquals("Suppressed: Resource$CloseFailException: Resource ID = 0", getLine(doc, 3).trim());
+		assertEquals("at Resource.close(Resource.java:26)", getLine(doc, 4).trim());
+		assertEquals("at Foo.bar(Foo.java)", getLine(doc, 5).trim());
+		assertEquals("... 1 more", getLine(doc, 6).trim());
+		checkIndentationConsistency(doc, 0);
+
+		// multiple suppressed
+		doc = consoleDocumentFormatted("Exception in thread \"main\" java.lang.Exception: Main block\n" + "  at Foo3.main(Foo3.java:7)\n"
+				+ "     Suppressed: Resource$CloseFailException: Resource ID = 2\n" + "      at Resource.close(Resource.java:26)\n"
+				+ "   \t\tat Foo3.main(Foo3.java:5)\n" + "Suppressed: Resource$CloseFailException: Resource ID = 1\n"
+				+ "      at Resource.close(Resource.java:26)\n" + "                at Foo3.main(Foo3.java:5)\n" + "");
+		assertEquals("Exception in thread \"main\" java.lang.Exception: Main block", getLine(doc, 0));
+		assertEquals("at Foo3.main(Foo3.java:7)", getLine(doc, 1).trim());
+		assertEquals("Suppressed: Resource$CloseFailException: Resource ID = 2", getLine(doc, 2).trim());
+		assertEquals("at Resource.close(Resource.java:26)", getLine(doc, 3).trim());
+		assertEquals("at Foo3.main(Foo3.java:5)", getLine(doc, 4).trim());
+		assertEquals("Suppressed: Resource$CloseFailException: Resource ID = 1", getLine(doc, 5).trim());
+		assertEquals("at Resource.close(Resource.java:26)", getLine(doc, 6).trim());
+		assertEquals("at Foo3.main(Foo3.java:5)", getLine(doc, 7).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting stack trace with mixture of cause and suppressed. */
+	public void testFormatSuppressedWithCause() {
+		// exception with suppressed and cause
+		IDocument doc = consoleDocumentFormatted("Exception in thread \"main\" java.lang.Exception: Main block\n" + "  at Foo3.main(Foo3.java:7)\n"
+				+ "  Suppressed: Resource$CloseFailException: Resource ID = 1\n" + "          at Resource.close(Resource.java:26)\n"
+				+ "          at Foo3.main(Foo3.java:5)\n" + "Caused by: java.lang.Exception: I did it\n" + "  at Foo3.main(Foo3.java:8)\n");
+		assertEquals("Exception in thread \"main\" java.lang.Exception: Main block", getLine(doc, 0));
+		assertEquals("at Foo3.main(Foo3.java:7)", getLine(doc, 1).trim());
+		assertEquals("Suppressed: Resource$CloseFailException: Resource ID = 1", getLine(doc, 2).trim());
+		assertEquals("at Resource.close(Resource.java:26)", getLine(doc, 3).trim());
+		assertEquals("at Foo3.main(Foo3.java:5)", getLine(doc, 4).trim());
+		assertEquals("Caused by: java.lang.Exception: I did it", getLine(doc, 5).trim());
+		assertEquals("at Foo3.main(Foo3.java:8)", getLine(doc, 6).trim());
+		checkIndentationConsistency(doc, 0);
+		// Additional indentation check. Since cause is linked to primary exception it must be less indented as suppressed stuff.
+		assertEquals(getLineIndentation(getLine(doc, 0)), getLineIndentation(getLine(doc, 5)));
+		assertEquals(getLineIndentation(getLine(doc, 1)), getLineIndentation(getLine(doc, 6)));
+		assertTrue(getLineIndentation(getLine(doc, 3)) > getLineIndentation(getLine(doc, 5)));
+		assertTrue(getLineIndentation(getLine(doc, 3)) > getLineIndentation(getLine(doc, 6)));
+
+		// exception with suppressed and cause for the suppressed
+		doc = consoleDocumentFormatted("Exception in thread \"main\" java.lang.Exception: Main block\n" + "  at Foo4.main(Foo4.java:6)\n"
+				+ "  Suppressed: Resource2$CloseFailException: Resource ID = 1\n" + "          at Resource2.close(Resource2.java:20)\n"
+				+ "          at Foo4.main(Foo4.java:5)\n" + "  Caused by: java.lang.Exception: Rats, you caught me\n"
+				+ "          at Resource2$CloseFailException.<init>(Resource2.java:45)\n" + "          ... 2 more\n");
+		assertEquals("Exception in thread \"main\" java.lang.Exception: Main block", getLine(doc, 0));
+		assertEquals("at Foo4.main(Foo4.java:6)", getLine(doc, 1).trim());
+		assertEquals("Suppressed: Resource2$CloseFailException: Resource ID = 1", getLine(doc, 2).trim());
+		assertEquals("at Resource2.close(Resource2.java:20)", getLine(doc, 3).trim());
+		assertEquals("at Foo4.main(Foo4.java:5)", getLine(doc, 4).trim());
+		assertEquals("Caused by: java.lang.Exception: Rats, you caught me", getLine(doc, 5).trim());
+		assertEquals("at Resource2$CloseFailException.<init>(Resource2.java:45)", getLine(doc, 6).trim());
+		assertEquals("... 2 more", getLine(doc, 7).trim());
+		checkIndentationConsistency(doc, 0);
+		// Additional indentation check. Since cause is linked to suppressed exception it must be greater indented as primary exception stuff.
+		assertNotEquals(getLineIndentation(getLine(doc, 0)), getLineIndentation(getLine(doc, 5)));
+		assertEquals(getLineIndentation(getLine(doc, 2)), getLineIndentation(getLine(doc, 5)));
+		assertNotEquals(getLineIndentation(getLine(doc, 1)), getLineIndentation(getLine(doc, 6)));
+		assertEquals(getLineIndentation(getLine(doc, 3)), getLineIndentation(getLine(doc, 6)));
+		assertEquals(getLineIndentation(getLine(doc, 4)), getLineIndentation(getLine(doc, 7)));
+		assertTrue(getLineIndentation(getLine(doc, 5)) > getLineIndentation(getLine(doc, 0)));
+		assertTrue(getLineIndentation(getLine(doc, 6)) > getLineIndentation(getLine(doc, 1)));
+	}
+
+	/** Test formatting the rare [CIRCULAR REFERENCE:...] entry. */
+	public void testFormatCircular() {
+		IDocument doc = consoleDocumentFormatted("Exception in thread \"main\" Stacktrace$BadException\n"
+				+ "at Stacktrace.main\n(Stacktrace.java:4)\n" + " Caused by: Stacktrace$BadExceptionCompanion: Stacktrace$BadException\n"
+				+ "   at Stacktrace$BadException.<init>(Stacktrace.java:10)\n" + "    ... 1 more\n"
+				+ "  [CIRCULAR REFERENCE:Stacktrace$BadException]");
+		assertEquals("Exception in thread \"main\" Stacktrace$BadException", getLine(doc, 0));
+		assertEquals("at Stacktrace.main(Stacktrace.java:4)", getLine(doc, 1).trim());
+		assertEquals("Caused by: Stacktrace$BadExceptionCompanion: Stacktrace$BadException", getLine(doc, 2));
+		assertEquals("at Stacktrace$BadException.<init>(Stacktrace.java:10)", getLine(doc, 3).trim());
+		assertEquals("... 1 more", getLine(doc, 4).trim());
+		assertEquals("[CIRCULAR REFERENCE:Stacktrace$BadException]", getLine(doc, 5).trim());
+		checkIndentationConsistency(doc, 0);
+	}
+
+	/** Test formatting stack trace from an ant execution. (output mixed with ant prefixes) */
+	public void testFormatAnt() {
+		IDocument doc = consoleDocumentFormatted("[java] !ENTRY org.eclipse.debug.core 4 120 2005-01-11 03:02:30.321\n"
+				+ "     [java] !MESSAGE An exception occurred while dispatching debug events.\n" + "     [java] !STACK 0\n"
+				+ "     [java] java.lang.NullPointerException\n" + "     [java] 	at \n"
+				+ "org.eclipse.debug.internal.ui.views.console.ProcessConsole.closeStreams\n" + "(ProcessConsole.java:364)\n" + "     [java] 	at \n"
+				+ "org.eclipse.debug.internal.ui.views.console.ProcessConsole.handleDebugEvents\n" + "(ProcessConsole.java:438)\n"
+				+ "     [java] 	at org.eclipse.debug.core.DebugPlugin$EventNotifier.run\n" + "(DebugPlugin.java:1043)");
+		assertEquals("[java] !ENTRY org.eclipse.debug.core 4 120 2005-01-11 03:02:30.321", getLine(doc, 0));
+		assertEquals("[java] !MESSAGE An exception occurred while dispatching debug events.", getLine(doc, 1));
+		assertEquals("[java] !STACK 0", getLine(doc, 2));
+		assertEquals("[java] java.lang.NullPointerException", getLine(doc, 3));
+		assertEquals("at org.eclipse.debug.internal.ui.views.console.ProcessConsole.closeStreams(ProcessConsole.java:364)", getLine(doc, 4).replace("[java]", "").trim());
+		assertEquals("at org.eclipse.debug.internal.ui.views.console.ProcessConsole.handleDebugEvents(ProcessConsole.java:438)", getLine(doc, 5).replace("[java]", "").trim());
+		assertEquals("at org.eclipse.debug.core.DebugPlugin$EventNotifier.run(DebugPlugin.java:1043)", getLine(doc, 6).replace("[java]", "").trim());
+		checkIndentationConsistency(doc, 3);
+	}
+
 	private IDocument consoleDocumentWithText(String text) throws InterruptedException {
 		IDocument document = fConsole.getDocument();
 		document.set(text);
@@ -277,6 +502,90 @@
 		return document;
 	}
 
+	private String getLine(IDocument doc, int line) {
+		IRegion lineInfo;
+		try {
+			lineInfo = doc.getLineInformation(line);
+			return doc.get(lineInfo.getOffset(), lineInfo.getLength());
+		} catch (BadLocationException ex) {
+			return null;
+		}
+	}
+
+	/**
+	 * Do some tests on the stack trace indentation. No hardcoded valued just some general assumptions.
+	 *
+	 * @param doc
+	 *            document to test
+	 * @param startLine
+	 *            first line to check
+	 */
+	private void checkIndentationConsistency(IDocument doc, int startLine) {
+		boolean firstSuppress = true;
+		int lastIndent = -1;
+		// Remember how the next line's indentation can differ from the previous.
+		// -1 -> less indented
+		// 0 -> equal
+		// 1 -> more indented
+		int allowedIndentChange = 1;
+		for (int i = startLine, lineCount = doc.getNumberOfLines(); i < lineCount; i++) {
+			String line = getLine(doc, i);
+			line = line.replaceFirst("^\\[[^\\s\\]]+\\] ", ""); // remove and prefix if any
+			if (i != 0) { // first line can be empty
+				assertNotEquals("Empty line " + i, "", line);
+			}
+			assertFalse("Trailing whitespace in line " + i, RIGHT_INDENT.matcher(line).find());
+
+			boolean causedBy = line.trim().startsWith("Caused by: ");
+			boolean suppressed = line.trim().startsWith("Suppressed: ");
+			if (causedBy || (suppressed && !firstSuppress)) {
+				allowedIndentChange = -1;
+			}
+
+			int lineIndent = getLineIndentation(line);
+			if (allowedIndentChange < 0) {
+				assertTrue("Wrong indented line " + i + ": " + lastIndent + " > " + lineIndent, lastIndent > lineIndent);
+			} else if (allowedIndentChange == 0) {
+				assertEquals("Mixed indentation in line " + i, lastIndent, lineIndent);
+			} else if (allowedIndentChange > 0) {
+				assertTrue("Wrong indented line " + i + ": " + lastIndent + " < " + lineIndent, lastIndent < lineIndent);
+			}
+			lastIndent = lineIndent;
+			allowedIndentChange = 0;
+			if (causedBy || suppressed || i == startLine) {
+				allowedIndentChange = 1;
+			}
+			firstSuppress &= !suppressed;
+		}
+	}
+
+	private int getLineIndentation(String line) {
+		int tabSize = 4;
+		String indent = "";
+		Matcher m = LEFT_INDENT.matcher(line);
+		if (m.find()) {
+			indent = m.group();
+		}
+		int tabCount = indent.length() - indent.replace("\t", "").length();
+		return indent.length() + (tabSize - 1) * tabCount;
+	}
+
+	/**
+	 * Set given text, invoke formatting and wait until finished.
+	 *
+	 * @param text
+	 *            new console text
+	 * @return the consoles document
+	 */
+	private IDocument consoleDocumentFormatted(String text) {
+		IDocument document = fConsole.getDocument();
+		document.set(text);
+		fConsole.format();
+		// wait for document being formatted
+		TestUtil.waitForJobs(getName(), 30, 1000);
+		return document;
+	}
+
 	private String[] linkTextsAtPositions(int... offsets) throws BadLocationException {
 		IDocument document = fConsole.getDocument();
 
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java
index bbf67e4..a871df8 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java
@@ -207,7 +207,7 @@
 						return !var.isFinal() & !(var.isFinal() & var.isStatic());
 					}
 				}
-				else if (name.equals("DetailFormatterFilter") & (varValue instanceof IJavaObject)) { //$NON-NLS-1$
+				else if (name.equals("DetailFormatterFilter") && (varValue instanceof IJavaObject)) { //$NON-NLS-1$
 					if(value.equals("isDefined")) { //$NON-NLS-1$
 						return JavaDetailFormattersManager.getDefault().hasAssociatedDetailFormatter(((IJavaObject)varValue).getJavaType());
 					}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditDetailFormatterAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditDetailFormatterAction.java
index d172450..6b4c8ae 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditDetailFormatterAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditDetailFormatterAction.java
@@ -54,7 +54,7 @@
 			}
 			JavaDetailFormattersManager fm = JavaDetailFormattersManager.getDefault();
 			DetailFormatter formatter = fm.getAssociatedDetailFormatter(type);
-			if(formatter == null & type instanceof IJavaClassType) {
+			if(formatter == null && type instanceof IJavaClassType) {
 				formatter = fm.getDetailFormatterFromInterface((IJavaClassType) type);
 				if(formatter == null) {
 					formatter = fm.getDetailFormatterFromSuperclass((IJavaClassType) type);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenFromClipboardAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenFromClipboardAction.java
index 320d0e2..fd7189f 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenFromClipboardAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenFromClipboardAction.java
@@ -248,7 +248,7 @@
 	}
 
 	private static boolean isSingleLineInput(String inputText) {
-		String lineDelimiter = System.getProperty("line.separator"); //$NON-NLS-1$
+		String lineDelimiter = System.lineSeparator();
 		String s = inputText.trim();
 		return s.indexOf(lineDelimiter) == -1;
 	}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/breakpoints/StandardJavaBreakpointEditor.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/breakpoints/StandardJavaBreakpointEditor.java
index 049544d..bf68392 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/breakpoints/StandardJavaBreakpointEditor.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/breakpoints/StandardJavaBreakpointEditor.java
@@ -198,7 +198,7 @@
 			suspendThread= breakpoint.getSuspendPolicy() == IJavaBreakpoint.SUSPEND_THREAD;
 		}
 		fHitCountButton.setEnabled(enabled);
-		fHitCountButton.setSelection(enabled & hasHitCount);
+		fHitCountButton.setSelection(enabled && hasHitCount);
 		fHitCountText.setEnabled(hasHitCount);
 		fHitCountText.setText(text);
 		fSuspendThread.setEnabled(enabled);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceConsole.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceConsole.java
index 6ab52b4..5b80944 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceConsole.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaStackTraceConsole.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Paul Pazderski - Bug 546900: Fix IO handling in JavaStacktraceConsole
  *     Paul Pazderski - Bug 343023: Clear the initial stack trace console message on first edit
+ *     Paul Pazderski - Bug 304219: Recognize more typical stack trace keywords for formatting
  *******************************************************************************/
 package org.eclipse.jdt.internal.debug.ui.console;
 
@@ -21,6 +22,8 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.StringTokenizer;
 
 import org.eclipse.core.runtime.IProgressMonitor;
@@ -80,6 +83,10 @@
     public final static String CONSOLE_TYPE = "javaStackTraceConsole"; //$NON-NLS-1$
     public final static String FILE_NAME = JDIDebugUIPlugin.getDefault().getStateLocation().toOSString() + File.separator + "stackTraceConsole.txt"; //$NON-NLS-1$
 
+	private static final String NL = "\n"; //$NON-NLS-1$
+	private static final String INDENT_STR = "    "; //$NON-NLS-1$
+	private static final int INDENT_WIDTH = 4;
+
     private JavaStackTraceConsolePartitioner partitioner = new JavaStackTraceConsolePartitioner();
     private IPropertyChangeListener propertyListener = new IPropertyChangeListener() {
         @Override
@@ -234,98 +241,136 @@
 
     }
 
-    /**
-     * Underlying format operation
-     * @param trace the stack trace to format
-     * @return the formatted stack trace for this console
-     */
-    private String format(String trace) {
-        StringTokenizer tokenizer = new StringTokenizer(trace, " \t\n\r\f", true); //$NON-NLS-1$
-        StringBuilder formattedTrace = new StringBuilder();
+	/**
+	 * Underlying format operation
+	 *
+	 * @param trace
+	 *            the stack trace to format
+	 * @return the formatted stack trace for this console
+	 */
+	private String format(String trace) {
+		StringTokenizer tokenizer = new StringTokenizer(trace, " \t\n\r\f", true); //$NON-NLS-1$
+		StringBuilder formattedTrace = new StringBuilder(trace.length());
 
-        boolean insideAt = false;
-        boolean newLine = true;
-        int pendingSpaces = 0;
-        boolean antTrace = false;
+		boolean insideAt = false;
+		boolean newLine = true;
+		int pendingSpaces = 0;
+		boolean antTrace = false;
+		int depth = 1;
+		// Block depth map is used to find the most likely indentation for a Caused.
+		// In combination with Suppressed the correct indentation can be ambiguous.
+		// Map has indentation in number of spaces of a previous block as key and formated
+		// indentation depth used for this block as value.
+		Map<Integer, Integer> blockDepth = new HashMap<>(3);
 
-        while (tokenizer.hasMoreTokens()) {
-            String token = tokenizer.nextToken();
-            if (token.length() == 0)
-			 {
+		while (tokenizer.hasMoreTokens()) {
+			String token = tokenizer.nextToken();
+			if (token.isEmpty()) {
 				continue; // paranoid
 			}
-            char c = token.charAt(0);
-            // handle delimiters
-            switch (c) {
-            case ' ':
-                if (newLine) {
-                    pendingSpaces++;
-                } else {
-                    pendingSpaces = 1;
-                }
-                continue;
-            case '\t':
-                if (newLine) {
-                    pendingSpaces += 4;
-                } else {
-                    pendingSpaces = 1;
-                }
-                continue;
-            case '\n':
-            case '\r':
-            case '\f':
-                if (insideAt) {
-                    pendingSpaces = 1;
-                } else {
-                    pendingSpaces = 0;
-                    newLine = true;
-                }
-                continue;
-            }
-            // consider newlines only before token starting with char '\"' or
-            // token "at" or "-".
-            if (newLine || antTrace) {
-                if (c == '\"') { // leading thread name, e.g. "Worker-124"
-                                    // prio=5
-                    formattedTrace.append("\n\n"); //$NON-NLS-1$  print 2 lines to break between threads
-                } else if ("-".equals(token)) { //$NON-NLS-1$ - locked ...
-                    formattedTrace.append("\n"); //$NON-NLS-1$
-                    formattedTrace.append("    "); //$NON-NLS-1$
-                    formattedTrace.append(token);
-                    pendingSpaces = 0;
-                    continue;
-                } else if ("at".equals(token)) { //$NON-NLS-1$  at ...
-                    if (!antTrace) {
-                        formattedTrace.append("\n"); //$NON-NLS-1$
-                        formattedTrace.append("    "); //$NON-NLS-1$
-                    } else {
-                        formattedTrace.append(' ');
-                    }
-                    insideAt = true;
-                    formattedTrace.append(token);
-                    pendingSpaces = 0;
-                    continue;
-                } else if (c == '[') {
-                    if(antTrace) {
-                        formattedTrace.append("\n"); //$NON-NLS-1$
-                    }
-                    formattedTrace.append(token);
-                    pendingSpaces = 0;
-                    newLine = false;
-                    antTrace = true;
-                    continue;
-                }
-                newLine = false;
-            }
-            if (pendingSpaces > 0) {
-                for (int i = 0; i < pendingSpaces; i++) {
-                    formattedTrace.append(' ');
-                }
-                pendingSpaces = 0;
-            }
-            formattedTrace.append(token);
-            insideAt = false;
-        }
-        return formattedTrace.toString();
-    }
+			char c = token.charAt(0);
+			// handle delimiters
+			switch (c) {
+				case ' ':
+					if (newLine) {
+						pendingSpaces++;
+					} else {
+						pendingSpaces = 1;
+					}
+					continue;
+				case '\t':
+					if (newLine) {
+						pendingSpaces += INDENT_WIDTH;
+					} else {
+						pendingSpaces = 1;
+					}
+					continue;
+				case '\n':
+				case '\r':
+				case '\f':
+					if (insideAt) {
+						pendingSpaces = 1;
+					} else {
+						pendingSpaces = 0;
+						newLine = true;
+					}
+					continue;
+			}
+			// consider newlines only before token starting with char '\"' or
+			// token "at", "-", "...", "Caused by:", "Suppressed:" and "[CIRCULAR".
+			if (newLine) {
+				if (c == '\"') { // leading thread name, e.g. "Worker-124" prio=5
+					formattedTrace.append(NL + NL); // print 2 lines to break between threads
+				} else if (c == '-' // - locked <address>
+						|| "...".equals(token)) { //$NON-NLS-1$ ... xx more
+					applyIndentedToken(formattedTrace, depth, token, antTrace);
+					pendingSpaces = 0;
+					continue;
+				} else if ("at".equals(token)) { //$NON-NLS-1$ at method
+					insideAt = true;
+					applyIndentedToken(formattedTrace, depth, token, antTrace);
+					pendingSpaces = 0;
+					continue;
+				} else if (c == '[') {
+					if ("[CIRCULAR".equals(token)) { //$NON-NLS-1$ [CIRCULAR REFERENCE:toString()]
+						applyIndentedToken(formattedTrace, depth, token, antTrace);
+						pendingSpaces = 0;
+					} else {
+						if (antTrace) {
+							formattedTrace.append(NL);
+						}
+						formattedTrace.append(token);
+						pendingSpaces = 0;
+						antTrace = true;
+					}
+					continue;
+				} else if ("Caused".equals(token)) { //$NON-NLS-1$ Caused by: reason
+					// Guess depth for Cause block. This can be interpreted as if the Caused
+					// block is moved to the left until it aligns with a previous Suppressed
+					// block or hit the line begin.
+					depth = 0;
+					for (Map.Entry<Integer, Integer> block : blockDepth.entrySet()) {
+						if (block.getKey() <= pendingSpaces && block.getValue() > depth) {
+							depth = block.getValue();
+						}
+					}
+					applyIndentedToken(formattedTrace, depth, token, antTrace);
+					depth++;
+					pendingSpaces = 0;
+					continue;
+				} else if ("Suppressed:".equals(token)) { //$NON-NLS-1$ Suppressed: reason
+					if (depth >= 2) {
+						depth--;
+					}
+					blockDepth.put(pendingSpaces, depth);
+					applyIndentedToken(formattedTrace, depth, token, antTrace);
+					depth = 2;
+					pendingSpaces = 0;
+					continue;
+				}
+				newLine = false;
+			}
+			if (pendingSpaces > 0) {
+				for (int i = 0; i < pendingSpaces; i++) {
+					formattedTrace.append(' ');
+				}
+				pendingSpaces = 0;
+			}
+			formattedTrace.append(token);
+			insideAt = false;
+		}
+		return formattedTrace.toString();
+	}
+
+	private void applyIndentedToken(StringBuilder formattedTrace, int depth, String token, boolean antTrace) {
+		if (antTrace) {
+			formattedTrace.append(' ');
+		} else {
+			formattedTrace.append(NL);
+		}
+		for (int i = 0; i < depth; i++) {
+			formattedTrace.append(INDENT_STR);
+		}
+		formattedTrace.append(token);
+	}
 }
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DataDisplay.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DataDisplay.java
index b65c669..af1a3a3 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DataDisplay.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DataDisplay.java
@@ -60,7 +60,7 @@
 		try {
 			// add a cariage return if needed.
 			if (offset != document.getLineInformationOfOffset(offset).getOffset()) {
-				expression= System.getProperty("line.separator") + expression.trim(); //$NON-NLS-1$
+				expression= System.lineSeparator() + expression.trim();
 			}
 			document.replace(offset, 0, expression);
 			fTextViewer.setSelectedRange(offset + expression.length(), 0);
@@ -75,7 +75,7 @@
 	 */
 	@Override
 	public void displayExpressionValue(String value) {
-		value= System.getProperty("line.separator") + '\t' + value; //$NON-NLS-1$
+		value= System.lineSeparator() + '\t' + value;
 		ITextSelection selection= (ITextSelection)fTextViewer.getSelectionProvider().getSelection();
 
 		int offset= selection.getOffset() + selection.getLength();
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DisplayView.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DisplayView.java
index 140ffa2..112c84e 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DisplayView.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/display/DisplayView.java
@@ -126,7 +126,7 @@
 			try {
 				// add a cariage return if needed.
 				if (offset != document.getLineInformationOfOffset(offset).getOffset()) {
-					expression= System.getProperty("line.separator") + expression.trim(); //$NON-NLS-1$
+					expression= System.lineSeparator() + expression.trim();
 				}
 				fSourceViewer.getDocument().replace(offset, 0, expression);
 				fSourceViewer.setSelectedRange(offset + expression.length(), 0);
@@ -141,7 +141,7 @@
 		 */
 		@Override
 		public void displayExpressionValue(String value) {
-			value= System.getProperty("line.separator") + '\t' + value; //$NON-NLS-1$
+			value= System.lineSeparator() + '\t' + value;
 			ITextSelection selection= (ITextSelection)fSourceViewer.getSelection();
 
 			int offset= selection.getOffset() + selection.getLength();
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java
index 5fd7379..3102884 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java
@@ -26,12 +26,14 @@
 import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IThread;
 import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
 import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
 import org.eclipse.debug.internal.ui.viewers.update.DebugEventHandler;
 import org.eclipse.debug.internal.ui.viewers.update.DebugTargetEventHandler;
 import org.eclipse.debug.internal.ui.viewers.update.DebugTargetProxy;
 import org.eclipse.debug.internal.ui.viewers.update.StackFrameEventHandler;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.ui.JavaDebugUtils;
 import org.eclipse.jdt.internal.debug.ui.monitors.JavaElementContentProvider;
 import org.eclipse.jdt.internal.debug.ui.snippeteditor.ScrapbookLauncher;
@@ -125,6 +127,8 @@
                     return;
                 }
             }
+			// Bug 559579: ensure the JavaThreadEventHandler has all suspended threads in case the Debug view is opened post launch
+			addSuspendedThreadsToThreadHandler(delta);
             // expand the target if no suspended thread
             fireModelChanged(delta);
         }
@@ -159,4 +163,21 @@
 		}
 		return stackFrameIndex;
 	}
+
+	private void addSuspendedThreadsToThreadHandler(ModelDelta delta) {
+		delta.accept(new IModelDeltaVisitor() {
+			@Override
+			public boolean visit(IModelDelta delta, int depth) {
+				Object element = delta.getElement();
+				if (element instanceof IJavaThread) {
+					IJavaThread thread = (IJavaThread) element;
+					boolean suspended = thread.isSuspended();
+					if (suspended) {
+						fThreadEventHandler.addSuspendedThread(thread);
+					}
+				}
+				return true;
+			}
+		});
+	}
 }
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java
index d54dbac..aea73c1 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java
@@ -305,6 +305,10 @@
 		}
 	}
 
+	void addSuspendedThread(IJavaThread thread) {
+		queueSuspendedThread(thread);
+	}
+
 	/**
 	 * Do not update for quiet resume/suspend
 	 */
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java
index b0ea3ed..77ac963 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/ReferenceTypeImpl.java
@@ -18,6 +18,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -1715,9 +1716,7 @@
 		if (lastDotOffset == -1) {
 			return sourceName;
 		}
-		char fileSeparator = System.getProperty("file.separator").charAt(0); //$NON-NLS-1$
-		return name.substring(0, lastDotOffset).replace('.', fileSeparator)
-				+ fileSeparator + sourceName;
+		return name.substring(0, lastDotOffset).replace('.', File.separatorChar) + File.separatorChar + sourceName;
 	}
 
 	/**
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java
index 131e292..ea9c3cb 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/SocketLaunchingConnectorImpl.java
@@ -15,6 +15,7 @@
  *******************************************************************************/
 package org.eclipse.jdi.internal.connect;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.net.ServerSocket;
@@ -184,16 +185,16 @@
 		String address = listenConnector.startListening(args);
 
 		// String for Executable.
-		String slash = System.getProperty("file.separator"); //$NON-NLS-1$
-		String execString = fHome + slash + "bin" + slash + fLauncher; //$NON-NLS-1$
+		String execString = fHome + File.separatorChar + "bin" + File.separatorChar + fLauncher; //$NON-NLS-1$
 
 		// Add Debug options.
 		execString += " -Xdebug -Xnoagent -Djava.compiler=NONE"; //$NON-NLS-1$
 		execString += " -Xrunjdwp:transport=dt_socket,address=" + address + ",server=n,suspend=" + (fSuspend ? "y" : "n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 
 		// Add User specified options.
-		if (fOptions != null)
+		if (fOptions != null) {
 			execString += " " + fOptions; //$NON-NLS-1$
+		}
 
 		// Add Main class.
 		execString += " " + fMain; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java
index d731972..826c087 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaWatchpoint.java
@@ -387,7 +387,7 @@
 		boolean[] def = getDefaultAccessAndModificationValues();
 		Object[] values = new Object[def.length];
 		for (int i = 0; i < def.length; i++) {
-			values[i] = new Boolean(def[i]);
+			values[i] = Boolean.valueOf(def[i]);
 		}
 		String[] attributes = new String[] { ACCESS, MODIFICATION };
 		setAttributes(attributes, values);
diff --git a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXDebugVMRunner.java b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXDebugVMRunner.java
index b36c0e3..edc0ebd 100644
--- a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXDebugVMRunner.java
+++ b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXDebugVMRunner.java
@@ -7,7 +7,7 @@
  *  https://www.eclipse.org/legal/epl-2.0/
  *
  *  SPDX-License-Identifier: EPL-2.0
- * 
+ *
  *  Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -20,7 +20,7 @@
  * Special override for MacOSX wrapping
  */
 public class MacOSXDebugVMRunner extends StandardVMDebugger {
-	
+
 	/**
 	 * Constructor
 	 * @param vmInstance
diff --git a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXLaunchingPlugin.java b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXLaunchingPlugin.java
index 34fd96a..3295b06 100644
--- a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXLaunchingPlugin.java
+++ b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXLaunchingPlugin.java
@@ -26,11 +26,11 @@
 		Assert.isTrue(fgPlugin == null);
 		fgPlugin= this;
 	}
-	
+
 	public static MacOSXLaunchingPlugin getDefault() {
 		return fgPlugin;
 	}
-	
+
 	/*
 	 * Convenience method which returns the unique identifier of this plug-in.
 	 */
diff --git a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstall.java b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstall.java
index 912df6a..fb51681 100644
--- a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstall.java
+++ b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstall.java
@@ -35,11 +35,11 @@
 		if (ILaunchManager.RUN_MODE.equals(mode)) {
 			return new MacOSXVMRunner(this);
 		}
-		
+
 		if (ILaunchManager.DEBUG_MODE.equals(mode)) {
 			return new MacOSXDebugVMRunner(this);
 		}
-		
+
 		return null;
 	}
 
diff --git a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstallType.java b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstallType.java
index 4a6c227..8ead971 100644
--- a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstallType.java
+++ b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMInstallType.java
@@ -37,9 +37,9 @@
 
 /**
  * This class provides the implementation of the {@link IVMInstallType} for Mac OSX.
- * 
- * The default VM locations are outlined below. each VM except for developer VMs provide links in the 
- * <code>/System/Library/Frameworks/JavaVM.framework/Versions/</code> folder, with a link named 
+ *
+ * The default VM locations are outlined below. each VM except for developer VMs provide links in the
+ * <code>/System/Library/Frameworks/JavaVM.framework/Versions/</code> folder, with a link named
  * <code>CurrentJDK</code> that points to the VM you have set using the Java preference tool in the system preferences.
  * <br><br>
  * The directory structure for Java VMs prior to Snow Leopard is as follows:
@@ -52,7 +52,7 @@
  *     Home/
  *       src.jar
  * </pre>
- * 
+ *
  * The directory structure for developer VMs is:
  * <pre>
  * /Library/Java/JavaVirtualMachines/
@@ -64,7 +64,7 @@
  *         ...
  *         src.zip
  * </pre>
- * 
+ *
  * The directory structure for Snow Leopard and Lion VMs is:
  * <pre>
  * /System/Library/Java/JavaVirtualMachines/
@@ -74,12 +74,12 @@
  *       Home/
  *         src.zip
  * </pre>
- * 
+ *
  * @see http://developer.apple.com/library/mac/#qa/qa1170/_index.html
  * @see http://developer.apple.com/library/mac/#releasenotes/Java/JavaSnowLeopardUpdate3LeopardUpdate8RN/NewandNoteworthy/NewandNoteworthy.html#//apple_ref/doc/uid/TP40010380-CH4-SW1
  */
 public class MacOSXVMInstallType extends StandardVMType {
-	
+
 	/** The OS keeps all the JVM versions in this directory */
 	private static final String JVM_VERSION_LOC= "/System/Library/Frameworks/JavaVM.framework/Versions/";	//$NON-NLS-1$
 	private static final File JVM_VERSIONS_FOLDER= new File(JVM_VERSION_LOC);
@@ -89,7 +89,7 @@
 	private static final String JVM_HOME= "Home";	//$NON-NLS-1$
 	/** The doc (for all JVMs) lives here (if the developer kit has been expanded)*/
 	private static final String JAVADOC_LOC= "/Developer/Documentation/Java/Reference/";	//$NON-NLS-1$
-	/** The doc for 1.4.1 is kept in a sub directory of the above. */ 
+	/** The doc for 1.4.1 is kept in a sub directory of the above. */
 	private static final String JAVADOC_SUBDIR= "/doc/api";	//$NON-NLS-1$
 	/**
 	 * The name of the src.zip file for the JDK source
@@ -118,20 +118,20 @@
 	static final String JVM_CLASSES = "Classes"; //$NON-NLS-1$
 	/**
 	 * The name of the Versions folder for legacy JRE/JDK installs
-	 * @since 3.2.200 
+	 * @since 3.2.200
 	 */
 	static final String JVM_VERSIONS = "Versions"; //$NON-NLS-1$
-				
+
 	@Override
 	public String getName() {
 		return Messages.MacOSXVMInstallType_0;
 	}
-	
+
 	@Override
 	public IVMInstall doCreateVMInstall(String id) {
 		return new MacOSXVMInstall(this, id);
 	}
-			
+
 	/*
 	 * @see IVMInstallType#detectInstallLocation()
 	 */
@@ -141,7 +141,7 @@
 			// try to find the VM used to launch Eclipse
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=407402
 			File defaultLocation = getJavaHomeLocation();
-			
+
 			// find all installed VMs
 			VMStandin[] vms = MacInstalledJREs.getInstalledJREs(null);
 			File firstLocation = null;
@@ -161,7 +161,7 @@
 					defaultInstall = install;
 				}
 			}
-			
+
 			// determine the default VM
 			if (defaultInstall == null) {
 				if (defaultLocation != null) {
@@ -194,8 +194,8 @@
 
 	/**
 	 * The proper way to find installed JREs is to parse the XML output produced from "java_home -X"
-	 * (see bug 325777). However, if that fails, revert to the hard coded search. 
-	 * 
+	 * (see bug 325777). However, if that fails, revert to the hard coded search.
+	 *
 	 * @return file that points to the default JRE install
 	 */
 	private File detectInstallLocationOld() {
@@ -204,7 +204,7 @@
 			return null;
 		}
 		if (!JVM_VERSIONS_FOLDER.exists() || !JVM_VERSIONS_FOLDER.isDirectory()) {
-			String message= NLS.bind(Messages.MacOSXVMInstallType_1, JVM_VERSIONS_FOLDER); 
+			String message= NLS.bind(Messages.MacOSXVMInstallType_1, JVM_VERSIONS_FOLDER);
 			LaunchingPlugin.log(message);
 			return null;
 		}
@@ -239,11 +239,11 @@
 		}
 		return defaultLocation;
 	}
-	
+
 	/**
 	 * The proper way to find installed JREs is to parse the XML output produced from "java_home -X"
-	 * (see bug 325777). However, if that fails, revert to the hard coded search. 
-	 * 
+	 * (see bug 325777). However, if that fails, revert to the hard coded search.
+	 *
 	 * @return array of files that point to JRE install directories
 	 */
 	private File[] getAllVersionsOld() {
@@ -257,13 +257,13 @@
 	/**
 	 * The proper way to find the default JRE is to parse the XML output produced from "java_home -X"
 	 * and take the first entry in the list. However, if that fails, revert to the hard coded search.
-	 * 
+	 *
 	 * @return a file that points to the default JRE install directory
 	 */
 	private File getCurrentJDKOld() {
 		return resolveSymbolicLinks(new File(JVM_VERSIONS_FOLDER, CURRENT_JDK));
 	}
-	
+
 	private File resolveSymbolicLinks(File file) {
 		try {
 			return file.getCanonicalFile();
@@ -285,9 +285,9 @@
 		File classes = new File(installLocation, "../Classes"); //$NON-NLS-1$
 		File lib1= new File(classes, "classes.jar"); //$NON-NLS-1$
 		File lib2= new File(classes, "ui.jar"); //$NON-NLS-1$
-		
+
 		String[] libs = new String[] { lib1.toString(),lib2.toString() };
-		
+
 		File lib = new File(installLocation, "lib"); //$NON-NLS-1$
 		File extDir = new File(lib, "ext"); //$NON-NLS-1$
 		String[] dirs = null;
@@ -303,11 +303,11 @@
 			endDirs = new String[] {endDir.getAbsolutePath()};
 		} else {
 			endDirs = new String[0];
-		} 
-		
+		}
+
 		return new LibraryInfo("???", libs, dirs, endDirs);		 //$NON-NLS-1$
 	}
-	
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.internal.launching.StandardVMType#getDefaultSystemLibrarySource(java.io.File)
 	 */
@@ -344,12 +344,12 @@
 	}
 
 	/**
-	 * Checks to see if <code>src.zip</code> or <code>src.jar</code> exists in the given parent 
+	 * Checks to see if <code>src.zip</code> or <code>src.jar</code> exists in the given parent
 	 * folder. Returns <code>null</code> if it does not exist.
 	 * <br><br>
 	 * The newer naming of the archive is <code>src.zip</code> and the older (pre-1.6) is
 	 * <code>src.jar</code>
-	 * 
+	 *
 	 * @param parent the parent directory
 	 * @return the {@link File} for the source archive or <code>null</code>
 	 * @since 3.2.200
@@ -367,7 +367,7 @@
 		}
 		return null;
 	}
-	
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.internal.launching.StandardVMType#validateInstallLocation(java.io.File)
 	 */
@@ -381,14 +381,14 @@
 		}
 		return new Status(IStatus.ERROR, id, 0, Messages.MacOSXVMInstallType_2, null);
 	}
-	
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.jdt.internal.launching.StandardVMType#getDefaultJavadocLocation(java.io.File)
 	 */
 	@Override
 	public URL getDefaultJavadocLocation(File installLocation) {
 		// try in local filesystem
-		String id= null;	
+		String id= null;
 		try {
 			String post= File.separator + JVM_HOME;
 			String path= installLocation.getCanonicalPath();
@@ -416,7 +416,7 @@
 				}
 			}
 		}
-		
+
 		// fall back
 		return super.getDefaultJavadocLocation(installLocation);
 	}
diff --git a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMRunner.java b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMRunner.java
index d981ba2..2760adc 100644
--- a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMRunner.java
+++ b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/MacOSXVMRunner.java
@@ -7,7 +7,7 @@
  *  https://www.eclipse.org/legal/epl-2.0/
  *
  *  SPDX-License-Identifier: EPL-2.0
- * 
+ *
  *  Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -17,7 +17,7 @@
 import org.eclipse.jdt.launching.IVMInstall;
 
 public class MacOSXVMRunner extends StandardVMRunner {
-	
+
 	/**
 	 * Constructor
 	 * @param vmInstance
diff --git a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/Messages.java b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/Messages.java
index 487a865..03473f2 100644
--- a/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/Messages.java
+++ b/org.eclipse.jdt.launching.macosx/macosx/org/eclipse/jdt/internal/launching/macosx/Messages.java
@@ -7,7 +7,7 @@
  *  https://www.eclipse.org/legal/epl-2.0/
  *
  *  SPDX-License-Identifier: EPL-2.0
- * 
+ *
  *  Contributors:
  *  IBM - Initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.launching.ui.macosx/META-INF/MANIFEST.MF b/org.eclipse.jdt.launching.ui.macosx/META-INF/MANIFEST.MF
index 17dd5e6..03bfcd4 100644
--- a/org.eclipse.jdt.launching.ui.macosx/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.launching.ui.macosx/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.launching.ui.macosx;singleton:=true
-Bundle-Version: 1.2.400.qualifier
+Bundle-Version: 1.2.600.qualifier
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-Vendor: %providerName
diff --git a/org.eclipse.jdt.launching.ui.macosx/pom.xml b/org.eclipse.jdt.launching.ui.macosx/pom.xml
index 51b107c..da9f982 100644
--- a/org.eclipse.jdt.launching.ui.macosx/pom.xml
+++ b/org.eclipse.jdt.launching.ui.macosx/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.launching.ui.macosx</artifactId>
-  <version>1.2.400-SNAPSHOT</version>
+  <version>1.2.600-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleAttributes.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleAttributes.java
index 7cb7505..75aa216 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleAttributes.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleAttributes.java
@@ -12,15 +12,15 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.macbundler;
-   
+
 /**
  * All keys used in the BundleDescription.
  */
 public interface BundleAttributes {
 	static final String LAUNCHER = "CFBundleExecutable"; //$NON-NLS-1$
-	
+
 	static final String ALL= "ALL"; //$NON-NLS-1$
-	
+
 	static final String GETINFO = "GetInfo"; //$NON-NLS-1$
 	static final String IDENTIFIER = "Identifier"; //$NON-NLS-1$
 	static final String ICONFILE = "IconFile"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleBuilder.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleBuilder.java
index b946056..9f98ba2 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleBuilder.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleBuilder.java
@@ -38,11 +38,11 @@
 
 
 public class BundleBuilder implements BundleAttributes {
-	
+
 	private List<Process> fProcesses= new ArrayList<Process>();
 	private BundleDescription fBundleDescription;
-	
-	
+
+
 	/**
 	 * Create a new bundle
 	 * @param bd the new description
@@ -50,9 +50,9 @@
 	 * @throws IOException if something happens
 	 */
 	public void createBundle(BundleDescription bd, IProgressMonitor pm) throws IOException {
-		
+
 		fBundleDescription= bd;
-		
+
 		File tmp_dir= new File(bd.get(DESTINATIONDIRECTORY));
 		String app_dir_name= bd.get(APPNAME) + ".app";	//$NON-NLS-1$
 		File app_dir= new File(tmp_dir, app_dir_name);
@@ -60,7 +60,7 @@
 			deleteDir(app_dir);
 		}
 		app_dir= createDir(tmp_dir, app_dir_name, false);
-		
+
 		File contents_dir= createDir(app_dir, "Contents", false);	//$NON-NLS-1$
 		createPkgInfo(contents_dir);
 
@@ -68,14 +68,14 @@
 		String launcher_path= bd.get(LAUNCHER);
 		if (launcher_path == null) {
 			throw new IOException();
-		}		
+		}
 		String launcher= copyFile(macos_dir, launcher_path, null);
-		
+
 		File resources_dir= createDir(contents_dir, "Resources", false);	//$NON-NLS-1$
 		File java_dir= createDir(resources_dir, "Java", false);	//$NON-NLS-1$
-				
+
 		createInfoPList(contents_dir, resources_dir, java_dir, launcher);
-		
+
 		Iterator<Process> iter= fProcesses.iterator();
 		while (iter.hasNext()) {
 			Process p= iter.next();
@@ -84,32 +84,32 @@
 			} catch (InterruptedException e) {
 				// silently ignore
 			}
-		}		
+		}
 	}
-	
+
 	private void createInfoPList(File contents_dir, File resources_dir, File java_dir, String launcher) throws IOException {
 		DocumentBuilder docBuilder= null;
 		DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
 		factory.setValidating(false);
-		try {   	
+		try {
 			docBuilder= factory.newDocumentBuilder();
 		} catch (ParserConfigurationException ex) {
 			System.err.println("createInfoPList: could not get XML builder"); //$NON-NLS-1$
 			throw new IOException("Could not get XML builder"); //$NON-NLS-1$
 		}
 		Document doc= docBuilder.newDocument();
-		
+
 		Element plist= doc.createElement("plist"); //$NON-NLS-1$
 		doc.appendChild(plist);
 		plist.setAttribute("version", "1.0"); //$NON-NLS-1$ //$NON-NLS-2$
-		
+
 		Element dict= doc.createElement("dict"); //$NON-NLS-1$
 		plist.appendChild(dict);
-		
+
 		pair(dict, "CFBundleExecutable", null, launcher); //$NON-NLS-1$
 		pair(dict, "CFBundleGetInfoString", GETINFO, null); //$NON-NLS-1$
 		pair(dict, "CFBundleInfoDictionaryVersion", null, "6.0"); //$NON-NLS-1$ //$NON-NLS-2$
-		
+
 		String iconName= null;
 		String appName= fBundleDescription.get(APPNAME, null);
 		if (appName != null)
@@ -121,41 +121,41 @@
 		 {
 			pair(dict, "CFBundleIconFile", null, fname); //$NON-NLS-1$
 		}
-		
+
 		pair(dict, "CFBundleIdentifier", IDENTIFIER, null); //$NON-NLS-1$
 		pair(dict, "CFBundleName", APPNAME, null); //$NON-NLS-1$
 		pair(dict, "CFBundlePackageType", null, "APPL"); //$NON-NLS-1$ //$NON-NLS-2$
 		pair(dict, "CFBundleShortVersionString", VERSION, null); //$NON-NLS-1$
 		pair(dict, "CFBundleSignature", SIGNATURE, "????"); //$NON-NLS-1$ //$NON-NLS-2$
 		pair(dict, "CFBundleVersion", null, "1.0.1"); //$NON-NLS-1$ //$NON-NLS-2$
-		
+
 		Element jdict= doc.createElement("dict"); //$NON-NLS-1$
 		add(dict, "Java", jdict); //$NON-NLS-1$
-		
+
 		pair(jdict, "JVMVersion", JVMVERSION, null); //$NON-NLS-1$
 		pair(jdict, "MainClass", MAINCLASS, null); //$NON-NLS-1$
 		pair(jdict, "WorkingDirectory", WORKINGDIR, null); //$NON-NLS-1$
-		
+
 		if (fBundleDescription.get(USES_SWT, false))
 		 {
 			addTrue(jdict, "StartOnMainThread"); //$NON-NLS-1$
 		}
-		
+
 		String arguments= fBundleDescription.get(ARGUMENTS, null);
 		if (arguments != null) {
 			Element argArray= doc.createElement("array");	//$NON-NLS-1$
 			add(jdict, "Arguments", argArray);	//$NON-NLS-1$
-			StringTokenizer st= new StringTokenizer(arguments);	
+			StringTokenizer st= new StringTokenizer(arguments);
 			while (st.hasMoreTokens()) {
 				String arg= st.nextToken();
 				Element type= doc.createElement("string"); //$NON-NLS-1$
-				argArray.appendChild(type);	
-				type.appendChild(doc.createTextNode(arg));			
+				argArray.appendChild(type);
+				type.appendChild(doc.createTextNode(arg));
 			}
 		}
-		
+
 		pair(jdict, "VMOptions", VMOPTIONS, null); //$NON-NLS-1$
-		
+
 		int[] id= new int[] { 0 };
 		ResourceInfo[] ris= fBundleDescription.getResources(true);
 		if (ris.length > 0) {
@@ -196,7 +196,7 @@
 			System.err.println("createInfoPList: could not transform to XML"); //$NON-NLS-1$
 		}
 	}
-	
+
 	private void add(Element dict, String key, Element value) {
 		Document document= dict.getOwnerDocument();
 		Element k= document.createElement("key"); //$NON-NLS-1$
@@ -204,18 +204,18 @@
 		k.appendChild(document.createTextNode(key));
 		dict.appendChild(value);
 	}
-	
+
 	private void create(Element parent, String s) {
 		Document document= parent.getOwnerDocument();
 		Element type= document.createElement("string"); //$NON-NLS-1$
-		parent.appendChild(type);	
+		parent.appendChild(type);
 		type.appendChild(document.createTextNode(s));
 	}
 
 	private void createTrue(Element parent) {
 		Document document= parent.getOwnerDocument();
 		Element type= document.createElement("true"); //$NON-NLS-1$
-		parent.appendChild(type);	
+		parent.appendChild(type);
 	}
 
 	private void add(Element dict, String key, String value) {
@@ -225,7 +225,7 @@
 		k.appendChild(document.createTextNode(key));
 		create(dict, value);
 	}
-	
+
 	private void addTrue(Element dict, String key) {
 		Document document= dict.getOwnerDocument();
 		Element k= document.createElement("key"); //$NON-NLS-1$
@@ -233,7 +233,7 @@
 		k.appendChild(document.createTextNode(key));
 		createTrue(dict);
 	}
-	
+
 	private void pair(Element dict, String outkey, String inkey, String dflt) {
 		String value= null;
 		if (inkey != null) {
@@ -245,7 +245,7 @@
 			add(dict, outkey, value);
 		}
 	}
-	
+
 	private String processClasspathEntry(File java_dir, String name, int[] id_ref) throws IOException {
 		File f= new File(name);
 		if (f.isDirectory()) {
@@ -259,14 +259,14 @@
 		}
 		return "$JAVAROOT/" + name; //$NON-NLS-1$
 	}
-	
+
 	private void createPkgInfo(File contents_dir) throws IOException {
 		File pkgInfo= new File(contents_dir, "PkgInfo"); //$NON-NLS-1$
 		try (FileOutputStream os = new FileOutputStream(pkgInfo)) {
 			os.write(("APPL" + fBundleDescription.get(SIGNATURE, "????")).getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 	}
-		
+
 	private static void deleteDir(File dir) {
 		File[] files= dir.listFiles();
 		if (files != null) {
@@ -276,7 +276,7 @@
 		}
 		dir.delete();
 	}
-	
+
 	private File createDir(File parent_dir, String dir_name, boolean remove) throws IOException {
 		File dir= new File(parent_dir, dir_name);
 		if (dir.exists()) {
@@ -291,7 +291,7 @@
 		}
 		return dir;
 	}
-	
+
 	private String copyFile(File todir, String fromPath, String toname) throws IOException {
 		if (toname == null) {
 			int pos= fromPath.lastIndexOf('/');
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleDescription.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleDescription.java
index 89a9eaf..1dc2b80 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleDescription.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleDescription.java
@@ -37,7 +37,7 @@
 
 
 class BundleDescription implements BundleAttributes {
-	
+
 	private static final String STUB= "/System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/MacOS/JavaApplicationStub"; //$NON-NLS-1$
 	private static final String ICON= "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Resources/GenericApp.icns"; //$NON-NLS-1$
 	private static  Set<String> RUN_MODE;
@@ -45,18 +45,18 @@
 		RUN_MODE = new HashSet<String>();
 		RUN_MODE.add(ILaunchManager.RUN_MODE);
 	}
-		
+
 	private ListenerList<IPropertyChangeListener> fListeners= new ListenerList<>();
 	private Properties fProperties= new Properties();
 	private List<ResourceInfo> fClassPath= new ArrayList<ResourceInfo>();
 	private List<ResourceInfo> fResources= new ArrayList<ResourceInfo>();
 	Properties fProperties2= new Properties();
-	
-	
+
+
 	BundleDescription() {
 		clear();
 	}
-	
+
 	void clear() {
 		fProperties.clear();
 		fClassPath.clear();
@@ -65,7 +65,7 @@
 		fProperties.put(SIGNATURE, "????"); //$NON-NLS-1$
 		fProperties.put(ICONFILE, ICON);
 	}
-	
+
 	void addResource(ResourceInfo ri, boolean onClasspath) {
 		if (onClasspath) {
 			fClassPath.add(ri);
@@ -73,12 +73,12 @@
 			fResources.add(ri);
 		}
 	}
-	
+
 	boolean removeResource(ResourceInfo ri, boolean onClasspath) {
 		if (onClasspath) {
 			return fClassPath.remove(ri);
 		}
-		return fResources.remove(ri);	
+		return fResources.remove(ri);
 	}
 
 	ResourceInfo[] getResources(boolean onClasspath) {
@@ -87,23 +87,23 @@
 		}
 		return fResources.toArray(new ResourceInfo[fResources.size()]);
 	}
-	
+
 	void addListener(IPropertyChangeListener listener) {
 		fListeners.add(listener);
 	}
-	
+
 	void removeListener(IPropertyChangeListener listener) {
 		fListeners.remove(listener);
 	}
-	
+
 	String get(String key) {
 		return fProperties.getProperty(key);
 	}
-	
+
 	public String get(String key, String dflt) {
 		return fProperties.getProperty(key, dflt);
 	}
-	
+
 	public boolean get(String key, boolean dflt) {
 		Boolean v= (Boolean) fProperties.get(key);
 		if (v == null) {
@@ -111,11 +111,11 @@
 		}
 		return v.booleanValue();
 	}
-	
+
 	void setValue(String key, Object value) {
 		fProperties.put(key, value);
 	}
-	
+
 	private static AbstractJavaLaunchConfigurationDelegate getDelegate(ILaunchConfiguration lc) throws CoreException {
 		ILaunchDelegate[] delegates = lc.getType().getDelegates(RUN_MODE);
 		for (int i = 0; i < delegates.length; i++) {
@@ -125,7 +125,7 @@
 		}
 		throw new CoreException(new Status(IStatus.ERROR, MacOSXUILaunchingPlugin.getUniqueIdentifier(), "Internal Error: missing Java launcher")); //$NON-NLS-1$
 	}
-	
+
 	@SuppressWarnings("deprecation")
 	void inititialize(ILaunchConfiguration lc) {
 		AbstractJavaLaunchConfigurationDelegate lcd;
@@ -134,11 +134,11 @@
 		} catch (CoreException e) {
 			return;
 		}
-		
+
 		String appName= lc.getName();
 		fProperties.put(APPNAME, appName);
 		fProperties.put(GETINFO, appName + Util.getString("BundleDescription.copyright.format")); //$NON-NLS-1$
-		
+
 		try {
 			fProperties.put(MAINCLASS, lcd.getMainTypeName(lc));
 		} catch (CoreException e) {
@@ -161,7 +161,7 @@
 		} catch (CoreException e) {
 			fProperties.put(MAINCLASS, ""); //$NON-NLS-1$
 		}
-		
+
 		try {
 			String[] classpath= lcd.getClasspath(lc);
 			for (int i= 0; i < classpath.length; i++) {
@@ -170,7 +170,7 @@
 		} catch (CoreException e) {
 			//
 		}
-		
+
 		String vmOptions2= ""; //$NON-NLS-1$
 		String vmOptions= null;
 		try {
@@ -202,7 +202,7 @@
 		}
 
 		fProperties.put(VMOPTIONS, vmOptions2);
-		
+
 		boolean isSWT= false;
 		Iterator<ResourceInfo> iter= fResources.iterator();
 		while (iter.hasNext()) {
@@ -213,20 +213,20 @@
 			}
 		}
 		fProperties.put(USES_SWT, Boolean.valueOf(isSWT));
-		
+
 		String launcher= null;
 		if (isSWT)
 		 {
 			launcher= System.getProperty("org.eclipse.swtlauncher");	//$NON-NLS-1$
 		}
-		
+
 		if (launcher == null) {
 			setValue(JVMVERSION, "1.4*"); //$NON-NLS-1$
-			launcher= STUB;		
+			launcher= STUB;
 		}
 		setValue(LAUNCHER, launcher);
 
-		
+
 		IJavaProject p= null;
 		try {
 			p= lcd.getJavaProject(lc);
@@ -239,10 +239,10 @@
 		else {
 			fProperties.put(IDENTIFIER, ""); //$NON-NLS-1$
 		}
-				
+
 		fireChange();
 	}
-	
+
 	void fireChange() {
 		PropertyChangeEvent e= new PropertyChangeEvent(this, ALL, null, null);
 		for (IPropertyChangeListener listener : fListeners) {
@@ -255,7 +255,7 @@
 		if (path.startsWith("../")) { //$NON-NLS-1$
 			lib_dir= new File(wd, path);
 		} else {
-			lib_dir= new File(path);			
+			lib_dir= new File(path);
 		}
 		if (lib_dir.isDirectory()) {
 			File[] dlls= lib_dir.listFiles();
@@ -272,7 +272,7 @@
 			}
 		}
 	}
-	
+
 	static boolean verify(ILaunchConfiguration lc) {
 		String name= lc.getName();
 		if (name.indexOf("jpage") >= 0) { //$NON-NLS-1$
@@ -289,7 +289,7 @@
 			return false;
 		}
 	}
-	
+
 	static boolean matches(ILaunchConfiguration lc, IJavaProject project) {
 		AbstractJavaLaunchConfigurationDelegate lcd;
 		try {
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardBasePage.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardBasePage.java
index bf043bb..4cbb7c8 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardBasePage.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardBasePage.java
@@ -36,7 +36,7 @@
 
 
 public abstract class BundleWizardBasePage extends DialogPage implements IWizardPage, BundleAttributes, IPropertyChangeListener {
-	
+
 	/**
 	 * The page that was shown right before this page became visible;
 	 * <code>null</code> if none.
@@ -51,20 +51,20 @@
 	 * if this page has yet to be added to a wizard.
 	 */
 	private IWizard fWizard;
-	
+
 	BundleDescription fBundleDescription;
 
-	
+
 	BundleWizardBasePage(String key, BundleDescription bd) {
 		super(Util.getString(key + ".title")); //$NON-NLS-1$
 		fKey= key;
 		fBundleDescription= bd;
 		//setMessage(Util.getString(fKey + ".message")); //$NON-NLS-1$
 		setDescription(Util.getString(fKey + ".description")); //$NON-NLS-1$
-		
+
 		bd.addListener(this);
 	}
-	
+
 	/* (non-Javadoc)
 	 * Method declared in WizardPage
 	 */
@@ -77,7 +77,7 @@
 		}
 		super.setVisible(visible);
 	}
-	
+
 	void enterPage() {
 		//System.out.println("enterPage: " + getName());
 	}
@@ -102,18 +102,18 @@
 	 */
 	@Override
 	final public void createControl(Composite parent) {
-		
+
 		Composite c= new Composite(parent, SWT.NULL);
 		c.setLayout(new GridLayout(1, false));
 		setControl(c);
-		
+
 		createContents(c);
 
 		checkIfPageComplete();
 	}
-	
+
 	abstract public void createContents(Composite parent);
-	
+
 	static void setHeightHint(Control control, int height) {
 		GridData gd1= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
 		gd1.heightHint= height;
@@ -142,7 +142,7 @@
 		if (lines == 2) {
 			gd.heightHint= 30;
 		}
-		t.setLayoutData(gd);	
+		t.setLayoutData(gd);
 		hookField(t, key);
 		return t;
 	}
@@ -178,7 +178,7 @@
 		c.setLayout(gl);
 		return c;
 	}
-	
+
 	void hookField(final Text tf, final String key) {
 		tf.addModifyListener(new ModifyListener() {
 			@Override
@@ -188,7 +188,7 @@
 			}
 		});
 	}
-		
+
 	void hookField(final Combo tf, final String key) {
 		tf.addModifyListener(new ModifyListener() {
 			@Override
@@ -198,17 +198,17 @@
 			}
 		});
 	}
-	
+
 	void hookButton(final Button b, final String key) {
 		b.addSelectionListener(new SelectionAdapter() {
 			@Override
 			public void widgetSelected(SelectionEvent e) {
-				fBundleDescription.setValue(key, new Boolean(b.getSelection()));
+				fBundleDescription.setValue(key, Boolean.valueOf(b.getSelection()));
 				checkIfPageComplete();
 			}
 		});
 	}
-	
+
 	final void checkIfPageComplete() {
 		IWizardContainer c= (fWizard != null) ? fWizard.getContainer() : null;
 		if (c != null && this == c.getCurrentPage()) {
@@ -217,7 +217,7 @@
 	}
 
 	/////////////////////////////////////////////////////////
-	
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.wizard.IWizardPage#canFlipToNextPage()
 	 */
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage2.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage2.java
index 9dd99f5..d8cb8b3 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage2.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage2.java
@@ -29,11 +29,11 @@
 
 
 public class BundleWizardPage2 extends BundleWizardBasePage {
-	
+
 	Text fWorkingDir;
 	Table fClassPath;
 	Table fResources;
-	
+
 
 	protected BundleWizardPage2(BundleDescription bd) {
 		super("page2", bd); //$NON-NLS-1$
@@ -41,7 +41,7 @@
 
 	@Override
 	public void createContents(Composite parent) {
-		
+
 		Composite c= createComposite(parent, 2);
 			createLabel(c, Util.getString("page2.workingDirectory.label"), GridData.VERTICAL_ALIGN_CENTER); //$NON-NLS-1$
 			fWorkingDir= createText(c, WORKINGDIR, 1);
@@ -49,7 +49,7 @@
 		fClassPath= createTableGroup(parent, Util.getString("page2.addToClasspath.group.label"), true); //$NON-NLS-1$
 		fResources= createTableGroup(parent, Util.getString("page2.addToBundle.group.label"), false); //$NON-NLS-1$
 	}
-	
+
 	Table createTableGroup(Composite parent, String groupName, final boolean onClasspath) {
 		Group g1= createGroup(parent, groupName, 1);
 			final Table table= new Table(g1, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION);
@@ -99,13 +99,13 @@
 			});
 		return table;
 	}
-	
+
 	private void add(Table t, ResourceInfo ri) {
 		TableItem ti= new TableItem(t, SWT.NONE);
 		ti.setData(ri);
 		ti.setText(ri.fPath);
 	}
-		
+
 	private void remove(Table table, boolean b, Button removeButton) {
 		TableItem[] selection= table.getSelection();
 		for (int i= 0; i < selection.length; i++) {
@@ -135,7 +135,7 @@
 				add(fClassPath, ris[i]);
 			}
 		}
-		
+
 		if (fResources != null) {
 			fResources.removeAll();
 			ResourceInfo[] ris= fBundleDescription.getResources(false);
@@ -144,7 +144,7 @@
 			}
 		}
 	}
-		
+
 	@Override
 	public boolean isPageComplete() {
 		return true;
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage3.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage3.java
index a2ce2d8..36b3340 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage3.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/BundleWizardPage3.java
@@ -43,16 +43,16 @@
 	public void createContents(Composite c) {
 
 		Composite c1= createComposite(c, 4);
-			
+
 			createLabel(c1, Util.getString("page3.identifier.label"), GridData.VERTICAL_ALIGN_CENTER); //$NON-NLS-1$
 			fIdentifier= createText(c1, IDENTIFIER, 1);
-		
+
 			createLabel(c1, Util.getString("page3.signature.label"), GridData.VERTICAL_ALIGN_CENTER); //$NON-NLS-1$
 			fSignature= createText(c1, SIGNATURE, 1);
 
 		createLabel(c, Util.getString("page3.vmOptions.label"), GridData.VERTICAL_ALIGN_CENTER); //$NON-NLS-1$
 		fVMOptions= createText(c, VMOPTIONS, 2);
-		
+
 		Group g= createGroup(c, Util.getString("page3.propertiesGroup.label"), 1); //$NON-NLS-1$
 		fProperties= new Table(g, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI);
 		fProperties.setHeaderVisible(true);
@@ -64,11 +64,11 @@
 			}
 		});
 		setHeightHint(fProperties, 60);
-		
+
 		TableColumn col0= new TableColumn(fProperties, SWT.NONE);
 		col0.setText(Util.getString("page3.keys.column.label")); //$NON-NLS-1$
 		col0.setWidth(150);
-		
+
 		TableColumn col1= new TableColumn(fProperties, SWT.NONE);
 		col1.setText(Util.getString("page3.values.column.label")); //$NON-NLS-1$
 		col1.setWidth(150);
@@ -93,9 +93,9 @@
 				ti.setText(0, key);
 				ti.setText(1, value);
 			}
-		}		
+		}
 	}
-	
+
 	@Override
 	public boolean isPageComplete() {
 		return true;
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacBundleWizard.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacBundleWizard.java
index abe0ab9..2d54043 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacBundleWizard.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacBundleWizard.java
@@ -25,14 +25,14 @@
 
 
 public class MacBundleWizard extends Wizard implements IExportWizard, BundleAttributes {
-	
+
 	IWorkbench fWorkbench;
 	IStructuredSelection fSelection;
 	BundleDescription fBundleDescription= new BundleDescription();
 
 	public MacBundleWizard() {
 		setDefaultPageImageDescriptor(createWizardImageDescriptor("exportapp_wiz.png")); //$NON-NLS-1$
- 		setWindowTitle(Util.getString("MacBundleWizard.title")); //$NON-NLS-1$	
+ 		setWindowTitle(Util.getString("MacBundleWizard.title")); //$NON-NLS-1$
 	}
 
 	/* (non-Javadoc)
@@ -43,7 +43,7 @@
 		fWorkbench= workbench;
 		fSelection= selection;
 	}
-	
+
 	IStructuredSelection getSelection() {
 		return fSelection;
 	}
@@ -64,7 +64,7 @@
 	 * @see org.eclipse.jface.wizard.Wizard#performFinish()
 	 */
 	@Override
-	public boolean performFinish() {		
+	public boolean performFinish() {
 		try {
 			BundleBuilder bb= new BundleBuilder();
 			bb.createBundle(fBundleDescription, null);
@@ -77,7 +77,7 @@
 
 	private static ImageDescriptor createWizardImageDescriptor(String name) {
 		try {
-			URL baseUrl= MacOSXUILaunchingPlugin.getDefault().getBundle().getEntry("/icons/full/wizban/"); //$NON-NLS-1$	
+			URL baseUrl= MacOSXUILaunchingPlugin.getDefault().getBundle().getEntry("/icons/full/wizban/"); //$NON-NLS-1$
 			if (baseUrl != null) {
 				return ImageDescriptor.createFromURL(new URL(baseUrl, name));
 			}
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacOSXUILaunchingPlugin.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacOSXUILaunchingPlugin.java
index ff78123..5174672 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacOSXUILaunchingPlugin.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/MacOSXUILaunchingPlugin.java
@@ -18,7 +18,7 @@
 
 
 public class MacOSXUILaunchingPlugin extends Plugin {
-	
+
 	private static MacOSXUILaunchingPlugin fgPlugin;
 
 	public MacOSXUILaunchingPlugin() {
@@ -26,7 +26,7 @@
 		Assert.isTrue(fgPlugin == null);
 		fgPlugin= this;
 	}
-	
+
 	public static MacOSXUILaunchingPlugin getDefault() {
 		return fgPlugin;
 	}
@@ -43,5 +43,4 @@
 		}
 		return getDefault().getBundle().getSymbolicName();
 	}
-	
 }
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/ResourceInfo.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/ResourceInfo.java
index 6b36346..8ad4891 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/ResourceInfo.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/ResourceInfo.java
@@ -14,9 +14,9 @@
 package org.eclipse.jdt.internal.ui.macbundler;
 
 public class ResourceInfo {
-	
+
 	String fPath;
-	
+
 	ResourceInfo(String path) {
 		fPath= path;
 	}
diff --git a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/Util.java b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/Util.java
index ad532da..1e1f05e 100644
--- a/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/Util.java
+++ b/org.eclipse.jdt.launching.ui.macosx/src/org/eclipse/jdt/internal/ui/macbundler/Util.java
@@ -18,7 +18,7 @@
 
 
 public class Util {
-	
+
 	private static final String RESOURCE_BUNDLE= "org.eclipse.jdt.internal.ui.macbundler.BundleMessages";	//$NON-NLS-1$
 	private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
 
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java
index c8660ec..e538000 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/IJavaLaunchConfigurationConstants.java
@@ -84,7 +84,7 @@
 
 	/**
 	 * Launch configuration attribute key. The value is the module name for the main type to launch.
-	 * 
+	 *
 	 * @since 3.17
 	 */
 	public static final String ATTR_MODULE_NAME = LaunchingPlugin.getUniqueIdentifier() + ".MODULE_NAME"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/environments/ExecutionEnvironmentDescription.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/environments/ExecutionEnvironmentDescription.java
index 926f2e1..b170c34 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/environments/ExecutionEnvironmentDescription.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/environments/ExecutionEnvironmentDescription.java
@@ -309,7 +309,7 @@
 			boolean appendArgument = !key.startsWith(EE_ARG_FILTER);
 			if (appendArgument) {
 				arguments.append(key);
-				if (!value.equals("")) { //$NON-NLS-1$
+				if (!value.isEmpty()) {
 					arguments.append('=');
 					value = resolveHome(value);
 					if (value.indexOf(' ') > -1){