Bug 577182: [16] Provide option in New Record Creation Wizard to create
stubs for the main function.

Change-Id: I8010d9cb690ac7b4a42db10266df8b0dd2f7743b
Signed-off-by: Kalyan Prasad Tatavarthi <kalyan_prasad@in.ibm.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/187674
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/wizardapi/NewTypeWizardTest17.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/wizardapi/NewTypeWizardTest17.java
index 137ef42..513ab78 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/wizardapi/NewTypeWizardTest17.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/wizardapi/NewTypeWizardTest17.java
@@ -1197,7 +1197,7 @@
 		wizardPage.setEnclosingTypeSelection(false, true);
 		wizardPage.setTypeName("Rec1", true);
 
-		wizardPage.setMethodStubSelection(true, true);
+		wizardPage.setMethodStubSelection(false, true, true);
 
 		List<ITypeBinding> interfaces= new ArrayList<>();
 		wizardPage.setSuperInterfacesList(interfaces, true);
@@ -1250,7 +1250,7 @@
 	}
 
 	@Test
-	public void testCreateRecordWithOutAbstractMethodStubs() throws Exception {
+	public void testCreateRecordWithOutAbstractMethodStubsAndMain() throws Exception {
 		fJProject1= projectSetup.getProject();
 		fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
 		fpack1= fSourceFolder.createPackageFragment("test1", false, null);
@@ -1261,7 +1261,7 @@
 		wizardPage.setEnclosingTypeSelection(false, true);
 		wizardPage.setTypeName("Rec1", true);
 
-		wizardPage.setMethodStubSelection(false, true);
+		wizardPage.setMethodStubSelection(false, false, true);
 
 		List<ITypeBinding> interfaces= new ArrayList<>();
 		wizardPage.setSuperInterfacesList(interfaces, true);
@@ -1289,6 +1289,123 @@
 		StringAsserts.assertEqualStringIgnoreDelim(actual, expected);
 	}
 
+	@Test
+	public void testCreateRecordWithMain() throws Exception {
+		fJProject1= projectSetup.getProject();
+		fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+		fpack1= fSourceFolder.createPackageFragment("test1", false, null);
+
+		NewRecordWizardPage wizardPage= new NewRecordWizardPage();
+		wizardPage.setPackageFragmentRoot(fSourceFolder, true);
+		wizardPage.setPackageFragment(fpack1, true);
+		wizardPage.setEnclosingTypeSelection(false, true);
+		wizardPage.setTypeName("Rec1", true);
+
+		wizardPage.setMethodStubSelection(true, false, true);
+
+		List<ITypeBinding> interfaces= new ArrayList<>();
+		wizardPage.setSuperInterfacesList(interfaces, true);
+
+		wizardPage.setAddComments(true, true);
+		wizardPage.enableCommentControl(true);
+
+		wizardPage.createType(null);
+
+		String actual= wizardPage.getCreatedType().getCompilationUnit().getSource();
+
+		String expected= "" +
+				"/**\n" +
+				" * File\n" +
+				" */\n" +
+				"package test1;\n" +
+				"\n" +
+				"/**\n" +
+				" * Type\n" +
+				" */\n" +
+				"public record Rec1() {\n" +
+				"\n" +
+				"    /**\n" +
+				"     * Method\n" +
+				"     */\n" +
+				"    public static void main(String[] args) {\n" +
+				"\n" +
+				"    }\n" +
+				"\n" +
+				"}" ;
+
+		StringAsserts.assertEqualStringIgnoreDelim(actual, expected);
+	}
+
+	@Test
+	public void testCreateRecordWithAbstractMethodStubsAndMain() throws Exception {
+		fJProject1= projectSetup.getProject();
+		fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+		fpack1= fSourceFolder.createPackageFragment("test1", false, null);
+
+		NewRecordWizardPage wizardPage= new NewRecordWizardPage();
+		wizardPage.setPackageFragmentRoot(fSourceFolder, true);
+		wizardPage.setPackageFragment(fpack1, true);
+		wizardPage.setEnclosingTypeSelection(false, true);
+		wizardPage.setTypeName("Rec1", true);
+
+		wizardPage.setMethodStubSelection(true, true, true);
+
+		List<ITypeBinding> interfaces= new ArrayList<>();
+		wizardPage.setSuperInterfacesList(interfaces, true);
+
+		wizardPage.setAddComments(true, true);
+		wizardPage.enableCommentControl(true);
+
+		wizardPage.createType(null);
+
+		String actual= wizardPage.getCreatedType().getCompilationUnit().getSource();
+
+		String expected= "" +
+				"/**\n" +
+				" * File\n" +
+				" */\n" +
+				"package test1;\n" +
+				"\n" +
+				"/**\n" +
+				" * Type\n" +
+				" */\n" +
+				"public record Rec1() {\n" +
+				"\n" +
+				"    /**\n" +
+				"     * Overridden\n" +
+				"     */\n" +
+				"    @Override\n" +
+				"    public boolean equals(Object arg0) {\n" +
+				"        return false;\n" +
+				"    }\n" +
+				"\n" +
+				"    /**\n" +
+				"     * Overridden\n" +
+				"     */\n" +
+				"    @Override\n" +
+				"    public int hashCode() {\n" +
+				"        return 0;\n" +
+				"    }\n" +
+				"\n" +
+				"    /**\n" +
+				"     * Overridden\n" +
+				"     */\n" +
+				"    @Override\n" +
+				"    public String toString() {\n" +
+				"        return null;\n" +
+				"    }\n\n" +
+				"    /**\n" +
+				"     * Method\n" +
+				"     */\n" +
+				"    public static void main(String[] args) {\n" +
+				"\n" +
+				"    }\n" +
+				"\n" +
+				"}" ;
+
+		StringAsserts.assertEqualStringIgnoreDelim(actual, expected);
+	}
+
 	protected static CompilationUnit getASTRoot(ICompilationUnit cu) {
 		return ASTResolving.createQuickFixAST(cu, null);
 	}
diff --git a/org.eclipse.jdt.ui/.settings/.api_filters b/org.eclipse.jdt.ui/.settings/.api_filters
index 63b2da0..9c11233 100644
--- a/org.eclipse.jdt.ui/.settings/.api_filters
+++ b/org.eclipse.jdt.ui/.settings/.api_filters
@@ -185,6 +185,19 @@
             </message_arguments>
         </filter>
     </resource>
+    <resource path="ui/org/eclipse/jdt/ui/wizards/NewRecordWizardPage.java" type="org.eclipse.jdt.ui.wizards.NewRecordWizardPage">
+        <filter comment="this was not an api( in a noreference class), so can be removed" id="338792546">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.ui.wizards.NewRecordWizardPage"/>
+                <message_argument value="setMethodStubSelection(boolean, boolean)"/>
+            </message_arguments>
+        </filter>
+        <filter comment="@since not required for overridden methods" id="1143996420">
+            <message_arguments>
+                <message_argument value="createControl(Composite)"/>
+            </message_arguments>
+        </filter>
+    </resource>
     <resource path="ui/org/eclipse/jdt/ui/wizards/NewTypeWizardPage.java" type="org.eclipse.jdt.ui.wizards.NewTypeWizardPage">
         <filter id="336658481">
             <message_arguments>
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewClassWizardPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewClassWizardPage.java
index a40dac8..bd65217 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewClassWizardPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewClassWizardPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 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
@@ -32,8 +32,6 @@
 
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.manipulation.CodeGeneration;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
 import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
@@ -265,25 +263,7 @@
 		createInheritedMethods(type, doConstr, doInherited, imports, new SubProgressMonitor(monitor, 1));
 
 		if (doMain) {
-			StringBuilder buf= new StringBuilder();
-			final String lineDelim= "\n"; // OK, since content is formatted afterwards //$NON-NLS-1$
-			if (isAddComments()) {
-				String comment= CodeGeneration.getMethodComment(type.getCompilationUnit(), type.getTypeQualifiedName('.'), "main", new String[] { "args" }, new String[0], Signature.createTypeSignature("void", true), null, lineDelim); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-				if (comment != null) {
-					buf.append(comment);
-					buf.append(lineDelim);
-				}
-			}
-			buf.append("public static void main("); //$NON-NLS-1$
-			buf.append(imports.addImport("java.lang.String")); //$NON-NLS-1$
-			buf.append("[] args) {"); //$NON-NLS-1$
-			buf.append(lineDelim);
-			final String content= CodeGeneration.getMethodBodyContent(type.getCompilationUnit(), type.getTypeQualifiedName('.'), "main", false, "", lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
-			if (content != null && content.length() != 0)
-				buf.append(content);
-			buf.append(lineDelim);
-			buf.append("}"); //$NON-NLS-1$
-			type.createMethod(buf.toString(), null, false, null);
+			createMainMethod(type, imports);
 		}
 
 		IDialogSettings dialogSettings= getDialogSettings();
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewRecordWizardPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewRecordWizardPage.java
index 2041283..b6a4de4 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewRecordWizardPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewRecordWizardPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 IBM Corporation and others.
+ * Copyright (c) 2020, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -45,9 +45,7 @@
  * To implement a different kind of a new record wizard page, extend <code>NewTypeWizardPage</code>.
  * </p>
  *
- *
  * @noextend This class is not intended to be subclassed by clients.
- * @noreference This class is not intended to be referenced by clients.
  */
 public class NewRecordWizardPage extends NewTypeWizardPage {
 
@@ -59,6 +57,7 @@
 
 	/**
 	 * Creates a new <code>NewRecordWizardPage</code>
+	 * @since 3.25
 	 */
 	public NewRecordWizardPage() {
 		super(TYPE, PAGE_NAME);
@@ -67,6 +66,7 @@
 		setDescription(NewWizardMessages.NewRecordWizardPage_description);
 
 		String[] buttonNames= new String[] {
+				NewWizardMessages.NewClassWizardPage_methods_main,
 				NewWizardMessages.NewRecordWizardPage_methods_inherited
 		};
 		fMethodStubsButtons= new SelectionButtonDialogFieldGroup(SWT.CHECK, buttonNames, 1);
@@ -81,6 +81,7 @@
 	 * page.
 	 *
 	 * @param selection used to initialize the fields
+	 * @since 3.25
 	 */
 	public void init(IStructuredSelection selection) {
 		IJavaElement jelem= getInitialJavaElement(selection);
@@ -88,7 +89,8 @@
 		initTypePage(jelem);
 		doStatusUpdate();
 
-		boolean createUnimplemented= true;
+		boolean createUnimplemented= false;
+		boolean createMain= false;
 		IDialogSettings dialogSettings= getDialogSettings();
 		if (dialogSettings != null) {
 			IDialogSettings section= dialogSettings.getSection(PAGE_NAME);
@@ -97,7 +99,7 @@
 			}
 		}
 
-		setMethodStubSelection(createUnimplemented, true);
+		setMethodStubSelection(createMain, createUnimplemented, true);
 	}
 
 	// ------ validation --------
@@ -130,9 +132,6 @@
 
 	// ------ UI --------
 
-	/*
-	 * @see WizardPage#createControl
-	 */
 	@Override
 	public void createControl(Composite parent) {
 		initializeDialogUnits(parent);
@@ -192,12 +191,15 @@
 	/**
 	 * Sets the selection state of the method stub checkboxes.
 	 *
+	 * @param createMain initial selection state of the 'Create Main' checkbox.
 	 * @param createInherited initial selection state of the 'Create inherited abstract methods' checkbox.
 	 * @param canBeModified if <code>true</code> the method stub checkboxes can be changed by
 	 * the user. If <code>false</code> the buttons are "read-only"
+	 * @since 3.25
 	 */
-	public void setMethodStubSelection(boolean createInherited, boolean canBeModified) {
-		fMethodStubsButtons.setSelection(0, createInherited);
+	public void setMethodStubSelection(boolean createMain, boolean createInherited, boolean canBeModified) {
+		fMethodStubsButtons.setSelection(0, createMain);
+		fMethodStubsButtons.setSelection(1, createInherited);
 
 		fMethodStubsButtons.setEnabled(canBeModified);
 	}
@@ -207,32 +209,48 @@
 	 * checkbox.
 	 *
 	 * @return the selection state of the 'Create inherited abstract methods' checkbox
+	 * @since 3.25
 	 */
 	public boolean isCreateInherited() {
+		return fMethodStubsButtons.isSelected(1);
+	}
+
+	/**
+	 * Returns the current selection state of the 'Create Main' checkbox.
+	 *
+	 * @return the selection state of the 'Create Main' checkbox
+	 * @since 3.25
+	 */
+	public boolean isCreateMain() {
 		return fMethodStubsButtons.isSelected(0);
 	}
 
 	// ---- creation ----------------
 
-		/*
-		 * @see NewTypeWizardPage#createTypeMembers
-		 */
-		@Override
-		protected void createTypeMembers(IType type, ImportsManager imports, IProgressMonitor monitor) throws CoreException {
-			boolean doInherited= isCreateInherited();
-			createInheritedMethods(type, false, doInherited, imports, SubMonitor.convert(monitor, 1));
+	/*
+	 * @see NewTypeWizardPage#createTypeMembers
+	 */
+	@Override
+	protected void createTypeMembers(IType type, ImportsManager imports, IProgressMonitor monitor) throws CoreException {
+		boolean doInherited= isCreateInherited();
+		boolean doMain= isCreateMain();
+		createInheritedMethods(type, false, doInherited, imports, SubMonitor.convert(monitor, 1));
 
-			IDialogSettings dialogSettings= getDialogSettings();
-			if (dialogSettings != null) {
-				IDialogSettings section= dialogSettings.getSection(PAGE_NAME);
-				if (section == null) {
-					section= dialogSettings.addNewSection(PAGE_NAME);
-				}
-				section.put(SETTINGS_CREATEUNIMPLEMENTED, doInherited);
-			}
-
-			if (monitor != null) {
-				monitor.done();
-			}
+		if (doMain) {
+			createMainMethod(type, imports);
 		}
+
+		IDialogSettings dialogSettings= getDialogSettings();
+		if (dialogSettings != null) {
+			IDialogSettings section= dialogSettings.getSection(PAGE_NAME);
+			if (section == null) {
+				section= dialogSettings.addNewSection(PAGE_NAME);
+			}
+			section.put(SETTINGS_CREATEUNIMPLEMENTED, doInherited);
+		}
+
+		if (monitor != null) {
+			monitor.done();
+		}
+	}
 }
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewTypeWizardPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewTypeWizardPage.java
index ca453e4..a03a7b0 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewTypeWizardPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/NewTypeWizardPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2020 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
@@ -3265,6 +3265,39 @@
 		return null;
 	}
 
+	/**
+	 * Creates the stub for 'public static void main(String[] args)' method
+	 *
+	 * @param type the type for which the main method is to be created
+	 * @param imports an import manager to add all needed import statements
+	 * @return the created method.
+	 * @throws CoreException thrown when the creation fails.
+	 * @since 3.25
+	 */
+	protected IMethod createMainMethod(IType type, ImportsManager imports) throws CoreException{
+		if (type != null ) {
+			StringBuilder buf= new StringBuilder();
+			final String lineDelim= "\n"; // OK, since content is formatted afterwards //$NON-NLS-1$
+			if (isAddComments()) {
+				String comment= CodeGeneration.getMethodComment(type.getCompilationUnit(), type.getTypeQualifiedName('.'), "main", new String[] { "args" }, new String[0], Signature.createTypeSignature("void", true), null, lineDelim); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				if (comment != null) {
+					buf.append(comment);
+					buf.append(lineDelim);
+				}
+			}
+			buf.append("public static void main("); //$NON-NLS-1$
+			buf.append(imports.addImport("java.lang.String")); //$NON-NLS-1$
+			buf.append("[] args) {"); //$NON-NLS-1$
+			buf.append(lineDelim);
+			final String content= CodeGeneration.getMethodBodyContent(type.getCompilationUnit(), type.getTypeQualifiedName('.'), "main", false, "", lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+			if (content != null && content.length() != 0)
+				buf.append(content);
+			buf.append(lineDelim);
+			buf.append("}"); //$NON-NLS-1$
+			return type.createMethod(buf.toString(), null, false, null);
+		}
+		return null;
+	}
 
 	/**
 	 * Creates the bodies of all unimplemented methods and constructors and adds them to the type.