Bug 577731 - Merge remote-tracking branch 'origin/master' into BETA_JAVA18

Change-Id: I79d9d8a2ca4f6bbb4923a6d766c343c3cceb7a88
diff --git a/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF
index 0d2ae5f..8319272 100644
--- a/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug.tests; singleton:=true
-Bundle-Version: 3.11.1500.qualifier
+Bundle-Version: 3.11.1600.qualifier
 Bundle-ClassPath: javadebugtests.jar
 Bundle-Activator: org.eclipse.jdt.debug.testplugin.JavaTestPlugin
 Bundle-Vendor: %providerName
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug575551.java b/org.eclipse.jdt.debug.tests/java8/Bug575551.java
new file mode 100644
index 0000000..930b981
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug575551.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Gayan Perera and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Gayan Perera - initial API and implementation
+ *******************************************************************************/
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class Bug575551 {
+	public void hoverOverLocal(String[] names) throws InterruptedException, ExecutionException {
+		CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
+			return Stream.of(names).filter(s -> {
+				try {
+					return CompletableFuture.supplyAsync(() -> {
+						return containsDigit(s.codePointAt(0), names.length);
+					}).get();
+				} catch (Exception e) {
+					return false;
+				}
+			}).collect(Collectors.toList());
+		});
+		future.get();
+	}
+	
+	private boolean containsDigit(int c, int length) {
+		return Bug575551.Character.isDigit(c) && c == length;
+	}
+	
+	public static void main(String[] args) throws InterruptedException, ExecutionException {
+		new Bug575551().hoverOverLocal(new String[] {"name"});
+	}
+	
+	public static class Character {
+		public static boolean isDigit(int c) {
+			return (new CharacterLatin()).isDigit(c);
+		}
+		
+		private static class CharacterLatin {
+			public boolean isDigit(int ch) {
+				return ch > 0;
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/pom.xml b/org.eclipse.jdt.debug.tests/pom.xml
index 0ae9d16..4eea521 100644
--- a/org.eclipse.jdt.debug.tests/pom.xml
+++ b/org.eclipse.jdt.debug.tests/pom.xml
@@ -19,7 +19,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug.tests</artifactId>
-  <version>3.11.1500-SNAPSHOT</version>
+  <version>3.11.1600-SNAPSHOT</version>
   <packaging>eclipse-test-plugin</packaging>
   <properties>
     <code.ignoredWarnings>${tests.ignoredWarnings}</code.ignoredWarnings>
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index f2fcc68..599ed29 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -500,6 +500,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "Bug574395"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug571310"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug573547"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug575551"));
 	    		loaded18 = true;
 	    		waitForBuild();
 	        }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
index 351302a..39c8b3c 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
@@ -183,6 +183,23 @@
 		assertEquals("wrong result : ", "ab", value.getValueString());
 	}
 
+	public void testEvaluate_Bug575551_onIntermediateFrame_InsideLambda_OutFromMethodInvocationFrame() throws Exception {
+		createMethodBreakpoint("Bug575551$Character$CharacterLatin", "isDigit",
+				"(I)Z", true, false);
+		javaThread = launchToBreakpoint("Bug575551");
+		assertNotNull("The program did not suspend", javaThread);
+		// at method invocation stack
+		IValue value = doEval(javaThread, "ch");
+		assertEquals("wrong result at method stack : ", String.valueOf((int) 'n'), value.getValueString());
+
+		// at 1st lambda stack
+		value = doEval(javaThread, () -> (IJavaStackFrame) javaThread.getStackFrames()[3], "names.length");
+		assertEquals("wrong result at 1st lambda stack : ", "1", value.getValueString());
+
+		value = doEval(javaThread, () -> (IJavaStackFrame) javaThread.getStackFrames()[3], "s");
+		assertEquals("wrong result at 1st lambda stack : ", "name", value.getValueString());
+	}
+
 	private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
 		createLineBreakpoint(lineNumber, testClass);
 		javaThread = launchToBreakpoint(testClass);
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/ModelPresentationTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/ModelPresentationTests.java
index 89f50cd..29dc48d 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/ModelPresentationTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/ModelPresentationTests.java
@@ -13,6 +13,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests.ui.presentation;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.eclipse.debug.ui.IDebugModelPresentation;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
@@ -23,6 +26,8 @@
 import org.eclipse.jdt.debug.core.IJavaVariable;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
 import org.eclipse.jdt.internal.debug.ui.JDIModelPresentation;
+import org.eclipse.jdt.internal.debug.ui.display.JavaInspectExpression;
+import org.eclipse.swt.graphics.Color;
 
 /**
  * Tests for some of the methods of the model presentation
@@ -31,6 +36,7 @@
  */
 public class ModelPresentationTests extends AbstractDebugTest {
 
+	private Map<String, Color> colors = new HashMap<>();
 	/**
 	 * Constructor
 	 */
@@ -38,6 +44,22 @@
 		super("Model Presentation tests");
 	}
 
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		colors.clear();
+		colors.put("org.eclipse.jdt.debug.ui.LabeledObject", new Color(255, 0, 0));
+	}
+
+	private JDIModelPresentation mock() {
+		return new JDIModelPresentation() {
+			@Override
+			protected Color getColorFromRegistry(String symbolicName) {
+				return colors.get(symbolicName);
+			}
+		};
+	}
+
 	/**
 	 * Tests that the type signature + value signatures do not cause problems when the values are "&lt;unknown&gt;" - this
 	 * case arises when you manually suspend a VM and try to inspect / view object values
@@ -45,7 +67,7 @@
 	 * @throws Exception
 	 */
 	public void testUnknownValueText() throws Exception {
-		JDIModelPresentation pres = new JDIModelPresentation();
+		JDIModelPresentation pres = mock();
 		try {
 			TestIJavaType type = new TestIJavaType("foo", "<unknown>");
 			TestIJavaValue value = new TestIJavaValue(type, "<unknown>", null, "<unknown>", null);
@@ -65,7 +87,7 @@
 	 * @throws Exception
 	 */
 	public void testAllNullValueText() throws Exception {
-		JDIModelPresentation pres = new JDIModelPresentation();
+		JDIModelPresentation pres = mock();
 		try {
 			TestIJavaType type = new TestIJavaType(null, null);
 			TestIJavaValue value = new TestIJavaValue(type, null, null, null, null);
@@ -86,11 +108,9 @@
 	 * @throws Exception
 	 */
 	public void testSimpleStringValueText() throws Exception {
-		JDIModelPresentation pres = new JDIModelPresentation();
+		JDIModelPresentation pres = mock();
 		try {
-			String sig = Signature.createTypeSignature("java.lang.String", false);
-			TestIJavaType type = new TestIJavaType("foobar", sig);
-			TestIJavaValue value = new TestIJavaValue(type, sig, null, "org.test.MyClass", "test Java value");
+			var value = createJavaObject();
 			String val = pres.getValueText(value);
 			assertNotNull("the value should have been computed", val);
 			assertEquals("The value text should be '\"MyClass test Java value\"'", "MyClass test Java value", val);
@@ -106,11 +126,9 @@
 	 * @throws Exception
 	 */
 	public void testResolvedStringValueText() throws Exception {
-		JDIModelPresentation pres = new JDIModelPresentation();
+		JDIModelPresentation pres = mock();
 		try {
-			String sig = Signature.createTypeSignature("java.lang.String", true);
-			TestIJavaType type = new TestIJavaType("foobar", sig);
-			TestIJavaValue value = new TestIJavaValue(type, sig, null, "org.test.MyClass", "test Java value");
+			var value = createJavaObject();
 			String val = pres.getValueText(value);
 			assertNotNull("the value should have been computed", val);
 			assertEquals("The value text should be '\"MyClass test Java value\"'", "MyClass test Java value", val);
@@ -125,12 +143,10 @@
 	 *
 	 * @throws Exception
 	 */
-	public void testResolvedStringValueTextWithLabel() throws Exception {
-		var pres = new JDIModelPresentation();
+	public void testStringValueTextWithLabel() throws Exception {
+		var pres = mock();
 		try {
-			var sig = Signature.createTypeSignature("java.lang.String", true);
-			var type = new TestIJavaType("foobar", sig);
-			var value = new TestIJavaObjectValue(type, sig, null, "org.test.MyClass", "test Java value");
+			var value = createJavaObject();
 			value.setLabel("myLabel");
 			var valTxt = pres.getValueText(value);
 			assertNotNull("the value should have been computed", valTxt);
@@ -141,6 +157,136 @@
 	}
 
 	/**
+	 * Tests getting the value text for a simple String type
+	 *
+	 * @throws Exception
+	 */
+	public void testStringVariableWithValueText() throws Exception {
+		JDIModelPresentation pres = mock();
+		try {
+			var value = createJavaObject();
+			var variable = new TestIJavaVariable("myVariable", value);
+			String val = pres.getText(variable);
+			assertNotNull("the value should have been computed", val);
+			assertEquals("The value text should be '\"myVariable= MyClass test Java value\"'", "myVariable= MyClass test Java value", val);
+			var foreground = pres.getForeground(variable);
+			assertNull("the foreground color should have been null", foreground);
+		} finally {
+			pres.dispose();
+		}
+	}
+
+	/**
+	 * Tests getting the value text for a simple String type with a label
+	 *
+	 * @throws Exception
+	 */
+	public void testStringVariableWithValueTextWithLabel() throws Exception {
+		var pres = mock();
+		try {
+			var value = createJavaObject();
+			value.setLabel("myLabel");
+			var variable = new TestIJavaVariable("myVariable", value);
+			var valTxt = pres.getText(variable);
+			assertNotNull("the value should have been computed", valTxt);
+			assertEquals("The value text should be '\"myVariable= (myLabel) MyClass test Java value\"'", "myVariable= (myLabel) MyClass test Java value", valTxt);
+			var foreground = pres.getForeground(variable);
+			assertNotNull("the foreground should have been computed", foreground);
+		} finally {
+			pres.dispose();
+		}
+	}
+
+	/**
+	 * Tests for handling IWatchExpression
+	 *
+	 * @throws Exception
+	 */
+	public void testWatchExpression() throws Exception {
+		JDIModelPresentation pres = mock();
+		try {
+			var value = createJavaObject();
+			var variable = new TestIWatchExpression("myVariable", value);
+			String val = pres.getText(variable);
+			assertNotNull("the value should have been computed", val);
+			assertEquals("The value text should be '\"\\\"myVariable\\\"= MyClass test Java value\"'", "\"myVariable\"= MyClass test Java value", val);
+			var foreground = pres.getForeground(variable);
+			assertNull("the foreground color should have been null", foreground);
+		} finally {
+			pres.dispose();
+		}
+	}
+
+	/**
+	 * Tests for handling IWatchExpression with a label
+	 *
+	 * @throws Exception
+	 */
+	public void testWatchExpressionWithLabel() throws Exception {
+		var pres = mock();
+		try {
+			var value = createJavaObject();
+			value.setLabel("myLabel");
+			var variable = new TestIWatchExpression("myVariable", value);
+			var valTxt = pres.getText(variable);
+			assertNotNull("the value should have been computed", valTxt);
+			assertEquals("The value text should be '\"\\\"myVariable\\\"= (myLabel) MyClass test Java value\"'", "\"myVariable\"= (myLabel) MyClass test Java value", valTxt);
+			var foreground = pres.getForeground(variable);
+			assertNotNull("the foreground should have been computed", foreground);
+		} finally {
+			pres.dispose();
+		}
+	}
+
+	/**
+	 * Tests for handling JavaInspectExpression
+	 *
+	 * @throws Exception
+	 */
+	public void testJavaInspectExpression() throws Exception {
+		JDIModelPresentation pres = mock();
+		try {
+			var value = createJavaObject();
+			var variable = new JavaInspectExpression("myVariable", value);
+			String val = pres.getText(variable);
+			assertNotNull("the value should have been computed", val);
+			assertEquals("The value text should be '\"\\\"myVariable\\\"= MyClass test Java value\"'", "\"myVariable\"= MyClass test Java value", val);
+			var foreground = pres.getForeground(variable);
+			assertNull("the foreground color should have been null", foreground);
+		} finally {
+			pres.dispose();
+		}
+	}
+
+	/**
+	 * Tests for handling JavaInspectExpression with a label
+	 *
+	 * @throws Exception
+	 */
+	public void testJavaInspectExpressionWithLabel() throws Exception {
+		var pres = mock();
+		try {
+			var value = createJavaObject();
+			value.setLabel("myLabel");
+			var variable = new JavaInspectExpression("myVariable", value);
+			var valTxt = pres.getText(variable);
+			assertNotNull("the value should have been computed", valTxt);
+			assertEquals("The value text should be '\"\\\"myVariable\\\"= (myLabel) MyClass test Java value\"'", "\"myVariable\"= (myLabel) MyClass test Java value", valTxt);
+			var foreground = pres.getForeground(variable);
+			assertNotNull("the foreground should have been computed", foreground);
+		} finally {
+			pres.dispose();
+		}
+	}
+
+	private TestIJavaObjectValue createJavaObject() {
+		var sig = Signature.createTypeSignature("java.lang.String", true);
+		var type = new TestIJavaType("foobar", sig);
+		var value = new TestIJavaObjectValue(type, sig, null, "org.test.MyClass", "test Java value");
+		return value;
+	}
+
+	/**
 	 * Tests a simple array value text
 	 *
 	 * @throws Exception
@@ -169,7 +315,7 @@
 	public void testShowTypeTest() throws Exception {
 		String typeName = "ModelPresentationTests";
 		IJavaLineBreakpoint bp = createLineBreakpoint(19, typeName);
-		JDIModelPresentation pres = new JDIModelPresentation();
+		JDIModelPresentation pres = mock();
 
 		IJavaThread thread = null;
 		try {
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/TestIJavaVariable.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/TestIJavaVariable.java
new file mode 100644
index 0000000..68218b9
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/TestIJavaVariable.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Zsombor Gegesy and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Zsombor Gegesy - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.ui.presentation;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.jdt.debug.core.IJavaType;
+import org.eclipse.jdt.debug.core.IJavaVariable;
+
+public class TestIJavaVariable implements IJavaVariable {
+
+	private String name;
+	private IValue value;
+
+	public TestIJavaVariable(String name, IValue value) {
+		this.name = name;
+		this.value = value;
+	}
+
+	@Override
+	public IValue getValue() throws DebugException {
+		return value;
+	}
+
+	@Override
+	public String getName() throws DebugException {
+		return name;
+	}
+
+	@Override
+	public String getReferenceTypeName() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public boolean hasValueChanged() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public String getModelIdentifier() {
+		return null;
+	}
+
+	@Override
+	public IDebugTarget getDebugTarget() {
+		return null;
+	}
+
+	@Override
+	public ILaunch getLaunch() {
+		return null;
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return null;
+	}
+
+	@Override
+	public void setValue(String expression) throws DebugException {
+
+	}
+
+	@Override
+	public void setValue(IValue value) throws DebugException {
+		this.value = value;
+	}
+
+	@Override
+	public boolean supportsValueModification() {
+		return false;
+	}
+
+	@Override
+	public boolean verifyValue(String expression) throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean verifyValue(IValue value) throws DebugException {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public boolean isPublic() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean isPrivate() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean isProtected() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean isPackagePrivate() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean isFinal() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean isStatic() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public boolean isSynthetic() throws DebugException {
+		return false;
+	}
+
+	@Override
+	public String getSignature() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public String getGenericSignature() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public IJavaType getJavaType() throws DebugException {
+		return null;
+	}
+
+	@Override
+	public boolean isLocal() throws DebugException {
+		return false;
+	}
+
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/TestIWatchExpression.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/TestIWatchExpression.java
new file mode 100644
index 0000000..7c9415a
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/presentation/TestIWatchExpression.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Zsombor Gegesy and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Zsombor Gegesy - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.debug.tests.ui.presentation;
+
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IWatchExpression;
+
+public class TestIWatchExpression implements IWatchExpression {
+	private IValue value;
+	private String expressionText;
+
+	public TestIWatchExpression(String expressionText, IValue value) {
+		this.expressionText = expressionText;
+		this.value = value;
+	}
+
+	@Override
+	public boolean hasErrors() {
+		return false;
+	}
+
+	@Override
+	public String[] getErrorMessages() {
+		return null;
+	}
+
+	@Override
+	public String getExpressionText() {
+		return expressionText;
+	}
+
+	@Override
+	public IValue getValue() {
+		return value;
+	}
+
+	@Override
+	public IDebugTarget getDebugTarget() {
+		return null;
+	}
+
+	@Override
+	public void dispose() {
+
+	}
+
+	@Override
+	public String getModelIdentifier() {
+		return null;
+	}
+
+	@Override
+	public ILaunch getLaunch() {
+		return null;
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return null;
+	}
+
+	@Override
+	public void evaluate() {
+
+	}
+
+	@Override
+	public void setExpressionContext(IDebugElement context) {
+
+	}
+
+	@Override
+	public void setExpressionText(String expressionText) {
+
+	}
+
+	@Override
+	public boolean isPending() {
+		return false;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return true;
+	}
+
+	@Override
+	public void setEnabled(boolean enabled) {
+	}
+
+}
diff --git a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
index c1acfc4..ca7b15f 100644
--- a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
@@ -42,7 +42,7 @@
  org.eclipse.debug.ui;bundle-version="[3.13.400,4.0.0)",
  org.eclipse.jdt.debug;bundle-version="[3.19.0,4.0.0)",
  org.eclipse.jdt.launching;bundle-version="[3.19.0,4.0.0)",
- org.eclipse.jdt.ui;bundle-version="[3.22.0,4.0.0)",
+ org.eclipse.jdt.ui;bundle-version="[3.26.0,4.0.0)",
  org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
  org.eclipse.ltk.core.refactoring;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.ui.console;bundle-version="[3.4.0,4.0.0)",
diff --git a/org.eclipse.jdt.debug.ui/plugin.properties b/org.eclipse.jdt.debug.ui/plugin.properties
index 7a3f817..cdb3237 100644
--- a/org.eclipse.jdt.debug.ui/plugin.properties
+++ b/org.eclipse.jdt.debug.ui/plugin.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2021 IBM Corporation and others.
+# Copyright (c) 2000, 2022 IBM Corporation and others.
 #
 # This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
@@ -18,6 +18,7 @@
 vmCapabilitiesPageName=VM Capabilities
 AddBreakpoint.label=Toggle &Breakpoint
 AddTracepoint.label=Toggle &Tracepoint
+AddLambdaEntryBreakpoint.label=Toggle &Lambda Entry Breakpoint
 
 addTypeStepFilterAction.label=&Filter Type
 addTypeStepFilterAction.tooltip=Filter the selected type(s)
@@ -126,6 +127,9 @@
 openConcreteVarTypeHierarchy.label=Open Actual Type Hierarch&y
 openConcreteVarTypeHierarchy.tooltip=Open the Variable's Actual Implementation Type Hierarchy
 
+openFieldDeclaration.label=Open &Field Declaration
+openFieldDeclaration.tooltip=Open the Declaration of the Field
+
 openRecType.label=Open Actual T&ype
 openRecType.tooltip=Open the Actual Type
 
@@ -233,7 +237,11 @@
 
 ToggleTracepointAction.label=Toggle Tra&cepoint
 ToggleTracepointCommand.label=Toggle Tracepoint
-ToggleTracepointCommand.description=Creates or removes a tracepoint  
+ToggleTracepointCommand.description=Creates or removes a tracepoint
+
+ToggleLambdaEntryBreakpointAction.label=Toggle Lambda Entry Breakpoint
+ToggleLambdaEntryBreakpointCommand.label=Toggle &Lambda Entry Breakpoint
+ToggleLambdaEntryBreakpointCommand.description=Creates or removes a lambda entry breakpoint  
 
 AddBookmark.label=Add Boo&kmark...
 AddBookmark.tooltip=Add Bookmark...
diff --git a/org.eclipse.jdt.debug.ui/plugin.xml b/org.eclipse.jdt.debug.ui/plugin.xml
index 6e88711..6b6594a 100644
--- a/org.eclipse.jdt.debug.ui/plugin.xml
+++ b/org.eclipse.jdt.debug.ui/plugin.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?eclipse version="3.0"?>
 <!--
-     Copyright (c) 2005, 2021 IBM Corporation and others.
+     Copyright (c) 2005, 2022 IBM Corporation and others.
 
      This program and the accompanying materials
      are made available under the terms of the Eclipse Public License 2.0
@@ -160,6 +160,16 @@
                id="org.eclipse.jdt.debug.ui.actions.ToggleTracepoint">
          </action>
          <action
+               definitionId="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint"
+               label="%ToggleLambdaEntryBreakpointAction.label"
+               icon="icons/full/obj16/brkp_obj.png"
+               disabledIcon="icons/full/obj16/brkpd_obj.png"
+               helpContextId="toggle_tracepoint_action_context"
+               class="org.eclipse.jdt.internal.debug.ui.actions.RetargetToggleLambdaEntryBreakpointAction"
+               menubarPath="org.eclipse.ui.run/lineBreakpointBeforeGroup"
+               id="org.eclipse.jdt.debug.ui.actions.ToggleLambdaEntryBreakpoint">
+         </action>
+         <action
 	           definitionId="org.eclipse.jdt.debug.ui.commands.AddClassPrepareBreakpoint"
                label="%classPrepareAction.label"
                icon="$nl$/icons/full/obj16/class_obj.png"
@@ -646,6 +656,22 @@
             objectClass="org.eclipse.jdt.debug.core.IJavaVariable"
             id="org.eclipse.jdt.debug.ui.FilteredJavaVariableActions">
          <filter
+               name="JavaVariableFilter"
+               value="isFieldVariable">
+         </filter>
+         <action
+               label="%openFieldDeclaration.label"
+               tooltip="%openFieldDeclaration.tooltip"
+               class="org.eclipse.jdt.internal.debug.ui.actions.OpenVariableDeclarationAction"
+               menubarPath="emptyNavigationGroup"
+               enablesFor="1"
+               id="org.eclipse.jdt.debug.ui.actions.OpenVariableDeclarationAction">
+         </action>
+      </objectContribution>
+      <objectContribution
+            objectClass="org.eclipse.jdt.debug.core.IJavaVariable"
+            id="org.eclipse.jdt.debug.ui.FilteredJavaVariableActions">
+         <filter
                name="PrimitiveVariableActionFilter"
                value="isPrimitive">
          </filter>
@@ -990,6 +1016,15 @@
                menubarPath="debug">
          </action>
          <action
+               class="org.eclipse.jdt.internal.debug.ui.actions.RulerToggleLambdaEntryBreakpointActionDelegate"
+               helpContextId="manage_breakpoint_action_context"
+               icon="icons/full/obj16/brkp_obj.png"
+               id="org.eclipse.jdt.debug.ui.actions.RulerToggleLambdaEntryBreakpointAction"
+               definitionId="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint"
+               label="%AddLambdaEntryBreakpoint.label"
+               menubarPath="debug">
+         </action>
+         <action
                label="%EnableBreakpoint.label"
                helpContextId="enable_disable_breakpoint_action_context"
                class="org.eclipse.debug.ui.actions.RulerEnableDisableBreakpointActionDelegate"
@@ -1034,6 +1069,15 @@
                menubarPath="debug">
          </action>
          <action
+               class="org.eclipse.jdt.internal.debug.ui.actions.RulerToggleLambdaEntryBreakpointActionDelegate"
+               helpContextId="manage_breakpoint_action_context"
+               icon="icons/full/obj16/brkp_obj.png"
+               id="org.eclipse.jdt.debug.ui.actions.RulerToggleLambdaEntryBreakpointAction"
+               definitionId="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint"
+               label="%AddLambdaEntryBreakpoint.label"
+               menubarPath="debug">
+         </action>
+         <action
                label="%EnableBreakpoint.label"
                helpContextId="enable_disable_breakpoint_action_context"
                class="org.eclipse.debug.ui.actions.RulerEnableDisableBreakpointActionDelegate"
@@ -2672,6 +2716,12 @@
             id="org.eclipse.jdt.debug.ui.commands.ToggleTracepoint">
       </command>
       <command
+            name="%ToggleLambdaEntryBreakpointCommand.label"
+            description="%ToggleLambdaEntryBreakpointCommand.description"
+            categoryId="org.eclipse.debug.ui.category.run"
+            id="org.eclipse.jdt.debug.ui.commands.ToggleLambdaEntryBreakpoint">
+      </command>
+      <command
             name="%ActionDefinition.addException.name"
             description="%ActionDefinition.addException.description"
             categoryId="org.eclipse.debug.ui.category.run"
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java
index 53a7b46..1bf6647 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/BreakpointMarkerUpdater.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2015 IBM Corporation and others.
+ * Copyright (c) 2006, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,6 +25,7 @@
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaPatternBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaStratumLineBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaWatchpoint;
@@ -67,6 +68,7 @@
  *
  * @since 3.3
  */
+@SuppressWarnings("deprecation")
 public class BreakpointMarkerUpdater implements IMarkerUpdater {
 
 	public BreakpointMarkerUpdater() {}
@@ -113,7 +115,22 @@
 			return false;
 		}
 		try {
-			ValidBreakpointLocationLocator loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset())+1, true, true);
+			ValidBreakpointLocationLocator loc;
+			if (breakpoint instanceof IJavaMethodBreakpoint && ((IJavaMethodBreakpoint) breakpoint).isEntry()) {
+				IMarker m = breakpoint.getMarker();
+				if (m != null) {
+					int charStart = m.getAttribute(IMarker.CHAR_START, -1);
+					int charEnd = m.getAttribute(IMarker.CHAR_END, -1);
+					int length = charEnd - charStart + 1;
+					loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset())
+							+ 1, true, true, position.getOffset(), length);
+
+				} else {
+					loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset()) + 1, true, true);
+				}
+			} else {
+				loc = new ValidBreakpointLocationLocator(unit, document.getLineOfOffset(position.getOffset()) + 1, true, true);
+			}
 			unit.accept(loc);
 			if(loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_NOT_FOUND) {
 				return false;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/CreateStepFilterDialog.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/CreateStepFilterDialog.java
deleted file mode 100644
index 03e069c..0000000
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/CreateStepFilterDialog.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2004, 2015 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.jdt.internal.debug.ui;
-
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.dialogs.IDialogSettings;
-import org.eclipse.jface.dialogs.StatusDialog;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Text;
-
-public class CreateStepFilterDialog extends StatusDialog {
-
-	private static final String DEFAULT_NEW_FILTER_TEXT = ""; //$NON-NLS-1$
-
-	private Text text;
-	private Filter filter;
-	private Button okButton;
-
-	private boolean filterValid;
-	private boolean okClicked;
-	private Filter[] existingFilters;
-
-	private CreateStepFilterDialog(Shell parent, Filter filter, Filter[] existingFilters) {
-		super(parent);
-		setShellStyle(getShellStyle() | SWT.RESIZE);
-		this.filter = filter;
-		this.existingFilters = existingFilters;
-
-		setTitle(DebugUIMessages.CreateStepFilterDialog_2);
-		setStatusLineAboveButtons(false);
-
-	}
-
-	static Filter showCreateStepFilterDialog(Shell parent, Filter[] existingFilters) {
-		CreateStepFilterDialog createStepFilterDialog = new CreateStepFilterDialog(parent, new Filter(DEFAULT_NEW_FILTER_TEXT, true), existingFilters);
-		createStepFilterDialog.create();
-		createStepFilterDialog.open();
-
-		return createStepFilterDialog.filter;
-	}
-
-	@Override
-	protected void createButtonsForButtonBar(Composite parent) {
-		okButton= createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
-		okButton.setEnabled(false);
-		createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
-	}
-
-	@Override
-	protected Control createDialogArea(Composite parent) {
-		Composite container = (Composite)super.createDialogArea(parent);
-
-		GridLayout gridLayout = new GridLayout();
-		gridLayout.numColumns = 2;
-		gridLayout.marginHeight = 15;
-		gridLayout.marginWidth = 15;
-		container.setLayout(gridLayout);
-
-		int textStyles = SWT.SINGLE | SWT.LEFT;
-		Label label= new Label(container, textStyles);
-		label.setText(DebugUIMessages.CreateStepFilterDialog_3);
-		label.setFont(container.getFont());
-
-		// create & configure Text widget for editor
-		// Fix for bug 1766.  Border behavior on for text fields varies per platform.
-		// On Motif, you always get a border, on other platforms,
-		// you don't.  Specifying a border on Motif results in the characters
-		// getting pushed down so that only there very tops are visible.  Thus,
-		// we have to specify different style constants for the different platforms.
-		if (!SWT.getPlatform().equals("motif")) {  //$NON-NLS-1$
-			textStyles |= SWT.BORDER;
-		}
-
-		text = new Text(container, textStyles);
-		GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
-		gridData.horizontalSpan=1;
-		gridData.widthHint = 300;
-		text.setLayoutData(gridData);
-		text.setFont(container.getFont());
-
-		text.addModifyListener(new ModifyListener() {
-			@Override
-			public void modifyText(ModifyEvent e) {
-				validateChange();
-				if (!filterValid) {
-					updateStatus(new StatusInfo(IStatus.ERROR, DebugUIMessages.CreateStepFilterDialog_4));
-				} else if (isDuplicateFilter(text.getText().trim())) {
-					updateStatus(new StatusInfo(IStatus.WARNING, DebugUIMessages.CreateStepFilterDialog_5));
-					return;
-				} else {
-					updateStatus(new StatusInfo());
-				}
-			}
-		});
-
-		return container;
-	}
-
-	private void validateChange() {
-		String trimmedValue = text.getText().trim();
-
-		if (trimmedValue.length()>0 && validateInput(trimmedValue)) {
-			okButton.setEnabled(true);
-			filter.setName(text.getText());
-			filterValid = true;
-		} else {
-			okButton.setEnabled(false);
-			filter.setName(DEFAULT_NEW_FILTER_TEXT);
-			filterValid = false;
-		}
-	}
-
-	private boolean isDuplicateFilter(String trimmedValue) {
-		for (Filter existingFilter : existingFilters) {
-			if (existingFilter.getName().equals(trimmedValue)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	/**
-	 * A valid step filter is simply one that is a valid Java identifier.
-	 * and, as defined in the JDI spec, the regular expressions used for
-	 * step filtering must be limited to exact matches or patterns that
-	 * begin with '*' or end with '*'. Beyond this, a string cannot be validated
-	 * as corresponding to an existing type or package (and this is probably not
-	 * even desirable).
-	 */
-	private boolean validateInput(String trimmedValue) {
-		char firstChar= trimmedValue.charAt(0);
-		if (!Character.isJavaIdentifierStart(firstChar)) {
-			if (!(firstChar == '*')) {
-				return false;
-			}
-		}
-		int length= trimmedValue.length();
-		for (int i= 1; i < length; i++) {
-			char c= trimmedValue.charAt(i);
-			if (!Character.isJavaIdentifierPart(c)) {
-				if (c == '.' && i != (length - 1)) {
-					continue;
-				}
-				if (c == '*' && i == (length - 1)) {
-					continue;
-				}
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Returns the name of the section that this dialog stores its settings in
-	 *
-	 * @return String
-	 */
-	protected String getDialogSettingsSectionName() {
-		return IJavaDebugUIConstants.PLUGIN_ID + ".CREATE_STEP_FILTER_DIALOG_SECTION"; //$NON-NLS-1$
-	}
-
-	/* (non-Javadoc)
-	 * @see org.eclipse.jface.window.Window#close()
-	 */
-	@Override
-	public boolean close() {
-		if (!okClicked) {
-			filterValid = false;
-			filter = null;
-		}
-		return super.close();
-	}
-
-	 /* (non-Javadoc)
-     * @see org.eclipse.jface.dialogs.Dialog#getDialogBoundsSettings()
-     */
-    @Override
-	protected IDialogSettings getDialogBoundsSettings() {
-    	 IDialogSettings settings = JDIDebugUIPlugin.getDefault().getDialogSettings();
-         IDialogSettings section = settings.getSection(getDialogSettingsSectionName());
-         if (section == null) {
-             section = settings.addNewSection(getDialogSettingsSectionName());
-         }
-         return section;
-    }
-
-	@Override
-	protected void okPressed() {
-		okClicked = true;
-		super.okPressed();
-	}
-}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
index 13966b0..c4392c0 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
@@ -84,6 +84,7 @@
 	public static String JavaDebugPreferencePage_19;
 	public static String JavaDebugPreferencePage_0;
 	public static String JavaDebugPreferencePage_20;
+	public static String JavaDebugPreferencePage_28;
 
 	public static String JavaDebugPreferencePage_advancedSourcelookup;
 	public static String JavaDebugPreferencePage_listenToThreadNameChanges;
@@ -257,6 +258,10 @@
 	public static String NoLineNumberAttributesStatusHandler_Java_Breakpoint_1;
 	public static String NoLineNumberAttributesStatusHandler_2;
 
+	public static String JavaVariableValueEditor_prompt_before_final_value_change_title;
+	public static String JavaVariableValueEditor_prompt_before_final_value_change_message;
+	public static String JavaVariableValueEditor_prompt_before_final_value_change_toggle_message;
+
 	public static String JavaDetailFormattersPreferencePage_Add__Formatter____5;
 	public static String JavaDetailFormattersPreferencePage_Allow_you_to_create_a_new_detail_formatter_6;
 	public static String JavaDetailFormattersPreferencePage__Remove_7;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
index 997b505..19af002 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2019 IBM Corporation and others.
+# Copyright (c) 2000, 2022 IBM Corporation and others.
 #
 # This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
@@ -205,6 +205,11 @@
 NoLineNumberAttributesStatusHandler_Java_Breakpoint_1=Java Breakpoint
 NoLineNumberAttributesStatusHandler_2=Unable to install breakpoint in {0} due to missing line number attributes. Modify compiler options to generate line number attributes.
 
+JavaVariableValueEditor_prompt_before_final_value_change_title=Change final value?
+JavaVariableValueEditor_prompt_before_final_value_change_message=Changing final values could break the application you are currently debugging.\
+\n\nContinue with change?
+JavaVariableValueEditor_prompt_before_final_value_change_toggle_message=Don't show this dialog again
+
 JavaDetailFormattersPreferencePage_Add__Formatter____5=Ad&d...
 JavaDetailFormattersPreferencePage_Allow_you_to_create_a_new_detail_formatter_6=Allow you to create a new detail formatter
 JavaDetailFormattersPreferencePage__Remove_7=&Remove
@@ -324,6 +329,7 @@
 JavaDebugPreferencePage_25=Access & Modification
 JavaDebugPreferencePage_26=Access
 JavaDebugPreferencePage_27=Modification
+JavaDebugPreferencePage_28=Warn before modifyin&g final fields
 JavaDebugPreferencePage_SuspendOnRecurrencePolicy=Suspend policy for rec&urring exception instances:
 JavaDebugPreferencePage_SuspendOnRecurrencePolicy_Always=Always
 JavaDebugPreferencePage_SuspendOnRecurrencePolicy_Unconfigured=Unconfigured
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/Filter.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/Filter.java
deleted file mode 100644
index 0cd72c9..0000000
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/Filter.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.debug.ui;
-
-
-/**
- * Model object that represents a single entry in a filter table.
- */
-public class Filter {
-
-	private String fName;
-	private boolean fChecked;
-
-	public Filter(String name, boolean checked) {
-		setName(name);
-		setChecked(checked);
-	}
-
-	public String getName() {
-		return fName;
-	}
-
-	public void setName(String name) {
-		fName = name;
-	}
-
-	public boolean isChecked() {
-		return fChecked;
-	}
-
-	public void setChecked(boolean checked) {
-		fChecked = checked;
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (o instanceof Filter) {
-			Filter other = (Filter) o;
-			if (getName().equals(other.getName())) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	@Override
-	public int hashCode() {
-		return getName().hashCode();
-	}
-}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/FilterLabelProvider.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/FilterLabelProvider.java
deleted file mode 100644
index 28fa4d7..0000000
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/FilterLabelProvider.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.debug.ui;
-
-
-import org.eclipse.jdt.ui.ISharedImages;
-import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.swt.graphics.Image;
-
-/**
- * Label provider for Filter model objects
- */
-public class FilterLabelProvider extends LabelProvider implements ITableLabelProvider {
-
-	private static final Image IMG_CUNIT =
-		JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_CLASS);
-	private static final Image IMG_PKG =
-		JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_PACKAGE);
-
-	/**
-	 * @see ITableLabelProvider#getColumnText(Object, int)
-	 */
-	@Override
-	public String getColumnText(Object object, int column) {
-		if (column == 0) {
-			return ((Filter) object).getName();
-		}
-		return ""; //$NON-NLS-1$
-	}
-
-	/**
-	 * @see ILabelProvider#getText(Object)
-	 */
-	@Override
-	public String getText(Object element) {
-		return ((Filter) element).getName();
-	}
-
-	/**
-	 * @see ITableLabelProvider#getColumnImage(Object, int)
-	 */
-	@Override
-	public Image getColumnImage(Object object, int column) {
-		String name = ((Filter) object).getName();
-		if (name.endsWith("*") || name.equals("(default package)")) { //$NON-NLS-1$ //$NON-NLS-2$
-			return IMG_PKG;
-		}
-		return IMG_CUNIT;
-	}
-}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/FilterViewerComparator.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/FilterViewerComparator.java
deleted file mode 100644
index dbb4380..0000000
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/FilterViewerComparator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
- *
- * This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License 2.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *
- * Contributors:
- *     IBM Corporation - initial API and implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.debug.ui;
-
-import org.eclipse.jface.viewers.ContentViewer;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.ui.model.WorkbenchViewerComparator;
-
-public class FilterViewerComparator extends WorkbenchViewerComparator {
-	@Override
-	public int compare(Viewer viewer, Object e1, Object e2) {
-		ILabelProvider lprov =
-			(ILabelProvider) ((ContentViewer) viewer).getLabelProvider();
-		String name1 = lprov.getText(e1);
-		String name2 = lprov.getText(e2);
-		if (name1 == null) {
-			name1 = ""; //$NON-NLS-1$
-		}
-		if (name2 == null) {
-			name2 = ""; //$NON-NLS-1$
-		}
-		if (name1.length() > 0 && name2.length() > 0) {
-			char char1 = name1.charAt(name1.length() - 1);
-			char char2 = name2.charAt(name2.length() - 1);
-			if (char1 == '*' && char1 != char2) {
-				return -1;
-			}
-			if (char2 == '*' && char2 != char1) {
-				return 1;
-			}
-		}
-		return name1.compareTo(name2);
-	}
-}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/IJDIPreferencesConstants.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/IJDIPreferencesConstants.java
index 3b525ff..6f0af1f 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/IJDIPreferencesConstants.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/IJDIPreferencesConstants.java
@@ -213,6 +213,8 @@
 	 */
 	public static final String PREF_ALERT_UNABLE_TO_INSTALL_BREAKPOINT = IJavaDebugUIConstants.PLUGIN_ID + ".prompt_unable_to_install_breakpoint"; //$NON-NLS-1$
 
+	public static final String PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS = IJavaDebugUIConstants.PLUGIN_ID + ".prompt_before_modifying_final_fields"; //$NON-NLS-1$
+
 	public static final String PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR= "org.eclipse.jdt.debug.ui.InDeadlockColor"; //$NON-NLS-1$
 
 	public static final String PREF_LABELED_OBJECT_COLOR = IJavaDebugUIConstants.PLUGIN_ID + ".LabeledObject"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java
index 7f24377..b5963e4 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java
@@ -36,6 +36,7 @@
 		store.setDefault(IJDIPreferencesConstants.PREF_ALERT_HCR_NOT_SUPPORTED, true);
 		store.setDefault(IJDIPreferencesConstants.PREF_ALERT_OBSOLETE_METHODS, true);
 		store.setDefault(IJDIPreferencesConstants.PREF_ALERT_UNABLE_TO_INSTALL_BREAKPOINT, true);
+		store.setDefault(IJDIPreferencesConstants.PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS, true);
 		store.setDefault(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT, true);
 
 		store.setDefault(IJDIPreferencesConstants.PREF_SHOW_QUALIFIED_NAMES, false);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
index 7bed684..18503d4 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
@@ -2119,36 +2119,55 @@
 	 */
 	@Override
 	public Color getForeground(Object element) {
-		if (element instanceof IJavaVariable) {
+		if (element instanceof IJavaObject) {
 			try {
-				var variable = ((IJavaVariable) element).getValue();
-				if (variable instanceof IJavaObject) {
-					var label = ((IJavaObject) variable).getLabel();
-					if (label != null) {
-						return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(IJDIPreferencesConstants.PREF_LABELED_OBJECT_COLOR);
-					}
+				var label = ((IJavaObject) element).getLabel();
+				if (label != null) {
+					return getColorFromRegistry(IJDIPreferencesConstants.PREF_LABELED_OBJECT_COLOR);
 				}
+				return null;
 			} catch (DebugException e) {
 			}
 		}
+		if (element instanceof IJavaVariable) {
+			try {
+				return getForeground(((IJavaVariable) element).getValue());
+			} catch (DebugException e) {
+			}
+		}
+		if (element instanceof IWatchExpression) {
+			var watchValue = ((IWatchExpression) element).getValue();
+			return getForeground(watchValue);
+		}
+		if (element instanceof JavaInspectExpression) {
+			var value = ((JavaInspectExpression) element).getValue();
+			return getForeground(value);
+		}
 		if (element instanceof JavaContendedMonitor && ((JavaContendedMonitor) element).getMonitor().isInDeadlock()) {
-			return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
+			return getColorFromRegistry(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
 		}
 		if (element instanceof JavaOwnedMonitor && ((JavaOwnedMonitor)element).getMonitor().isInDeadlock()) {
-			return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
+			return getColorFromRegistry(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
 		}
 		if (element instanceof JavaWaitingThread && ((JavaWaitingThread)element).getThread().isInDeadlock()) {
-			return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
+			return getColorFromRegistry(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
 		}
 		if (element instanceof JavaOwningThread && ((JavaOwningThread)element).getThread().isInDeadlock()) {
-			return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
+			return getColorFromRegistry(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
 		}
 		if (element instanceof IJavaThread && ThreadMonitorManager.getDefault().isInDeadlock((IJavaThread)element)) {
-			return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
+			return getColorFromRegistry(IJDIPreferencesConstants.PREF_THREAD_MONITOR_IN_DEADLOCK_COLOR);
 		}
 		return null;
 	}
 
+	/**
+	 * Visible for testing.
+	 */
+	protected Color getColorFromRegistry(String symbolicName) {
+		return PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get(symbolicName);
+	}
+
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object)
 	 */
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
index a6e14ce..18f9a25 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
@@ -84,6 +84,7 @@
 	private Button fSuspendDuringEvaluations;
 	private Button fOpenInspector;
 	private Button fPromptUnableToInstallBreakpoint;
+	private Button fPromptBeforeModifyingFinalFields;
 	private Button fPromptDeleteConditionalBreakpoint;
 	private Button fFilterUnrelatedBreakpoints;
 	private Button fOnlyIncludeExportedEntries;
@@ -181,6 +182,7 @@
 		fConnectionTimeoutText.load();
 
 		SWTFactory.createVerticalSpacer(composite, 1);
+		fPromptBeforeModifyingFinalFields = SWTFactory.createCheckButton(composite, DebugUIMessages.JavaDebugPreferencePage_28, null, false, 1);
 		fPromptUnableToInstallBreakpoint = SWTFactory.createCheckButton(composite, DebugUIMessages.JavaDebugPreferencePage_19, null, false, 1);
 		fPromptDeleteConditionalBreakpoint= SWTFactory.createCheckButton(composite, DebugUIMessages.JavaDebugPreferencePage_promptWhenDeletingCondidtionalBreakpoint, null, false, 1);
 		fFilterUnrelatedBreakpoints = SWTFactory.createCheckButton(composite, DebugUIMessages.JavaDebugPreferencePage_filterUnrelatedBreakpoints, null, false, 1);
@@ -225,6 +227,7 @@
 		store.setValue(IJDIPreferencesConstants.PREF_ALERT_OBSOLETE_METHODS, fAlertObsoleteButton.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS, fSuspendButton.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_SUSPEND_ON_COMPILATION_ERRORS, fSuspendOnCompilationErrors.getSelection());
+		store.setValue(IJDIPreferencesConstants.PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS, fPromptBeforeModifyingFinalFields.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_ALERT_UNABLE_TO_INSTALL_BREAKPOINT, fPromptUnableToInstallBreakpoint.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT, fPromptDeleteConditionalBreakpoint.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION, fOpenInspector.getSelection());
@@ -277,6 +280,7 @@
 		fAlertHCRButton.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_ALERT_HCR_FAILED));
 		fAlertHCRNotSupportedButton.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_ALERT_HCR_NOT_SUPPORTED));
 		fAlertObsoleteButton.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_ALERT_OBSOLETE_METHODS));
+		fPromptBeforeModifyingFinalFields.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS));
 		fPromptUnableToInstallBreakpoint.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_ALERT_UNABLE_TO_INSTALL_BREAKPOINT));
 		fPromptDeleteConditionalBreakpoint.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT));
 		fOpenInspector.setSelection(store.getDefaultBoolean(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION));
@@ -317,6 +321,7 @@
 		fAlertHCRButton.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_ALERT_HCR_FAILED));
 		fAlertHCRNotSupportedButton.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_ALERT_HCR_NOT_SUPPORTED));
 		fAlertObsoleteButton.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_ALERT_OBSOLETE_METHODS));
+		fPromptBeforeModifyingFinalFields.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS));
 		fPromptUnableToInstallBreakpoint.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_ALERT_UNABLE_TO_INSTALL_BREAKPOINT));
 		fPromptDeleteConditionalBreakpoint.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT));
 		fOpenInspector.setSelection(store.getBoolean(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION));
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaStepFilterPreferencePage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaStepFilterPreferencePage.java
index 3133c29..85d4048 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaStepFilterPreferencePage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaStepFilterPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -14,47 +14,24 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.debug.ui;
 
-import java.util.ArrayList;
-
 import org.eclipse.debug.internal.ui.SWTFactory;
 import org.eclipse.debug.ui.DebugUITools;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.search.SearchEngine;
-import org.eclipse.jdt.ui.IJavaElementSearchConstants;
-import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jdt.internal.ui.filtertable.FilterManager;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.ButtonLabel;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.DialogLabels;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterTableConfig;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferencePage;
-import org.eclipse.jface.viewers.CheckStateChangedEvent;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
-import org.eclipse.jface.viewers.ICheckStateListener;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.TableItem;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.dialogs.ElementListSelectionDialog;
-import org.eclipse.ui.dialogs.SelectionDialog;
 
 /**
  * The preference page for Java step filtering, located at the node Java > Debug > Step Filtering
@@ -64,41 +41,17 @@
 public class JavaStepFilterPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
 
 	public static final String PAGE_ID = "org.eclipse.jdt.debug.ui.JavaStepFilterPreferencePage"; //$NON-NLS-1$
-
-	/**
-	 * Content provider for the table.  Content consists of instances of StepFilter.
-	 * @since 3.2
-	 */
-	class StepFilterContentProvider implements IStructuredContentProvider {
-		public StepFilterContentProvider() {
-			initTableState(false);
-		}
-
-		@Override
-		public Object[] getElements(Object inputElement) {return getAllFiltersFromTable();}
-
-		@Override
-		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
-
-		@Override
-		public void dispose() {}
-	}
+	private final static FilterManager STEP_FILTERS = new FilterManager(IJDIPreferencesConstants.PREF_ACTIVE_FILTERS_LIST, IJDIPreferencesConstants.PREF_INACTIVE_FILTERS_LIST);
 
 	//widgets
-	private CheckboxTableViewer fTableViewer;
+	private JavaFilterTable fStepFilterTable;
 	private Button fUseStepFiltersButton;
-	private Button fAddPackageButton;
-	private Button fAddTypeButton;
-	private Button fRemoveFilterButton;
-	private Button fAddFilterButton;
 	private Button fFilterSyntheticButton;
 	private Button fFilterStaticButton;
 	private Button fFilterGetterButton;
 	private Button fFilterSetterButton;
 	private Button fFilterConstructorButton;
 	private Button fStepThruButton;
-	private Button fSelectAllButton;
-	private Button fDeselectAllButton;
 
 	/**
 	 * Constructor
@@ -129,16 +82,6 @@
 	public void init(IWorkbench workbench) {}
 
 	/**
-	 * handles the filter button being clicked
-	 * @param event the clicked event
-	 */
-	private void handleFilterViewerKeyPress(KeyEvent event) {
-		if (event.character == SWT.DEL && event.stateMask == 0) {
-			removeFilters();
-		}
-	}
-
-	/**
 	 * Create a group to contain the step filter related widgetry
 	 */
 	private void createStepFilterPreferences(Composite parent) {
@@ -153,57 +96,30 @@
 				public void widgetDefaultSelected(SelectionEvent e) {}
 			}
 		);
-		SWTFactory.createLabel(container, DebugUIMessages.JavaStepFilterPreferencePage_Defined_step_fi_lters__8, 2);
-		fTableViewer = CheckboxTableViewer.newCheckList(container, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
-		fTableViewer.getTable().setFont(container.getFont());
-		fTableViewer.setLabelProvider(new FilterLabelProvider());
-		fTableViewer.setComparator(new FilterViewerComparator());
-		fTableViewer.setContentProvider(new StepFilterContentProvider());
-		fTableViewer.setInput(getAllStoredFilters(false));
-		fTableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
-		fTableViewer.addCheckStateListener(new ICheckStateListener() {
-			@Override
-			public void checkStateChanged(CheckStateChangedEvent event) {
-				((Filter)event.getElement()).setChecked(event.getChecked());
-			}
-		});
-		fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-			@Override
-			public void selectionChanged(SelectionChangedEvent event) {
-				ISelection selection = event.getSelection();
-				if (selection.isEmpty()) {
-					fRemoveFilterButton.setEnabled(false);
-				} else {
-					fRemoveFilterButton.setEnabled(true);
-				}
-			}
-		});
-		fTableViewer.getControl().addKeyListener(new KeyAdapter() {
-			@Override
-			public void keyPressed(KeyEvent event) {
-				handleFilterViewerKeyPress(event);
-			}
-		});
+		initializeDialogUnits(container);
 
-		createStepFilterButtons(container);
+		this.fStepFilterTable = new JavaFilterTable(this, STEP_FILTERS,
+				new FilterTableConfig()
+				.setAddFilter(new ButtonLabel(DebugUIMessages.JavaStepFilterPreferencePage_Add__Filter_9, DebugUIMessages.JavaStepFilterPreferencePage_Key_in_the_name_of_a_new_step_filter_10))
+				.setAddType(new ButtonLabel(DebugUIMessages.JavaStepFilterPreferencePage_Add__Type____11, DebugUIMessages.JavaStepFilterPreferencePage_Choose_a_Java_type_and_add_it_to_step_filters_12))
+				.setAddPackage(new ButtonLabel(DebugUIMessages.JavaStepFilterPreferencePage_Add__Package____13, DebugUIMessages.JavaStepFilterPreferencePage_Choose_a_package_and_add_it_to_step_filters_14))
+				.setRemove(new ButtonLabel(DebugUIMessages.JavaStepFilterPreferencePage__Remove_15, DebugUIMessages.JavaStepFilterPreferencePage_Remove_all_selected_step_filters_16))
+				.setSelectAll(new ButtonLabel(DebugUIMessages.JavaStepFilterPreferencePage__Select_All_1, DebugUIMessages.JavaStepFilterPreferencePage_Selects_all_step_filters_2))
+				.setDeselectAll(new ButtonLabel(DebugUIMessages.JavaStepFilterPreferencePage_Deselect_All_3, DebugUIMessages.JavaStepFilterPreferencePage_Deselects_all_step_filters_4))
+				.setAddTypeDialog(new DialogLabels(DebugUIMessages.JavaStepFilterPreferencePage_Add_type_to_step_filters_20, DebugUIMessages.JavaStepFilterPreferencePage_Select_a_type_to_filter_when_stepping_23))
+				.setErrorAddTypeDialog(new DialogLabels(DebugUIMessages.JavaStepFilterPreferencePage_Add_type_to_step_filters_20, DebugUIMessages.JavaStepFilterPreferencePage_Could_not_open_type_selection_dialog_for_step_filters_21))
+				.setAddPackageDialog(new DialogLabels(DebugUIMessages.JavaStepFilterPreferencePage_Add_package_to_step_filters_24, DebugUIMessages.JavaStepFilterPreferencePage_Select_a_package_to_filter_when_stepping_27))
+				.setLabelText(DebugUIMessages.JavaStepFilterPreferencePage_Defined_step_fi_lters__8)
+				.setHelpContextId(IJavaDebugHelpContextIds.JAVA_STEP_FILTER_PREFERENCE_PAGE));
+
+		fStepFilterTable.createTable(container);
+
 		createStepFilterCheckboxes(container);
 
 		setPageEnablement(fUseStepFiltersButton.getSelection());
 	}
 
 	/**
-	 * initializes the checked state of the filters when the dialog opens
-	 * @since 3.2
-	 */
-	private void initTableState(boolean defaults) {
-		Filter[] filters = getAllStoredFilters(defaults);
-		for(int i = 0; i < filters.length; i++) {
-			fTableViewer.add(filters[i]);
-			fTableViewer.setChecked(filters[i], filters[i].isChecked());
-		}
-	}
-
-	/**
 	 * Enables or disables the widgets on the page, with the
 	 * exception of <code>fUseStepFiltersButton</code> according
 	 * to the passed boolean
@@ -211,19 +127,13 @@
 	 * @since 3.2
 	 */
 	protected void setPageEnablement(boolean enabled) {
-		fAddFilterButton.setEnabled(enabled);
-		fAddPackageButton.setEnabled(enabled);
-		fAddTypeButton.setEnabled(enabled);
-		fDeselectAllButton.setEnabled(enabled);
-		fSelectAllButton.setEnabled(enabled);
 		fFilterConstructorButton.setEnabled(enabled);
 		fStepThruButton.setEnabled(enabled);
 		fFilterGetterButton.setEnabled(enabled);
 		fFilterSetterButton.setEnabled(enabled);
 		fFilterStaticButton.setEnabled(enabled);
 		fFilterSyntheticButton.setEnabled(enabled);
-		fTableViewer.getTable().setEnabled(enabled);
-		fRemoveFilterButton.setEnabled(enabled & !fTableViewer.getSelection().isEmpty());
+		fStepFilterTable.setEnabled(enabled);
 	}
 
 	/**
@@ -251,168 +161,6 @@
 				null, getPreferenceStore().getBoolean(IJDIPreferencesConstants.PREF_STEP_THRU_FILTERS), 2);
 	}
 
-	/**
-	 * Creates the button for the step filter options
-	 * @param container the parent container
-	 */
-	private void createStepFilterButtons(Composite container) {
-		initializeDialogUnits(container);
-		// button container
-		Composite buttonContainer = new Composite(container, SWT.NONE);
-		GridData gd = new GridData(GridData.FILL_VERTICAL);
-		buttonContainer.setLayoutData(gd);
-		GridLayout buttonLayout = new GridLayout();
-		buttonLayout.numColumns = 1;
-		buttonLayout.marginHeight = 0;
-		buttonLayout.marginWidth = 0;
-		buttonContainer.setLayout(buttonLayout);
-	//Add filter button
-		fAddFilterButton = SWTFactory.createPushButton(buttonContainer,
-				DebugUIMessages.JavaStepFilterPreferencePage_Add__Filter_9,
-				DebugUIMessages.JavaStepFilterPreferencePage_Key_in_the_name_of_a_new_step_filter_10, null);
-		fAddFilterButton.addListener(SWT.Selection, new Listener() {
-			@Override
-			public void handleEvent(Event e) {
-				addFilter();
-			}
-		});
-	//Add type button
-		fAddTypeButton = SWTFactory.createPushButton(buttonContainer,
-				DebugUIMessages.JavaStepFilterPreferencePage_Add__Type____11,
-				DebugUIMessages.JavaStepFilterPreferencePage_Choose_a_Java_type_and_add_it_to_step_filters_12, null);
-		fAddTypeButton.addListener(SWT.Selection, new Listener() {
-			@Override
-			public void handleEvent(Event e) {
-				addType();
-			}
-		});
-	//Add package button
-		fAddPackageButton = SWTFactory.createPushButton(buttonContainer,
-				DebugUIMessages.JavaStepFilterPreferencePage_Add__Package____13,
-				DebugUIMessages.JavaStepFilterPreferencePage_Choose_a_package_and_add_it_to_step_filters_14, null);
-		fAddPackageButton.addListener(SWT.Selection, new Listener() {
-			@Override
-			public void handleEvent(Event e) {
-				addPackage();
-			}
-		});
-	//Remove button
-		fRemoveFilterButton = SWTFactory.createPushButton(buttonContainer,
-				DebugUIMessages.JavaStepFilterPreferencePage__Remove_15,
-				DebugUIMessages.JavaStepFilterPreferencePage_Remove_all_selected_step_filters_16,
-				null);
-		fRemoveFilterButton.addListener(SWT.Selection, new Listener() {
-			@Override
-			public void handleEvent(Event e) {
-				removeFilters();
-			}
-		});
-		fRemoveFilterButton.setEnabled(false);
-
-		Label separator= new Label(buttonContainer, SWT.NONE);
-		separator.setVisible(false);
-		gd = new GridData();
-		gd.horizontalAlignment= GridData.FILL;
-		gd.verticalAlignment= GridData.BEGINNING;
-		gd.heightHint= 4;
-		separator.setLayoutData(gd);
-	//Select All button
-		fSelectAllButton = SWTFactory.createPushButton(buttonContainer,
-				DebugUIMessages.JavaStepFilterPreferencePage__Select_All_1,
-				DebugUIMessages.JavaStepFilterPreferencePage_Selects_all_step_filters_2, null);
-		fSelectAllButton.addListener(SWT.Selection, new Listener() {
-			@Override
-			public void handleEvent(Event e) {
-				fTableViewer.setAllChecked(true);
-			}
-		});
-	//De-Select All button
-		fDeselectAllButton = SWTFactory.createPushButton(buttonContainer,
-				DebugUIMessages.JavaStepFilterPreferencePage_Deselect_All_3,
-				DebugUIMessages.JavaStepFilterPreferencePage_Deselects_all_step_filters_4, null);
-		fDeselectAllButton.addListener(SWT.Selection, new Listener() {
-			@Override
-			public void handleEvent(Event e) {
-				fTableViewer.setAllChecked(false);
-			}
-		});
-
-	}
-
-	/**
-	 * Allows a new filter to be added to the listing
-	 */
-	private void addFilter() {
-		Filter newfilter = CreateStepFilterDialog.showCreateStepFilterDialog(getShell(), getAllFiltersFromTable());
-		if (newfilter != null) {
-			fTableViewer.add(newfilter);
-			fTableViewer.setChecked(newfilter, true);
-			fTableViewer.refresh(newfilter);
-		}
-	}
-
-	/**
-	 * add a new type to the listing of available filters
-	 */
-	private void addType() {
-		try {
-			SelectionDialog dialog = JavaUI.createTypeDialog(getShell(),
-				PlatformUI.getWorkbench().getProgressService(),
-				SearchEngine.createWorkspaceScope(),
-				IJavaElementSearchConstants.CONSIDER_CLASSES,
-				false);
-			dialog.setTitle(DebugUIMessages.JavaStepFilterPreferencePage_Add_type_to_step_filters_20);
-			dialog.setMessage(DebugUIMessages.JavaStepFilterPreferencePage_Select_a_type_to_filter_when_stepping_23);
-			if (dialog.open() == IDialogConstants.OK_ID) {
-				Object[] types = dialog.getResult();
-				if (types != null && types.length > 0) {
-					IType type = (IType)types[0];
-					addFilter(type.getFullyQualifiedName(), true);
-				}
-			}
-		}
-		catch (JavaModelException jme) {
-			ExceptionHandler.handle(jme,
-					DebugUIMessages.JavaStepFilterPreferencePage_Add_type_to_step_filters_20,
-					DebugUIMessages.JavaStepFilterPreferencePage_Could_not_open_type_selection_dialog_for_step_filters_21);
-		}
-	}
-
-	/**
-	 * add a new package to the list of all available package filters
-	 */
-	private void addPackage() {
-		try {
-			ElementListSelectionDialog dialog = JDIDebugUIPlugin.createAllPackagesDialog(getShell(), null, false);
-			dialog.setTitle(DebugUIMessages.JavaStepFilterPreferencePage_Add_package_to_step_filters_24);
-			dialog.setMessage(DebugUIMessages.JavaStepFilterPreferencePage_Select_a_package_to_filter_when_stepping_27);
-			dialog.setMultipleSelection(true);
-			if (dialog.open() == IDialogConstants.OK_ID) {
-				Object[] packages = dialog.getResult();
-				if (packages != null) {
-					IJavaElement pkg = null;
-					for (int i = 0; i < packages.length; i++) {
-						pkg = (IJavaElement)packages[i];
-						String filter = pkg.getElementName() + ".*"; //$NON-NLS-1$
-						addFilter(filter, true);
-					}
-				}
-			}
-
-		}
-		catch (JavaModelException jme) {
-			ExceptionHandler.handle(jme,
-					DebugUIMessages.JavaStepFilterPreferencePage_Add_package_to_step_filters_24,
-					DebugUIMessages.JavaStepFilterPreferencePage_Could_not_open_package_selection_dialog_for_step_filters_25);
-		}
-	}
-
-	/**
-	 * Removes the currently selected filters.
-	 */
-	protected void removeFilters() {
-		fTableViewer.remove(((IStructuredSelection)fTableViewer.getSelection()).toArray());
-	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.jface.preference.PreferencePage#performOk()
@@ -421,23 +169,7 @@
 	public boolean performOk() {
 		DebugUITools.setUseStepFilters(fUseStepFiltersButton.getSelection());
 		IPreferenceStore store = getPreferenceStore();
-		ArrayList<String> active = new ArrayList<>();
-		ArrayList<String> inactive = new ArrayList<>();
-		String name = ""; //$NON-NLS-1$
-		Filter[] filters = getAllFiltersFromTable();
-		for(int i = 0; i < filters.length; i++) {
-			name = filters[i].getName();
-			if(filters[i].isChecked()) {
-				active.add(name);
-			}
-			else {
-				inactive.add(name);
-			}
-		}
-		String pref = JavaDebugOptionsManager.serializeList(active.toArray(new String[active.size()]));
-		store.setValue(IJDIPreferencesConstants.PREF_ACTIVE_FILTERS_LIST, pref);
-		pref = JavaDebugOptionsManager.serializeList(inactive.toArray(new String[inactive.size()]));
-		store.setValue(IJDIPreferencesConstants.PREF_INACTIVE_FILTERS_LIST, pref);
+		fStepFilterTable.performOk(store);
 		store.setValue(IJDIPreferencesConstants.PREF_FILTER_CONSTRUCTORS, fFilterConstructorButton.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_FILTER_STATIC_INITIALIZERS, fFilterStaticButton.getSelection());
 		store.setValue(IJDIPreferencesConstants.PREF_FILTER_GETTERS, fFilterGetterButton.getSelection());
@@ -462,64 +194,8 @@
 		fFilterSetterButton.setSelection(getPreferenceStore().getDefaultBoolean(IJDIPreferencesConstants.PREF_FILTER_SETTERS));
 		fStepThruButton.setSelection(getPreferenceStore().getDefaultBoolean(IJDIPreferencesConstants.PREF_STEP_THRU_FILTERS));
 
-		fTableViewer.getTable().removeAll();
-		initTableState(true);
+		fStepFilterTable.performDefaults();
 		super.performDefaults();
 	}
 
-	/**
-	 * adds a single filter to the viewer
-	 * @param filter the new filter to add
-	 * @param checked the checked state of the new filter
-	 * @since 3.2
-	 */
-	protected void addFilter(String filter, boolean checked) {
-		if(filter != null) {
-			Filter f = new Filter(filter, checked);
-			fTableViewer.add(f);
-			fTableViewer.setChecked(f, checked);
-		}
-	}
-
-	/**
-	 * returns all of the filters from the table, this includes ones that have not yet been saved
-	 * @return a possibly empty lits of filters fron the table
-	 * @since 3.2
-	 */
-	protected Filter[] getAllFiltersFromTable() {
-		TableItem[] items = fTableViewer.getTable().getItems();
-		Filter[] filters = new Filter[items.length];
-		for(int i = 0; i < items.length; i++) {
-			filters[i] = (Filter)items[i].getData();
-			filters[i].setChecked(items[i].getChecked());
-		}
-		return filters;
-	}
-
-	/**
-	 * Returns all of the committed filters
-	 * @return an array of committed filters
-	 * @since 3.2
-	 */
-	protected Filter[] getAllStoredFilters(boolean defaults) {
-		Filter[] filters = null;
-		String[] activefilters, inactivefilters;
-		IPreferenceStore store = getPreferenceStore();
-		if(defaults) {
-			activefilters = JavaDebugOptionsManager.parseList(store.getDefaultString(IJDIPreferencesConstants.PREF_ACTIVE_FILTERS_LIST));
-			inactivefilters = JavaDebugOptionsManager.parseList(store.getDefaultString(IJDIPreferencesConstants.PREF_INACTIVE_FILTERS_LIST));
-		}
-		else {
-			activefilters = JavaDebugOptionsManager.parseList(store.getString(IJDIPreferencesConstants.PREF_ACTIVE_FILTERS_LIST));
-			inactivefilters = JavaDebugOptionsManager.parseList(store.getString(IJDIPreferencesConstants.PREF_INACTIVE_FILTERS_LIST));
-		}
-		filters = new Filter[activefilters.length + inactivefilters.length];
-		for(int i = 0; i < activefilters.length; i++) {
-			filters[i] = new Filter(activefilters[i], true);
-		}
-		for(int i = 0; i < inactivefilters.length; i++) {
-			filters[i+activefilters.length] = new Filter(inactivefilters[i], false);
-		}
-		return filters;
-	}
 }
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 a871df8..fbf7705 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
@@ -21,6 +21,7 @@
 import org.eclipse.jdt.debug.core.IJavaArrayType;
 import org.eclipse.jdt.debug.core.IJavaClassType;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaFieldVariable;
 import org.eclipse.jdt.debug.core.IJavaObject;
 import org.eclipse.jdt.debug.core.IJavaType;
 import org.eclipse.jdt.debug.core.IJavaVariable;
@@ -195,6 +196,9 @@
 					if (value.equals("isObjectValue")) { //$NON-NLS-1$
 						return varValue != null && JDIObjectValue.class.isAssignableFrom(varValue.getClass());
 					}
+					if (value.equals("isFieldVariable")) { //$NON-NLS-1$
+						return var instanceof IJavaFieldVariable;
+					}
 				}
 				else if (name.equals("ConcreteVariableActionFilter") && value.equals("isConcrete")) { //$NON-NLS-1$ //$NON-NLS-2$
 					return isDeclaredSameAsConcrete(var);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java
index 351f3c9..61fe1da 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2021 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -168,6 +168,8 @@
 
 	public static String TracepointToggleAction_Unavailable;
 
+	public static String LambdaEntryBreakpointToggleAction_Unavailable;
+
 	public static String Override_Dependencies_title;
 	public static String Override_Dependencies_button;
 	public static String Override_Dependencies_button1;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties
index 425b5f7..d1ad471 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ActionMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2021 IBM Corporation and others.
+# Copyright (c) 2000, 2022 IBM Corporation and others.
 #
 # This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
@@ -149,6 +149,7 @@
 EditClasspathEntryAction_0=Ed&it...
 ProjectSelectionDialog_0=Choose &project(s) to add:
 TracepointToggleAction_Unavailable=The operation is unavailable on the current selection.
+LambdaEntryBreakpointToggleAction_Unavailable=The operation is unavailable on the current selection.
 Override_Dependencies_title=Override Dependencies
 Override_Dependencies_button=&Override
 Override_Dependencies_button1=&Override Dependencies...
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java
index eeb3d97..903d26e 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2017 IBM Corporation and others.
+ * Copyright (c) 2016, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,6 +25,7 @@
 public class BreakpointToggleUtils {
 
 	private static boolean isTracepoint = false;
+	private static boolean isLambdaEntryBreakpoint = false;
 
 
 	public static void setUnsetTracepoints(boolean tracePoint) {
@@ -35,6 +36,14 @@
 		return isTracepoint;
 	}
 
+	public static void setUnsetLambdaEntryBreakpoint(boolean lambdaEntryBreakpoint) {
+		isLambdaEntryBreakpoint = lambdaEntryBreakpoint;
+	}
+
+	public static boolean isToggleLambdaEntryBreakpoint() {
+		return isLambdaEntryBreakpoint;
+	}
+
 	/**
 	 * Convenience method for printing messages to the status line
 	 *
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/JavaVariableValueEditor.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/JavaVariableValueEditor.java
index 612ce57..c64958a 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/JavaVariableValueEditor.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/JavaVariableValueEditor.java
@@ -17,9 +17,15 @@
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.debug.ui.actions.IVariableValueEditor;
 import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.debug.core.IJavaModifiers;
 import org.eclipse.jdt.debug.core.IJavaVariable;
+import org.eclipse.jdt.internal.debug.ui.DebugUIMessages;
+import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants;
 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
 import org.eclipse.jdt.internal.debug.ui.JDIModelPresentation;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.swt.widgets.Shell;
 
 /**
@@ -27,9 +33,6 @@
  */
 public class JavaVariableValueEditor implements IVariableValueEditor {
 
-    /* (non-Javadoc)
-     * @see org.eclipse.debug.ui.actions.IVariableValueEditor#editVariable(org.eclipse.debug.core.model.IVariable, org.eclipse.swt.widgets.Shell)
-     */
     @Override
 	public boolean editVariable(IVariable variable, Shell shell) {
         String signature= null;
@@ -41,6 +44,10 @@
 	    if (signature == null) {
 	        return false;
 	    }
+		if (!isAllowedToModifyValue(variable)) {
+			// return true to avoid further processing
+			return true;
+		}
 	    IVariableValueEditor editor;
         if (JDIModelPresentation.isObjectValue(signature)) {
             editor= new JavaObjectValueEditor();
@@ -51,11 +58,13 @@
         return editor.editVariable(variable, shell);
     }
 
-    /* (non-Javadoc)
-     * @see org.eclipse.debug.ui.actions.IVariableValueEditor#saveVariable(org.eclipse.debug.core.model.IVariable, java.lang.String, org.eclipse.swt.widgets.Shell)
-     */
     @Override
 	public boolean saveVariable(IVariable variable, String expression, Shell shell) {
+		if (!isAllowedToModifyValue(variable)) {
+			// return true to avoid further processing
+			return true;
+		}
+
         // set the value of chars directly if expression is a single character (not an expression to evaluate)
     	if (expression.length() == 1 && variable instanceof IJavaVariable){
     		IJavaVariable javaVariable = (IJavaVariable)variable;
@@ -74,6 +83,50 @@
         return editor.saveVariable(variable, expression, shell);
     }
 
+	/**
+	 * @return {@code false} to prohibit editing a variable
+	 */
+	protected boolean isAllowedToModifyValue(IVariable variable) {
+		if (variable instanceof IJavaModifiers) {
+			IJavaModifiers modifiers = (IJavaModifiers) variable;
+			boolean allowed = isAllowedToModifyFinalValue(modifiers);
+			if (!allowed) {
+				// prohibit editing a variable that is declared as final
+				return false;
+			}
+		}
+		return true;
+	}
+
+	protected boolean isAllowedToModifyFinalValue(IJavaModifiers variable) {
+		IPreferenceStore preferenceStore = JDIDebugUIPlugin.getDefault().getPreferenceStore();
+		String key = IJDIPreferencesConstants.PREF_PROMPT_BEFORE_MODIFYING_FINAL_FIELDS;
+		if (!preferenceStore.getBoolean(key)) {
+			return true;
+		}
+		try {
+			if (!variable.isFinal()) {
+				return true;
+			}
+		} catch (DebugException e) {
+			JDIDebugUIPlugin.log(e);
+		}
+		return promptIfAllowedToModifyFinalValue(preferenceStore, key);
+	}
+
+	protected boolean promptIfAllowedToModifyFinalValue(IPreferenceStore preferenceStore, String key) {
+		boolean dontShowAgain = false;
+		final MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(
+				JDIDebugUIPlugin.getActiveWorkbenchShell(),
+				DebugUIMessages.JavaVariableValueEditor_prompt_before_final_value_change_title,
+				DebugUIMessages.JavaVariableValueEditor_prompt_before_final_value_change_message,
+				DebugUIMessages.JavaVariableValueEditor_prompt_before_final_value_change_toggle_message,
+				dontShowAgain,
+				preferenceStore,
+				key);
+		return dialog.getReturnCode() == IDialogConstants.YES_ID;
+	}
+
     public static String getSignature(IVariable variable) throws DebugException {
         String signature= null;
 		IJavaVariable javaVariable = variable.getAdapter(IJavaVariable.class);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java
index eb82441..2537a52 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenTypeAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -23,7 +23,6 @@
 import org.eclipse.core.runtime.Status;
 import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.model.IDebugElement;
-import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.search.IJavaSearchConstants;
@@ -55,12 +54,8 @@
 		try {
 			while (itr.hasNext()) {
 				Object element= itr.next();
-				Object sourceElement = resolveSourceElement(element);
-				if (sourceElement != null) {
-					openInEditor(sourceElement);
-				} else {
-					IStatus status = new Status(IStatus.INFO, IJavaDebugUIConstants.PLUGIN_ID, IJavaDebugUIConstants.INTERNAL_ERROR, "Source not found", null); //$NON-NLS-1$
-					throw new CoreException(status);
+				if (openElement(action, element)) {
+					return;
 				}
 			}
 		} catch(CoreException e) {
@@ -68,6 +63,29 @@
 		}
 	}
 
+	/**
+	 * Open the selected element, return true, if further selections should not be checked.
+	 *
+	 * @param action
+	 *            the action proxy that handles the presentation portion of the action
+	 * @param element
+	 *            the selected element.
+	 * @return true, if no other openElement calls should be made. Used, when multiple element is selected, and the action works as trying until one
+	 *         succeeds.
+	 * @throws CoreException
+	 *             if source element is not found.
+	 */
+	protected boolean openElement(IAction action, Object element) throws DebugException, CoreException {
+		IType sourceElement = resolveSourceElement(element);
+		if (sourceElement != null) {
+			openInEditor(element, sourceElement);
+		} else {
+			IStatus status = new Status(IStatus.INFO, IJavaDebugUIConstants.PLUGIN_ID, IJavaDebugUIConstants.INTERNAL_ERROR, "Source not found", null); //$NON-NLS-1$
+			throw new CoreException(status);
+		}
+		return false;
+	}
+
 	protected abstract IDebugElement getDebugElement(IAdaptable element);
 
 	/**
@@ -86,8 +104,8 @@
 	 * @return the source element to open or <code>null</code> if none
 	 * @throws CoreException
 	 */
-	protected Object resolveSourceElement(Object e) throws CoreException {
-		Object source = null;
+	protected IType resolveSourceElement(Object e) throws CoreException {
+		IType source = null;
 		IAdaptable element= (IAdaptable) e;
 		IDebugElement dbgElement= getDebugElement(element);
 		if (dbgElement != null) {
@@ -107,20 +125,11 @@
 		return source;
 	}
 
-	protected void openInEditor(Object sourceElement) throws CoreException {
+	protected void openInEditor(Object element, IType sourceElement) throws CoreException {
 		if (isHierarchy()) {
-			if (sourceElement instanceof IJavaElement) {
-				OpenTypeHierarchyUtil.open((IJavaElement)sourceElement, getWorkbenchWindow());
-			} else {
-				typeHierarchyError();
-			}
+			OpenTypeHierarchyUtil.open(sourceElement, getWorkbenchWindow());
 		} else {
-			if(sourceElement instanceof IJavaElement) {
-				JavaUI.openInEditor((IJavaElement) sourceElement);
-			}
-			else {
-				showErrorMessage(ActionMessages.OpenTypeAction_2);
-			}
+			JavaUI.openInEditor(sourceElement);
 		}
 	}
 
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeAction.java
index edf4d29..72e1048 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -14,12 +14,12 @@
 package org.eclipse.jdt.internal.debug.ui.actions;
 
 
-import java.util.Iterator;
-
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.debug.core.IJavaType;
 import org.eclipse.jdt.debug.core.IJavaValue;
 import org.eclipse.jdt.debug.core.IJavaVariable;
@@ -27,9 +27,7 @@
 import org.eclipse.jdt.internal.debug.core.model.JDIInterfaceType;
 import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue;
 import org.eclipse.jdt.internal.debug.core.model.JDIVariable;
-import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
 import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.viewers.IStructuredSelection;
 
 /**
  * Opens the concrete type of variable - i.e. it's value's actual type.
@@ -48,38 +46,34 @@
 		return null;
 	}
 
-
 	@Override
-	public void run(IAction action) {
-		IStructuredSelection selection = getCurrentSelection();
-		if (selection == null) {
-			return;
-		}
-		Iterator<?> itr = selection.iterator();
-		try {
-			while (itr.hasNext()) {
-				Object element = itr.next();
-				if (element instanceof JDIVariable && ((JDIVariable) element).getJavaType() instanceof JDIInterfaceType) {
-					JDIObjectValue val = (JDIObjectValue) ((JDIVariable) element).getValue();
-					if (val.getJavaType().toString().contains("$$Lambda$")) { //$NON-NLS-1$
-						OpenVariableDeclaredTypeAction declaredAction = new OpenVariableDeclaredTypeAction();
-						declaredAction.setActivePart(action, getPart());
-						declaredAction.run(action);
-						return;
-					}
-				}
-				Object sourceElement = resolveSourceElement(element);
-				if (sourceElement != null) {
-						openInEditor(sourceElement);
-				} else {
-						IStatus status = new Status(IStatus.INFO, IJavaDebugUIConstants.PLUGIN_ID, IJavaDebugUIConstants.INTERNAL_ERROR, "Source not found", null); //$NON-NLS-1$
-						throw new CoreException(status);
+	protected boolean openElement(IAction action, Object element) throws DebugException, CoreException {
+		if (element instanceof JDIVariable) {
+			final var jdiVariable = (JDIVariable) element;
+			if (isInterfaceType(jdiVariable)) {
+				final var val = (JDIObjectValue) jdiVariable.getValue();
+				if (val.getJavaType().toString().contains("$$Lambda$")) { //$NON-NLS-1$
+					OpenVariableDeclaredTypeAction declaredAction = new OpenVariableDeclaredTypeAction();
+					declaredAction.setActivePart(action, getPart());
+					declaredAction.run(action);
+					return true;
 				}
 			}
 		}
-		catch (CoreException e) {
-			JDIDebugUIPlugin.statusDialog(e.getStatus());
+		IType sourceElement = resolveSourceElement(element);
+		if (sourceElement != null) {
+			openInEditor(element, sourceElement);
+			return false;
 		}
+		IStatus status = new Status(IStatus.INFO, IJavaDebugUIConstants.PLUGIN_ID, IJavaDebugUIConstants.INTERNAL_ERROR, "Source not found", null); //$NON-NLS-1$
+		throw new CoreException(status);
 	}
 
+	private boolean isInterfaceType(JDIVariable jdiVariable) {
+		try {
+			return jdiVariable.getJavaType() instanceof JDIInterfaceType;
+		} catch (DebugException e) {
+			return false;
+		}
+	}
 }
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeHierarchyAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeHierarchyAction.java
index 115ec19..6123723 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeHierarchyAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableConcreteTypeHierarchyAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,21 +13,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.debug.ui.actions;
 
-import java.util.Iterator;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
-import org.eclipse.jdt.internal.debug.core.model.JDIInterfaceType;
-import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue;
-import org.eclipse.jdt.internal.debug.core.model.JDIVariable;
-import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.viewers.IStructuredSelection;
-
 /**
- * Opens the concrete type hierarhcy of variable - i.e. it's value's actual type.
+ * Opens the concrete type hierarchy of variable - i.e. it's value's actual type.
  */
 public class OpenVariableConcreteTypeHierarchyAction extends OpenVariableConcreteTypeAction {
 
@@ -39,36 +26,4 @@
 		return true;
 	}
 
-	@Override
-	public void run(IAction action) {
-		IStructuredSelection selection = getCurrentSelection();
-		if (selection == null) {
-			return;
-		}
-		Iterator<?> itr = selection.iterator();
-		try {
-			while (itr.hasNext()) {
-				Object element = itr.next();
-				if (element instanceof JDIVariable && ((JDIVariable) element).getJavaType() instanceof JDIInterfaceType) {
-					JDIObjectValue val = (JDIObjectValue) ((JDIVariable) element).getValue();
-					if (val.getJavaType().toString().contains("$$Lambda$")) { //$NON-NLS-1$
-						OpenVariableDeclaredTypeAction declaredAction = new OpenVariableDeclaredTypeHierarchyAction();
-						declaredAction.setActivePart(action, getPart());
-						declaredAction.run(action);
-						return;
-					}
-				}
-				Object sourceElement = resolveSourceElement(element);
-				if (sourceElement != null) {
-					openInEditor(sourceElement);
-				} else {
-					IStatus status = new Status(IStatus.INFO, IJavaDebugUIConstants.PLUGIN_ID, IJavaDebugUIConstants.INTERNAL_ERROR, "Source not found", null); //$NON-NLS-1$
-					throw new CoreException(status);
-				}
-			}
-		}
-		catch (CoreException e) {
-			JDIDebugUIPlugin.statusDialog(e.getStatus());
-		}
-	}
 }
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableDeclarationAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableDeclarationAction.java
new file mode 100644
index 0000000..626fbff
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/OpenVariableDeclarationAction.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2022 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Zsombor Gegesy - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.debug.core.IJavaFieldVariable;
+import org.eclipse.jdt.debug.core.IJavaType;
+import org.eclipse.jdt.internal.debug.core.model.JDIFieldVariable;
+import org.eclipse.jdt.ui.JavaUI;
+
+/**
+ * Open the source code, where the variable is declared.
+ *
+ */
+public class OpenVariableDeclarationAction extends OpenVariableConcreteTypeAction {
+
+	@Override
+	protected IJavaType getTypeToOpen(IDebugElement element) throws CoreException {
+		if (element instanceof IJavaFieldVariable) {
+			var variable = (IJavaFieldVariable) element;
+			return variable.getDeclaringType();
+		}
+		return null;
+	}
+
+	@Override
+	protected void openInEditor(Object element, IType sourceElement) throws CoreException {
+		if (element instanceof JDIFieldVariable) {
+			var field = (JDIFieldVariable) element;
+			var fieldElement = sourceElement.getField(field.getName());
+			var editor = JavaUI.openInEditor(fieldElement);
+			if (editor != null) {
+				return;
+			}
+		}
+		super.openInEditor(element, sourceElement);
+	}
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RetargetToggleLambdaEntryBreakpointAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RetargetToggleLambdaEntryBreakpointAction.java
new file mode 100644
index 0000000..e24b19a
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RetargetToggleLambdaEntryBreakpointAction.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 20227 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.internal.ui.actions.breakpoints.RetargetToggleBreakpointAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Global retargettable toggle Line Entry action.
+ *
+ * @since 3.12
+ *
+ */
+public class RetargetToggleLambdaEntryBreakpointAction extends RetargetToggleBreakpointAction {
+
+	@Override
+	protected void performAction(Object target, ISelection selection, IWorkbenchPart part) throws CoreException {
+		BreakpointToggleUtils.setUnsetLambdaEntryBreakpoint(true);
+		super.performAction(target, selection, part);
+	}
+
+	@Override
+	protected boolean canPerformAction(Object target, ISelection selection, IWorkbenchPart part) {
+		return super.canPerformAction(target, selection, part);
+	}
+
+	@Override
+	protected String getOperationUnavailableMessage() {
+		return ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RulerToggleLambdaEntryBreakpointActionDelegate.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RulerToggleLambdaEntryBreakpointActionDelegate.java
new file mode 100644
index 0000000..df131df
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/RulerToggleLambdaEntryBreakpointActionDelegate.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2022 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.texteditor.AbstractRulerActionDelegate;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+public class RulerToggleLambdaEntryBreakpointActionDelegate extends AbstractRulerActionDelegate implements IActionDelegate2 {
+
+	private IEditorPart currentEditor;
+	private IAction dummyAction;
+
+	@Override
+	protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
+		dummyAction = new Action() {
+			// empty implementation to make compiler happy
+		};
+		return dummyAction;
+	}
+
+	@Override
+	public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) {
+		currentEditor = targetEditor;
+	}
+
+	@Override
+	public void init(IAction action) {
+	}
+
+	@Override
+	public void dispose() {
+		currentEditor = null;
+		dummyAction = null;
+		super.dispose();
+	}
+
+	@Override
+	public void runWithEvent(IAction action, Event event) {
+		if (!(currentEditor instanceof ITextEditor)) {
+			return;
+		}
+		IVerticalRulerInfo rulerInfo = currentEditor.getAdapter(IVerticalRulerInfo.class);
+		if (rulerInfo == null) {
+			return;
+		}
+		int lineOfLastMouseButtonActivity = rulerInfo.getLineOfLastMouseButtonActivity();
+		if (lineOfLastMouseButtonActivity < 0) {
+			return;
+		}
+		IDocument document = getDocument((ITextEditor) currentEditor);
+		if (document == null) {
+			return;
+		}
+		ToggleBreakpointAdapter toggle = new ToggleBreakpointAdapter();
+		try {
+			ITextSelection selection = getTextSelection(currentEditor, document, lineOfLastMouseButtonActivity);
+			if (toggle.canToggleLineBreakpoints(currentEditor, selection)) {
+				BreakpointToggleUtils.setUnsetLambdaEntryBreakpoint(true);
+				toggle.toggleBreakpoints(currentEditor, selection);
+			}
+		} catch (BadLocationException | CoreException e) {
+			DebugUIPlugin.log(e);
+		}
+	}
+
+	private static IDocument getDocument(ITextEditor editor) {
+		IDocumentProvider provider = editor.getDocumentProvider();
+		if (provider != null) {
+			return provider.getDocument(editor.getEditorInput());
+		}
+		IDocument doc = editor.getAdapter(IDocument.class);
+		if (doc != null) {
+			return doc;
+		}
+		return null;
+	}
+
+	private static ITextSelection getTextSelection(IEditorPart editor, IDocument document, int line) throws BadLocationException {
+		IRegion region = document.getLineInformation(line);
+		ITextSelection textSelection = new TextSelection(document, region.getOffset(), 0);
+		ISelectionProvider provider = editor.getSite().getSelectionProvider();
+		if (provider != null) {
+			ISelection selection = provider.getSelection();
+			if (selection instanceof ITextSelection && ((ITextSelection) selection).getStartLine() <= line
+					&& ((ITextSelection) selection).getEndLine() >= line) {
+				textSelection = (ITextSelection) selection;
+			}
+		}
+		return textSelection;
+	}
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java
index 8b131a6..4e34313 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java
@@ -19,6 +19,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.core.resources.IFile;
@@ -81,6 +82,7 @@
 import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType;
 import org.eclipse.jdt.internal.corext.template.java.JavaContextType;
 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
+import org.eclipse.jdt.internal.debug.core.breakpoints.FirstLambdaLocationLocator;
 import org.eclipse.jdt.internal.debug.core.breakpoints.ValidBreakpointLocationLocator;
 import org.eclipse.jdt.internal.debug.ui.BreakpointUtils;
 import org.eclipse.jdt.internal.debug.ui.DebugWorkingCopyManager;
@@ -101,6 +103,7 @@
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.TextSelection;
 import org.eclipse.jface.text.source.Annotation;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.IVerticalRulerInfo;
@@ -245,6 +248,123 @@
         job.schedule();
     }
 
+	public void toggleLambdaMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection, final ValidBreakpointLocationLocator loc) {
+		Job job = new Job("Toggle Lambda Method Breakpoints") { //$NON-NLS-1$
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				if (monitor.isCanceled()) {
+					return Status.CANCEL_STATUS;
+				}
+				try {
+					return doToggleLambdaMethodBreakpoints(part, finalSelection, loc, monitor);
+				} catch (CoreException e) {
+					return e.getStatus();
+				} finally {
+					BreakpointToggleUtils.setUnsetTracepoints(false);
+				}
+			}
+		};
+		job.setPriority(Job.INTERACTIVE);
+		job.setSystem(true);
+		job.schedule();
+	}
+
+	public void toggleLambdaEntryMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection, final String lambdaMethodName) {
+		Job job = new Job("Toggle Lambda Entry Method Breakpoints") { //$NON-NLS-1$
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				if (monitor.isCanceled()) {
+					return Status.CANCEL_STATUS;
+				}
+				try {
+					return doToggleLambdaEntryMethodBreakpoints(part, finalSelection, lambdaMethodName, monitor);
+				} catch (CoreException e) {
+					return e.getStatus();
+				} finally {
+					BreakpointToggleUtils.setUnsetTracepoints(false);
+				}
+			}
+		};
+		job.setPriority(Job.INTERACTIVE);
+		job.setSystem(true);
+		job.schedule();
+	}
+
+	static IStatus doToggleLambdaEntryMethodBreakpoints(IWorkbenchPart part, ISelection selection, String lambdaMethodName, IProgressMonitor monitor) throws CoreException {
+		ITextEditor textEditor = getTextEditor(part);
+		if (textEditor == null || !(selection instanceof ITextSelection)) {
+			return Status.OK_STATUS;
+		}
+		ITextSelection textSelection = (ITextSelection) selection;
+		IEditorInput editorInput = textEditor.getEditorInput();
+		ITypeRoot root = getTypeRoot(editorInput);
+		if (root instanceof ICompilationUnit) {
+			ICompilationUnit unit = (ICompilationUnit) root;
+			synchronized (unit) {
+				unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
+			}
+			IJavaElement[] elements = unit.codeSelect(textSelection.getOffset(), textSelection.getLength());
+			if (elements == null || elements.length == 0) {
+				BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+				return Status.OK_STATUS;
+			}
+			IMethod method = null;
+			if (elements[0] instanceof IMethod) {
+				method = (IMethod) elements[0];
+			} else if (elements[0].getParent() instanceof IMethod) {
+				method = (IMethod) elements[0].getParent();
+			}
+
+			if (method != null) {
+				doToggleMethodBreakpoint(method, lambdaMethodName, part, selection, monitor);
+			} else {
+				BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+			}
+		}
+		return Status.OK_STATUS;
+	}
+
+
+	static IStatus doToggleLambdaMethodBreakpoints(IWorkbenchPart part, ISelection selection, ValidBreakpointLocationLocator loc, IProgressMonitor monitor) throws CoreException {
+		ITextEditor textEditor = getTextEditor(part);
+		if (textEditor == null || !(selection instanceof ITextSelection)) {
+			return Status.OK_STATUS;
+		}
+		ITextSelection textSelection = (ITextSelection) selection;
+		IEditorInput editorInput = textEditor.getEditorInput();
+		ITypeRoot root = getTypeRoot(editorInput);
+		if (root instanceof ICompilationUnit) {
+			ICompilationUnit unit = (ICompilationUnit) root;
+			synchronized (unit) {
+				unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
+			}
+			IJavaElement[] elements = unit.codeSelect(textSelection.getOffset(), textSelection.getLength());
+			if (elements == null || elements.length == 0) {
+				ValidBreakpointLocationLocator locNew = new ValidBreakpointLocationLocator(loc.getCompilationUnit(), textSelection.getStartLine()
+						+ 1, true, true);
+				locNew.getCompilationUnit().accept(locNew);
+				toggleLineBreakpoints(part, selection, false, locNew);
+				return Status.OK_STATUS;
+			}
+			IMethod method = null;
+			if (elements[0] instanceof IMethod) {
+				method = (IMethod) elements[0];
+			} else if (elements[0].getParent() instanceof IMethod) {
+				method = (IMethod) elements[0].getParent();
+			}
+
+			if (method != null) {
+				doToggleMethodBreakpoint(method, loc.getLambdaMethodName(), part, selection, monitor);
+			} else {
+				ValidBreakpointLocationLocator locNew = new ValidBreakpointLocationLocator(loc.getCompilationUnit(), textSelection.getStartLine()
+						+ 1, true, true);
+				locNew.getCompilationUnit().accept(locNew);
+				toggleLineBreakpoints(part, selection, false, locNew);
+			}
+
+		}
+		return Status.OK_STATUS;
+	}
 	static IStatus doToggleMethodBreakpoints(IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
 		BreakpointToggleUtils.report(null, part);
 		ISelection selection = finalSelection;
@@ -272,6 +392,10 @@
 	}
 
 	private static void doToggleMethodBreakpoint(IMethod member, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
+		doToggleMethodBreakpoint(member, null, part, finalSelection, monitor);
+	}
+
+	private static void doToggleMethodBreakpoint(IMethod member, String lambdaMethodName, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
 		IJavaBreakpoint breakpoint = getMethodBreakpoint(member);
 		if (breakpoint != null) {
 			if (BreakpointToggleUtils.isToggleTracepoints()) {
@@ -293,7 +417,7 @@
 		BreakpointUtils.addJavaBreakpointAttributes(attributes, member);
 		IType type = member.getDeclaringType();
 		String signature = member.getSignature();
-		String mname = member.getElementName();
+		String mname = Optional.ofNullable(lambdaMethodName).orElse(member.getElementName());
 		if (member.isConstructor()) {
 			mname = "<init>"; //$NON-NLS-1$
 			if (type.isEnum()) {
@@ -1432,9 +1556,21 @@
 			JDIDebugUIPlugin.log("Failed to parse CU for: " + editor.getTitle(), new IllegalStateException()); //$NON-NLS-1$
 			return;
 		}
-		ValidBreakpointLocationLocator loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine() + 1, true, true);
+		ValidBreakpointLocationLocator loc = null;
+		boolean lambdaEntryBP = false;
+		if (BreakpointToggleUtils.isToggleLambdaEntryBreakpoint()) {
+			loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine()
+				+ 1, true, true, ts.getOffset(), ts.getLength());
+			lambdaEntryBP = true;
+			BreakpointToggleUtils.setUnsetLambdaEntryBreakpoint(false);
+		} else {
+			loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine() + 1, true, true);
+		}
 		unit.accept(loc);
-		if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_METHOD) {
+
+		if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LAMBDA_METHOD) {
+			toggleLambdaMethodBreakpoints(part, ts, loc);
+		} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_METHOD) {
 			toggleMethodBreakpoints(part, ts);
 		} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_FIELD) {
 			if (BreakpointToggleUtils.isToggleTracepoints()) {
@@ -1444,7 +1580,31 @@
 			}
 			toggleWatchpoints(part, ts);
 		} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LINE) {
-			toggleLineBreakpoints(part, ts, false, loc);
+			if (lambdaEntryBP) {
+				IEditorInput editorInput = editor.getEditorInput();
+				IDocumentProvider documentProvider = editor.getDocumentProvider();
+				if (documentProvider == null) {
+					BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+					throw new CoreException(Status.CANCEL_STATUS);
+				}
+				IDocument document = documentProvider.getDocument(editorInput);
+				try {
+					IRegion region = document.getLineInformation(ts.getStartLine());
+					FirstLambdaLocationLocator firstLambda = new FirstLambdaLocationLocator(region.getOffset(), region.getOffset() + region.getLength());
+					unit.accept(firstLambda);
+					if (firstLambda.getNodeLength() == -1 || firstLambda.getNodeOffset() == -1) {
+						BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+						return;
+					}
+					ITextSelection textSelection = new TextSelection(document, firstLambda.getNodeOffset(), firstLambda.getNodeLength());
+					toggleLambdaEntryMethodBreakpoints(part, textSelection, firstLambda.getLambdaMethodName());
+				} catch (BadLocationException e) {
+					BreakpointToggleUtils.report(ActionMessages.LambdaEntryBreakpointToggleAction_Unavailable, part);
+				}
+
+			} else {
+				toggleLineBreakpoints(part, ts, false, loc);
+			}
 		}
 	}
 
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/InstalledJREsBlock.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/InstalledJREsBlock.java
index 1911a08..59852dc 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/InstalledJREsBlock.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/jres/InstalledJREsBlock.java
@@ -153,7 +153,7 @@
 				fVMList.refresh();
 			}
 			else {
-				display.syncExec(new Runnable() {
+				display.asyncExec(new Runnable() {
 					@Override
 					public void run() {
 						fVMList.refresh();
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/ExceptionFilterEditor.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/ExceptionFilterEditor.java
index 0aad2b2..aa7cecf 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/ExceptionFilterEditor.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/ExceptionFilterEditor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -17,94 +17,31 @@
 import java.util.List;
 
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.search.SearchEngine;
 import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint;
-import org.eclipse.jdt.internal.debug.ui.ExceptionHandler;
-import org.eclipse.jdt.internal.debug.ui.Filter;
-import org.eclipse.jdt.internal.debug.ui.FilterLabelProvider;
-import org.eclipse.jdt.internal.debug.ui.FilterViewerComparator;
 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
-import org.eclipse.jdt.ui.IJavaElementSearchConstants;
-import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.jface.viewers.CheckStateChangedEvent;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jdt.internal.ui.filtertable.Filter;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.ButtonLabel;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.DialogLabels;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterStorage;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterTableConfig;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.viewers.ColumnLayoutData;
 import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.ICheckStateListener;
-import org.eclipse.jface.viewers.IContentProvider;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.TableLayout;
-import org.eclipse.jface.viewers.Viewer;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.TableEditor;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.FontMetrics;
-import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Listener;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.TableItem;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.dialogs.ElementListSelectionDialog;
-import org.eclipse.ui.dialogs.SelectionDialog;
 
 
 public class ExceptionFilterEditor {
 
 	protected static final String DEFAULT_PACKAGE = "(default package)"; //$NON-NLS-1$
 	private IJavaExceptionBreakpoint fBreakpoint;
-	private Button fAddFilterButton;
-	private Button fAddPackageButton;
-	private Button fAddTypeButton;
-	private Button fRemoveFilterButton;
-	private Text fEditorText;
-	private String fInvalidEditorText = null;
-	private TableEditor fTableEditor;
-	private TableItem fNewTableItem;
-	private Filter fNewFilter;
-	private CheckboxTableViewer fFilterViewer;
-	private Table fFilterTable;
-	private FilterContentProvider fFilterContentProvider;
 
-	private SelectionListener fSelectionListener= new SelectionAdapter() {
-		@Override
-		public void widgetSelected(SelectionEvent e) {
-			Object source = e.getSource();
-			if (source == fAddTypeButton) {
-				addType();
-			} else if (source == fAddPackageButton) {
-				addPackage();
-			} else if (source == fAddFilterButton) {
-				editFilter();
-			} else if (source == fRemoveFilterButton) {
-				removeFilters();
-			}
-		}
-	};
+	private JavaFilterTable fJavaFilterTable;
 
 	public ExceptionFilterEditor(Composite parent, JavaExceptionBreakpointAdvancedPage page) {
 		fBreakpoint = (IJavaExceptionBreakpoint) page.getBreakpoint();
@@ -127,457 +64,83 @@
 		gd.horizontalSpan= 2;
 		label.setLayoutData(gd);
 
-		fFilterTable = new Table(outer, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
-
 		TableLayout tableLayout = new TableLayout();
 		ColumnLayoutData[] columnLayoutData = new ColumnLayoutData[1];
 		columnLayoutData[0] = new ColumnWeightData(100);
 		tableLayout.addColumnData(columnLayoutData[0]);
-		fFilterTable.setLayout(tableLayout);
-		fFilterTable.setFont(parent.getFont());
-		new TableColumn(fFilterTable, SWT.NONE);
 
-		fFilterViewer = new CheckboxTableViewer(fFilterTable);
-		fTableEditor = new TableEditor(fFilterTable);
-		fFilterViewer.setLabelProvider(new FilterLabelProvider());
-		fFilterViewer.setComparator(new FilterViewerComparator());
-		fFilterContentProvider = new FilterContentProvider(fFilterViewer);
-		fFilterViewer.setContentProvider(fFilterContentProvider);
-		// input just needs to be non-null
-		fFilterViewer.setInput(this);
-		gd = new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL);
-		gd.widthHint = 100;
-		gd.heightHint = 100;
-		fFilterViewer.getTable().setLayoutData(gd);
-		fFilterViewer.addCheckStateListener(new ICheckStateListener() {
+		createFilterTable(outer);
+	}
+
+	private void createFilterTable(Composite outer) {
+		fJavaFilterTable = new JavaFilterTable(new FilterStorage() {
+
 			@Override
-			public void checkStateChanged(CheckStateChangedEvent event) {
-				Filter filter = (Filter) event.getElement();
-				fFilterContentProvider.toggleFilter(filter);
-			}
-		});
-		fFilterViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-			@Override
-			public void selectionChanged(SelectionChangedEvent event) {
-				ISelection selection = event.getSelection();
-				if (selection.isEmpty()) {
-					fRemoveFilterButton.setEnabled(false);
-				} else {
-					fRemoveFilterButton.setEnabled(true);
+			public void setStoredFilters(IPreferenceStore store, Filter[] filters) {
+				List<String> inclusionFilters = new ArrayList<>(filters.length);
+				List<String> exclusionFilters = new ArrayList<>(filters.length);
+				for (Object f : filters) {
+					Filter filter = (Filter) f;
+					String name = filter.getName();
+					if (name.equals(DEFAULT_PACKAGE)) {
+						name = ""; //$NON-NLS-1$
+					}
+					if (filter.isChecked()) {
+						inclusionFilters.add(name);
+					} else {
+						exclusionFilters.add(name);
+					}
+				}
+				try {
+					fBreakpoint.setInclusionFilters(inclusionFilters.toArray(new String[inclusionFilters.size()]));
+					fBreakpoint.setExclusionFilters(exclusionFilters.toArray(new String[exclusionFilters.size()]));
+				} catch (CoreException ce) {
+					JDIDebugUIPlugin.log(ce);
 				}
 			}
-		});
-		fFilterViewer.getTable().addKeyListener(new KeyAdapter() {
-			@Override
-			public void keyPressed(KeyEvent event) {
-				if (event.character == SWT.DEL && event.stateMask == 0) {
-					removeFilters();
-				}
-			}
-		});
 
-		createFilterButtons(outer);
+			@Override
+			public Filter[] getStoredFilters(boolean defaults) {
+				if (defaults) {
+					return new Filter[0];
+				}
+				try {
+					String[] iFilters = fBreakpoint.getInclusionFilters();
+					String[] eFilters = fBreakpoint.getExclusionFilters();
+					List<Filter> storedFilters = new ArrayList<>(iFilters.length + eFilters.length);
+					for (String filter : iFilters) {
+						storedFilters.add(toFilter(filter, true));
+					}
+					for (String filter : eFilters) {
+						storedFilters.add(toFilter(filter, false));
+					}
+					return storedFilters.toArray(Filter[]::new);
+				} catch (CoreException ce) {
+					JDIDebugUIPlugin.log(ce);
+					return new Filter[0];
+				}
+
+			}
+		}, new FilterTableConfig()
+				.setAddFilter(new ButtonLabel(PropertyPageMessages.ExceptionFilterEditor_6, PropertyPageMessages.ExceptionFilterEditor_7))
+				.setAddType(new ButtonLabel(PropertyPageMessages.ExceptionFilterEditor_8, PropertyPageMessages.ExceptionFilterEditor_9))
+				.setAddPackage(new ButtonLabel(PropertyPageMessages.ExceptionFilterEditor_10, PropertyPageMessages.ExceptionFilterEditor_11))
+				.setRemove(new ButtonLabel(PropertyPageMessages.ExceptionFilterEditor_12, PropertyPageMessages.ExceptionFilterEditor_13))
+				.setAddPackageDialog(new DialogLabels(PropertyPageMessages.ExceptionFilterEditor_15, PropertyPageMessages.ExceptionFilterEditor_18))
+				.setAddTypeDialog(new DialogLabels(PropertyPageMessages.ExceptionFilterEditor_19, PropertyPageMessages.ExceptionFilterEditor_22))
+				.setErrorAddTypeDialog(new DialogLabels(PropertyPageMessages.ExceptionFilterEditor_19, PropertyPageMessages.ExceptionFilterEditor_20)));
+		fJavaFilterTable.createTable(outer);
+	}
+
+	private Filter toFilter(String stringFilter, boolean include) {
+		if (stringFilter.length() == 0) {
+			return new Filter(DEFAULT_PACKAGE, include);
+		}
+		return new Filter(stringFilter, include);
 	}
 
 	protected void doStore() {
-		Object[] filters = fFilterContentProvider.getElements(null);
-		List<String> inclusionFilters = new ArrayList<>(filters.length);
-		List<String> exclusionFilters = new ArrayList<>(filters.length);
-		for (Object f : filters) {
-			Filter filter = (Filter) f;
-			String name = filter.getName();
-			if (name.equals(DEFAULT_PACKAGE)) {
-				name = ""; //$NON-NLS-1$
-			}
-			if (filter.isChecked()) {
-				inclusionFilters.add(name);
-			} else {
-				exclusionFilters.add(name);
-			}
-		}
-		try {
-			fBreakpoint.setInclusionFilters(inclusionFilters.toArray(new String[inclusionFilters.size()]));
-			fBreakpoint.setExclusionFilters(exclusionFilters.toArray(new String[exclusionFilters.size()]));
-		} catch (CoreException ce) {
-			JDIDebugUIPlugin.log(ce);
-		}
-
-	}
-
-	private void createFilterButtons(Composite container) {
-		// button container
-		Font font= container.getFont();
-		Composite buttonContainer = new Composite(container, SWT.NONE);
-		buttonContainer.setFont(font);
-		GridData gd = new GridData(GridData.FILL_VERTICAL);
-		buttonContainer.setLayoutData(gd);
-		GridLayout buttonLayout = new GridLayout();
-		buttonLayout.numColumns = 1;
-		buttonLayout.marginHeight = 0;
-		buttonLayout.marginWidth = 0;
-		buttonContainer.setLayout(buttonLayout);
-
-		fAddFilterButton = createPushButton(buttonContainer,
-				PropertyPageMessages.ExceptionFilterEditor_6,
-				PropertyPageMessages.ExceptionFilterEditor_7);
-		fAddTypeButton = createPushButton(buttonContainer,
-				PropertyPageMessages.ExceptionFilterEditor_8,
-				PropertyPageMessages.ExceptionFilterEditor_9);
-		fAddPackageButton = createPushButton(buttonContainer,
-				PropertyPageMessages.ExceptionFilterEditor_10,
-				PropertyPageMessages.ExceptionFilterEditor_11);
-		fRemoveFilterButton = createPushButton(buttonContainer,
-				PropertyPageMessages.ExceptionFilterEditor_12,
-				PropertyPageMessages.ExceptionFilterEditor_13);
-		fRemoveFilterButton.setEnabled(false);
-	}
-
-	/**
-	 * Creates a fully configured push button with the given label and tooltip.
-	 */
-	private Button createPushButton(Composite parent, String text, String tooltipText) {
-		Button button = new Button(parent, SWT.PUSH);
-		button.setFont(parent.getFont());
-		button.setText(text);
-		button.setToolTipText(tooltipText);
-		GridData gd = getButtonGridData(button);
-		button.setLayoutData(gd);
-		button.addSelectionListener(fSelectionListener);
-		return button;
-	}
-
-	private static GridData getButtonGridData(Button button) {
-		GridData gd = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
-		GC gc = new GC(button);
-		gc.setFont(button.getFont());
-		FontMetrics fontMetrics = gc.getFontMetrics();
-		gc.dispose();
-		int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH);
-		gd.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
-		return gd;
-	}
-
-	/**
-	 * Create a new filter in the table (with the default 'new filter' value),
-	 * then open up an in-place editor on it.
-	 */
-	private void editFilter() {
-		// if a previous edit is still in progress, finish it
-		if (fEditorText != null) {
-			validateChangeAndCleanup();
-		}
-
-		fNewFilter = fFilterContentProvider.addFilter(""); //$NON-NLS-1$
-		fNewTableItem = fFilterTable.getItem(0);
-
-		// create & configure Text widget for editor
-		// Fix for bug 1766.  Border behavior on for text fields varies per platform.
-		// On Motif, you always get a border, on other platforms,
-		// you don't.  Specifying a border on Motif results in the characters
-		// getting pushed down so that only there very tops are visible.  Thus,
-		// we have to specify different style constants for the different platforms.
-		int textStyles = SWT.SINGLE | SWT.LEFT;
-		if (!SWT.getPlatform().equals("motif")) { //$NON-NLS-1$
-			textStyles |= SWT.BORDER;
-		}
-		fEditorText = new Text(fFilterTable, textStyles);
-		GridData gd = new GridData(GridData.FILL_BOTH);
-		fEditorText.setLayoutData(gd);
-
-		// set the editor
-		fTableEditor.horizontalAlignment = SWT.LEFT;
-		fTableEditor.grabHorizontal = true;
-		fTableEditor.setEditor(fEditorText, fNewTableItem, 0);
-
-		// get the editor ready to use
-		fEditorText.setText(fNewFilter.getName());
-		fEditorText.selectAll();
-		setEditorListeners(fEditorText);
-		fEditorText.setFocus();
-	}
-
-	private void setEditorListeners(Text text) {
-		// CR means commit the changes, ESC means abort and don't commit
-		text.addKeyListener(new KeyAdapter() {
-			@Override
-			public void keyReleased(KeyEvent event) {
-				if (event.character == SWT.CR) {
-					if (fInvalidEditorText != null) {
-						fEditorText.setText(fInvalidEditorText);
-						fInvalidEditorText = null;
-					} else {
-						validateChangeAndCleanup();
-					}
-				} else if (event.character == SWT.ESC) {
-					removeNewFilter();
-					cleanupEditor();
-				}
-			}
-		});
-		// Consider loss of focus on the editor to mean the same as CR
-		text.addFocusListener(new FocusAdapter() {
-			@Override
-			public void focusLost(FocusEvent event) {
-				if (fInvalidEditorText != null) {
-					fEditorText.setText(fInvalidEditorText);
-					fInvalidEditorText = null;
-				} else {
-					validateChangeAndCleanup();
-				}
-			}
-		});
-		// Consume traversal events from the text widget so that CR doesn't
-		// traverse away to dialog's default button.  Without this, hitting
-		// CR in the text field closes the entire dialog.
-		text.addListener(SWT.Traverse, new Listener() {
-			@Override
-			public void handleEvent(Event event) {
-				event.doit = false;
-			}
-		});
-	}
-
-	private void validateChangeAndCleanup() {
-		String trimmedValue = fEditorText.getText().trim();
-		// if the new value is blank, remove the filter
-		if (trimmedValue.length() < 1) {
-			removeNewFilter();
-		}
-		// if it's invalid, beep and leave sitting in the editor
-		else if (!validateEditorInput(trimmedValue)) {
-			fInvalidEditorText = trimmedValue;
-			fEditorText.setText(PropertyPageMessages.ExceptionFilterEditor_14);
-			return;
-			// otherwise, commit the new value if not a duplicate
-		} else {
-			for (Object f : fFilterContentProvider.getElements(null)) {
-				Filter filter = (Filter) f;
-				if (filter.getName().equals(trimmedValue)) {
-					removeNewFilter();
-					cleanupEditor();
-					return;
-				}
-			}
-			fNewTableItem.setText(trimmedValue);
-			fNewFilter.setName(trimmedValue);
-			fFilterViewer.refresh();
-		}
-		cleanupEditor();
-	}
-
-	/**
-	 * A valid filter is simply one that is a valid Java identifier.
-	 * and, as defined in the JDI spec, the regular expressions used for
-	 * scoping must be limited to exact matches or patterns that
-	 * begin with '*' or end with '*'. Beyond this, a string cannot be validated
-	 * as corresponding to an existing type or package (and this is probably not
-	 * even desirable).
-	 */
-	private boolean validateEditorInput(String trimmedValue) {
-		char firstChar = trimmedValue.charAt(0);
-		if (!Character.isJavaIdentifierStart(firstChar)) {
-			if (!(firstChar == '*')) {
-				return false;
-			}
-		}
-		int length = trimmedValue.length();
-		for (int i = 1; i < length; i++) {
-			char c = trimmedValue.charAt(i);
-			if (!Character.isJavaIdentifierPart(c)) {
-				if (c == '.' && i != (length - 1)) {
-					continue;
-				}
-				if (c == '*' && i == (length - 1)) {
-					continue;
-				}
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Cleanup all widgetry & resources used by the in-place editing
-	 */
-	private void cleanupEditor() {
-		if (fEditorText != null) {
-			fNewFilter = null;
-			fNewTableItem = null;
-			fTableEditor.setEditor(null, null, 0);
-			fEditorText.getDisplay().asyncExec(new Runnable() {
-				@Override
-				public void run() {
-					fEditorText.dispose();
-					fEditorText = null;
-				}
-			});
-		}
-	}
-
-	private void removeFilters() {
-		IStructuredSelection selection = (IStructuredSelection) fFilterViewer.getSelection();
-		fFilterContentProvider.removeFilters(selection.toArray());
-	}
-
-	private void removeNewFilter() {
-		fFilterContentProvider.removeFilters(new Object[] { fNewFilter });
-	}
-
-	private void addPackage() {
-		Shell shell = fAddPackageButton.getDisplay().getActiveShell();
-		ElementListSelectionDialog dialog = null;
-		try {
-			dialog = JDIDebugUIPlugin.createAllPackagesDialog(shell, null, false);
-		} catch (JavaModelException jme) {
-			String title = PropertyPageMessages.ExceptionFilterEditor_15;
-			String message = PropertyPageMessages.ExceptionFilterEditor_16;
-			ExceptionHandler.handle(jme, title, message);
-			return;
-		}
-		if (dialog == null) {
-			return;
-		}
-		dialog.setTitle(PropertyPageMessages.ExceptionFilterEditor_15);
-		dialog.setMessage(PropertyPageMessages.ExceptionFilterEditor_18);
-		dialog.setMultipleSelection(true);
-		if (dialog.open() == IDialogConstants.CANCEL_ID) {
-			return;
-		}
-		Object[] packages = dialog.getResult();
-		if (packages != null) {
-			for (Object p : packages) {
-				IJavaElement pkg = (IJavaElement) p;
-				String filter = pkg.getElementName();
-				if (filter.length() < 1) {
-					filter = DEFAULT_PACKAGE;
-				} else {
-					filter += ".*"; //$NON-NLS-1$
-				}
-				Filter f = fFilterContentProvider.addFilter(filter);
-				fFilterContentProvider.checkFilter(f, true);
-			}
-		}
-	}
-
-	private void addType() {
-		Shell shell = fAddTypeButton.getDisplay().getActiveShell();
-		SelectionDialog dialog = null;
-		try {
-			dialog = JavaUI.createTypeDialog(shell, PlatformUI.getWorkbench().getProgressService(), SearchEngine.createWorkspaceScope(), IJavaElementSearchConstants.CONSIDER_CLASSES, false);
-		} catch (JavaModelException jme) {
-			String title = PropertyPageMessages.ExceptionFilterEditor_19;
-			String message = PropertyPageMessages.ExceptionFilterEditor_20;
-			ExceptionHandler.handle(jme, title, message);
-			return;
-		}
-
-		dialog.setTitle(PropertyPageMessages.ExceptionFilterEditor_19);
-		dialog.setMessage(PropertyPageMessages.ExceptionFilterEditor_22);
-		if (dialog.open() == IDialogConstants.CANCEL_ID) {
-			return;
-		}
-
-		Object[] types = dialog.getResult();
-		if (types != null) {
-			for (Object t : types) {
-				IType type = (IType) t;
-				Filter f = fFilterContentProvider.addFilter(type.getFullyQualifiedName());
-				fFilterContentProvider.checkFilter(f, true);
-			}
-		}
-	}
-
-	/**
-	 * Content provider for the table.  Content consists of instances of Filter.
-	 */
-	protected class FilterContentProvider implements IStructuredContentProvider {
-
-		private CheckboxTableViewer fViewer;
-		private List<Filter> fFilters;
-
-		public FilterContentProvider(CheckboxTableViewer viewer) {
-			fViewer = viewer;
-			populateFilters();
-		}
-
-		protected void populateFilters() {
-			String[] iFilters = null;
-			String[] eFilters = null;
-			try {
-				iFilters = fBreakpoint.getInclusionFilters();
-				eFilters = fBreakpoint.getExclusionFilters();
-			} catch (CoreException ce) {
-				JDIDebugUIPlugin.log(ce);
-				iFilters = new String[] {
-				};
-				eFilters = new String[] {
-				};
-			}
-			fFilters = new ArrayList<>();
-			populateFilters(iFilters, true);
-			populateFilters(eFilters, false);
-
-		}
-
-		protected void populateFilters(String[] filters, boolean checked) {
-			for (String name : filters) {
-				if (name.length() == 0) {
-					name = DEFAULT_PACKAGE;
-				}
-				Filter filter = addFilter(name);
-				checkFilter(filter, checked);
-			}
-		}
-
-		public Filter addFilter(String name) {
-			Filter filter = new Filter(name, false);
-			if (!fFilters.contains(filter)) {
-				fFilters.add(filter);
-				fViewer.add(filter);
-			}
-			return filter;
-		}
-
-		public void removeFilters(Object[] filters) {
-			for (Object f : filters) {
-				Filter filter = (Filter) f;
-				fFilters.remove(filter);
-			}
-			fViewer.remove(filters);
-		}
-
-		public void toggleFilter(Filter filter) {
-			boolean newState = !filter.isChecked();
-			filter.setChecked(newState);
-			fViewer.setChecked(filter, newState);
-		}
-
-		public void checkFilter(Filter filter, boolean checked) {
-			filter.setChecked(checked);
-			fViewer.setChecked(filter, checked);
-		}
-
-		/**
-		 * @see IStructuredContentProvider#getElements(Object)
-		 */
-		@Override
-		public Object[] getElements(Object inputElement) {
-			return fFilters.toArray();
-		}
-
-		/**
-		 * @see IContentProvider#inputChanged(Viewer, Object, Object)
-		 */
-		@Override
-		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-		}
-
-		/**
-		 * @see IContentProvider#dispose()
-		 */
-		@Override
-		public void dispose() {
-		}
+		fJavaFilterTable.performOk(null);
 	}
 
 }
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/snippeteditor/SelectImportsDialog.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/snippeteditor/SelectImportsDialog.java
index 869ffb6..1b47c18 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/snippeteditor/SelectImportsDialog.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/snippeteditor/SelectImportsDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -14,246 +14,80 @@
 package org.eclipse.jdt.internal.debug.ui.snippeteditor;
 
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.eclipse.debug.internal.ui.SWTFactory;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchEngine;
-import org.eclipse.jdt.internal.debug.ui.ExceptionHandler;
-import org.eclipse.jdt.internal.debug.ui.Filter;
-import org.eclipse.jdt.internal.debug.ui.FilterLabelProvider;
-import org.eclipse.jdt.internal.debug.ui.FilterViewerComparator;
 import org.eclipse.jdt.internal.debug.ui.IJavaDebugHelpContextIds;
-import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
-import org.eclipse.jdt.ui.IJavaElementSearchConstants;
-import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jdt.internal.ui.filtertable.Filter;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.ButtonLabel;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.DialogLabels;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterStorage;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterTableConfig;
 import org.eclipse.jface.dialogs.TitleAreaDialog;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.viewers.TableViewer;
-import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.osgi.util.NLS;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.dialogs.ElementListSelectionDialog;
-import org.eclipse.ui.dialogs.SelectionDialog;
 
 public class SelectImportsDialog extends TitleAreaDialog {
 
-	private String[] fImports;
-	private Button fAddPackageButton;
-	private Button fAddTypeButton;
-	private Button fRemoveImportsButton;
-	private TableViewer fImportsViewer;
-	private Table fImportsTable;
+	private JavaFilterTable fJavaFilterTable;
 	private JavaSnippetEditor fEditor;
 
-	private ImportsContentProvider fImportContentProvider;
-
-	/**
-	 * Content provider for the table.  Content consists of instances of Filter.
-	 */
-	protected class ImportsContentProvider implements IStructuredContentProvider {
-
-		private TableViewer fViewer;
-		private List<Filter> fImportNames;
-
-		public ImportsContentProvider(TableViewer viewer) {
-			fViewer = viewer;
-			populateImports();
-		}
-
-		protected void populateImports() {
-			fImportNames= new ArrayList<>(1);
-			if (fImports != null) {
-				for (String name : fImports) {
-					addImport(name);
-				}
-			}
-		}
-
-		protected void addImport(String name) {
-			Filter imprt = new Filter(name, false);
-			if (!fImportNames.contains(imprt)) {
-				fImportNames.add(imprt);
-				fViewer.add(imprt);
-			}
-		}
-
-
-		protected void removeImports(Object[] imports) {
-			for (Object i : imports) {
-				Filter imprt = (Filter) i;
-				fImportNames.remove(imprt);
-			}
-			fViewer.remove(imports);
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
-		 */
-		@Override
-		public Object[] getElements(Object inputElement) {
-			return fImportNames.toArray();
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
-		 */
-		@Override
-		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
-		}
-
-		/* (non-Javadoc)
-		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
-		 */
-		@Override
-		public void dispose() {
-		}
-	}
-
 	public SelectImportsDialog(JavaSnippetEditor editor, String[] imports) {
 		super(editor.getShell());
 		fEditor= editor;
-		fImports= imports;
-	}
+		fJavaFilterTable = new JavaFilterTable(new FilterStorage() {
 
-	private void createImportButtons(Composite container) {
-		PlatformUI.getWorkbench().getHelpSystem().setHelp(container, IJavaDebugHelpContextIds.SNIPPET_IMPORTS_DIALOG);
-		Composite bcomp = SWTFactory.createComposite(container, container.getFont(), 1, 1, GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_FILL, 0, 0);
-		GridLayout gl = (GridLayout) bcomp.getLayout();
-		gl.verticalSpacing = 0;
-		// Add type button
-		fAddTypeButton = SWTFactory.createPushButton(bcomp,
-				SnippetMessages.getString("SelectImportsDialog.Add_&Type_1"),  //$NON-NLS-1$
-				SnippetMessages.getString("SelectImportsDialog.Choose_a_Type_to_Add_as_an_Import_2"),  //$NON-NLS-1$
-				null);
-		fAddTypeButton.addSelectionListener(new SelectionListener() {
 			@Override
-			public void widgetSelected(SelectionEvent se) {
-				addType();
+			public Filter[] getStoredFilters(boolean defaults) {
+				if (imports == null) {
+					return new Filter[0];
+				}
+				Filter[] result = new Filter[imports.length];
+				for (int i = 0; i < imports.length; i++) {
+					result[i] = new Filter(imports[i], true);
+				}
+				return result;
 			}
+
 			@Override
-			public void widgetDefaultSelected(SelectionEvent se) {
+			public void setStoredFilters(IPreferenceStore store, Filter[] filters) {
+				fEditor.setImports(imports);
 			}
-		});
 
-		// Add package button
-		fAddPackageButton = SWTFactory.createPushButton(bcomp,
-				SnippetMessages.getString("SelectImportsDialog.Add_&Package_3"),  //$NON-NLS-1$
-				SnippetMessages.getString("SelectImportsDialog.Choose_a_Package_to_Add_as_an_Import_4"),  //$NON-NLS-1$
-				null);
-		fAddPackageButton.addSelectionListener(new SelectionListener() {
+		},
+				new FilterTableConfig()
+					.setAddType(new ButtonLabel(
+							SnippetMessages.getString("SelectImportsDialog.Add_&Type_1"), //$NON-NLS-1$
+							SnippetMessages.getString("SelectImportsDialog.Choose_a_Type_to_Add_as_an_Import_2"))) //$NON-NLS-1$
+					.setAddPackage(new ButtonLabel(
+							SnippetMessages.getString("SelectImportsDialog.Add_&Package_3"), //$NON-NLS-1$
+							SnippetMessages.getString("SelectImportsDialog.Choose_a_Package_to_Add_as_an_Import_4"))) //$NON-NLS-1$
+					.setRemove(new ButtonLabel(
+							SnippetMessages.getString("SelectImportsDialog.&Remove_5"), //$NON-NLS-1$
+							SnippetMessages.getString("SelectImportsDialog.Remove_All_Selected_Imports_6"))) //$NON-NLS-1$
+					.setAddPackageDialog(new DialogLabels(
+							SnippetMessages.getString("SelectImportsDialog.Add_package_as_import_7"), //$NON-NLS-1$
+							SnippetMessages.getString("SelectImportsDialog.&Select_a_package_to_add_as_an_Import_10"))) //$NON-NLS-1$
+					.setAddTypeDialog(new DialogLabels(
+							SnippetMessages.getString("SelectImportsDialog.Add_Type_as_Import_12"), //$NON-NLS-1$
+							SnippetMessages.getString("SelectImportsDialog.&Select_a_type_to_add_to_add_as_an_import_15"))) //$NON-NLS-1$
+					.setConsiderAllTypes(true)
+					.setCheckable(false)
+					.setLabelText(SnippetMessages.getString("SelectImportsDialog.imports_heading")) //$NON-NLS-1$
+					.setHelpContextId(IJavaDebugHelpContextIds.SNIPPET_IMPORTS_DIALOG)) {
 			@Override
-			public void widgetSelected(SelectionEvent se) {
-				addPackage();
+			protected IJavaSearchScope getTypeSearchScope() {
+				return SearchEngine.createJavaSearchScope(new IJavaElement[]{fEditor.getJavaProject()}, true);
 			}
-			@Override
-			public void widgetDefaultSelected(SelectionEvent se) {
-			}
-		});
-
-		// Remove button
-		fRemoveImportsButton = SWTFactory.createPushButton(bcomp,
-				SnippetMessages.getString("SelectImportsDialog.&Remove_5"),  //$NON-NLS-1$
-				SnippetMessages.getString("SelectImportsDialog.Remove_All_Selected_Imports_6"),  //$NON-NLS-1$
-				null);
-		fRemoveImportsButton.addSelectionListener(new SelectionListener() {
-			@Override
-			public void widgetSelected(SelectionEvent se) {
-				removeImports();
-			}
-			@Override
-			public void widgetDefaultSelected(SelectionEvent se) {
-			}
-		});
-		fRemoveImportsButton.setEnabled(false);
-	}
-
-	private void removeImports() {
-		IStructuredSelection selection = (IStructuredSelection)fImportsViewer.getSelection();
-		fImportContentProvider.removeImports(selection.toArray());
-	}
-
-	private void addPackage() {
-		Shell shell= fAddPackageButton.getDisplay().getActiveShell();
-		ElementListSelectionDialog dialog = null;
-		try {
-			IJavaProject project= fEditor.getJavaProject();
-			List<IJavaElement> projects= new ArrayList<>();
-			projects.add(project);
-			for (IPackageFragmentRoot root : project.getAllPackageFragmentRoots()) {
-				projects.add(root.getParent());
-			}
-			dialog = JDIDebugUIPlugin.createAllPackagesDialog(shell, projects.toArray(new IJavaProject[projects.size()]), false);
-		} catch (JavaModelException jme) {
-			String title= SnippetMessages.getString("SelectImportsDialog.Add_package_as_import_7"); //$NON-NLS-1$
-			String message= SnippetMessages.getString("SelectImportsDialog.Could_not_open_package_selection_dialog_8");  //$NON-NLS-1$
-			ExceptionHandler.handle(jme, title, message);
-			return;
-		}
-		if (dialog == null) {
-			return;
-		}
-		dialog.setTitle(SnippetMessages.getString("SelectImportsDialog.Add_package_as_import_7"));  //$NON-NLS-1$
-		dialog.setMessage(SnippetMessages.getString("SelectImportsDialog.&Select_a_package_to_add_as_an_Import_10")); //$NON-NLS-1$
-		dialog.setMultipleSelection(true);
-		if (dialog.open() == IDialogConstants.CANCEL_ID) {
-			return;
-		}
-		Object[] packages= dialog.getResult();
-		if (packages != null) {
-			for (Object p : packages) {
-				IJavaElement pkg = (IJavaElement) p;
-				String filter = pkg.getElementName();
-				filter += ".*"; //$NON-NLS-1$
-				fImportContentProvider.addImport(filter);
-			}
-		}
-	}
-
-	private void addType() {
-		Shell shell= fAddTypeButton.getDisplay().getActiveShell();
-		SelectionDialog dialog= null;
-		try {
-			dialog= JavaUI.createTypeDialog(shell, PlatformUI.getWorkbench().getProgressService(),
-				SearchEngine.createJavaSearchScope(new IJavaElement[]{fEditor.getJavaProject()}, true), IJavaElementSearchConstants.CONSIDER_ALL_TYPES, false);
-		} catch (JavaModelException jme) {
-			String title= SnippetMessages.getString("SelectImportsDialog.Add_Type_as_Import_12"); //$NON-NLS-1$
-			String message= SnippetMessages.getString("SelectImportsDialog.Could_not_open_class_selection_dialog_13"); //$NON-NLS-1$
-			ExceptionHandler.handle(jme, title, message);
-			return;
-		}
-
-		dialog.setTitle(SnippetMessages.getString("SelectImportsDialog.Add_Type_as_Import_12")); //$NON-NLS-1$
-		dialog.setMessage(SnippetMessages.getString("SelectImportsDialog.&Select_a_type_to_add_to_add_as_an_import_15")); //$NON-NLS-1$
-		if (dialog.open() == IDialogConstants.CANCEL_ID) {
-			return;
-		}
-
-		Object[] types= dialog.getResult();
-		if (types != null && types.length > 0) {
-			IType type = (IType)types[0];
-			fImportContentProvider.addImport(type.getFullyQualifiedName());
-		}
+		};
 	}
 
 	/* (non-Javadoc)
@@ -268,31 +102,11 @@
 		gl.marginLeft = 7;
 		gl.marginTop = 0;
 		gl.marginBottom = 0;
-		SWTFactory.createLabel(outer, SnippetMessages.getString("SelectImportsDialog.imports_heading"), 2); //$NON-NLS-1$
-		fImportsTable= new Table(outer, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
-		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
-		gd.heightHint = 150;
-		fImportsTable.setLayoutData(gd);
-		fImportsViewer = new TableViewer(fImportsTable);
-		fImportsViewer.setLabelProvider(new FilterLabelProvider());
-		fImportsViewer.setComparator(new FilterViewerComparator());
-		fImportContentProvider = new ImportsContentProvider(fImportsViewer);
-		fImportsViewer.setContentProvider(fImportContentProvider);
-		// input just needs to be non-null
-		fImportsViewer.setInput(this);
-		fImportsViewer.addSelectionChangedListener(new ISelectionChangedListener() {
-			@Override
-			public void selectionChanged(SelectionChangedEvent event) {
-				ISelection selection = event.getSelection();
-				if (selection.isEmpty()) {
-					fRemoveImportsButton.setEnabled(false);
-				} else {
-					fRemoveImportsButton.setEnabled(true);
-				}
-			}
-		});
-		createImportButtons(outer);
-		applyDialogFont(outer);
+
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(outer, IJavaDebugHelpContextIds.SNIPPET_IMPORTS_DIALOG);
+
+		fJavaFilterTable.createTable(outer);
+
 		return parent;
 	}
 
@@ -301,16 +115,7 @@
 	 */
 	@Override
 	protected void okPressed() {
-		String[] imports= null;
-		Object[] results= fImportContentProvider.getElements(null);
-		if (results != null && results.length > 0) {
-			imports= new String[results.length];
-			for (int i = 0; i < results.length; i++) {
-				Filter imprt = (Filter)results[i];
-				imports[i]= imprt.getName();
-			}
-		}
-		fEditor.setImports(imports);
+		fJavaFilterTable.performOk(null);
 		super.okPressed();
 	}
 
diff --git a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
index b02536c..c0d4efe 100644
--- a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true
-Bundle-Version: 3.19.0.qualifier
+Bundle-Version: 3.19.100.qualifier
 Bundle-ClassPath: jdimodel.jar
 Bundle-Activator: org.eclipse.jdt.internal.debug.core.JDIDebugPlugin
 Bundle-Vendor: %providerName
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
index 82f5ff9..2152c60 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
@@ -420,11 +420,11 @@
 
 	private void scanAndFixSignature(String genericSignature, String erasureSignature, StringBuilder fixedSignature) {
 		/*
-		 * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current content. For example variable
-		 * type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
+		 * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current context.
+		 * For example variable type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
 		 *
 		 * and also generic signature such as Ljava/util/function/Predicate<+Ljava/util/List<Ljava/lang/Integer;>;>; Ljava/util/Comparator<-TT;>;
-		 * which will fail the properly resolved to the type.
+		 * which will fail to properly resolved to the type.
 		 */
 		if (genericSignature.startsWith(String.valueOf(Signature.C_TYPE_VARIABLE)) ||
 				genericSignature.startsWith(String.valueOf(Signature.C_CAPTURE)) ||
@@ -444,8 +444,11 @@
 
 		String[] typeArguments = Signature.getTypeArguments(genericSignature);
 		if (typeArguments.length > 0) {
-			if (typeArguments.length == 1 && typeArguments[0].equals(String.valueOf(Signature.C_STAR))) {
-				// this is when we have recursive generics, so remove the generics to avoid compilation issues.
+			if (typeArguments.length == 1 &&
+					(typeArguments[0].equals(String.valueOf(Signature.C_STAR)) ||
+							typeArguments[0].startsWith(String.valueOf(new char[] { Signature.C_EXTENDS, Signature.C_TYPE_VARIABLE })))) {
+				// this is when we have recursive generics or we have a upper bound type variable
+				// so remove the generics to avoid compilation issues.
 				return;
 			}
 
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java
new file mode 100644
index 0000000..9f743a2
--- /dev/null
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/FirstLambdaLocationLocator.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2022 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.core.breakpoints;
+
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.LambdaExpression;
+
+public class FirstLambdaLocationLocator extends ASTVisitor {
+	private int fNodeLength = -1;
+	private int fNodeOffset = -1;
+	private int fLineOffset = -1;
+	private int fLineEndPosition = -1;
+	private String fLambdaMethodName;
+	private boolean fLocationFound = false;
+
+	public FirstLambdaLocationLocator(int lineOffset, int lineEndPosition) {
+		fLineOffset = lineOffset;
+		fLineEndPosition = lineEndPosition;
+	}
+
+	/**
+	 * Return of the name of the lambda method where the valid location is.
+	 */
+	public String getLambdaMethodName() {
+		return fLambdaMethodName;
+	}
+
+	public int getNodeLength() {
+		return fNodeLength;
+	}
+
+	public int getNodeOffset() {
+		return fNodeOffset;
+	}
+
+	@Override
+	public boolean visit(LambdaExpression node) {
+		if (fLocationFound) {
+			return false;
+		}
+		if (node.getStartPosition() < fLineOffset || node.getStartPosition() > fLineEndPosition) {
+			return false;
+		}
+		fNodeLength = node.getLength();
+		fNodeOffset = node.getStartPosition();
+		IMethodBinding methodBinding = node.resolveMethodBinding();
+		if (methodBinding != null) {
+			fLambdaMethodName = toMethodName(methodBinding);
+			fLocationFound = true;
+		}
+		return false;
+	}
+
+	private String toMethodName(IMethodBinding methodBinding) {
+		String key = methodBinding.getKey();
+		return key.substring(key.indexOf('.') + 1, key.indexOf('('));
+	}
+
+}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
index 42f014c..206894a 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaMethodBreakpoint.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 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
@@ -30,6 +30,7 @@
 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
 import org.eclipse.jdt.internal.debug.core.model.JDIThread;
+import org.eclipse.jdt.internal.debug.core.model.LambdaUtils;
 import org.eclipse.jdt.internal.debug.core.model.MethodResult;
 import org.eclipse.jdt.internal.debug.core.model.MethodResult.ResultType;
 
@@ -464,7 +465,7 @@
 				}
 			}
 
-			if (getMethodName() != null) {
+			if (getMethodName() != null && !LambdaUtils.isLambdaMethod(method)) {
 				if (!method.name().equals(getMethodName())) {
 					return true;
 				}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java
index 76cdc9a..91d3864 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/ValidBreakpointLocationLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2003, 2019 IBM Corporation and others.
+ * Copyright (c) 2003, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -54,6 +54,7 @@
 import org.eclipse.jdt.core.dom.FieldDeclaration;
 import org.eclipse.jdt.core.dom.ForStatement;
 import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.IVariableBinding;
 import org.eclipse.jdt.core.dom.IfStatement;
@@ -63,6 +64,7 @@
 import org.eclipse.jdt.core.dom.InstanceofExpression;
 import org.eclipse.jdt.core.dom.Javadoc;
 import org.eclipse.jdt.core.dom.LabeledStatement;
+import org.eclipse.jdt.core.dom.LambdaExpression;
 import org.eclipse.jdt.core.dom.LineComment;
 import org.eclipse.jdt.core.dom.MarkerAnnotation;
 import org.eclipse.jdt.core.dom.MemberRef;
@@ -125,6 +127,8 @@
 	public static final int LOCATION_LINE = 1;
 	public static final int LOCATION_METHOD = 2;
 	public static final int LOCATION_FIELD = 3;
+	public static final int LOCATION_LAMBDA_METHOD = 4;
+
 
 	private CompilationUnit fCompilationUnit;
 	private int fLineNumber;
@@ -134,10 +138,15 @@
 
 	private int fLocationType;
 	private boolean fLocationFound;
+	private boolean fLambdaVisited;
+	private String fLambdaMethodName;
 	private String fTypeName;
 	private int fLineLocation;
 	private int fMemberOffset;
+	private int fNodeLength;
 	private List<String> fLabels;
+	private int fInputOffset;
+	private int fInputLength;
 
 	/**
 	 * @param compilationUnit
@@ -156,6 +165,30 @@
 		fBindingsResolved = bindingsResolved;
 		fBestMatch = bestMatch;
 		fLocationFound = false;
+		fInputOffset = -1;
+		fInputLength = -1;
+	}
+
+	/**
+	 * @param compilationUnit
+	 *            the JDOM CompilationUnit of the source code.
+	 * @param lineNumber
+	 *            the line number in the source code where to put the breakpoint.
+	 * @param bestMatch
+	 *            if <code>true</code> look for the best match, otherwise look only for a valid line
+	 * @param offset
+	 *            selection offset on which breakpoints should be toggled
+	 * @param end
+	 *            selection end on which breakpoints should be toggled
+	 */
+	public ValidBreakpointLocationLocator(CompilationUnit compilationUnit, int lineNumber, boolean bindingsResolved, boolean bestMatch, int offset, int end) {
+		fCompilationUnit = compilationUnit;
+		fLineNumber = lineNumber;
+		fBindingsResolved = bindingsResolved;
+		fBestMatch = bestMatch;
+		fLocationFound = false;
+		fInputOffset = offset;
+		fInputLength = end;
 	}
 
 	/**
@@ -189,6 +222,12 @@
 	}
 
 	/**
+	 * Return of the name of the lambda method where the valid location is.
+	 */
+	public String getLambdaMethodName() {
+		return fLambdaMethodName;
+	}
+	/**
 	 * Return the line number of the computed valid location
 	 */
 	public int getLineLocation() {
@@ -206,6 +245,13 @@
 		return fMemberOffset;
 	}
 
+	public int getNodeLength() {
+		return fNodeLength;
+	}
+
+	public CompilationUnit getCompilationUnit() {
+		return fCompilationUnit;
+	}
 	/**
 	 * Compute the name of the type which contains this node. <br>
 	 * <br>
@@ -281,13 +327,17 @@
 	 *            lines.
 	 */
 	private boolean visit(ASTNode node, boolean isCode) {
+		int startPosition = node.getStartPosition();
+		int startLine = lineNumber(startPosition);
+		int endLine = lineNumber(startPosition + node.getLength() - 1);
+
 		// if we already found a correct location
-		// no need to check the element inside.
-		if (fLocationFound) {
+		// no need to check the element inside if the line number doesn't match.
+		// if line numbers match we still need to visit the whole expression in this line
+		// to make sure we have any lambda's we were looking for which we didn't visited yet.
+		if (fLambdaVisited || (fLocationFound && fLineNumber != startLine)) {
 			return false;
 		}
-		int startPosition = node.getStartPosition();
-		int endLine = lineNumber(startPosition + node.getLength() - 1);
 		// if the position is not in this part of the code
 		// no need to check the element inside.
 		if (endLine < fLineNumber) {
@@ -298,7 +348,6 @@
 		// breakpoint is requested on this line or on a previous line, this is a
 		// valid
 		// location
-		int startLine = lineNumber(startPosition);
 		if (isCode && (fLineNumber <= startLine)) {
 			fLineLocation = startLine;
 			fLocationFound = true;
@@ -595,6 +644,15 @@
 	 */
 	@Override
 	public boolean visit(ClassInstanceCreation node) {
+		if (visit(node, false)) {
+			List<? extends ASTNode> arguments = node.arguments();
+			for (ASTNode astNode : arguments) {
+				if (astNode instanceof LambdaExpression) {
+					astNode.accept(this);
+					return false;
+				}
+			}
+		}
 		return visit(node, true);
 	}
 
@@ -708,7 +766,16 @@
 	 */
 	@Override
 	public boolean visit(ExpressionStatement node) {
-		return visit(node, false);
+		if (fLocationFound && fLambdaVisited) {
+			return false;
+		}
+		if (visit(node, false)) {
+			if (node.getExpression() instanceof MethodInvocation) {
+				node.getExpression().accept(this);
+				return false;
+			}
+		}
+		return visit(node, true);
 	}
 
 	/**
@@ -948,6 +1015,56 @@
 		fLabels.remove(fLabels.size() - 1);
 	}
 
+	@Override
+	public boolean visit(LambdaExpression node) {
+		fMemberOffset = node.getStartPosition();
+		fNodeLength = node.getLength();
+		if (fInputOffset != -1 && fInputLength > 0 && fInputOffset >= fMemberOffset && fInputOffset + fInputLength <= fMemberOffset + fNodeLength) {
+			IMethodBinding methodBinding = node.resolveMethodBinding();
+			if (methodBinding != null) {
+				fLambdaVisited = true;
+				fLocationType = LOCATION_LAMBDA_METHOD;
+				fLambdaMethodName = toMethodName(methodBinding);
+				fLocationFound = true;
+				return false;
+			}
+		} else if (fLocationType != LOCATION_LAMBDA_METHOD) {
+			fLocationType = LOCATION_LINE;
+			fTypeName = computeTypeName(node);
+			int startLine = lineNumber(fMemberOffset);
+			if (fLineNumber <= startLine) {
+				if (fInputOffset != -1) {
+					fLineLocation = lineNumber(fInputOffset);
+				} else {
+					fLineLocation = startLine;
+				}
+			} else {
+				// visit the body
+				ASTNode body = node.getBody();
+				if (body instanceof Block) { // body is null for abstract methods
+					fLocationFound = false;
+					Block block1 = (Block) body;
+					if (visit(block1)) {
+						for (Object object : block1.statements()) {
+							if (object instanceof ASTNode) {
+								ASTNode node1 = (ASTNode) object;
+								node1.accept(this);
+							}
+
+						}
+					}
+				}
+			}
+			return false;
+		}
+		return visit(node, true);
+	}
+
+	private String toMethodName(IMethodBinding methodBinding) {
+		String key = methodBinding.getKey();
+		return key.substring(key.indexOf('.') + 1, key.indexOf('('));
+	}
+	
 	/*
 	 * (non-Javadoc)
 	 *
@@ -1028,6 +1145,27 @@
 	 */
 	@Override
 	public boolean visit(MethodInvocation node) {
+		if (fLocationFound && fLambdaVisited) {
+			return false;
+		}
+		if (visit(node, false)) {
+			// first run through arguments to avoid pre-mature line breakpoint identification
+			List<? extends ASTNode> arguments = node.arguments();
+			for (ASTNode astNode : arguments) {
+				// arguments needs to be accepted to handle stream operation where the lambda debug point
+				// is expected on a lambda expression which is a parameter on a nested method invocation like
+				// strings.stream().collect(Collectors.toMap(s -> s.substring(0), s -> s))
+				astNode.accept(this);
+				if (astNode instanceof LambdaExpression && fLambdaVisited) {
+					return false;
+				}
+			}
+
+			Expression expression = node.getExpression();
+			if (expression instanceof ClassInstanceCreation || expression instanceof MethodInvocation) {
+				expression.accept(this);
+			}
+		}
 		return visit(node, true);
 	}
 
@@ -1403,6 +1541,9 @@
 						fLocationFound = true;
 						fLocationType = LOCATION_LINE;
 						fTypeName = computeTypeName(node);
+						if (initializer instanceof MethodInvocation || initializer instanceof LambdaExpression) {
+							initializer.accept(this);
+						}
 					return false;
 				}
 				initializer.accept(this);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
index c246fbc..ce6c70d 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
@@ -2787,8 +2787,8 @@
 					fStepResultTimeoutTriggered.set(false);
 				}
 
+				Location stepOverLocation2 = fStepOverLocation;
 				if (getStepKind() == StepRequest.STEP_OVER) {
-					Location stepOverLocation2 = fStepOverLocation;
 					if (stepOverLocation2 != null && fStepOverFrameCount >= 0) {
 						int underlyingFrameCount = getUnderlyingFrameCount();
 						if (underlyingFrameCount > fStepOverFrameCount) {
@@ -2824,7 +2824,8 @@
 				// a filtered location, or if we're back where
 				// we started on a step into, do another step of the same kind
 				if (locationShouldBeFiltered(currentLocation)
-						|| shouldDoExtraStepInto(currentLocation)) {
+						|| shouldDoExtraStepInto(currentLocation)
+						|| (getStepKind() == StepRequest.STEP_OVER && isSyntheticAndNotAvailable(currentLocation, stepOverLocation2))) {
 					setRunning(true);
 					deleteStepRequest();
 					createSecondaryStepRequest();
@@ -2985,6 +2986,22 @@
 				fStepOverFrameCount =  -1;
 			}
 		}
+
+		private boolean isSyntheticAndNotAvailable(Location currentLocation, Location previousLocation) {
+			if (previousLocation != null) {
+				Method method = previousLocation.method();
+				if (method != null && method.isSynthetic()) {
+					boolean isLambdaMethod = LambdaUtils.isLambdaMethod(method);
+					if (isLambdaMethod) {
+						int currentLineNumber = currentLocation.lineNumber();
+						if (currentLineNumber == -1) {
+							return true;
+						}
+					}
+				}
+			}
+			return false;
+		}
 	}
 
 	/**
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
index ac0c551..aee1c97 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/LambdaUtils.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2018 IBM Corporation and others.
+ * Copyright (c) 2018, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,11 +13,12 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.debug.core.model;
 
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.model.IStackFrame;
@@ -29,11 +30,15 @@
 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDILambdaVariable;
 import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext;
 
+import com.sun.jdi.Method;
+
 /**
  * Utility class for Lambda Expressions and Stack frames Place holder for all Lambda operation encapsulation.
  */
 public class LambdaUtils {
 
+	private static final String LAMBDA_METHOD_PREFIX = "lambda$"; //$NON-NLS-1$
+
 	/**
 	 * Inspects the top stack frame of the context; if that frame is a lambda frame, looks for a variable with the specified name in that frame and
 	 * two frames below that frame.
@@ -83,9 +88,10 @@
 		List<IVariable> variables = new ArrayList<>();
 		if (LambdaUtils.isLambdaFrame(frame)) {
 			IThread thread = frame.getThread();
-			IStackFrame[] stackFrames = thread.getStackFrames();
-			for (int i = 0; i < Math.min(3, stackFrames.length); ++i) {
-				IStackFrame stackFrame = stackFrames[i];
+			// look for two frames below the frame which is provided instead starting from first frame.
+			List<IStackFrame> stackFrames = Stream.of(thread.getStackFrames()).dropWhile(f -> f != frame)
+					.limit(3).collect(Collectors.toUnmodifiableList());
+			for (IStackFrame stackFrame : stackFrames) {
 				IVariable[] stackFrameVariables = stackFrame.getVariables();
 				variables.addAll(Arrays.asList(stackFrameVariables));
 				for (IVariable frameVariable : stackFrameVariables) {
@@ -118,7 +124,7 @@
 	 * @since 3.8
 	 */
 	public static boolean isLambdaFrame(IJavaStackFrame frame) throws DebugException {
-		return frame.isSynthetic() && frame.getName().startsWith("lambda$"); //$NON-NLS-1$
+		return frame.isSynthetic() && frame.getName().startsWith(LAMBDA_METHOD_PREFIX);
 	}
 
 	/**
@@ -133,6 +139,18 @@
 		return (variable instanceof IJavaFieldVariable) && ((IJavaFieldVariable) variable).getDeclaringType().getName().contains("$Lambda$"); //$NON-NLS-1$
 	}
 
+	/**
+	 * Returns if the method is a lambda method.
+	 *
+	 * @param method
+	 *            the method for which to check
+	 * @return <code>True</code> if the method is a lambda method else return <code>False</code>
+	 * @since 3.20
+	 */
+	public static boolean isLambdaMethod(Method method) {
+		return method.name().startsWith(LAMBDA_METHOD_PREFIX);
+	}
+
 	private static boolean isLambdaObjectVariable(IVariable variable) {
 		return variable instanceof JDILambdaVariable;
 	}
diff --git a/org.eclipse.jdt.debug/pom.xml b/org.eclipse.jdt.debug/pom.xml
index 6962c64..7c9290d 100644
--- a/org.eclipse.jdt.debug/pom.xml
+++ b/org.eclipse.jdt.debug/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug</artifactId>
-  <version>3.19.0-SNAPSHOT</version>
+  <version>3.19.100-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/org.eclipse.jdt.launching/META-INF/MANIFEST.MF b/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
index 5d10e8c..7724823 100644
--- a/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.launching; singleton:=true
-Bundle-Version: 3.19.400.qualifier
+Bundle-Version: 3.19.500.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.launching.LaunchingPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.java
index 9845c55..56fc147 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.java
@@ -124,6 +124,7 @@
 	public static String StandardVMDebugger_Establishing_debug_connection____5;
 
 	public static String StandardVMRunner__0____1___2;
+	public static String StandardVMRunner__0____1___2_3;
 	public static String StandardVMRunner__0__at_localhost__1__1;
 	public static String StandardVMRunner_Specified_working_directory_does_not_exist_or_is_not_a_directory___0__3;
 	public static String StandardVMRunner_Launching_VM____1;
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.properties b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.properties
index 64aa308..41099b6 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.properties
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/LaunchingMessages.properties
@@ -102,6 +102,7 @@
 StandardVMDebugger_Establishing_debug_connection____5=Establishing debug connection...
 
 StandardVMRunner__0____1___2={0} ({1})
+StandardVMRunner__0____1___2_3={0} ({1}) [pid: {2}]
 StandardVMRunner__0__at_localhost__1__1={0} at localhost:{1}
 StandardVMRunner_Specified_working_directory_does_not_exist_or_is_not_a_directory___0__3=Specified working directory does not exist or is not a directory: {0}
 StandardVMRunner_Launching_VM____1=Launching VM...
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/Standard11xVMRunner.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/Standard11xVMRunner.java
index 33d7db5..16758a9 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/Standard11xVMRunner.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/Standard11xVMRunner.java
@@ -132,7 +132,7 @@
 			return;
 		}
 		String timestamp = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(new Date(System.currentTimeMillis()));
-		IProcess process= DebugPlugin.newProcess(launch, p, renderProcessLabel(cmdLine, timestamp));
+		IProcess process = DebugPlugin.newProcess(launch, p, renderProcessLabel(p, cmdLine, timestamp));
 		process.setAttribute(DebugPlugin.ATTR_PATH, cmdLine[0]);
 		process.setAttribute(IProcess.ATTR_CMDLINE, renderCommandLine(cmdLine));
 		String ltime = launch.getAttribute(DebugPlugin.ATTR_LAUNCH_TIMESTAMP);
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java
index f75790e..399d08b 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMDebugger.java
@@ -347,7 +347,7 @@
 					return;
 				}
 				String timestamp = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(new Date(System.currentTimeMillis()));
-				IProcess process= newProcess(launch, p, renderProcessLabel(cmdLine, timestamp), getDefaultProcessMap());
+				IProcess process = newProcess(launch, p, renderProcessLabel(p, cmdLine, timestamp), getDefaultProcessMap());
 				process.setAttribute(DebugPlugin.ATTR_PATH, cmdLine[0]);
 				process.setAttribute(IProcess.ATTR_CMDLINE, renderCommandLine(cmdLine));
 				String ltime = launch.getAttribute(DebugPlugin.ATTR_LAUNCH_TIMESTAMP);
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java
index 872f463..6997670 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMRunner.java
@@ -81,13 +81,31 @@
 
 	/**
 	 * Returns the 'rendered' name for the specified command line
-	 * @param commandLine the command line
-	 * @param timestamp the run-at time for the process
+	 *
+	 * @param p
+	 * @param commandLine
+	 *            the command line
+	 * @param timestamp
+	 *            the run-at time for the process
 	 * @return the name for the process
 	 */
-	public static String renderProcessLabel(String[] commandLine, String timestamp) {
-		String format= LaunchingMessages.StandardVMRunner__0____1___2;
-		return NLS.bind(format, new String[] { commandLine[0], timestamp });
+	public static String renderProcessLabel(Process p, String[] commandLine, String timestamp) {
+		String processId = getProcessId(p);
+		if (processId == null) {
+			String format = LaunchingMessages.StandardVMRunner__0____1___2;
+			return NLS.bind(format, new String[] { commandLine[0], timestamp });
+		}
+		String format = LaunchingMessages.StandardVMRunner__0____1___2_3;
+		return NLS.bind(format, new String[] { commandLine[0], timestamp, processId });
+	}
+
+	private static String getProcessId(Process p) {
+		try {
+			return p != null ? Long.toString(p.pid()) : null;
+		} catch (UnsupportedOperationException e) {
+			// ignore, pid() is not implemented in this JVM
+		}
+		return null;
 	}
 
 	/**
@@ -524,7 +542,7 @@
 			return;
 		}
 		String timestamp = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(new Date(System.currentTimeMillis()));
-		IProcess process= newProcess(launch, p, renderProcessLabel(cmdLine, timestamp), getDefaultProcessMap());
+		IProcess process = newProcess(launch, p, renderProcessLabel(p, cmdLine, timestamp), getDefaultProcessMap());
 		process.setAttribute(DebugPlugin.ATTR_PATH, cmdLine[0]);
 		process.setAttribute(IProcess.ATTR_CMDLINE, renderCommandLine(cmdLine));
 		String ltime = launch.getAttribute(DebugPlugin.ATTR_LAUNCH_TIMESTAMP);
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java
index da19c89..b71b371 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/JavaLaunchDelegate.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -111,7 +111,7 @@
 					if (modName != null && modName.length() > 0) {
 						String defaultModuleName = null;
 						String moduleName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MODULE_NAME, defaultModuleName);
-						if (moduleName != null) {
+						if (moduleName != null && !moduleName.isEmpty()) {
 							runConfig.setModuleDescription(moduleName);
 						} else {
 							runConfig.setModuleDescription(modName);
diff --git a/org.eclipse.jdt.launching/pom.xml b/org.eclipse.jdt.launching/pom.xml
index e51b4ed..15a6b81 100644
--- a/org.eclipse.jdt.launching/pom.xml
+++ b/org.eclipse.jdt.launching/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright (c) 2012, 2021 Eclipse Foundation and others.
+  Copyright (c) 2012, 2022 Eclipse Foundation and others.
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.launching</artifactId>
-  <version>3.19.400-SNAPSHOT</version>
+  <version>3.19.500-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   
   <build>