Merge pull request #2146 from apache/master

Sync master to release 12.0 beta 5
diff --git a/enterprise/j2ee.common/src/org/netbeans/modules/j2ee/common/ClasspathUtil.java b/enterprise/j2ee.common/src/org/netbeans/modules/j2ee/common/ClasspathUtil.java
index 16d1324..af2be10 100644
--- a/enterprise/j2ee.common/src/org/netbeans/modules/j2ee/common/ClasspathUtil.java
+++ b/enterprise/j2ee.common/src/org/netbeans/modules/j2ee/common/ClasspathUtil.java
@@ -24,7 +24,9 @@
 import java.io.IOException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -292,18 +294,33 @@
                 J2eePlatform j2eePlatformLocal = j2eePlatform != null ? j2eePlatform : Deployment.getDefault().getJ2eePlatform(j2eeModuleProvider.getServerInstanceID());
                 if (j2eePlatformLocal != null) {
                     try {
-                        return j2eePlatformLocal.getClasspathEntries(j2eeModuleProvider.getConfigSupport().getLibraries());
+                        File[] files = j2eePlatformLocal.getClasspathEntries(j2eeModuleProvider.getConfigSupport().getLibraries());
+                        sortClassPathEntries(files);
+                        return files;
                     } catch (ConfigurationException ex) {
                         LOGGER.log(Level.FINE, null, ex);
-                        return j2eePlatformLocal.getClasspathEntries();
+                        File[] files = j2eePlatformLocal.getClasspathEntries();
+                        sortClassPathEntries(files);
+                        return files;
                     }
                 }
             }
         }
         if (j2eePlatform != null) {
-            return j2eePlatform.getClasspathEntries();
+            File[] files = j2eePlatform.getClasspathEntries();
+            sortClassPathEntries(files);
+            return files;
         }
         return new File[]{};
     }
+    
+    private static void sortClassPathEntries(File[] files) {
+        Arrays.sort(files, new Comparator < File > () {
+            @Override
+            public int compare(File f1, File f2) {
+                return f1.getAbsolutePath().compareTo(f2.getAbsolutePath());
+            }
+        });
+    }
 
 }
diff --git a/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/ConfigurationPanel.java b/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/ConfigurationPanel.java
index da9b7ce..d1343f6 100644
--- a/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/ConfigurationPanel.java
+++ b/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/ConfigurationPanel.java
@@ -117,7 +117,7 @@
             
             if (extraModule.isRequiredFor(jdk)) {
                 jCheckBox.setSelected(true);
-                jCheckBox.setEnabled(false);
+//                jCheckBox.setEnabled(false);
                 extrasFilter.add(extraModule);
             }
             jCheckBox.addActionListener(e -> {
diff --git a/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FindComponentModules.java b/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FindComponentModules.java
index 59dd307..d1a9fca 100644
--- a/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FindComponentModules.java
+++ b/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FindComponentModules.java
@@ -299,7 +299,7 @@
     private void registerExtraDownloadable(FeatureInfo fi, FeatureInfo.ExtraModuleInfo fmi) {
         boolean required = false;
         if (fmi.isRequiredFor(jdk)) {
-            required = true;
+//            required = true;
         }
         if (fi.getExtraModulesRequiredText() != null && fi.getExtraModulesRecommendedText() == null) {
             required = true;
diff --git a/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FoDUpdateUnitProvider.java b/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FoDUpdateUnitProvider.java
index 3a2f4a1..b0e49d8 100644
--- a/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FoDUpdateUnitProvider.java
+++ b/ergonomics/ide.ergonomics/src/org/netbeans/modules/ide/ergonomics/fod/FoDUpdateUnitProvider.java
@@ -103,7 +103,7 @@
                 boolean required = false;
 
                 if (mi.isRequiredFor(jdk)) {
-                    required = true;
+//                    required = true;
                 }
                 if (fi.getExtraModulesRequiredText() != null && fi.getExtraModulesRecommendedText() == null) {
                     required = true;
diff --git a/ide/editor.fold.nbui/src/org/netbeans/modules/editor/fold/ui/FoldViewFactory.java b/ide/editor.fold.nbui/src/org/netbeans/modules/editor/fold/ui/FoldViewFactory.java
index 1c91044..c729e3e 100644
--- a/ide/editor.fold.nbui/src/org/netbeans/modules/editor/fold/ui/FoldViewFactory.java
+++ b/ide/editor.fold.nbui/src/org/netbeans/modules/editor/fold/ui/FoldViewFactory.java
@@ -260,24 +260,25 @@
 
     @Override
     public void foldHierarchyChanged(FoldHierarchyEvent evt) {
-        if (!collapsedFoldEncountered) {
-            // Check if any collapsed fold was added or a collapsed/expanded state changed
-            for (int i = evt.getAddedFoldCount() - 1; i >= 0; i--) {
-                if (evt.getAddedFold(i).isCollapsed()) {
-                    collapsedFoldEncountered = true;
+        boolean collapsedAdded = false;
+        boolean changedToCollapsed = false;
+        // Check if any collapsed fold was added or a collapsed/expanded state changed
+        for (int i = evt.getAddedFoldCount() - 1; i >= 0; i--) {
+            if (evt.getAddedFold(i).isCollapsed()) {
+                collapsedAdded = true;
+                break;
+            }
+        }
+        if (!collapsedAdded) {
+            for (int i = evt.getFoldStateChangeCount() - 1; i >= 0; i--) {
+                FoldStateChange foldStateChange = evt.getFoldStateChange(i);
+                if (foldStateChange.isCollapsedChanged() && foldStateChange.getFold().isCollapsed()) {
+                    changedToCollapsed = true;
                     break;
                 }
             }
-            if (!collapsedFoldEncountered) {
-                for (int i = evt.getFoldStateChangeCount() - 1; i >= 0; i--) {
-                    FoldStateChange foldStateChange = evt.getFoldStateChange(i);
-                    if (foldStateChange.isCollapsedChanged() && foldStateChange.getFold().isCollapsed()) {
-                        collapsedFoldEncountered = true;
-                        break;
-                    }
-                }
-            }
         }
+        collapsedFoldEncountered |= collapsedAdded || changedToCollapsed;
         JTextComponent comp = textComponent();
         if (collapsedFoldEncountered && comp != null) {
             // [TODO] there could be more detailed inspection done among folds
@@ -289,7 +290,11 @@
                 ViewUtils.log(CHANGE_LOG, "CHANGE in FoldViewFactory: <" + // NOI18N
                         startOffset + "," + endOffset + ">\n"); // NOI18N
             }
-            comp.putClientProperty("editorcaret.updateRetainsVisibleOnce", Boolean.TRUE);
+            if (collapsedAdded) {
+                // this hint covers a specific case when a fold is created as *initially* collapsed
+                // to maintain caret position on screen, if the caret was visible. 
+                comp.putClientProperty("editorcaret.updateRetainsVisibleOnce", Boolean.TRUE);
+            }
             fireEvent(EditorViewFactoryChange.createList(startOffset, endOffset,
                     EditorViewFactoryChange.Type.PARAGRAPH_CHANGE));
         }
diff --git a/ide/editor.lib2/src/org/netbeans/api/editor/caret/EditorCaret.java b/ide/editor.lib2/src/org/netbeans/api/editor/caret/EditorCaret.java
index 76a9cd9d..926c5e3 100644
--- a/ide/editor.lib2/src/org/netbeans/api/editor/caret/EditorCaret.java
+++ b/ide/editor.lib2/src/org/netbeans/api/editor/caret/EditorCaret.java
@@ -1999,6 +1999,9 @@
                 if (cbounds != null) {
                     // save relative position of the main caret
                     maybeSaveCaretOffset(cbounds);
+                    if (log) {
+                        LOG.fine("EditorCaret.update: forced:true, savedBounds=" + cbounds + ", relativeOffset=" + lastCaretVisualOffset + "\n"); // NOI18N
+                    }
                 }
             }
             if (!calledFromPaint && !c.isValid() /* && maintainVisible == null */) {
@@ -2025,6 +2028,11 @@
                         scroll = scrollToLastCaret;
                         scrollToLastCaret = false;
                     }
+                    if (lastCaretVisualOffset == -1) {
+                        // wasn't able to save the visual offset, the caret was already off screen. Do not scroll just because of fold updates.
+                        forceUpdate = false;
+                        c.putClientProperty("editorcaret.updateRetainsVisibleOnce", null); // NOI18N
+                    }
                     if (scroll || forceUpdate) {
                         Rectangle caretBounds;
                         Rectangle oldCaretBounds;
@@ -2035,6 +2043,10 @@
                             caretBounds = lastCaretItem.getCaretBounds();
                             oldCaretBounds = caretBounds;
                         }
+                        if (log) {
+                            LOG.fine("EditorCaret.update: caretBounds=" + caretBounds + "\n"); // NOI18N
+                            LOG.fine("EditorCaret.update: oldCaretBounds=" + oldCaretBounds + "\n"); // NOI18N
+                        }
                         if (caretBounds != null) {
                             Rectangle scrollBounds = new Rectangle(caretBounds); // Must possibly be cloned upon change
                             if (viewport != null && isWrapping()) {
diff --git a/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/IgnoreUnignoreCommand.java b/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/IgnoreUnignoreCommand.java
index a5c19d6..255ef1b 100644
--- a/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/IgnoreUnignoreCommand.java
+++ b/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/IgnoreUnignoreCommand.java
@@ -137,9 +137,7 @@
             for (ListIterator<IgnoreRule> it = ignoreRules.listIterator(); it.hasNext(); ) {
                 String s = it.next().getPattern(false);
                 bw.write(s, 0, s.length());
-                if (it.hasNext()) {
-                    bw.newLine();
-                }
+                bw.newLine();
             }
         } finally {
             if (bw != null) {
diff --git a/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/AbstractGitTestCase.java b/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/AbstractGitTestCase.java
index 5b72680..2fff96b 100644
--- a/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/AbstractGitTestCase.java
+++ b/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/AbstractGitTestCase.java
@@ -98,23 +98,15 @@
     }
 
     protected void write(File file, String str) throws IOException {
-        FileWriter w = null;
-        try {
-            w = new FileWriter(file);
+        try (FileWriter w = new FileWriter(file)) {
             w.write(str);
             w.flush();
-        } finally {
-            if (w != null) {
-                w.close();
-            }
         }
     }
 
     protected String read(File file) throws IOException {
         StringBuilder sb = new StringBuilder();
-        BufferedReader r = null;
-        try {
-            r = new BufferedReader(new FileReader(file));
+        try (BufferedReader r = new BufferedReader(new FileReader(file))) {
             String s = r.readLine();
             if (s != null) {
                 while( true ) {
@@ -124,14 +116,22 @@
                     sb.append('\n');
                 }
             }
-        } finally {
-            if (r != null) {
-                r.close();
-            }
         }
         return sb.toString();
     }
 
+    protected boolean containsCRorLF(File file) throws IOException {
+        try (BufferedReader r = new BufferedReader(new FileReader(file))) {
+            int i;
+            while ((i = r.read()) > -1) {
+                if (i == '\n' || i == '\r') {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     protected static void assertStatus (Map<File, GitStatus> statuses, File workDir, File file, boolean tracked, Status headVsIndex, Status indexVsWorking, Status headVsWorking, boolean conflict) {
         GitStatus status = statuses.get(file);
         assertNotNull(file.getAbsolutePath() + " not in " + statuses.keySet(), status);
diff --git a/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/IgnoreTest.java b/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/IgnoreTest.java
index 98f7c2c..28234bd 100644
--- a/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/IgnoreTest.java
+++ b/ide/libs.git/test/unit/src/org/netbeans/libs/git/jgit/commands/IgnoreTest.java
@@ -589,4 +589,13 @@
         statuses = client.getStatus(new File[0], NULL_PROGRESS_MONITOR);
         assertEquals(Status.STATUS_IGNORED, statuses.get(f).getStatusIndexWC());
     }
+
+    public void testGitIgnoreEndsWithNewLine () throws Exception {
+        File f = new File(workDir, "file");
+        f.createNewFile();
+        File gitIgnore = new File(workDir, Constants.DOT_GIT_IGNORE);
+        File[] ignores = getClient(workDir).ignore(new File[] { f }, NULL_PROGRESS_MONITOR);
+        assertTrue(gitIgnore.exists());
+        assertTrue("The .gitignore file should ends with an empty new line.",containsCRorLF(gitIgnore));
+    }
 }
diff --git a/ide/o.eclipse.jgit/external/binaries-list b/ide/o.eclipse.jgit/external/binaries-list
index 6d97cfd..d8fcf30 100644
--- a/ide/o.eclipse.jgit/external/binaries-list
+++ b/ide/o.eclipse.jgit/external/binaries-list
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-75C27F087134757A8AC335E637C117D68D41C773 org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r
+E0BA7A468E8C62DA8521CA3A06A061D4DDE95223 org.eclipse.jgit:org.eclipse.jgit:5.5.1.201910021850-r
diff --git a/ide/o.eclipse.jgit/external/org.eclipse.jgit-5.5.0.201909110433-r-license.txt b/ide/o.eclipse.jgit/external/org.eclipse.jgit-5.5.1.201910021850-r-license.txt
similarity index 97%
rename from ide/o.eclipse.jgit/external/org.eclipse.jgit-5.5.0.201909110433-r-license.txt
rename to ide/o.eclipse.jgit/external/org.eclipse.jgit-5.5.1.201910021850-r-license.txt
index 13d4a9f..3590582 100644
--- a/ide/o.eclipse.jgit/external/org.eclipse.jgit-5.5.0.201909110433-r-license.txt
+++ b/ide/o.eclipse.jgit/external/org.eclipse.jgit-5.5.1.201910021850-r-license.txt
@@ -1,6 +1,6 @@
 Name: JGit Library
 Origin: Eclipse
-Version: 5.5.0.201909110433-r
+Version: 5.5.1.201910021850-r
 Description: Integration library for Git client
 License: EDL-1.0
 URL: http://www.eclipse.org/jgit/download/
diff --git a/ide/o.eclipse.jgit/nbproject/project.properties b/ide/o.eclipse.jgit/nbproject/project.properties
index 4628519..16d0891 100644
--- a/ide/o.eclipse.jgit/nbproject/project.properties
+++ b/ide/o.eclipse.jgit/nbproject/project.properties
@@ -14,5 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-release.external/org.eclipse.jgit-5.5.0.201909110433-r.jar=modules/org-eclipse-jgit.jar
+release.external/org.eclipse.jgit-5.5.1.201910021850-r.jar=modules/org-eclipse-jgit.jar
 is.autoload=true
diff --git a/ide/o.eclipse.jgit/nbproject/project.xml b/ide/o.eclipse.jgit/nbproject/project.xml
index 3b8d6ce..3c7e798 100644
--- a/ide/o.eclipse.jgit/nbproject/project.xml
+++ b/ide/o.eclipse.jgit/nbproject/project.xml
@@ -73,7 +73,7 @@
             <public-packages/>
             <class-path-extension>
                 <runtime-relative-path>org-eclipse-jgit.jar</runtime-relative-path>
-                <binary-origin>external/org.eclipse.jgit-5.5.0.201909110433-r.jar</binary-origin>
+                <binary-origin>external/org.eclipse.jgit-5.5.1.201910021850-r.jar</binary-origin>
             </class-path-extension>
         </data>
     </configuration>
diff --git a/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java b/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
index 7be3a9f..74994da 100644
--- a/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
+++ b/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
@@ -386,6 +386,9 @@
                         }
                         sourcePositions = new SourcePositionsImpl(block, sourcePositions, sp[0], blockPos, -1);
                         path = tu.getPathElementOfKind(Tree.Kind.LAMBDA_EXPRESSION, tu.pathFor(new TreePath(blockPath.getParentPath(), block), offset, sourcePositions));
+                        if (path == null) {
+                            return null;
+                        }
                         lambdaBody = ((LambdaExpressionTree) path.getLeaf()).getBody();
                         bodyPos = (int) sourcePositions.getStartPosition(root, lambdaBody);
                         if (bodyPos >= offset) {
diff --git a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask18FeaturesTest.java b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask18FeaturesTest.java
index 98f5b18..b8cda0c 100644
--- a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask18FeaturesTest.java
+++ b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask18FeaturesTest.java
@@ -338,6 +338,10 @@
         performTest("LambdaExpressionOutsideMethodBody", 959, null, "lambdaOutsideMethodBodyContent.pass", "1.8");
     }
     
+    public void testNETBEANS_4259() throws Exception {
+        performTest("LambdaExpression", 986, "return (String s", "stringVarName.pass", "1.8");
+    }
+
     static {
         JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
     }
diff --git a/java/java.openjdk.project/release/scripts/build-langtools-consol.xml b/java/java.openjdk.project/release/scripts/build-langtools-consol.xml
index c2aa3e4..ffa8ce2 100644
--- a/java/java.openjdk.project/release/scripts/build-langtools-consol.xml
+++ b/java/java.openjdk.project/release/scripts/build-langtools-consol.xml
@@ -18,7 +18,7 @@
  - under the License.
  -->
 <!--
-SUPPORTED_ACTIONS: build,clean,rebuild,run.single,debug.single,compile.single,run,select.tool,debug
+SUPPORTED_ACTIONS: build,build-fast,clean,rebuild,run.single,debug.single,compile.single,run,select.tool,debug
 -->
 <project name="jdk-project-build-langtools">
     <condition property="langtools.jdk.home" value="${nb.jdk.project.target.java.home}">
@@ -27,5 +27,7 @@
             <available file="javac.exe" filepath="${nb.jdk.project.target.java.home}/bin" />
         </or>
     </condition>
-    <import file="${basedir}/make/langtools/netbeans/langtools/build.xml"/>
+    <property name="langtools.build.location" value="make/langtools/netbeans/langtools/build.xml" />
+    <import file="${basedir}/${langtools.build.location}"/>
+    <target name="build-fast" depends="build" />
 </project>
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java
index b34d6f1..9edd57c 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/ActionProviderImpl.java
@@ -409,12 +409,15 @@
     static String builtClassesDirsForBootClassPath(FileObject testFile) {
         File buildDir = BuildUtils.getBuildTargetDir(testFile);
         Project prj = FileOwnerQuery.getOwner(testFile);
+        Settings settings = prj.getLookup().lookup(Settings.class);
+        boolean useLangtoolsBuild = settings == null || settings.isUseAntBuild();
         List<FileObject> roots = new ArrayList<>();
 
         if (buildDir != null) {
             FileObject repo = prj.getProjectDirectory().getParent().getParent();
             if (repo.getNameExt().equals("langtools") &&
-                ShortcutUtils.getDefault().shouldUseCustomTest(repo.getNameExt(), FileUtil.getRelativePath(repo, testFile))) {
+                ShortcutUtils.getDefault().shouldUseCustomTest(repo.getNameExt(), FileUtil.getRelativePath(repo, testFile)) &&
+                useLangtoolsBuild) {
                 listAllRoots(BuildUtils.getFileObject(prj.getProjectDirectory(), "../.."), new LinkedList<>(Arrays.asList("build", "classes")), roots);
                 listAllRoots(BuildUtils.getFileObject(prj.getProjectDirectory(), "../.."), new LinkedList<>(Arrays.asList("build", "*", "classes")), roots);
             } else {
@@ -441,12 +444,15 @@
     static boolean fullBuild(FileObject testFile) {
         File buildDir = BuildUtils.getBuildTargetDir(testFile);
         Project prj = FileOwnerQuery.getOwner(testFile);
+        Settings settings = prj.getLookup().lookup(Settings.class);
+        boolean useLangtoolsBuild = settings == null || settings.isUseAntBuild();
 
         if (buildDir != null) {
             FileObject repo = prj.getProjectDirectory().getParent().getParent();
             String repoName = ShortcutUtils.getDefault().inferLegacyRepository(prj);
             return !("langtools".equals(repoName) &&
-                    ShortcutUtils.getDefault().shouldUseCustomTest(repoName, FileUtil.getRelativePath(repo, testFile)));
+                    ShortcutUtils.getDefault().shouldUseCustomTest(repoName, FileUtil.getRelativePath(repo, testFile)) &&
+                    useLangtoolsBuild);
         }
 
         return false;
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java
index 2097caa..8671561 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/ActionProviderImpl.java
@@ -99,6 +99,7 @@
     private final FileObject script;
     private final FileObject genericScript;
     private final String[] supportedActions;
+    private final String[] genericSupportedActions;
 
     public ActionProviderImpl(JDKProject project) {
         this.project = project;
@@ -128,10 +129,15 @@
 
         script = FileUtil.toFileObject(scriptFile);
 
+        supportedActions = readSupportedActions(script);
+        genericSupportedActions = readSupportedActions(genericScript);
+    }
+
+    private String[] readSupportedActions(FileObject from) {
         String[] supported = new String[0];
 
         try {
-            for (String l : script.asLines("UTF-8")) {
+            for (String l : from.asLines("UTF-8")) {
                 if (l.contains("SUPPORTED_ACTIONS:")) {
                     String[] actions = l.substring(l.indexOf(':') + 1).trim().split(",");
                     Set<String> filteredActions = new HashSet<>();
@@ -151,13 +157,13 @@
             //???
             Exceptions.printStackTrace(ex);
         }
-        
-        supportedActions = supported;
+        return supported;
     }
 
     @Override
     public String[] getSupportedActions() {
-        return supportedActions;
+        Settings settings = project.getLookup().lookup(Settings.class);
+        return settings.isUseAntBuild() ? supportedActions : genericSupportedActions;
     }
 
     @Override
@@ -171,8 +177,17 @@
             }
         }
         FileObject scriptFO = script;
+        Settings settings = project.getLookup().lookup(Settings.class);
+        Properties props = new Properties();
+        if (settings.isUseAntBuild()) {
+            props.put("langtools.build.location", settings.getAntBuildLocation());
+        } else {
+            scriptFO = genericScript;
+            if (COMMAND_BUILD_FAST.equals(command)) {
+                command = COMMAND_BUILD_GENERIC_FAST;
+            }
+        }
         if (COMMAND_BUILD_GENERIC_FAST.equals(command)) {
-            Settings settings = project.getLookup().lookup(Settings.class);
             switch (settings.getRunBuildSetting()) {
                 case NEVER:
                     ActionProgress.start(context).finished(true);
@@ -184,7 +199,6 @@
             scriptFO = genericScript;
             command = COMMAND_BUILD_FAST; //XXX: should only do this if genericScript supports it
         }
-        Properties props = new Properties();
         FileObject basedirFO = project.currentModule != null ? scriptFO == genericScript ? project.moduleRepository.getJDKRoot()
                                                                                          : repository
                                                              : repository.getParent();
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/Settings.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/Settings.java
index 0b0fd0c..d993f44 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/Settings.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/Settings.java
@@ -33,6 +33,10 @@
 
     private static final String KEY_BUILD_BEFORE_TESTS = "build-before-test";
     private static final String KEY_JTREG_LOCATION = "jtreg-location";
+    private static final String KEY_USE_ANT_BUILD = "use-langtools-ant-build";
+    private static final String KEY_ANT_BUILD_LOCATION = "langtools-ant-build-location";
+
+    private static final String DEF_ANT_BUILD_LOCATION = "make/langtools/netbeans/langtools/build.xml";
 
     private final Project prj;
 
@@ -64,6 +68,22 @@
         getPrivatePreferences().put(KEY_JTREG_LOCATION, jtregLocation);
     }
 
+    public boolean isUseAntBuild() {
+        return getPrivatePreferences().getBoolean(KEY_USE_ANT_BUILD, true);
+    }
+
+    public void setUseAntBuild(boolean useAntBuild) {
+        getPrivatePreferences().putBoolean(KEY_USE_ANT_BUILD, useAntBuild);
+    }
+
+    public String getAntBuildLocation() {
+        return getPrivatePreferences().get(KEY_ANT_BUILD_LOCATION, DEF_ANT_BUILD_LOCATION);
+    }
+
+    public void setAntBuildLocation(String antBuildLocation) {
+        getPrivatePreferences().put(KEY_ANT_BUILD_LOCATION, antBuildLocation);
+    }
+
     public void flush() {
         try {
             getPrivatePreferences().flush();
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/BuildCategory.form b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/BuildCategory.form
new file mode 100644
index 0000000..9560599
--- /dev/null
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/BuildCategory.form
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements.  See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership.  The ASF licenses this file
+ - to you under the Apache License, Version 2.0 (the
+ - "License"); you may not use this file except in compliance
+ - with the License.  You may obtain a copy of the License at
+ -
+ -   http://www.apache.org/licenses/LICENSE-2.0
+ -
+ - Unless required by applicable law or agreed to in writing,
+ - software distributed under the License is distributed on an
+ - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ - KIND, either express or implied.  See the License for the
+ - specific language governing permissions and limitations
+ - under the License.
+ -->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace min="21" pref="21" max="-2" attributes="0"/>
+                      <Component id="antBuildLocationLabel" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="antBuildLocation" max="32767" attributes="0"/>
+                  </Group>
+                  <Component id="useAntBuild" pref="380" max="32767" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="useAntBuild" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="antBuildLocationLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="antBuildLocation" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace pref="244" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JCheckBox" name="useAntBuild">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties" key="BuildCategory.useAntBuild.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useAntBuildActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="antBuildLocationLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties" key="BuildCategory.antBuildLocationLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="antBuildLocation">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties" key="BuildCategory.antBuildLocation.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/BuildCategory.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/BuildCategory.java
new file mode 100644
index 0000000..31a6988
--- /dev/null
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/BuildCategory.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.openjdk.project.customizer;
+
+import javax.swing.JComponent;
+import org.netbeans.modules.java.openjdk.project.JDKProject;
+import org.netbeans.modules.java.openjdk.project.Settings;
+import org.netbeans.spi.project.ui.support.ProjectCustomizer;
+import org.openide.util.Lookup;
+
+/**
+ *
+ * @author lahvac
+ */
+public class BuildCategory extends javax.swing.JPanel {
+
+    /**
+     * Creates new form BuildCategory
+     */
+    public BuildCategory(boolean useAntBuild, String antBuildLocation) {
+        initComponents();
+        this.useAntBuild.setSelected(useAntBuild);
+        this.antBuildLocation.setText(antBuildLocation);
+        updateEnableDisable();
+    }
+
+    private void updateEnableDisable() {
+        antBuildLocationLabel.setEnabled(useAntBuild.isSelected());
+        antBuildLocation.setEnabled(useAntBuild.isSelected());
+    }
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        useAntBuild = new javax.swing.JCheckBox();
+        antBuildLocationLabel = new javax.swing.JLabel();
+        antBuildLocation = new javax.swing.JTextField();
+
+        org.openide.awt.Mnemonics.setLocalizedText(useAntBuild, org.openide.util.NbBundle.getMessage(BuildCategory.class, "BuildCategory.useAntBuild.text")); // NOI18N
+        useAntBuild.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                useAntBuildActionPerformed(evt);
+            }
+        });
+
+        org.openide.awt.Mnemonics.setLocalizedText(antBuildLocationLabel, org.openide.util.NbBundle.getMessage(BuildCategory.class, "BuildCategory.antBuildLocationLabel.text")); // NOI18N
+
+        antBuildLocation.setText(org.openide.util.NbBundle.getMessage(BuildCategory.class, "BuildCategory.antBuildLocation.text")); // NOI18N
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(21, 21, 21)
+                        .addComponent(antBuildLocationLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(antBuildLocation))
+                    .addComponent(useAntBuild, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(useAntBuild)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(antBuildLocationLabel)
+                    .addComponent(antBuildLocation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(244, Short.MAX_VALUE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void useAntBuildActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useAntBuildActionPerformed
+        updateEnableDisable();
+    }//GEN-LAST:event_useAntBuildActionPerformed
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JTextField antBuildLocation;
+    private javax.swing.JLabel antBuildLocationLabel;
+    private javax.swing.JCheckBox useAntBuild;
+    // End of variables declaration//GEN-END:variables
+
+    @ProjectCustomizer.CompositeCategoryProvider.Registration(projectType=JDKProject.PROJECT_KEY, position=100)
+    public static ProjectCustomizer.CompositeCategoryProvider createCategoryProvider() {
+        return new ProjectCustomizer.CompositeCategoryProvider() {
+            @Override
+            public ProjectCustomizer.Category createCategory(Lookup context) {
+                if (context.lookup(Settings.class) != null)
+                    return ProjectCustomizer.Category.create("build", "Build", null);
+                return null;
+            }
+            @Override
+            public JComponent createComponent(ProjectCustomizer.Category category, Lookup context) {
+                Settings settings = context.lookup(Settings.class);
+                BuildCategory panel = new BuildCategory(settings.isUseAntBuild(), settings.getAntBuildLocation());
+                category.setOkButtonListener(evt -> {
+                    settings.setUseAntBuild(panel.useAntBuild.isSelected());
+                    settings.setAntBuildLocation(panel.antBuildLocation.getText());
+                });
+                category.setStoreListener(evt -> settings.flush());
+                return panel;
+            }
+        };
+    }
+}
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties
index ddf8b88..004a947 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/Bundle.properties
@@ -19,3 +19,6 @@
 TestCategory.buildBeforeTestLabel.text=&Build before running tests:
 TestCategory.jLabel1.text=JTReg location:
 TestCategory.jtregLocation.text=
+BuildCategory.antBuildLocation.text=
+BuildCategory.useAntBuild.text=Use ant build for langtools
+BuildCategory.antBuildLocationLabel.text=Ant build location:
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.form b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.form
index c83038f..c460f34 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.form
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.form
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
+
 <!--
  - Licensed to the Apache Software Foundation (ASF) under one
  - or more contributor license agreements.  See the NOTICE file
@@ -17,6 +18,7 @@
  - specific language governing permissions and limitations
  - under the License.
  -->
+
 <Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
   <AuxValues>
     <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.java
index 8865446..d1d9392 100644
--- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.java
+++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/project/customizer/TestCategory.java
@@ -141,7 +141,7 @@
         put(RunBuild.NEVER, "Never");
     }};
 
-    @CompositeCategoryProvider.Registration(projectType=JDKProject.PROJECT_KEY)
+    @CompositeCategoryProvider.Registration(projectType=JDKProject.PROJECT_KEY, position=200)
     public static CompositeCategoryProvider createCategoryProvider() {
         return new CompositeCategoryProvider() {
             @Override
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
index 799e173..1df27b2 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
@@ -1268,13 +1268,15 @@
             return true;
         }
 
-        public Boolean scanRecord(ClassTree node, Void p) {
+        private Boolean scanRecord(ClassTree node, Void p) {
             boolean old = continuationIndent;
+            int oldIndent = indent;
             try {
+                continuationIndent = true;
                 ModifiersTree mods = node.getModifiers();
                 if (mods != null) {
                     if (scan(mods, p)) {
-                        continuationIndent = true;
+
                         if (cs.placeNewLineAfterModifiers()) {
                             newline();
                         } else {
@@ -1287,12 +1289,17 @@
                 }
                 accept(IDENTIFIER);
                 space();
+
+                if (!ERROR.contentEquals(node.getSimpleName())) {
+                    accept(IDENTIFIER, UNDERSCORE);
+                }
+
                 List<? extends TypeParameterTree> tparams = node.getTypeParameters();
                 if (tparams != null && !tparams.isEmpty()) {
                     if (LT == accept(LT)) {
                         tpLevel++;
                     }
-                    continuationIndent = true;
+
                     for (Iterator<? extends TypeParameterTree> it = tparams.iterator(); it.hasNext();) {
                         TypeParameterTree tparam = it.next();
                         scan(tparam, p);
@@ -1316,16 +1323,11 @@
                                 break;
                         }
                     }
-                    spaces(1, true);
+                    spaces(0, true);
                 }
 
-                if (!ERROR.contentEquals(node.getSimpleName())) {
-                    accept(IDENTIFIER, UNDERSCORE);
-                }
-                //continuationIndent = true;
                 spaces(cs.spaceBeforeMethodDeclParen() ? 1 : 0);
                 accept(LPAREN);
-                int oldIndent = indent;
                 List<? extends Tree> members = node.getMembers();
                 List recParams = new ArrayList<Tree>();
 
@@ -1333,52 +1335,112 @@
                     if (member.getKind() == Tree.Kind.VARIABLE) {
                         ModifiersTree modifiers = ((VariableTree) member).getModifiers();
                         Set<Modifier> modifierSet = modifiers.getFlags();
-                        boolean isPublicModPresent = false;
 
-                        if (modifiers == null || !modifierSet.contains(Modifier.STATIC)) {
+                        if (!modifierSet.contains(Modifier.STATIC)) {
                             recParams.add(member);
                         }
                     }
                 }
 
-                if (members != null && !members.isEmpty()) {
-                    int oldLastIndent = lastIndent;
-                    try {
-                        spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
-                        wrapList(cs.wrapMethodParams(), cs.alignMultilineMethodParams(), false, COMMA, recParams);
-                        accept(RPAREN);
-                        spaces(true ? 1 : 0, tokens.offset() < startOffset);
-                        accept(LBRACE);
-                        continuationIndent = old;
-                        indent += indentSize;
+                if (!recParams.isEmpty()) {
+                    spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
+                    wrapList(cs.wrapMethodParams(), cs.alignMultilineMethodParams(), false, COMMA, recParams);
+                }
+                accept(RPAREN);
+                List<? extends Tree> impls = node.getImplementsClause();
+                if (impls != null && !impls.isEmpty()) {
+                    wrapToken(cs.wrapExtendsImplementsKeyword(), 1, IMPLEMENTS);
+                    wrapList(cs.wrapExtendsImplementsList(), cs.alignMultilineImplements(), true, COMMA, impls);
+                }
+                int oldLastIndent = lastIndent;
+                int lastMaxPreservedBlankLines = maxPreservedBlankLines;
+                maxPreservedBlankLines = cs.getMaximumBlankLinesInDeclarations();
+                classLeftBracePlacement();
 
+                continuationIndent = old;
+                try {
+                    if (members != null && !members.isEmpty()) {
+
+                        boolean isFirstMember = true;
+                        blankLines(node.getSimpleName().length() == 0 ? 0 : cs.getBlankLinesAfterClassHeader());
                         for (Tree member : members) {
-                            if (member.getKind() != Tree.Kind.VARIABLE || !recParams.contains(member)) {
-                                newline();
-                                scan(member, p);
+                            if (recParams.contains(member)) {
+                                continue;
+                            }
+                            blankLines(0);
+                            switch (member.getKind()) {
+                                case VARIABLE:
+                                    boolean b = tokens.moveNext();
+                                    if (b) {
+                                        tokens.movePrevious();
+                                        if (!isFirstMember) {
+                                            blankLines(cs.getBlankLinesBeforeFields());
+                                        }
+                                        scan(member, p);
+                                        blankLines(cs.getBlankLinesAfterFields());
+                                    }
+                                    break;
+                                default:
+                                    if (!isFirstMember) {
+                                        blankLines(cs.getBlankLinesBeforeMethods());
+                                    }
+                                    scan(member, p);
+                                    blankLines(cs.getBlankLinesAfterMethods());
+                            }
+                            if (isFirstMember) {
+                                isFirstMember = false;
                             }
                         }
 
-                    } finally {
-                        indent = oldIndent;
-                        lastIndent = oldLastIndent;
-                        continuationIndent = isLastIndentContinuation;
+                        spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
                     }
-                    spaces(cs.spaceWithinMethodDeclParens() ? 1 : 0, true);
-                } else {
-                    accept(RPAREN);
-                    accept(LBRACE);
+                } finally {
+                    indent = oldIndent;
+                    lastIndent = oldLastIndent;
+                    continuationIndent = old;
+                    maxPreservedBlankLines = lastMaxPreservedBlankLines;
                 }
-
                 newline();
-                indent = oldIndent;
                 accept(RBRACE);
             } finally {
                 continuationIndent = old;
             }
-
             return true;
         }
+
+        private void classLeftBracePlacement() {
+            CodeStyle.BracePlacement bracePlacement = cs.getClassDeclBracePlacement();
+            boolean spaceBeforeLeftBrace = cs.spaceBeforeClassDeclLeftBrace();
+            int old = indent = lastIndent;
+            int halfIndent = lastIndent;
+            switch (bracePlacement) {
+                case SAME_LINE:
+                    spaces(spaceBeforeLeftBrace ? 1 : 0, tokens.offset() < startOffset);
+                    accept(LBRACE);
+                    indent = lastIndent + indentSize;
+                    break;
+                case NEW_LINE:
+                    newline();
+                    accept(LBRACE);
+                    indent = lastIndent + indentSize;
+                    break;
+                case NEW_LINE_HALF_INDENTED:
+                    int oldLast = lastIndent;
+                    indent = lastIndent + (indentSize >> 1);
+                    halfIndent = indent;
+                    newline();
+                    accept(LBRACE);
+                    indent = oldLast + indentSize;
+                    break;
+                case NEW_LINE_INDENTED:
+                    indent = lastIndent + indentSize;
+                    halfIndent = indent;
+                    newline();
+                    accept(LBRACE);
+                    break;
+            }
+        }
+
         @Override
         public Boolean visitMethod(MethodTree node, Void p) {
             boolean old = continuationIndent;
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java
index 092df1c..361b681 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reindenter.java
@@ -40,6 +40,7 @@
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.TryTree;
+import com.sun.source.tree.TypeParameterTree;
 import com.sun.source.tree.VariableTree;
 import com.sun.source.tree.WhileLoopTree;
 import com.sun.source.util.SourcePositions;
@@ -69,6 +70,7 @@
 import com.sun.tools.javac.util.Log;
 import java.util.ArrayList;
 import java.util.Arrays;
+import javax.lang.model.element.Modifier;
 import org.netbeans.api.java.lexer.JavaTokenId;
 import org.netbeans.api.java.source.CodeStyle;
 import org.netbeans.api.lexer.TokenHierarchy;
@@ -815,6 +817,9 @@
                 if (last.getKind().toString().equals(TreeShims.SWITCH_EXPRESSION)) {
                    currentIndent = getSwitchIndent(startOffset, endOffset,nextTokenId,lastPos,currentIndent) ;
                 }
+                else if (last.getKind().toString().equals(TreeShims.RECORD)) {
+                    currentIndent = getRecordIndent(startOffset, endOffset, nextTokenId, lastPos, currentIndent);
+                }
                 else currentIndent = getContinuationIndent(path, currentIndent);
                 break;
         }
@@ -896,6 +901,104 @@
         return currentIndent;
     }
 
+    private int getRecordIndent(int startOffset, int endOffset, JavaTokenId nextTokenId, int lastPos, int currentIndent) throws BadLocationException {
+        LinkedList<? extends Tree> path = getPath(startOffset);
+        Tree last = path.getFirst();
+        TokenSequence<JavaTokenId> token = findFirstNonWhitespaceToken(startOffset, endOffset);
+        nextTokenId = token != null ? token.token().id() : null;
+        if (nextTokenId != null && nextTokenId == JavaTokenId.RBRACE) {
+            if (isLeftBraceOnNewLine(lastPos, startOffset)) {
+                switch (cs.getClassDeclBracePlacement()) {
+                    case NEW_LINE_INDENTED:
+                        currentIndent += cs.getIndentSize();
+                        break;
+                    case NEW_LINE_HALF_INDENTED:
+                        currentIndent += (cs.getIndentSize() / 2);
+                        break;
+                }
+            }
+        } else {
+
+            token = findFirstNonWhitespaceToken(startOffset, lastPos);
+            JavaTokenId prevTokenId = token != null ? token.token().id() : null;
+            if (prevTokenId != null) {
+                switch (prevTokenId) {
+                    case LBRACE:
+                        if (path.size() > 1 && path.get(1).getKind() == Kind.NEW_CLASS && isLeftBraceOnNewLine(lastPos, startOffset)) {
+                            switch (cs.getClassDeclBracePlacement()) {
+                                case SAME_LINE:
+                                case NEW_LINE:
+                                    currentIndent += cs.getIndentSize();
+                                    break;
+                                case NEW_LINE_HALF_INDENTED:
+                                    currentIndent += (cs.getIndentSize() - cs.getIndentSize() / 2);
+                                    break;
+                            }
+                        } else {
+                            currentIndent += cs.indentTopLevelClassMembers() ? cs.getIndentSize() : 0;
+                        }
+                        break;
+                    case COMMA:
+                        List<? extends Tree> implClauses = ((ClassTree) last).getImplementsClause();
+                        if (!implClauses.isEmpty() && getStartPosition(implClauses.get(0)) < token.offset()) {
+                            currentIndent = getMultilineIndent(implClauses, path, token.offset(), currentIndent, cs.alignMultilineImplements(), true);
+                            break;
+                        }
+                        List<? extends Tree> members = ((ClassTree) last).getMembers();
+                        if (!members.isEmpty() && getStartPosition(members.get(0)) < token.offset()) {
+                            currentIndent = getMultilineIndent(members, path, token.offset(), currentIndent, cs.alignMultilineMethodParams(), true);
+                            break;
+                        }
+                        List<? extends TypeParameterTree> typeParams = ((ClassTree) last).getTypeParameters();
+                        if (!typeParams.isEmpty() && getStartPosition(typeParams.get(0)) < token.offset()) {
+                            currentIndent = getMultilineIndent(typeParams, path, token.offset(), currentIndent, cs.alignMultilineMethodParams(), true);
+                            break;
+                        }
+                        break;
+                    case IDENTIFIER:
+                    case GT:
+                    case GTGT:
+                    case GTGTGT:
+                    case RPAREN:
+                        if (nextTokenId != null && nextTokenId == JavaTokenId.LBRACE) {
+                            switch (cs.getClassDeclBracePlacement()) {
+                                case NEW_LINE_INDENTED:
+                                    currentIndent += cs.getIndentSize();
+                                    break;
+                                case NEW_LINE_HALF_INDENTED:
+                                    currentIndent += (cs.getIndentSize() / 2);
+                                    break;
+                            }
+                        } else {
+                            currentIndent += cs.getContinuationIndentSize();
+                        }
+                        break;
+
+                    default:
+                        Tree t = null;
+                        for (Tree member : ((ClassTree) last).getMembers()) {
+
+                            if (member.getKind() == Tree.Kind.VARIABLE && !((VariableTree) member).getModifiers().getFlags().contains(Modifier.STATIC)) {
+                                continue;
+                            }
+                            if (getEndPosition(member) > startOffset) {
+                                break;
+                            }
+                            t = member;
+                        }
+                        if (t != null) {
+                            int i = getCurrentIndent(t, path);
+                            currentIndent = i < 0 ? currentIndent + (cs.indentTopLevelClassMembers() ? cs.getIndentSize() : 0) : i;
+                            return currentIndent;
+                        }
+
+                        currentIndent += cs.getContinuationIndentSize();
+                }
+            }
+        }
+        return currentIndent;
+    }
+
     private int getStartPosition(Tree last) {
         return (int) sp.getStartPosition(cut, last);
     }
diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
index fa1fd2e..7939666 100644
--- a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
+++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
@@ -5124,6 +5124,108 @@
         reformat(doc, content, golden);
     }
 
+    public void testRecord1() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "public record g3<T extends Object>() implements Cloneable{\n"
+                + "public g3 {\n"
+                + "System.out.println(\"hello\");\n"
+                + "}}}";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public record g3<T extends Object>() implements Cloneable {\n\n"
+                + "        public g3 {\n"
+                + "            System.out.println(\"hello\");\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+
+    public void testRecord2() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n"
+                + "public record g3<T extends Object>() {static int r =10;\n"
+                + "public g3 {\n"
+                + "System.out.println(\"hello\");\n"
+                + "}"
+                + "static{}"
+                + "}}";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public record g3<T extends Object>() {\n\n"
+                + "        static int r = 10;\n\n"
+                + "        public g3 {\n"
+                + "            System.out.println(\"hello\");\n"
+                + "        }\n\n"
+                + "        static {\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        reformat(doc, content, golden);
+    }
+
+    public void testRecord3() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = (EditorCookie) testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "public record g3(){}}";
+
+        String golden
+                = "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public record g3() {\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+   
     private void reformat(Document doc, String content, String golden) throws Exception {
         reformat(doc, content, golden, 0, content.length());
     }
diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java
index 93a059a..e792883 100644
--- a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java
+++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/ReindenterTest.java
@@ -1976,6 +1976,95 @@
         performSpanIndentationTest("package t;\npublic class T {\n|private final String s = \"\"\"\n1\n  2\n 3\n\"\"\";|\n}\n",
                 "package t;\npublic class T {\n    private final String s = \"\"\"\n                             1\n                               2\n                              3\n                             \"\"\";\n}\n");
     }
+    
+    public void testLineIndentationBeforeRecord() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performLineIndentationTest("package t;\n| public record T() {\n}\n",
+                "package t;\npublic record T() {\n}\n");
+    }
+
+    public void testNewLineIndentationBeforeRecodBody() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performNewLineIndentationTest("package t;\npublic record T()|{\n}\n",
+                "package t;\npublic record T()\n{\n}\n");
+    }
+
+    public void testLineIndentationBeforeHalfIndentedRecordBody() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        preferences.put("classDeclBracePlacement", CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name());
+        try {
+            performLineIndentationTest("package t;\npublic record T()\n|{\n}\n",
+                    "package t;\npublic record T()\n  {\n}\n");
+        } finally {
+            preferences.remove("classDeclBracePlacement");
+        }
+    }
+
+    public void testNewLineIndentationInsideRecord() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performNewLineIndentationTest("package t;\npublic record T() {|\n}\n",
+                "package t;\npublic record T() {\n    \n}\n");
+    }
+
+    public void testNewLineIndentationBeforeEmptyRecordEnd() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performNewLineIndentationTest("package t;\npublic record T() {|}\n",
+                "package t;\npublic record T() {\n}\n");
+    }
+
+    public void testLineIndentationBeforeEmptyRecordEnd() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        performLineIndentationTest("package t;\npublic record T() {\n|}\n",
+                "package t;\npublic record T() {\n}\n");
+    }
+
+    public void testLineIndentationBeforeEmptyHalfIndentedRecordEnd() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            //OK, skip test:
+            return;
+        }
+        Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
+        preferences.put("classDeclBracePlacement", CodeStyle.BracePlacement.NEW_LINE_HALF_INDENTED.name());
+        try {
+            performLineIndentationTest("package t;\npublic record T()\n  {\n|    }\n",
+                    "package t;\npublic record T()\n  {\n  }\n");
+        } finally {
+            preferences.remove("classDeclBracePlacement");
+        }
+    }
 
     private void performNewLineIndentationTest(String code, String golden) throws Exception {
         int pos = code.indexOf('|');
diff --git a/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java b/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java
index a3aac55..a9dd035 100644
--- a/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java
+++ b/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java
@@ -211,6 +211,8 @@
     
     //TODO these effectively need updating once in a while
     private static final String SUREFIRE_VERSION_SAFE = "2.15"; //2.16 is broken
+    // surefire 2.22 is needed for JUnit 5
+    private static final String SUREFIRE_VERSION_SAFE_5 = "2.22.0";
     private static final String JUNIT_VERSION_SAFE = "4.11";
 
     @Override public void invokeAction(final String action, final Lookup lookup) {
@@ -288,14 +290,17 @@
 
     @Messages({
         "run_single_method_disabled=Surefire 2.8+ with JUnit 4.8+ or TestNG needed to run a single test method.",
+        "run_single_method_disabled5=Surefire 2.22.0 is required to run a single test method with JUnit5.",
         "TIT_RequiresUpdateOfPOM=Feature requires update of POM",
-        "TXT_Run_Single_method=<html>Executing single test method requires Surefire 2.8+ and JUnit in version 4.8 and bigger. <br/><br/>Update your pom.xml?</html>"
+        "TXT_Run_Single_method=<html>Executing single test method requires Surefire 2.8+ and JUnit in version 4.8 and bigger. <br/><br/>Update your pom.xml?</html>",
+        "TXT_Run_Single_method5=<html>Executing single test method with JUnit 5 requires Surefire 2.22.0. <br/><br/>Update your pom.xml?</html>"
     })    
     private boolean checkSurefire(final String action) {
         if (action.equals(SingleMethod.COMMAND_RUN_SINGLE_METHOD) || action.equals(SingleMethod.COMMAND_DEBUG_SINGLE_METHOD)) {
             if (!runSingleMethodEnabled()) {
+                boolean ju5 = usingJUnit5();
                 if (NbPreferences.forModule(ActionProviderImpl.class).getBoolean(SHOW_SUREFIRE_WARNING, true)) {
-                    WarnPanel pnl = new WarnPanel(TXT_Run_Single_method());
+                    WarnPanel pnl = new WarnPanel(ju5 ? TXT_Run_Single_method5() : TXT_Run_Single_method());
                     Object o = DialogDisplayer.getDefault().notify(new NotifyDescriptor.Confirmation(pnl, TIT_RequiresUpdateOfPOM(), NotifyDescriptor.YES_NO_OPTION));
                     if (pnl.disabledWarning()) {
                         NbPreferences.forModule(ActionProviderImpl.class).putBoolean(SHOW_SUREFIRE_WARNING, false);
@@ -304,9 +309,24 @@
                         RequestProcessor.getDefault().post(new Runnable() {
                             @Override
                             public void run() {
+                                String surefireVersion = null;
+                                String junitVersion = null;
+                                
+                                if (ju5 && !usingSurefire2_22()) {
+                                    surefireVersion = SUREFIRE_VERSION_SAFE_5;
+                                } else if (!usingSurefire28()) {
+                                    surefireVersion = SUREFIRE_VERSION_SAFE;
+                                }
+                                if (!ju5) {
+                                    junitVersion = usingJUnit4() || usingTestNG() ? null : JUNIT_VERSION_SAFE;
+                                }
+                                
                                 Utilities.performPOMModelOperations(
                                         proj.getProjectDirectory().getFileObject("pom.xml"),
-                                        Collections.singletonList(new UpdateSurefireOperation(usingSurefire28() ? null : SUREFIRE_VERSION_SAFE, usingJUnit4() || usingTestNG() ? null : JUNIT_VERSION_SAFE)));
+                                        Collections.singletonList(new UpdateSurefireOperation(
+                                                surefireVersion, junitVersion
+                                        ))
+                                );
                                 //this appears to run too fast, before the resolved model is updated.
 //                                SwingUtilities.invokeLater(new Runnable() {
 //                                    @Override
@@ -319,7 +339,8 @@
                         return false;
                     }
                 }
-                StatusDisplayer.getDefault().setStatusText(run_single_method_disabled());
+                StatusDisplayer.getDefault().setStatusText(
+                        ju5 ? run_single_method_disabled5() : run_single_method_disabled());
                 return false;
             }
         }
diff --git a/platform/applemenu/src/org/netbeans/modules/applemenu/layer.xml b/platform/applemenu/src/org/netbeans/modules/applemenu/layer.xml
index 148c2f4..9d435d3 100644
--- a/platform/applemenu/src/org/netbeans/modules/applemenu/layer.xml
+++ b/platform/applemenu/src/org/netbeans/modules/applemenu/layer.xml
@@ -98,7 +98,7 @@
     <!-- quick search enabled for ide in toolbar by default -->
         <folder name="QuickSearch">
             <attr name="displayName" bundlevalue="org.netbeans.modules.applemenu.Bundle#Toolbars/QuickSearch"/>
-            <attr name="position" intvalue="700"/>
+            <attr name="position" intvalue="710"/>
             <file name="org-netbeans-modules-quicksearch-QuickSearchAction.shadow">
                 <attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-quicksearch-QuickSearchAction.instance"/>
                 <attr name="position" intvalue="250"/>