From 58d3a8ca7cd0f688dc8ae85f6c88f22514ddb7aa Mon Sep 17 00:00:00 2001 From: Siddharth Srinivasan Date: Mon, 22 Sep 2025 21:26:45 +0530 Subject: [PATCH] Backporting useful NB28 patches --- build.xml | 18 +- patches/8662.diff | 404 +++++++++ patches/8664.diff | 1049 ++++++++++++++++++++++++ patches/8694.diff | 89 ++ patches/{8745-draft.diff => 8745.diff} | 2 +- patches/8748.diff | 8 + patches/8760.diff | 14 + patches/8762.diff | 512 ++++++++++++ patches/8769.diff | 12 + patches/8797.diff | 54 ++ patches/8816.diff | 176 ++++ patches/8821.diff | 13 + 12 files changed, 2346 insertions(+), 5 deletions(-) create mode 100644 patches/8662.diff create mode 100644 patches/8664.diff create mode 100644 patches/8694.diff rename patches/{8745-draft.diff => 8745.diff} (96%) create mode 100644 patches/8748.diff create mode 100644 patches/8760.diff create mode 100644 patches/8762.diff create mode 100644 patches/8769.diff create mode 100644 patches/8797.diff create mode 100644 patches/8816.diff create mode 100644 patches/8821.diff diff --git a/build.xml b/build.xml index 96c811bd..11642ba2 100644 --- a/build.xml +++ b/build.xml @@ -49,14 +49,24 @@ patches/6330.diff patches/7610.diff patches/8038-draft.diff - patches/8690.diff - patches/8829.diff - patches/8828.diff patches/7893-draft.diff patches/8460-draft.diff - patches/8745-draft.diff + patches/8662.diff + patches/8664.diff + patches/8690.diff + patches/8694.diff + patches/8745.diff + patches/8748.diff + patches/8760.diff patches/8770.diff + patches/8762.diff + patches/8769.diff + patches/8797.diff + patches/8816.diff + patches/8821.diff patches/8827.diff + patches/8828.diff + patches/8829.diff patches/8856-draft.diff patches/disable-error-notification.diff patches/mvn-sh.diff diff --git a/patches/8662.diff b/patches/8662.diff new file mode 100644 index 00000000..f50a5ab2 --- /dev/null +++ b/patches/8662.diff @@ -0,0 +1,404 @@ +diff --git a/java/java.api.common/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImpl.java b/java/java.api.common/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImpl.java +index 65d735c60007..f871a84dafed 100644 +--- a/java/java.api.common/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImpl.java ++++ b/java/java.api.common/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImpl.java +@@ -32,10 +32,13 @@ + import java.util.Collections; + import java.util.HashSet; + import java.util.List; ++import java.util.Objects; + import java.util.Optional; + import java.util.Queue; + import java.util.Set; + import java.util.stream.Collectors; ++import javax.lang.model.element.Element; ++import javax.lang.model.element.ElementKind; + import javax.lang.model.element.ModuleElement; + import javax.swing.event.ChangeListener; + import org.netbeans.api.annotations.common.CheckForNull; +@@ -60,7 +63,7 @@ + import org.openide.util.WeakListeners; + + /** +- * An implementation of the {@link AccessibilityQueryImplementation} based on the module-info. ++ * An implementation of the {@link AccessibilityQueryImplementation2} based on the module-info. + * Accessible through the {@link QuerySupport#createModuleInfoAccessibilityQuery}. + * @author Tomas Zezula + */ +@@ -179,7 +182,8 @@ private ExportsCache getCache() { + todo.offer(tests.getRoots()); + } + for (FileObject[] work : todo) { +- readExports(work, rootsCollector).ifPresent(data::add); ++ Collections.addAll(rootsCollector, work); ++ extractExports(work).ifPresent(data::add); + } + + ec = new ExportsCache(rootsCollector, data); +@@ -232,48 +236,49 @@ private Collection collectModuleRoots( + final MultiModule model = MultiModule.getOrCreate(mods, src); + for (String modName : model.getModuleNames()) { + final ClassPath cp = model.getModuleSources(modName); +- res.add(cp.getRoots()); ++ if (cp != null) { ++ res.add(cp.getRoots()); ++ } + } + return res; + } + + @NonNull +- private static Optional,Set>> readExports( +- @NonNull final FileObject[] roots, +- @NonNull final Set rootsCollector) { +- Collections.addAll(rootsCollector, roots); +- final Optional moduleInfo = Arrays.stream(roots) +- .map((root) -> root.getFileObject(MODULE_INFO_JAVA)) +- .filter((mi) -> mi != null) +- .findFirst(); +- if (!moduleInfo.isPresent()) { +- return Optional.empty(); +- } +- final Set rootsSet = new HashSet<>(); +- Collections.addAll(rootsSet, roots); +- final Set exportsSet = readExports(moduleInfo.get(), rootsSet); +- return Optional.of(Pair.of(rootsSet, exportsSet)); ++ private static Optional, Set>> extractExports( ++ @NonNull final FileObject[] roots) { ++ return Arrays.stream(roots) ++ .map(root -> root.getFileObject(MODULE_INFO_JAVA)) ++ .filter(Objects::nonNull) ++ .findFirst() ++ .map(mi -> { ++ Set rootsSet = new HashSet<>(); ++ Collections.addAll(rootsSet, roots); ++ Set exportsSet = readExports(mi, rootsSet); ++ return Pair.of(rootsSet, exportsSet); ++ }); + } + + @NonNull + private static Set readExports( +- @NonNull final FileObject moduleInfo, +- @NonNull final Set roots) { ++ @NonNull final FileObject moduleInfo, ++ @NonNull final Set roots) { + final Set exports = new HashSet<>(); + final JavaSource src = JavaSource.forFileObject(moduleInfo); + if (src != null) { + try { + src.runUserActionTask((cc) -> { + cc.toPhase(JavaSource.Phase.RESOLVED); +- final CompilationUnitTree cu = cc.getCompilationUnit(); +- if (cu.getTypeDecls().size() == 1 && cu.getTypeDecls().get(0) instanceof ModuleTree) { +- final ModuleTree mt = (ModuleTree) cu.getTypeDecls().get(0); +- final ModuleElement me = (ModuleElement) cc.getTrees().getElement(TreePath.getPath(cu, mt)); +- if (me != null) { ++ CompilationUnitTree cu = cc.getCompilationUnit(); ++ ModuleTree mt = cu.getModule(); ++ if (mt != null) { ++ TreePath path = TreePath.getPath(cu, mt); ++ Element element = cc.getTrees().getElement(path); ++ if (element.getKind() == ElementKind.MODULE) { ++ ModuleElement me = (ModuleElement) element; + for (ModuleElement.Directive directive : me.getDirectives()) { + if (directive.getKind() == ModuleElement.DirectiveKind.EXPORTS) { +- final ModuleElement.ExportsDirective export = (ModuleElement.ExportsDirective) directive; +- final String pkgName = export.getPackage().getQualifiedName().toString(); ++ ModuleElement.ExportsDirective export = (ModuleElement.ExportsDirective) directive; ++ String pkgName = export.getPackage().getQualifiedName().toString(); + exports.addAll(findPackage(pkgName, roots)); + } + } +diff --git a/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImplTest.java b/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImplTest.java +new file mode 100644 +index 000000000000..8484c955be98 +--- /dev/null ++++ b/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/ModuleInfoAccessibilityQueryImplTest.java +@@ -0,0 +1,141 @@ ++/* ++ * 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.api.common.queries; ++ ++import java.io.IOException; ++import java.io.OutputStream; ++import java.nio.charset.StandardCharsets; ++import java.util.Map; ++import org.junit.Before; ++import org.junit.Test; ++import org.netbeans.api.java.queries.AccessibilityQuery.Accessibility; ++import org.netbeans.api.project.Project; ++import org.netbeans.junit.NbTestCase; ++import org.netbeans.modules.java.api.common.TestProject; ++import org.netbeans.modules.java.api.common.ant.UpdateHelper; ++import org.netbeans.spi.java.queries.AccessibilityQueryImplementation2.Result; ++import org.netbeans.spi.project.support.ant.AntProjectHelper; ++import org.netbeans.spi.project.support.ant.EditableProperties; ++import org.openide.filesystems.FileObject; ++import org.openide.filesystems.FileUtil; ++import org.openide.util.test.MockLookup; ++ ++/** ++ * ++ * @author peterhull ++ */ ++public class ModuleInfoAccessibilityQueryImplTest extends NbTestCase { ++ ++ private static final String MODULE_INFO_JAVA = "module-info.java"; //NOI18N ++ ++ // Module definition which exports mymodule but not myinternal ++ private static final String MODULE_INFO = """ ++ module mymodule { ++ exports mypackage; ++ } ++ """; ++ ++ private FileObject src; ++ private FileObject test; ++ private FileObject workDir; ++ private TestProject testProject; ++ private FileObject mypackage; ++ private FileObject myinternal; ++ ++ public ModuleInfoAccessibilityQueryImplTest(String name) { ++ super(name); ++ } ++ ++ @Before ++ @Override ++ public void setUp() throws Exception { ++ super.setUp(); ++ clearWorkDir(); ++ MockLookup.setInstances(TestProject.createProjectType()); ++ workDir = FileUtil.toFileObject(FileUtil.normalizeFile(getWorkDir())); ++ src = workDir.createFolder("src"); //NOI18N ++ test = workDir.createFolder("test"); //NOI18N ++ mypackage = src.createFolder("mypackage"); //NOI18N ++ myinternal = src.createFolder("myinternal"); //NOI18N ++ try (OutputStream os = src.createAndOpen(MODULE_INFO_JAVA)) { ++ os.write(MODULE_INFO.getBytes(StandardCharsets.UTF_8)); ++ } ++ Project prj = TestProject.createProject(workDir, src, test); ++ testProject = prj.getLookup().lookup(TestProject.class); ++ // Using modules, so project has to be source level 9 or later. ++ UpdateHelper helper = testProject.getUpdateHelper(); ++ EditableProperties properties = helper.getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); ++ properties.putAll(Map.of("javac.source", "9", "javac.target", "9")); ++ helper.putProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH, properties); ++ /* Modular project has the structure ++ ROOT ++ +-src ++ | +-mypackage ++ | | `-*.java ++ | +-myinternal ++ | + `-*.java ++ | `-module-info.java ++ `-test ++ `-mypackage ++ `-MyClassTest.java ++ */ ++ } ++ ++ /** ++ * Test of isPubliclyAccessible method, of class ++ * ModuleInfoAccessibilityQueryImpl. Tests if an exported package ++ * 'mypackage' is accessible. ++ * ++ * @throws java.io.IOException if test file creation failed. ++ */ ++ @Test ++ public void testIsPubliclyAccessible1() throws IOException { ++ ModuleInfoAccessibilityQueryImpl instance = new ModuleInfoAccessibilityQueryImpl(null, testProject.getSourceRoots(), null, testProject.getTestRoots()); ++ Result result = instance.isPubliclyAccessible(mypackage); ++ // Return value can be null, that's a fail ++ if (result == null) { ++ fail("AccessibilityQuery returned null"); //NOI18N ++ } else { ++ Accessibility accessibility = result.getAccessibility(); ++ Accessibility expAccessibility = Accessibility.EXPORTED; ++ assertEquals(expAccessibility, accessibility); ++ } ++ } ++ ++ /** ++ * Test of isPubliclyAccessible method, of class ++ * ModuleInfoAccessibilityQueryImpl. Tests if a not-exported package ++ * 'myinternal' is not accessible. ++ * ++ * @throws java.io.IOException if test file creation failed. ++ */ ++ @Test ++ public void testIsPubliclyAccessible2() throws IOException { ++ ModuleInfoAccessibilityQueryImpl instance = new ModuleInfoAccessibilityQueryImpl(null, testProject.getSourceRoots(), null, testProject.getTestRoots()); ++ Result result = instance.isPubliclyAccessible(myinternal); ++ // Return value can be null, that's a fail ++ if (result == null) { ++ fail("AccessibilityQuery returned null"); //NOI18N ++ } else { ++ Accessibility accessibility = result.getAccessibility(); ++ Accessibility expAccessibility = Accessibility.PRIVATE; ++ assertEquals(expAccessibility, accessibility); ++ } ++ } ++} +diff --git a/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/UnitTestsCompilerOptionsQueryImplTest.java b/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/UnitTestsCompilerOptionsQueryImplTest.java +index e6529eb794c8..6928413cd2bd 100644 +--- a/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/UnitTestsCompilerOptionsQueryImplTest.java ++++ b/java/java.api.common/test/unit/src/org/netbeans/modules/java/api/common/queries/UnitTestsCompilerOptionsQueryImplTest.java +@@ -112,7 +112,6 @@ public void testJDK9_UnnamedModule() { + assertEquals(Collections.emptyList(), args); + } + +- @Ignore // TODO failure + public void testJDK9_TestInlinedIntoSourceModule() throws IOException { + setSourceLevel(project, "9"); //NOI18N + final String srcModuleName = "org.nb.App"; //NOI18N +@@ -132,7 +131,6 @@ public void testJDK9_TestInlinedIntoSourceModule() throws IOException { + args); + } + +- @Ignore // TODO failure + public void testJDK9_TestModule() throws IOException { + setSourceLevel(project, "9"); //NOI18N + final String srcModuleName = "org.nb.App"; //NOI18N +@@ -169,7 +167,6 @@ public void testExplicitArgs() { + assertEquals(options, args); + } + +- @Ignore // TODO failure + public void testSourceLevelChanges() throws IOException { + setSourceLevel(project, "1.8"); //NOI18N + final String srcModuleName = "org.nb.App"; //NOI18N +@@ -194,7 +191,6 @@ public void testSourceLevelChanges() throws IOException { + args); + } + +- @Ignore // TODO failure + public void testRootsChanges() throws IOException { + setSourceLevel(project, "9"); //NOI18N + final FileObject src2 = srcRoots.getRoots()[0].getParent().createFolder("src2"); +@@ -226,7 +222,6 @@ public void testRootsChanges() throws IOException { + args); + } + +- @Ignore // TODO failure + public void testModuleInfoCreation() throws IOException { + setSourceLevel(project, "9"); //NOI18N + final CompilerOptionsQueryImplementation impl = QuerySupport.createUnitTestsCompilerOptionsQuery(project.getEvaluator(), srcRoots, testRoots); +@@ -251,7 +246,6 @@ public void testModuleInfoCreation() throws IOException { + args); + } + +- @Ignore // TODO failure + public void testModuleInfoChanges() throws IOException { + setSourceLevel(project, "9"); //NOI18N + final String srcModuleName = "org.nb.App"; //NOI18N +diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java b/java/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java +index ddb82083e4d5..3bfa153618b9 100644 +--- a/java/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java ++++ b/java/java.source.base/src/org/netbeans/modules/java/source/JavaSourceUtilImpl.java +@@ -22,7 +22,6 @@ + + import com.sun.source.tree.CompilationUnitTree; + import com.sun.source.tree.ModuleTree; +-import com.sun.source.tree.Tree; + import com.sun.source.util.TreePath; + import org.netbeans.api.java.source.support.ErrorAwareTreeScanner; + import com.sun.source.util.Trees; +@@ -90,7 +89,6 @@ + import org.netbeans.spi.java.classpath.support.ClassPathSupport; + import org.openide.filesystems.FileObject; + import org.openide.filesystems.FileUtil; +-import org.openide.util.Pair; + import org.openide.util.Parameters; + + /** +@@ -102,6 +100,7 @@ + public final class JavaSourceUtilImpl extends org.netbeans.modules.java.preprocessorbridge.spi.JavaSourceUtilImpl { + private static final Logger LOGGER = Logger.getLogger(JavaSourceUtilImpl.class.getName()); + ++ @Override + protected long createTaggedCompilationController(FileObject file, int position, long currenTag, Object[] out) throws IOException { + assert file != null; + final JavaSource js = JavaSource.forFileObject(file); +@@ -290,12 +289,8 @@ protected ModuleInfoHandle getModuleInfoHandle(@NonNull final Object javaSource) + public String parseModuleName() throws IOException { + cc.toPhase(JavaSource.Phase.PARSED); + final CompilationUnitTree cu = cc.getCompilationUnit(); +- for (Tree decl : cu.getTypeDecls()) { +- if (decl.getKind() == Tree.Kind.MODULE) { +- return ((ModuleTree) decl).getName().toString(); +- } +- } +- return null; ++ ModuleTree mt = cu.getModule(); ++ return mt != null ? mt.getName().toString() : null; + } + + @Override +diff --git a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java +index b644653b09cc..875847a13e06 100644 +--- a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java ++++ b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/JavaSourceUtilImplTest.java +@@ -28,6 +28,7 @@ + import java.util.HashSet; + import java.util.Map; + import java.util.Map.Entry; ++import java.util.Objects; + import java.util.Set; + import java.util.stream.Collectors; + import javax.swing.event.ChangeListener; +@@ -39,6 +40,8 @@ + import org.netbeans.api.java.classpath.ClassPath; + import org.netbeans.api.java.classpath.JavaClassPathConstants; + import org.netbeans.api.java.queries.AnnotationProcessingQuery; ++import org.netbeans.modules.java.preprocessorbridge.spi.JavaSourceUtilImpl.ModuleInfoHandle; ++import org.netbeans.api.java.source.JavaSource; + import org.netbeans.api.java.source.SourceUtilsTestUtil2; + import org.netbeans.api.java.source.TestUtilities; + import org.netbeans.junit.NbTestCase; +@@ -65,6 +68,11 @@ public class JavaSourceUtilImplTest extends NbTestCase { + private FileObject cache; + private FileObject cacheSrc; + private FileObject ap; ++ private final String MODULE_INFO_SOURCE= ++ """ ++ module org.nb { ++ } ++ """; + + public JavaSourceUtilImplTest(String name) { + super(name); +@@ -274,7 +282,15 @@ private static void dump( + } + System.out.printf("Dumped into: %s%n", FileUtil.getFileDisplayName(wd)); + } +- ++ @Test ++ public void testGetModuleInfoHandle() throws Exception { ++ JavaSourceUtilImpl impl = new JavaSourceUtilImpl(); ++ FileObject ff = createFile(root,"module-info.java", MODULE_INFO_SOURCE); ++ JavaSource src = Objects.requireNonNull(JavaSource.forFileObject(ff)); ++ ModuleInfoHandle mih = Objects.requireNonNull(impl.getModuleInfoHandle(src)); ++ String moduleName = mih.parseModuleName(); ++ assertEquals("org.nb", moduleName); ++ } + static { + System.setProperty("SourcePath.no.source.filter", "true"); + } diff --git a/patches/8664.diff b/patches/8664.diff new file mode 100644 index 00000000..83e350fa --- /dev/null +++ b/patches/8664.diff @@ -0,0 +1,1049 @@ +diff --git a/ide/projectapi/nbproject/project.properties b/ide/projectapi/nbproject/project.properties +index 735ab72a9111..ca962f553e5c 100644 +--- a/ide/projectapi/nbproject/project.properties ++++ b/ide/projectapi/nbproject/project.properties +@@ -18,7 +18,7 @@ + is.autoload=true + + javac.compilerargs=-Xlint -Xlint:-serial +-javac.source=1.8 ++javac.release=17 + javadoc.arch=${basedir}/arch.xml + javadoc.apichanges=${basedir}/apichanges.xml + +diff --git a/ide/projectapi/src/org/netbeans/spi/project/NestedClass.java b/ide/projectapi/src/org/netbeans/spi/project/NestedClass.java +index 5df90f2a7104..14f97cf0b8c6 100644 +--- a/ide/projectapi/src/org/netbeans/spi/project/NestedClass.java ++++ b/ide/projectapi/src/org/netbeans/spi/project/NestedClass.java +@@ -46,11 +46,16 @@ public final class NestedClass { + * Creates a new instance holding the specified identification + * of a nested class. + * +- * @param className name of a class inside the file +- * @param topLevelClassName top level name of a class inside the file ++ * @param className name of a class inside the file. Can be an empty string ++ * if this NestedClass represents a top level element in the source file. ++ * This is relevant for Java, which allows multiple top level class ++ * declarations as long as they are not public. The class assumes, that the ++ * {@code className} follows java convention (i.e. is separated by dots). ++ * @param topLevelClassName top level name of a class inside the file. This ++ * is the simple name without package qualification. + * @param file file to be kept in the object + * @exception java.lang.IllegalArgumentException +- * if the file or class name is {@code null} ++ * if the file, topLevelClassName or class name is {@code null} + * @since 1.99 + */ + public NestedClass(String className, String topLevelClassName, FileObject file) { +@@ -90,7 +95,8 @@ public String getClassName() { + } + + /** +- * Returns name of a top level class within a file. ++ * Returns name of a top level class within a file. This is the simple name ++ * without package qualification. + * + * @return top level class name held by this object + * @since 1.99 +@@ -108,9 +114,19 @@ public String getTopLevelClassName() { + * @since 1.99 + */ + public String getFQN(String packageName) { +- return String.join(".", packageName, topLevelClassName, className); ++ String classNameSuffix; ++ if (className.isBlank()) { ++ classNameSuffix = topLevelClassName; ++ } else { ++ classNameSuffix = topLevelClassName + "." + className; ++ } ++ if (packageName.isBlank()) { ++ return classNameSuffix; ++ } else { ++ return String.join(".", packageName, classNameSuffix); ++ } + } +- ++ + /** + * Returns fully qualified name. + * +@@ -121,9 +137,19 @@ public String getFQN(String packageName) { + * @since 1.99 + */ + public String getFQN(String packageName, String nestedClassSeparator) { +- return String.join(".", packageName, String.join(nestedClassSeparator, topLevelClassName, className.replace(".", nestedClassSeparator))); ++ String classNameSuffix; ++ if (className.isBlank()) { ++ classNameSuffix = topLevelClassName; ++ } else { ++ classNameSuffix = topLevelClassName + nestedClassSeparator + className.replace(".", nestedClassSeparator); ++ } ++ if (packageName.isBlank()) { ++ return classNameSuffix; ++ } else { ++ return String.join(".", packageName, classNameSuffix); ++ } + } +- ++ + @Override + public int hashCode() { + int hash = 3; +diff --git a/java/gradle.test/nbproject/project.properties b/java/gradle.test/nbproject/project.properties +index f39ff4a02687..6ef89b565a6b 100644 +--- a/java/gradle.test/nbproject/project.properties ++++ b/java/gradle.test/nbproject/project.properties +@@ -16,6 +16,6 @@ + # under the License. + + is.eager=true +-javac.source=1.8 ++javac.release=17 + javac.compilerargs=-Xlint -Xlint:-serial + nbm.module.author=Laszlo Kishalmi +diff --git a/java/gradle.test/nbproject/project.xml b/java/gradle.test/nbproject/project.xml +index efe3ef690ebb..b796e54b21b0 100644 +--- a/java/gradle.test/nbproject/project.xml ++++ b/java/gradle.test/nbproject/project.xml +@@ -26,46 +26,46 @@ + org.netbeans.modules.gradle.test + + +- org.netbeans.modules.libs.gradle ++ org.netbeans.api.java.classpath ++ + + +- 8 +- 8.0.1 ++ 1 ++ 1.41.1 + + + +- org.netbeans.modules.gradle ++ org.netbeans.libs.javacapi + + + +- 2 +- 2.0 ++ 8.53 + + + +- org.netbeans.modules.gradle.java ++ org.netbeans.modules.extexecution + + + +- 1.17 ++ 2 ++ 1.45 + + + +- org.netbeans.api.java.classpath ++ org.netbeans.modules.gradle + + + +- 1 +- 1.41.1 ++ 2 ++ 2.0 + + + +- org.netbeans.modules.extexecution ++ org.netbeans.modules.gradle.java + + + +- 2 +- 1.45 ++ 1.17 + + + +@@ -118,6 +118,14 @@ + 1.3.1 + + ++ ++ org.netbeans.modules.libs.gradle ++ ++ ++ 8 ++ 8.0.1 ++ ++ + + org.netbeans.modules.projectapi + +diff --git a/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java b/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java +index a45f9d20176d..cacf2c8d43e1 100644 +--- a/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java ++++ b/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java +@@ -19,16 +19,17 @@ + + package org.netbeans.modules.gradle.test; + ++import java.nio.file.Path; + import java.util.Arrays; +-import org.netbeans.modules.gradle.api.NbGradleProject; + import java.util.Collection; +-import org.netbeans.modules.gradle.spi.GradleProgressListenerProvider; + import java.util.EnumSet; + import java.util.Map; + import java.util.Set; + import java.util.concurrent.ConcurrentHashMap; + import java.util.regex.Matcher; + import java.util.regex.Pattern; ++import java.util.stream.Collectors; ++import javax.lang.model.element.ElementKind; + import org.gradle.tooling.Failure; + import org.gradle.tooling.events.OperationDescriptor; + import org.gradle.tooling.events.OperationType; +@@ -46,8 +47,15 @@ + import org.gradle.tooling.events.test.TestSkippedResult; + import org.gradle.tooling.events.test.TestStartEvent; + import org.gradle.tooling.events.test.TestSuccessResult; ++import org.netbeans.api.java.source.ClasspathInfo; ++import org.netbeans.api.java.source.ElementHandle; ++import org.netbeans.api.java.source.SourceUtils; + import org.netbeans.api.project.Project; + import org.netbeans.api.project.ProjectUtils; ++import org.netbeans.modules.gradle.api.NbGradleProject; ++import org.netbeans.modules.gradle.java.api.GradleJavaProject; ++import org.netbeans.modules.gradle.java.api.GradleJavaSourceSet.SourceType; ++import org.netbeans.modules.gradle.spi.GradleProgressListenerProvider; + import org.netbeans.modules.gsf.testrunner.api.CommonUtils; + import org.netbeans.modules.gsf.testrunner.api.CoreManager; + import org.netbeans.modules.gsf.testrunner.api.Report; +@@ -57,6 +65,8 @@ + import org.netbeans.modules.gsf.testrunner.api.Testcase; + import org.netbeans.modules.gsf.testrunner.api.Trouble; + import org.netbeans.spi.project.ProjectServiceProvider; ++import org.openide.filesystems.FileObject; ++import org.openide.filesystems.FileUtil; + import org.openide.util.Lookup; + + /** +@@ -68,8 +78,8 @@ public final class GradleTestProgressListener implements ProgressListener, Gradl + + private final Project project; + private final Map sessions = new ConcurrentHashMap<>(); +- +- private Map> runningTests = new ConcurrentHashMap<>(); ++ private final Map> runningSuites = new ConcurrentHashMap<>(); ++ private final Map> runningTests = new ConcurrentHashMap<>(); + + public GradleTestProgressListener(Project project) { + this.project = project; +@@ -190,13 +200,21 @@ private void suiteFinish(TestFinishEvent evt, JvmTestOperationDescriptor op) { + TestSession session = sessions.get(getSessionKey(evt.getDescriptor())); + assert session != null; + TestOperationResult result = evt.getResult(); +- TestSuite currentSuite = session.getCurrentSuite(); + String suiteName = GradleTestSuite.suiteName(op); +- if (suiteName.equals(currentSuite.getName())) { ++ // In the NetBeans wording a testsuite is the class grouping multiple ++ // methods (testcase). In the gradle wording a suite can be nested, for ++ // example the hieararchy can be: ++ // - Gradle Test Executor started ++ // - Test class started ++ // => We flatten the list (suites are registered base on executed ++ // cases (see caseStart) ++ TestSuite testSuite = runningSuites.get(session).remove(suiteName); ++ if (testSuite != null) { + Report report = session.getReport(result.getEndTime() - result.getStartTime()); +- session.finishSuite(currentSuite); ++ session.finishSuite(testSuite); + CoreManager manager = getManager(); + if (manager != null) { ++ manager.displaySuiteRunning(session, testSuite); + manager.displayReport(session, report, true); + } + } +@@ -206,19 +224,21 @@ private void caseStart(TestStartEvent evt, JvmTestOperationDescriptor op) { + TestSession session = sessions.get(getSessionKey(evt.getDescriptor())); + assert session != null; + assert op.getParent() != null; +- TestSuite currentSuite = session.getCurrentSuite(); +- TestSuite newSuite = new GradleTestSuite(getSuiteOpDesc((JvmTestOperationDescriptor) op.getParent(), op.getClassName())); +- if ((currentSuite == null) || !currentSuite.equals(newSuite)) { +- session.addSuite(newSuite); +- CoreManager manager = getManager(); +- if (manager != null) { +- manager.displaySuiteRunning(session, newSuite); +- } ++ String suiteName = GradleTestSuite.suiteName(op.getParent()); ++ Map sessionSuites = runningSuites.computeIfAbsent(session, s -> new ConcurrentHashMap<>()); ++ TestSuite ts = sessionSuites.computeIfAbsent(suiteName, s -> { ++ TestSuite suite = new GradleTestSuite(getSuiteOpDesc((JvmTestOperationDescriptor) op.getParent(), op.getClassName())); ++ session.addSuite(suite); ++ return suite; ++ }); ++ CoreManager manager = getManager(); ++ if (manager != null && sessionSuites.size() == 1) { ++ manager.displaySuiteRunning(session, ts); + } + Testcase tc = new GradleTestcase(op, session); +- synchronized (this) { ++ synchronized (this) { + runningTests.get(session).put(getTestOpKey(op), tc); +- session.addTestCase(tc); ++ session.addTestCase(tc); + } + } + +@@ -233,7 +253,7 @@ private void caseFinish(TestFinishEvent evt, JvmTestOperationDescriptor op) { + TestOperationResult result = evt.getResult(); + long time = result.getEndTime() - result.getStartTime(); + tc.setTimeMillis(time); +- tc.setLocation(searchLocation(op.getClassName(), op.getMethodName(), null)); ++ tc.setLocation(searchLocation(tc, op.getClassName(), op.getMethodName(), null)); + if (result instanceof TestSuccessResult) { + tc.setStatus(Status.PASSED); + } +@@ -261,7 +281,7 @@ private void caseFinish(TestFinishEvent evt, JvmTestOperationDescriptor op) { + stackTrace = desc.split("\\n"); + trouble.setStackTrace(stackTrace); + } +- tc.setLocation(searchLocation(op.getClassName(), op.getMethodName(), stackTrace)); ++ tc.setLocation(searchLocation(tc, op.getClassName(), op.getMethodName(), stackTrace)); + tc.setTrouble(trouble); + } + +@@ -322,7 +342,39 @@ private static CoreManager getManager() { + + } + +- private String searchLocation(String className, String methodName, String[] stackTrace) { ++ private String searchLocation(Testcase tc, String className, String methodName, String[] stackTrace) { ++ Map classpathInfo = Map.of(); ++ NbGradleProject nbGradleProject = tc.getSession() ++ .getProject() ++ .getLookup() ++ .lookup(NbGradleProject.class); ++ GradleJavaProject gradleJavaProject = nbGradleProject != null ? nbGradleProject.projectLookup(GradleJavaProject.class) : null; ++ if (gradleJavaProject != null) { ++ classpathInfo = gradleJavaProject ++ .getSourceSets() ++ .values() ++ .stream() ++ .flatMap(gradleJavaSourceSet -> gradleJavaSourceSet.getSourceDirs(SourceType.JAVA).stream()) ++ .collect( ++ Collectors.toMap( ++ f -> ClasspathInfo.create(f), ++ f -> f.toPath() ++ ) ++ ); ++ } ++ ++ String relativePath = null; ++ for (Map.Entry ci : classpathInfo.entrySet()) { ++ FileObject fo = SourceUtils.getFile(ElementHandle.createTypeElementHandle(ElementKind.CLASS, className), ci.getKey()); ++ if (fo != null) { ++ relativePath = ci.getValue().relativize(FileUtil.toFile(fo).toPath()).toString(); ++ break; ++ } ++ } ++ if (relativePath != null) { ++ return relativePath; ++ } ++ + StringBuilder ret = new StringBuilder(className.length() + methodName.length() + 10); + String fileName = null; + String line = null; +diff --git a/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java b/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java +index 4e11099aff07..13733d9445c5 100644 +--- a/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java ++++ b/java/gradle.test/src/org/netbeans/modules/gradle/test/ui/nodes/GradleTestMethodNode.java +@@ -19,10 +19,6 @@ + + package org.netbeans.modules.gradle.test.ui.nodes; + +-import org.netbeans.modules.gradle.api.execute.RunUtils; +-import org.netbeans.modules.gradle.java.api.output.Location; +-import org.netbeans.modules.gradle.test.ui.nodes.Bundle; +-import org.netbeans.modules.gradle.test.GradleTestcase; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.List; +@@ -30,16 +26,21 @@ + import org.gradle.tooling.events.test.JvmTestOperationDescriptor; + import org.netbeans.api.extexecution.print.LineConvertors; + import org.netbeans.api.project.Project; ++import org.netbeans.modules.gradle.java.api.output.Location; ++import org.netbeans.modules.gradle.test.GradleTestcase; + import org.netbeans.modules.gsf.testrunner.api.Testcase; + import org.netbeans.modules.junit.ui.api.JUnitTestMethodNode; + import org.netbeans.spi.project.ActionProvider; +-import static org.netbeans.spi.project.SingleMethod.COMMAND_DEBUG_SINGLE_METHOD; +-import static org.netbeans.spi.project.SingleMethod.COMMAND_RUN_SINGLE_METHOD; ++import org.netbeans.spi.project.NestedClass; ++import org.netbeans.spi.project.SingleMethod; + import org.openide.filesystems.FileObject; + import org.openide.util.Lookup; + import org.openide.util.NbBundle; + import org.openide.util.lookup.Lookups; + ++import static org.netbeans.spi.project.SingleMethod.COMMAND_DEBUG_SINGLE_METHOD; ++import static org.netbeans.spi.project.SingleMethod.COMMAND_RUN_SINGLE_METHOD; ++ + /** + * + * @author Laszlo Kishalmi +@@ -66,14 +67,39 @@ public Action[] getActions(boolean context) { + actions.add(getPreferredAction()); + } + ActionProvider actionProvider = getProject().getLookup().lookup(ActionProvider.class); +- if ((actionProvider != null) && (testcase instanceof GradleTestcase)) { ++ if ((actionProvider != null) && testcase instanceof GradleTestcase gradleTestcase) { + List supportedActions = Arrays.asList(actionProvider.getSupportedActions()); + boolean runSupported = supportedActions.contains(COMMAND_RUN_SINGLE_METHOD); + boolean debugSupported = supportedActions.contains(COMMAND_DEBUG_SINGLE_METHOD); + +- JvmTestOperationDescriptor op = ((GradleTestcase) testcase).getOperation(); +- String tcName = op.getClassName() + '.' + op.getMethodName(); +- Lookup nodeContext = Lookups.singleton(RunUtils.simpleReplaceTokenProvider("selectedMethod", tcName)); ++ FileObject testFO = findFileObject(getTestLocation()); ++ JvmTestOperationDescriptor op = gradleTestcase.getOperation(); ++ // reporting adds signature to method name, this needs to be stripped away ++ String mName = op.getMethodName(); ++ if(mName != null) { ++ mName = mName.replaceFirst("[^\\p{javaJavaIdentifierPart}].*", ""); ++ } ++ String tcName = op.getClassName(); ++ ++ SingleMethod methodSpec; ++ if (tcName != null && tcName.contains("$")) { ++ String[] nestedSplit = tcName.split("\\$", 2); ++ String[] topLevelSplit = nestedSplit[0].split("\\."); ++ methodSpec = new SingleMethod(mName, new NestedClass(nestedSplit[1].replace("$", "."), topLevelSplit[topLevelSplit.length - 1], testFO)); ++ } else { ++ if (tcName != null) { ++ String[] topLevelSplit = tcName.split("\\."); ++ if (!testFO.getName().equals(topLevelSplit[topLevelSplit.length - 1])) { ++ methodSpec = new SingleMethod(mName, new NestedClass("", topLevelSplit[topLevelSplit.length - 1], testFO)); ++ } else { ++ methodSpec = new SingleMethod(testFO, mName); ++ } ++ } else { ++ methodSpec = new SingleMethod(testFO, mName); ++ } ++ } ++ ++ Lookup nodeContext = Lookups.fixed(methodSpec); + + if (runSupported) { + actions.add(new ReRunTestAction(actionProvider, nodeContext, COMMAND_RUN_SINGLE_METHOD, Bundle.LBL_RerunTest())); +@@ -83,7 +109,7 @@ public Action[] getActions(boolean context) { + actions.add(new ReRunTestAction(actionProvider, nodeContext, COMMAND_DEBUG_SINGLE_METHOD, Bundle.LBL_DebugTest())); + } + } +- return actions.toArray(new Action[0]); ++ return actions.toArray(Action[]::new); + } + + @Override +diff --git a/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java b/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java +index 90f5131ff935..c725dbd1d699 100644 +--- a/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java ++++ b/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java +@@ -1490,20 +1490,33 @@ public static String classNameFor(ClasspathInfo info, String relativePath, Neste + String className = rel.replace('/', '.'); + int lastDotIndex = className.lastIndexOf('.'); + String fqnForNestedClass = null; +- if (lastDotIndex > -1 && nestedClass != null) { +- String packageName = className.substring(0, lastDotIndex); ++ String topLevelClass = null; ++ if (nestedClass != null) { ++ String packageName; ++ if(lastDotIndex >= 0) { ++ packageName = className.substring(0, lastDotIndex); ++ } else { ++ packageName = ""; ++ } + fqnForNestedClass = nestedClass.getFQN(packageName, "$"); ++ topLevelClass = packageName + ( packageName.isBlank() ? "" : "." ) + nestedClass.getTopLevelClassName(); + } ++ // This is really an ugly hack. It is pure luck, that the cache directory ++ // is placed on the CP, nothing guarantes that or at least that is non ++ // obvious. This also makes it hard/impossible to test. + FileObject rsFile = cachedCP.findResource(rel + '.' + FileObjects.RS); + if (rsFile != null) { + List lines = new ArrayList<>(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(rsFile.getInputStream(), StandardCharsets.UTF_8))) { + String line; +- while ((line = in.readLine())!=null) { +- if (className.equals(line)) { ++ while ((line = in.readLine()) != null) { ++ if (topLevelClass == null && className.equals(line)) { + return className; +- } else if (fqnForNestedClass != null && fqnForNestedClass.equals(line)) { +- return line; ++ } else if (topLevelClass != null && topLevelClass.equals(line)) { ++ // The "RS" Index holds only toplevel classes, so we ++ // assume, that if the toplevel is found here, the FQN ++ // based on NestedClass is also present ++ return fqnForNestedClass; + } + lines.add(line); + } +@@ -1512,6 +1525,10 @@ public static String classNameFor(ClasspathInfo info, String relativePath, Neste + return lines.get(0); + } + } +- return className; ++ if(fqnForNestedClass != null) { ++ return fqnForNestedClass; ++ } else { ++ return className; ++ } + } + } +diff --git a/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java b/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java +index 00103e9b961d..d73a7f403ce8 100644 +--- a/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java ++++ b/java/junit.ui/src/org/netbeans/modules/junit/ui/actions/TestClassInfoTask.java +@@ -57,6 +57,7 @@ + import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods.Factory; + import org.netbeans.modules.parsing.spi.Parser; + import org.netbeans.spi.java.hints.unused.UsedDetector; ++import org.netbeans.spi.project.NestedClass; + import org.netbeans.spi.project.SingleMethod; + import org.openide.filesystems.FileObject; + import org.openide.util.Exceptions; +@@ -94,14 +95,17 @@ public static List computeTestMethods(CompilationInfo info, AtomicBo + private static List doComputeTestMethods(CompilationInfo info, AtomicBoolean cancel, int caretPosIfAny) { + List result = new ArrayList<>(); + if (caretPosIfAny == (-1)) { +- Optional anyClass = info.getCompilationUnit().getTypeDecls().stream().filter(t -> t.getKind() == Kind.CLASS).findAny(); +- if (!anyClass.isPresent()) { +- return Collections.emptyList(); ++ List clazzes = info.getCompilationUnit() ++ .getTypeDecls() ++ .stream() ++ .filter(t -> t.getKind() == Kind.CLASS) ++ .map(t -> (ClassTree) t) ++ .collect(Collectors.toList()); ++ for (ClassTree clazz : clazzes) { ++ TreePath pathToClass = new TreePath(new TreePath(info.getCompilationUnit()), clazz); ++ List methods = clazz.getMembers().stream().filter(m -> m.getKind() == Kind.METHOD).map(m -> new TreePath(pathToClass, m)).collect(Collectors.toList()); ++ collect(info, pathToClass, methods, true, cancel, result); + } +- ClassTree clazz = (ClassTree) anyClass.get(); +- TreePath pathToClass = new TreePath(new TreePath(info.getCompilationUnit()), clazz); +- List methods = clazz.getMembers().stream().filter(m -> m.getKind() == Kind.METHOD).map(m -> new TreePath(pathToClass, m)).collect(Collectors.toList()); +- collect(info, pathToClass, methods, true, cancel, result); + return result; + } + TreePath tp = info.getTreeUtilities().pathFor(caretPosIfAny); +@@ -126,6 +130,7 @@ private static void collect(CompilationInfo info, TreePath clazz, List + int clazzPreferred = treeUtilities.findNameSpan((ClassTree) clazz.getLeaf())[0]; + TypeElement typeElement = (TypeElement) trees.getElement(clazz); + TypeElement testcase = elements.getTypeElement(TESTCASE); ++ NestedClass nc = getNestedClass(info, typeElement); + boolean junit3 = (testcase != null && typeElement != null) ? info.getTypes().isSubtype(typeElement.asType(), testcase.asType()) : false; + for (TreePath tp : methods) { + if (cancel.get()) { +@@ -152,7 +157,7 @@ private static void collect(CompilationInfo info, TreePath clazz, List + try { + result.add(new TestMethod(elements.getBinaryName(typeElement).toString(), + doc != null ? doc.createPosition(clazzPreferred) : new SimplePosition(clazzPreferred), +- new SingleMethod(info.getFileObject(), mn), ++ nc == null ? new SingleMethod(info.getFileObject(), mn) : new SingleMethod(mn, nc), + doc != null ? doc.createPosition(start) : new SimplePosition(start), + doc != null ? doc.createPosition(preferred) : new SimplePosition(preferred), + doc != null ? doc.createPosition(end) : new SimplePosition(end))); +@@ -178,6 +183,24 @@ private static void collect(CompilationInfo info, TreePath clazz, List + } + } + ++ private static NestedClass getNestedClass(CompilationInfo ci, TypeElement te) { ++ List nesting = new ArrayList<>(); ++ Element currentElement = te; ++ while (currentElement != null && currentElement.getKind() == ElementKind.CLASS) { ++ nesting.add(0, currentElement.getSimpleName().toString()); ++ currentElement = currentElement.getEnclosingElement(); ++ } ++ if(nesting.size() < 1 || (nesting.size() == 1 && nesting.get(0).equals(ci.getFileObject().getName()))) { ++ return null; ++ } else { ++ return new NestedClass( ++ nesting.subList(1, nesting.size()).stream().collect(Collectors.joining(".")), ++ nesting.get(0), ++ ci.getFileObject() ++ ); ++ } ++ } ++ + private static boolean isTestSource(FileObject fo) { + ClassPath cp = ClassPath.getClassPath(fo, ClassPath.SOURCE); + if (cp != null) { +diff --git a/java/maven.junit.ui/nbproject/project.properties b/java/maven.junit.ui/nbproject/project.properties +index 26aa41b5ff22..ea24dfd387a4 100644 +--- a/java/maven.junit.ui/nbproject/project.properties ++++ b/java/maven.junit.ui/nbproject/project.properties +@@ -15,6 +15,6 @@ + # specific language governing permissions and limitations + # under the License. + is.eager=true +-javac.source=1.8 ++javac.release=17 + javac.compilerargs=-Xlint -Xlint:-serial + requires.nb.javac=true +diff --git a/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitNodeOpener.java b/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitNodeOpener.java +index daf44d4eb19c..d4d36712c3f7 100644 +--- a/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitNodeOpener.java ++++ b/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitNodeOpener.java +@@ -29,25 +29,25 @@ + import javax.lang.model.element.ElementKind; + import javax.lang.model.element.ExecutableElement; + import javax.lang.model.util.ElementFilter; +-import javax.swing.Action; + import org.netbeans.api.annotations.common.NonNull; + import org.netbeans.api.extexecution.print.LineConvertors.FileLocator; +-import org.netbeans.api.java.source.CompilationController; + import org.netbeans.api.java.source.JavaSource; + import org.netbeans.api.java.source.JavaSource.Phase; +-import org.netbeans.api.java.source.Task; + import org.netbeans.modules.gsf.testrunner.api.CommonUtils; + import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodNode; + import org.netbeans.modules.gsf.testrunner.ui.api.TestsuiteNode; + import org.netbeans.modules.junit.ui.api.JUnitTestMethodNode; + import org.netbeans.modules.java.testrunner.ui.api.NodeOpener; + import org.netbeans.modules.java.testrunner.ui.api.UIJavaUtils; ++import org.netbeans.modules.junit.api.JUnitTestcase; + import org.netbeans.modules.junit.ui.api.JUnitCallstackFrameNode; + import org.openide.ErrorManager; + import org.openide.filesystems.FileObject; + import org.openide.nodes.Children; + import org.openide.nodes.Node; + ++import static java.util.Arrays.asList; ++ + /** + * + * @author Marian Petras +@@ -57,33 +57,31 @@ public final class MavenJUnitNodeOpener extends NodeOpener { + + private static final Logger LOG = Logger.getLogger(MavenJUnitNodeOpener.class.getName()); + +- static final Action[] NO_ACTIONS = new Action[0]; +- ++ @Override + public void openTestsuite(TestsuiteNode node) { + Children childrens = node.getChildren(); + if (childrens != null) { + Node child = childrens.getNodeAt(0); +- if (child instanceof MavenJUnitTestMethodNode) { +- final FileObject fo = ((MavenJUnitTestMethodNode) child).getTestcaseFileObject(); ++ if (child instanceof MavenJUnitTestMethodNode junitMethodNode) { ++ final FileObject fo = junitMethodNode.getTestcaseFileObject(); ++ final MethodInfo mi = MethodInfo.fromTestCase(junitMethodNode.getTestcase()); + if (fo != null) { + final long[] line = new long[]{0}; + JavaSource javaSource = JavaSource.forFileObject(fo); + if (javaSource != null) { + try { +- javaSource.runUserActionTask(new Task() { +- @Override +- public void run(CompilationController compilationController) throws Exception { +- compilationController.toPhase(Phase.ELEMENTS_RESOLVED); +- Trees trees = compilationController.getTrees(); +- CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit(); +- List typeDecls = compilationUnitTree.getTypeDecls(); +- for (Tree tree : typeDecls) { +- Element element = trees.getElement(trees.getPath(compilationUnitTree, tree)); +- if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(fo.getName())) { +- long pos = trees.getSourcePositions().getStartPosition(compilationUnitTree, tree); +- line[0] = compilationUnitTree.getLineMap().getLineNumber(pos); +- break; +- } ++ javaSource.runUserActionTask(compilationController -> { ++ compilationController.toPhase(Phase.ELEMENTS_RESOLVED); ++ Trees trees = compilationController.getTrees(); ++ CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit(); ++ List typeDecls = compilationUnitTree.getTypeDecls(); ++ for (Tree tree : typeDecls) { ++ Element element = trees.getElement(trees.getPath(compilationUnitTree, tree)); ++ if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(mi.topLevelClass())) { ++ element = resolveNestedClass(mi.nestedClasses(), element); ++ long pos = trees.getSourcePositions().getStartPosition(compilationUnitTree, trees.getTree(element)); ++ line[0] = compilationUnitTree.getLineMap().getLineNumber(pos); ++ break; + } + } + }, true); +@@ -97,42 +95,43 @@ public void run(CompilationController compilationController) throws Exception { + } + } + ++ @Override + public void openTestMethod(final TestMethodNode node) { + if (!(node instanceof MavenJUnitTestMethodNode)) { + return; + } +- final FileObject fo = ((MavenJUnitTestMethodNode) node).getTestcaseFileObject(); ++ MavenJUnitTestMethodNode mtn = (MavenJUnitTestMethodNode) node; ++ final FileObject fo = mtn.getTestcaseFileObject(); ++ final MethodInfo mi = MethodInfo.fromTestCase(mtn.getTestcase()); + if (fo != null) { + final FileObject[] fo2open = new FileObject[]{fo}; + final long[] line = new long[]{0}; + JavaSource javaSource = JavaSource.forFileObject(fo2open[0]); + if (javaSource != null) { + try { +- javaSource.runUserActionTask(new Task() { +- @Override +- public void run(CompilationController compilationController) throws Exception { +- compilationController.toPhase(Phase.ELEMENTS_RESOLVED); +- Trees trees = compilationController.getTrees(); +- CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit(); +- List typeDecls = compilationUnitTree.getTypeDecls(); +- for (Tree tree : typeDecls) { +- Element element = trees.getElement(trees.getPath(compilationUnitTree, tree)); +- if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(fo2open[0].getName())) { +- List methodElements = ElementFilter.methodsIn(element.getEnclosedElements()); +- for (Element child : methodElements) { +- String name = node.getTestcase().getName(); // package.name.method.name +- if (child.getSimpleName().contentEquals(name.substring(name.lastIndexOf(".") + 1))) { +- long pos = trees.getSourcePositions().getStartPosition(compilationUnitTree, trees.getTree(child)); +- line[0] = compilationUnitTree.getLineMap().getLineNumber(pos); +- break; +- } ++ javaSource.runUserActionTask(compilationController -> { ++ compilationController.toPhase(Phase.ELEMENTS_RESOLVED); ++ Trees trees = compilationController.getTrees(); ++ CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit(); ++ List typeDecls = compilationUnitTree.getTypeDecls(); ++ for (Tree tree : typeDecls) { ++ Element element = trees.getElement(trees.getPath(compilationUnitTree, tree)); ++ if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(mi.topLevelClass())) { ++ element = resolveNestedClass(mi.nestedClasses(), element); ++ List methodElements = ElementFilter.methodsIn(element.getEnclosedElements()); ++ for (Element child : methodElements) { ++ String name = node.getTestcase().getName(); // package.name.method.name ++ if (child.getSimpleName().contentEquals(name.substring(name.lastIndexOf(".") + 1))) { ++ long pos = trees.getSourcePositions().getStartPosition(compilationUnitTree, trees.getTree(child)); ++ line[0] = compilationUnitTree.getLineMap().getLineNumber(pos); ++ break; + } +- // method not found in this FO, so try to find where this method belongs +- if (line[0] == 0) { +- UIJavaUtils.searchAllMethods(node, fo2open, line, compilationController, element); +- } +- break; + } ++ // method not found in this FO, so try to find where this method belongs ++ if (line[0] == 0) { ++ UIJavaUtils.searchAllMethods(node, fo2open, line, compilationController, element); ++ } ++ break; + } + } + }, true); +@@ -145,6 +144,7 @@ public void run(CompilationController compilationController) throws Exception { + } + } + ++ @Override + public void openCallstackFrame(Node node, @NonNull String frameInfo) { + if(frameInfo.isEmpty()) { // user probably clicked on a failed test method node, find failing line within the testMethod using the stacktrace + if (!(node instanceof JUnitTestMethodNode)) { +@@ -195,7 +195,7 @@ public void openCallstackFrame(Node node, @NonNull String frameInfo) { + // and ignore the infrastructure stack lines in the process + while (!testfo.equals(file) && index != -1) { + file = UIJavaUtils.getFile(st[index], lineNumStorage, locator); +- index = index - 1; ++ index -= 1; + } + } + } +@@ -206,4 +206,35 @@ public void openCallstackFrame(Node node, @NonNull String frameInfo) { + UIJavaUtils.openFile(file, lineNumStorage[0]); + } + ++ private Element resolveNestedClass(List nestedClasses, Element e) { ++ if(nestedClasses.isEmpty()) { ++ return e; ++ } else { ++ String simpleName = nestedClasses.get(0); ++ for(Element childElement: e.getEnclosedElements()) { ++ if(childElement.getSimpleName().contentEquals(simpleName)) { ++ return resolveNestedClass(nestedClasses.subList(1, nestedClasses.size()), childElement); ++ } ++ } ++ return e; ++ } ++ } ++ ++ private record MethodInfo (String packageName, String topLevelClass, List nestedClasses, String method) { ++ public static MethodInfo fromTestCase(JUnitTestcase testcase) { ++ String className = testcase.getClassName(); ++ String[] nestedClasses = className.split("\\$"); ++ String packageName = null; ++ int lastDotInTopLevelClass = nestedClasses[0].lastIndexOf("."); ++ if (lastDotInTopLevelClass >= 0) { ++ packageName = nestedClasses[0].substring(0, lastDotInTopLevelClass); ++ nestedClasses[0] = nestedClasses[0].substring(lastDotInTopLevelClass + 1); ++ } ++ String method = null; ++ if(testcase.getName().startsWith(className)) { ++ method = testcase.getName().substring(className.length() + 1); ++ } ++ return new MethodInfo(packageName, nestedClasses[0], asList(nestedClasses).subList(1, nestedClasses.length), method); ++ } ++ } + } +diff --git a/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitTestMethodNode.java b/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitTestMethodNode.java +index bb0b7f1af117..67ce0eecf6e3 100644 +--- a/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitTestMethodNode.java ++++ b/java/maven.junit.ui/src/org/netbeans/modules/maven/junit/ui/MavenJUnitTestMethodNode.java +@@ -28,18 +28,20 @@ + import org.netbeans.api.extexecution.print.LineConvertors; + import org.netbeans.api.project.FileOwnerQuery; + import org.netbeans.api.project.Project; +-import org.netbeans.modules.gsf.testrunner.api.Testcase; + import org.netbeans.modules.gsf.testrunner.api.TestMethodNodeAction; ++import org.netbeans.modules.gsf.testrunner.api.Testcase; + import org.netbeans.modules.junit.ui.api.JUnitTestMethodNode; + import org.netbeans.spi.project.ActionProvider; ++import org.netbeans.spi.project.NestedClass; + import org.netbeans.spi.project.SingleMethod; +-import static org.netbeans.spi.project.SingleMethod.COMMAND_DEBUG_SINGLE_METHOD; +-import static org.netbeans.spi.project.SingleMethod.COMMAND_RUN_SINGLE_METHOD; + import org.openide.filesystems.FileObject; + import org.openide.util.Lookup; + import org.openide.util.NbBundle.Messages; + import org.openide.util.lookup.Lookups; + ++import static org.netbeans.spi.project.SingleMethod.COMMAND_DEBUG_SINGLE_METHOD; ++import static org.netbeans.spi.project.SingleMethod.COMMAND_RUN_SINGLE_METHOD; ++ + /** + * mkleint: copied from junit module + * +@@ -72,13 +74,29 @@ public Action[] getActions(boolean context) { + if (actionProvider != null) { + String mName = testcase.getName(); + String tcName= testcase.getClassName(); +- if (tcName!=null ++ if (tcName != null + && mName.startsWith(tcName) +- && mName.charAt(tcName.length())=='.'){ +- mName= mName.substring(tcName.length()+1); ++ && mName.charAt(tcName.length()) == '.') { ++ mName = mName.substring(tcName.length() + 1); ++ } ++ SingleMethod methodSpec; ++ if (tcName != null && tcName.contains("$")) { ++ String[] nestedSplit = tcName.split("\\$", 2); ++ String[] topLevelSplit = nestedSplit[0].split("\\."); ++ methodSpec = new SingleMethod(mName, new NestedClass(nestedSplit[1].replace("$", "."), topLevelSplit[topLevelSplit.length - 1], testFO)); ++ } else { ++ if(tcName != null) { ++ String[] topLevelSplit = tcName.split("\\."); ++ if(! testFO.getName().equals(topLevelSplit[topLevelSplit.length - 1])) { ++ methodSpec = new SingleMethod(mName, new NestedClass("", topLevelSplit[topLevelSplit.length - 1], testFO)); ++ } else { ++ methodSpec = new SingleMethod(testFO, mName); ++ } ++ } else { ++ methodSpec = new SingleMethod(testFO, mName); ++ } + } +- SingleMethod methodSpec = new SingleMethod(testFO, mName); +- Lookup nodeContext = Lookups.singleton(methodSpec); ++ Lookup nodeContext = Lookups.fixed(methodSpec); + + for (String action : actionProvider.getSupportedActions()) { + if (unitTest +diff --git a/java/maven.junit/nbproject/project.xml b/java/maven.junit/nbproject/project.xml +index 9d92e0b37134..27429dc43a6c 100644 +--- a/java/maven.junit/nbproject/project.xml ++++ b/java/maven.junit/nbproject/project.xml +@@ -34,6 +34,14 @@ + 1.24 + + ++ ++ org.netbeans.libs.javacapi ++ ++ ++ ++ 8.53 ++ ++ + + org.netbeans.modules.gsf.testrunner + +diff --git a/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java b/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java +index bfa3aed455b5..2802ade19611 100644 +--- a/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java ++++ b/java/maven.junit/src/org/netbeans/modules/maven/junit/JUnitOutputListenerProvider.java +@@ -20,6 +20,7 @@ + + import java.io.File; + import java.io.IOException; ++import java.nio.file.Path; + import java.text.NumberFormat; + import java.text.ParseException; + import java.util.ArrayList; +@@ -30,6 +31,7 @@ + import java.util.List; + import java.util.Locale; + import java.util.Map; ++import java.util.Map.Entry; + import java.util.Objects; + import java.util.Set; + import java.util.StringTokenizer; +@@ -37,6 +39,8 @@ + import java.util.logging.Logger; + import java.util.regex.Matcher; + import java.util.regex.Pattern; ++import java.util.stream.Collectors; ++import javax.lang.model.element.ElementKind; + import javax.swing.event.ChangeListener; + import org.apache.maven.project.MavenProject; + import org.apache.maven.artifact.Artifact; +@@ -50,6 +54,9 @@ + import org.jdom2.input.SAXBuilder; + import org.netbeans.api.annotations.common.NonNull; + import org.netbeans.api.annotations.common.NullAllowed; ++import org.netbeans.api.java.source.ClasspathInfo; ++import org.netbeans.api.java.source.ElementHandle; ++import org.netbeans.api.java.source.SourceUtils; + import org.netbeans.api.project.FileOwnerQuery; + import org.netbeans.api.project.Project; + import org.netbeans.modules.gsf.testrunner.api.RerunHandler; +@@ -71,6 +78,7 @@ + import org.netbeans.modules.maven.api.execute.RunUtils; + import org.netbeans.modules.maven.api.output.OutputProcessor; + import org.netbeans.modules.maven.api.output.OutputVisitor; ++import org.openide.filesystems.FileObject; + import org.openide.filesystems.FileUtil; + import org.openide.util.Exceptions; + import org.openide.util.Lookup; +@@ -700,15 +708,20 @@ static Trouble constructTrouble(@NonNull String type, @NullAllowed String messag + + private File locateOutputDirAndWait(String candidateClass, boolean consume) { + String suffix = reportNameSuffix == null ? "" : "-" + reportNameSuffix; +- File outputDir = locateOutputDir(candidateClass, suffix, consume); +- if (outputDir == null && surefireRunningInParallel) { +- // try waiting a bit to give time for the result file to be created +- try { ++ File outputDir = null; ++ // Test report might be in flight, so scan for it multiple times. ++ // Problems were observed with surefire running tests in parallel and ++ // also single threaded mode at leat on linus. ++ try { ++ for (int i = 1; i <= 40; i++) { ++ outputDir = locateOutputDir(candidateClass, suffix, consume); ++ if (outputDir != null) { ++ LOG.log(Level.FINE, "Found output dir for test {0} in {1}. iteration ", new Object[]{candidateClass, i}); ++ break; ++ } + Thread.sleep(500); +- } catch (InterruptedException ex) { +- Exceptions.printStackTrace(ex); + } +- outputDir = locateOutputDir(candidateClass, suffix, consume); ++ } catch (InterruptedException ex) { + } + return outputDir; + } +@@ -730,6 +743,22 @@ private void generateTest() { + LOG.log(Level.FINE, "No session for outdir {0}", outputDir); + return; + } ++ Map classpathInfo = Map.of(); ++ NbMavenProject nbMavenProject = session.getProject() ++ .getLookup() ++ .lookup(NbMavenProject.class); ++ if(nbMavenProject != null) { ++ classpathInfo = nbMavenProject ++ .getMavenProject() ++ .getTestCompileSourceRoots() ++ .stream() ++ .map(p -> (p.endsWith("/") || p.endsWith("\\")) ? p : (p + "/")) ++ .map(p -> new File(p)) ++ .collect(Collectors.toMap( ++ f -> ClasspathInfo.create(f), ++ f -> f.toPath() ++ )); ++ } + if (report.length() > 50 * 1024 * 1024) { + LOG.log(Level.INFO, "Skipping report file as size is too big (> 50MB): {0}", report.getPath()); + return; +@@ -826,7 +855,19 @@ private void generateTest() { + classname = classname.substring(0, classname.length() - nameSuffix.length()); + } + test.setClassName(classname); +- test.setLocation(test.getClassName().replace('.', '/') + ".java"); ++ String relativePath = null; ++ for (Entry ci : classpathInfo.entrySet()) { ++ FileObject fo = SourceUtils.getFile(ElementHandle.createTypeElementHandle(ElementKind.CLASS, classname), ci.getKey()); ++ if (fo != null) { ++ relativePath = ci.getValue().relativize(FileUtil.toFile(fo).toPath()).toString(); ++ break; ++ } ++ } ++ if (relativePath != null) { ++ test.setLocation(relativePath); ++ } else { ++ test.setLocation(classname.replace('.', '/').split("\\$")[0] + ".java"); ++ } + } + session.addTestCase(test); + } +diff --git a/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java b/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java +index 1ebff0ee4680..183f2790f478 100644 +--- a/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java ++++ b/java/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java +@@ -226,8 +226,11 @@ private boolean usingJUnit4() { // SUREFIRE-724 + private boolean usingJUnit5() { + return proj.getLookup().lookup(NbMavenProject.class).getMavenProject().getArtifacts() + .stream() +- .anyMatch((a) -> ("org.junit.jupiter".equals(a.getGroupId()) && "junit-jupiter-engine".equals(a.getArtifactId()) || +- "org.junit.platform".equals(a.getGroupId()) && "junit-platform-engine".equals(a.getArtifactId()))); ++ .anyMatch((a) -> ( ++ "org.junit.jupiter".equals(a.getGroupId()) && "junit-jupiter-engine".equals(a.getArtifactId()) || ++ "org.junit.jupiter".equals(a.getGroupId()) && "junit-jupiter-api".equals(a.getArtifactId()) || ++ "org.junit.platform".equals(a.getGroupId()) && "junit-platform-engine".equals(a.getArtifactId())) ++ ); + } + + private boolean usingTestNG() { +diff --git a/java/maven/src/org/netbeans/modules/maven/execute/DefaultReplaceTokenProvider.java b/java/maven/src/org/netbeans/modules/maven/execute/DefaultReplaceTokenProvider.java +index e6c05cbf9ab8..e3ed61429aa8 100644 +--- a/java/maven/src/org/netbeans/modules/maven/execute/DefaultReplaceTokenProvider.java ++++ b/java/maven/src/org/netbeans/modules/maven/execute/DefaultReplaceTokenProvider.java +@@ -102,8 +102,22 @@ private static FileObject[] extractFileObjectsfromLookup(Lookup lookup) { + return files.toArray(new FileObject[0]); + } + +- @Override public Map createReplacements(String actionName, Lookup lookup) { ++ private static NestedClass extractNestedClassFromLookup(Lookup lookup) { + NestedClass nestedClass = lookup.lookup(NestedClass.class); ++ if (nestedClass != null) { ++ return nestedClass; ++ } ++ ++ SingleMethod sm = lookup.lookup(SingleMethod.class); ++ if (sm != null) { ++ return sm.getNestedClass(); ++ } ++ ++ return null; ++ } ++ ++ @Override public Map createReplacements(String actionName, Lookup lookup) { ++ NestedClass nestedClass = extractNestedClassFromLookup(lookup); + FileObject[] fos = extractFileObjectsfromLookup(lookup); + List projects = extractProjectsFromLookup(lookup); + diff --git a/patches/8694.diff b/patches/8694.diff new file mode 100644 index 00000000..4e68eb3d --- /dev/null +++ b/patches/8694.diff @@ -0,0 +1,89 @@ +diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java +index 6fe9ece2c0cb..82f5346568d1 100644 +--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java ++++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/NbProtocolServer.java +@@ -81,7 +81,9 @@ + import org.netbeans.api.debugger.jpda.JPDADebugger; + import org.netbeans.api.debugger.jpda.ObjectVariable; + import org.netbeans.api.debugger.jpda.Variable; ++import org.netbeans.api.project.Project; + import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable; ++import org.netbeans.modules.java.lsp.server.LspServerState; + import org.netbeans.modules.java.lsp.server.LspSession; + import org.netbeans.modules.java.lsp.server.URITranslator; + import org.netbeans.modules.java.lsp.server.debugging.breakpoints.NbBreakpointsRequestHandler; +@@ -165,6 +167,20 @@ public CompletableFuture initialize(InitializeRequestArguments arg + caught.setLabel("Caught Exceptions"); + caps.setExceptionBreakpointFilters(new ExceptionBreakpointsFilter[]{uncaught, caught}); + caps.setSupportsExceptionInfoRequest(true); ++ ++ LspServerState lspServerState = context.getLspSession().getLookup().lookup(LspServerState.class); ++ if (lspServerState != null) { ++ CompletableFuture initDone = lspServerState.openedProjects(); ++ if (!initDone.isDone()) { ++ LOGGER.log(Level.INFO, "Waiting on LS protocol server {0} to finish initialization", lspServerState); ++ return lspServerState.openedProjects().thenApply(prjs -> { ++ LOGGER.log(Level.FINE, "LS protocol server {0} initialized, DAP init complete", lspServerState); ++ return caps; ++ }); ++ } else { ++ LOGGER.log(Level.FINE, "LS protocol server {0} ready", lspServerState); ++ } ++ } + return CompletableFuture.completedFuture(caps); + } + +diff --git a/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java b/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java +index 81a7feb329f2..c1d60f9c4b71 100644 +--- a/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java ++++ b/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java +@@ -37,6 +37,7 @@ + import java.util.Map; + import java.util.UUID; + import java.util.concurrent.ExecutionException; ++import java.util.concurrent.atomic.AtomicInteger; + import java.util.function.Consumer; + import java.util.logging.Level; + import java.util.logging.Logger; +@@ -128,6 +129,12 @@ public class MavenCommandLineExecutor extends AbstractMavenExecutor { + private String processUUID; + private Process preProcess; + private String preProcessUUID; ++ ++ /** ++ * Diagnostics: stracktrace that shows what code requested the execution. ++ */ ++ private final Throwable trace; ++ + private static final SpecificationVersion VER18 = new SpecificationVersion("1.8"); //NOI18N + private static final Logger LOGGER = Logger.getLogger(MavenCommandLineExecutor.class.getName()); + +@@ -191,6 +198,11 @@ public ExecutorTask execute(RunConfig config, InputOutput io, TabContext tc) { + public MavenCommandLineExecutor(RunConfig conf, InputOutput io, TabContext tc) { + super(conf, tc); + this.io = io; ++ if (LOGGER.isLoggable(Level.FINER)) { ++ this.trace = new Throwable(); ++ } else { ++ this.trace = null; ++ } + } + + /** +@@ -331,6 +343,8 @@ public void actionPerformed(ActionEvent e) { + // ioput.getOut().println(key + ":" + env.get(key)); + // } + ProcessBuilder builder = constructBuilder(clonedConfig, ioput); ++ LOGGER.log(Level.FINER, "Executing process {0} from {1}", new Object[] { builder.command(), this }); ++ LOGGER.log(Level.FINER, "Origin:", this.trace); + printCoSWarning(clonedConfig, ioput); + processUUID = UUID.randomUUID().toString(); + builder.environment().put(KEY_UUID, processUUID); +@@ -348,6 +362,7 @@ public void actionPerformed(ActionEvent e) { + throw death; + } finally { + BuildExecutionSupport.registerFinishedItem(item); ++ LOGGER.log(Level.FINER, "Execution of {0} terminated", this ); + + try { //defend against badly written extensions.. + out.buildFinished(); diff --git a/patches/8745-draft.diff b/patches/8745.diff similarity index 96% rename from patches/8745-draft.diff rename to patches/8745.diff index 6776fd33..2432236e 100644 --- a/patches/8745-draft.diff +++ b/patches/8745.diff @@ -1,5 +1,5 @@ diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractJavaPlatformProviderOverride.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractJavaPlatformProviderOverride.java -index df668954dd..054f85d0e5 100644 +index df668954dd94..054f85d0e59e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractJavaPlatformProviderOverride.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/ui/AbstractJavaPlatformProviderOverride.java @@ -39,6 +39,14 @@ public abstract class AbstractJavaPlatformProviderOverride implements JavaPlatfo diff --git a/patches/8748.diff b/patches/8748.diff new file mode 100644 index 00000000..ccee7135 --- /dev/null +++ b/patches/8748.diff @@ -0,0 +1,8 @@ +diff --git a/platform/openide.util.lookup/src/META-INF/gradle/incremental.annotation.processors b/platform/openide.util.lookup/src/META-INF/gradle/incremental.annotation.processors +new file mode 100644 +index 000000000000..918b4bbf6505 +--- /dev/null ++++ b/platform/openide.util.lookup/src/META-INF/gradle/incremental.annotation.processors +@@ -0,0 +1 @@ ++org.netbeans.modules.openide.util.ServiceProviderProcessor,aggregating +\ No newline at end of file diff --git a/patches/8760.diff b/patches/8760.diff new file mode 100644 index 00000000..e0197dce --- /dev/null +++ b/patches/8760.diff @@ -0,0 +1,14 @@ +diff --git a/ide/editor.lib2/src/org/netbeans/spi/editor/highlighting/support/HighlightsContainers.java b/ide/editor.lib2/src/org/netbeans/spi/editor/highlighting/support/HighlightsContainers.java +index 5447ab950347..56de41045d8d 100644 +--- a/ide/editor.lib2/src/org/netbeans/spi/editor/highlighting/support/HighlightsContainers.java ++++ b/ide/editor.lib2/src/org/netbeans/spi/editor/highlighting/support/HighlightsContainers.java +@@ -38,6 +38,9 @@ class InlineHintsSettingsAwareContainer extends AbstractHighlightsContainer impl + + public InlineHintsSettingsAwareContainer() { + String mimeType = DocumentUtilities.getMimeType(doc); ++ if (mimeType == null) { ++ mimeType = ""; ++ } + prefs = MimeLookup.getLookup(mimeType).lookup(Preferences.class); + prefs.addPreferenceChangeListener(WeakListeners.create(PreferenceChangeListener.class, this, prefs)); + inlineSettingChanged(); diff --git a/patches/8762.diff b/patches/8762.diff new file mode 100644 index 00000000..df89d9e8 --- /dev/null +++ b/patches/8762.diff @@ -0,0 +1,512 @@ +diff --git a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java +index e720d5745c0c..7ac61fb4370f 100644 +--- a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java ++++ b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java +@@ -5631,7 +5631,10 @@ private boolean isOfSmartType(Env env, TypeMirror type, Set it = ((DeclaredType) type).getTypeArguments().iterator(); +- type = it.hasNext() ? it.next() : elements.getTypeElement(JAVA_LANG_OBJECT).asType(); //NOI18N ++ type = it.hasNext() ? it.next() : null; ++ if (type == null || type.getKind() == TypeKind.ERROR) { ++ type = elements.getTypeElement(JAVA_LANG_OBJECT).asType(); ++ } + } else { + return false; + } +@@ -5745,6 +5748,9 @@ private Set getSmartTypes(Env env) throws IOException { + } + } + } ++ if (st.isEmpty() && env.getPath().getLeaf().getKind() == Kind.ENHANCED_FOR_LOOP) { ++ st.add(controller.getElements().getTypeElement("java.lang.Object").asType()); ++ } + smartTypes = st; + } + } +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/forEachWithOutType.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/forEachWithOutType.pass +new file mode 100644 +index 000000000000..6c85b0660e5b +--- /dev/null ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/17/forEachWithOutType.pass +@@ -0,0 +1,138 @@ ++String[] data ++List intData ++Set undefData ++int a ++public String field ++protected native Object clone() ++public boolean equals(Object arg0) ++protected void finalize() ++public final native Class getClass() ++public native int hashCode() ++public final native void notify() ++public final native void notifyAll() ++public void op(int a) ++public String toString() ++public final void wait() ++public final native void wait(long arg0) ++public final void wait(long arg0, int arg1) ++boolean ++byte ++char ++double ++float ++int ++long ++new ++short ++super ++this ++AbstractMethodError ++Appendable ++ArithmeticException ++ArrayIndexOutOfBoundsException ++ArrayStoreException ++AssertionError ++AutoCloseable ++Boolean ++BootstrapMethodError ++Byte ++CharSequence ++Character ++Class ++ClassCastException ++ClassCircularityError ++ClassFormatError ++ClassLoader ++ClassNotFoundException ++ClassValue ++CloneNotSupportedException ++Cloneable ++Comparable ++Compiler ++Deprecated ++Double ++Enum ++EnumConstantNotPresentException ++Error ++Exception ++ExceptionInInitializerError ++Float ++FunctionalInterface ++IllegalAccessError ++IllegalAccessException ++IllegalArgumentException ++IllegalCallerException ++IllegalMonitorStateException ++IllegalStateException ++IllegalThreadStateException ++IncompatibleClassChangeError ++IndexOutOfBoundsException ++InheritableThreadLocal ++InstantiationError ++InstantiationException ++Integer ++InternalError ++InterruptedException ++Iterable ++LayerInstantiationException ++LinkageError ++Long ++Math ++Module ++ModuleLayer ++NegativeArraySizeException ++NoClassDefFoundError ++NoSuchFieldError ++NoSuchFieldException ++NoSuchMethodError ++NoSuchMethodException ++NullPointerException ++Number ++NumberFormatException ++Object ++OutOfMemoryError ++Override ++Package ++Process ++ProcessBuilder ++ProcessHandle ++Readable ++Record ++ReflectiveOperationException ++Runnable ++Runtime ++RuntimeException ++RuntimePermission ++SafeVarargs ++SecurityException ++SecurityManager ++Short ++StackOverflowError ++StackTraceElement ++StackWalker ++StrictMath ++String ++StringBuffer ++StringBuilder ++StringIndexOutOfBoundsException ++SuppressWarnings ++System ++Test ++Thread ++ThreadDeath ++ThreadGroup ++ThreadLocal ++Throwable ++TypeNotPresentException ++UnknownError ++UnsatisfiedLinkError ++UnsupportedClassVersionError ++UnsupportedOperationException ++VerifyError ++VirtualMachineError ++Void ++com ++java ++javax ++org ++sun +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/21/forEachWithOutType.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/21/forEachWithOutType.pass +new file mode 100644 +index 000000000000..8df0c6a97424 +--- /dev/null ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/21/forEachWithOutType.pass +@@ -0,0 +1,141 @@ ++String[] data ++List intData ++Set undefData ++int a ++public String field ++protected native Object clone() ++public boolean equals(Object arg0) ++protected void finalize() ++public final native Class getClass() ++public native int hashCode() ++public final native void notify() ++public final native void notifyAll() ++public void op(int a) ++public String toString() ++public final void wait() ++public final void wait(long arg0) ++public final void wait(long arg0, int arg1) ++boolean ++byte ++char ++double ++float ++int ++long ++new ++short ++super ++this ++AbstractMethodError ++Appendable ++ArithmeticException ++ArrayIndexOutOfBoundsException ++ArrayStoreException ++AssertionError ++AutoCloseable ++Boolean ++BootstrapMethodError ++Byte ++CharSequence ++Character ++Class ++ClassCastException ++ClassCircularityError ++ClassFormatError ++ClassLoader ++ClassNotFoundException ++ClassValue ++CloneNotSupportedException ++Cloneable ++Comparable ++Deprecated ++Double ++Enum ++EnumConstantNotPresentException ++Error ++Exception ++ExceptionInInitializerError ++Float ++FunctionalInterface ++IllegalAccessError ++IllegalAccessException ++IllegalArgumentException ++IllegalCallerException ++IllegalMonitorStateException ++IllegalStateException ++IllegalThreadStateException ++IncompatibleClassChangeError ++IndexOutOfBoundsException ++InheritableThreadLocal ++InstantiationError ++InstantiationException ++Integer ++InternalError ++InterruptedException ++Iterable ++LayerInstantiationException ++LinkageError ++Long ++MatchException ++Math ++Module ++ModuleLayer ++NegativeArraySizeException ++NoClassDefFoundError ++NoSuchFieldError ++NoSuchFieldException ++NoSuchMethodError ++NoSuchMethodException ++NullPointerException ++Number ++NumberFormatException ++Object ++OutOfMemoryError ++Override ++Package ++Process ++ProcessBuilder ++ProcessHandle ++Readable ++Record ++ReflectiveOperationException ++Runnable ++Runtime ++RuntimeException ++RuntimePermission ++SafeVarargs ++ScopedValue ++SecurityException ++SecurityManager ++Short ++StackOverflowError ++StackTraceElement ++StackWalker ++StrictMath ++String ++StringBuffer ++StringBuilder ++StringIndexOutOfBoundsException ++StringTemplate ++SuppressWarnings ++System ++Test ++Thread ++ThreadDeath ++ThreadGroup ++ThreadLocal ++Throwable ++TypeNotPresentException ++UnknownError ++UnsatisfiedLinkError ++UnsupportedClassVersionError ++UnsupportedOperationException ++VerifyError ++VirtualMachineError ++Void ++WrongThreadException ++com ++java ++javax ++org ++sun +diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/25/forEachWithOutType.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/25/forEachWithOutType.pass +new file mode 100644 +index 000000000000..db1d32543256 +--- /dev/null ++++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/25/forEachWithOutType.pass +@@ -0,0 +1,142 @@ ++String[] data ++List intData ++Set undefData ++int a ++public String field ++protected native Object clone() ++public boolean equals(Object arg0) ++protected void finalize() ++public final native Class getClass() ++public native int hashCode() ++public final native void notify() ++public final native void notifyAll() ++public void op(int a) ++public String toString() ++public final void wait() ++public final void wait(long arg0) ++public final void wait(long arg0, int arg1) ++boolean ++byte ++char ++double ++float ++int ++long ++new ++short ++super ++this ++AbstractMethodError ++Appendable ++ArithmeticException ++ArrayIndexOutOfBoundsException ++ArrayStoreException ++AssertionError ++AutoCloseable ++Boolean ++BootstrapMethodError ++Byte ++CharSequence ++Character ++Class ++ClassCastException ++ClassCircularityError ++ClassFormatError ++ClassLoader ++ClassNotFoundException ++ClassValue ++CloneNotSupportedException ++Cloneable ++Comparable ++Deprecated ++Double ++Enum ++EnumConstantNotPresentException ++Error ++Exception ++ExceptionInInitializerError ++Float ++FunctionalInterface ++IO ++IllegalAccessError ++IllegalAccessException ++IllegalArgumentException ++IllegalCallerException ++IllegalMonitorStateException ++IllegalStateException ++IllegalThreadStateException ++IncompatibleClassChangeError ++IndexOutOfBoundsException ++InheritableThreadLocal ++InstantiationError ++InstantiationException ++Integer ++InternalError ++InterruptedException ++Iterable ++LayerInstantiationException ++LinkageError ++Long ++MatchException ++Math ++Module ++ModuleLayer ++NegativeArraySizeException ++NoClassDefFoundError ++NoSuchFieldError ++NoSuchFieldException ++NoSuchMethodError ++NoSuchMethodException ++NullPointerException ++Number ++NumberFormatException ++Object ++OutOfMemoryError ++Override ++Package ++Process ++ProcessBuilder ++ProcessHandle ++Readable ++Record ++ReflectiveOperationException ++Runnable ++Runtime ++RuntimeException ++RuntimePermission ++SafeVarargs ++ScopedValue ++SecurityException ++SecurityManager ++Short ++StableValue ++StackOverflowError ++StackTraceElement ++StackWalker ++StrictMath ++String ++StringBuffer ++StringBuilder ++StringIndexOutOfBoundsException ++SuppressWarnings ++System ++Test ++Thread ++ThreadDeath ++ThreadGroup ++ThreadLocal ++Throwable ++TypeNotPresentException ++UnknownError ++UnsatisfiedLinkError ++UnsupportedClassVersionError ++UnsupportedOperationException ++VerifyError ++VirtualMachineError ++Void ++WrongThreadException ++com ++java ++javax ++org ++sun +diff --git a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAdvancedTest.java b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAdvancedTest.java +index 02e1ae0c0a95..192cb88986f5 100644 +--- a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAdvancedTest.java ++++ b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAdvancedTest.java +@@ -617,6 +617,10 @@ public void testInsideForEachBody() throws Exception { + performTest("ForEach", 940, null, "blockContentAfterForEach.pass"); + } + ++ public void testForEachMissingType() throws Exception { ++ performTest("SimpleEmptyMethodBody", 907, "java.util.List intData = null; java.util.Set undefData = null; String[] data = null; for (d : ", "forEachWithOutType.pass"); ++ } ++ + // Switch-case statement tests --------------------------------------------- + + public void testEmptyFileAfterTypingSwitchKeyword() throws Exception { +diff --git a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBParserFactory.java b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBParserFactory.java +index b718be770076..87fece4029b6 100644 +--- a/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBParserFactory.java ++++ b/java/lib.nbjavac/src/org/netbeans/lib/nbjavac/services/NBParserFactory.java +@@ -180,7 +180,7 @@ public JCStatement parseSimpleStatement() { + if (result instanceof JCEnhancedForLoop) { + JCEnhancedForLoop tree = (JCEnhancedForLoop) result; + if (getEndPos(tree.var) == Position.NOPOS) { +- endPosTable.storeEnd(tree.var, getEndPos(tree.var.vartype)); ++ ((EndPosTableImpl) endPosTable).setEnd(tree.var, getEndPos(tree.var.vartype)); + } + } + return result; +@@ -207,6 +207,18 @@ public void resetErrorEndPos() { + delegate.storeEnd(tree, endpos); + } + ++ public void setEnd(JCTree tree, int endpos) { ++ if (endpos >= 0) { ++ int oldErrorEndPos = delegate.errorEndPos; ++ try { ++ delegate.errorEndPos = -1; ++ delegate.storeEnd(tree, endpos); ++ } finally { ++ delegate.errorEndPos = oldErrorEndPos; ++ } ++ } ++ } ++ + @Override + public void setErrorEndPos(int errPos) { + delegate.setErrorEndPos(errPos); diff --git a/patches/8769.diff b/patches/8769.diff new file mode 100644 index 00000000..693950d9 --- /dev/null +++ b/patches/8769.diff @@ -0,0 +1,12 @@ +diff --git a/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java b/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java +index cacf2c8d43e1..c9c4a4417350 100644 +--- a/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java ++++ b/java/gradle.test/src/org/netbeans/modules/gradle/test/GradleTestProgressListener.java +@@ -365,6 +365,7 @@ private String searchLocation(Testcase tc, String className, String methodName, + + String relativePath = null; + for (Map.Entry ci : classpathInfo.entrySet()) { ++ if (ci.getKey() == null) continue; + FileObject fo = SourceUtils.getFile(ElementHandle.createTypeElementHandle(ElementKind.CLASS, className), ci.getKey()); + if (fo != null) { + relativePath = ci.getValue().relativize(FileUtil.toFile(fo).toPath()).toString(); diff --git a/patches/8797.diff b/patches/8797.diff new file mode 100644 index 00000000..0a432c35 --- /dev/null +++ b/patches/8797.diff @@ -0,0 +1,54 @@ +diff --git a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java +index d47d7096a08d..f797c28ce570 100644 +--- a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java ++++ b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java +@@ -49,6 +49,7 @@ + import java.util.Optional; + import java.util.Set; + import java.util.function.Consumer; ++import java.util.function.Function; + import java.util.function.Supplier; + import java.util.regex.Pattern; + import java.util.stream.Collectors; +@@ -1562,6 +1563,23 @@ private void detectDependencies(NbProjectInfoModel model) { + boolean ignoreUnresolvable = (project.getPlugins().hasPlugin("java-platform") && + Boolean.TRUE.equals(getProperty(project, "javaPlatform", "allowDependencies"))); + ++ // https://github.com/apache/netbeans/issues/8764 ++ Function projDependencyToProject = ++ sinceGradleOrDefault( ++ "9.0", ++ () -> { ++ Method getPath = ProjectDependency.class.getMethod("getPath"); ++ return dep -> { ++ try { ++ String path = (String) getPath.invoke(dep); ++ return project.findProject(path); ++ } catch (ReflectiveOperationException e) { ++ throw new UnsupportedOperationException(e); ++ } ++ }; ++ }, ++ () -> ProjectDependency::getDependencyProject); // removed in Gradle 9 ++ + visibleConfigurations.forEach(it -> { + String propBase = "configuration_" + it.getName() + "_"; + model.getInfo().put(propBase + "non_resolving", !resolvable(it)); +@@ -1660,7 +1678,7 @@ private void detectDependencies(NbProjectInfoModel model) { + String a; + if (d instanceof ProjectDependency) { + sb.append("*project:"); // NOI18N +- Project other = ((ProjectDependency)d).getDependencyProject(); ++ Project other = projDependencyToProject.apply((ProjectDependency) d); + g = other.getGroup().toString(); + a = other.getName(); + } else { +@@ -1679,7 +1697,7 @@ private void detectDependencies(NbProjectInfoModel model) { + long time_project_deps = System.currentTimeMillis(); + model.registerPerf(depPrefix + "module", time_project_deps - time_inspect_conf); + it.getDependencies().withType(ProjectDependency.class).forEach(it2 -> { +- Project prj = it2.getDependencyProject(); ++ Project prj = projDependencyToProject.apply(it2); + projects.put(prj.getPath(), prj.getProjectDir()); + projectNames.add(prj.getPath()); + }); diff --git a/patches/8816.diff b/patches/8816.diff new file mode 100644 index 00000000..9269883c --- /dev/null +++ b/patches/8816.diff @@ -0,0 +1,176 @@ +diff --git a/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml b/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml +index d493332788e4..ac4122a96709 100644 +--- a/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml ++++ b/java/maven/src/org/netbeans/modules/maven/execute/defaultActionMappings.xml +@@ -133,7 +133,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + +@@ -150,7 +150,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} +@@ -168,7 +168,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + +@@ -186,7 +186,7 @@ + + + process-test-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} +@@ -255,7 +255,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + +@@ -272,7 +272,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + +diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/api/customizer/ModelHandle2Test.java b/java/maven/test/unit/src/org/netbeans/modules/maven/api/customizer/ModelHandle2Test.java +index d0d66a131ab5..ae4b37f8477b 100644 +--- a/java/maven/test/unit/src/org/netbeans/modules/maven/api/customizer/ModelHandle2Test.java ++++ b/java/maven/test/unit/src/org/netbeans/modules/maven/api/customizer/ModelHandle2Test.java +@@ -162,7 +162,7 @@ public void testJettyDebugSingle() throws Exception { // # + " \n" + + " \n" + + " process-classes\n" + +-" org.codehaus.mojo:exec-maven-plugin:3.1.0:exec\n" + ++" org.codehaus.mojo:exec-maven-plugin:3.5.1:exec\n" + + " \n" + + " \n" + + " -classpath %classpath ${packageClassName}\n" + +@@ -177,7 +177,7 @@ public void testJettyDebugSingle() throws Exception { // # + " \n" + + " \n" + + " process-classes\n" + +-" org.codehaus.mojo:exec-maven-plugin:3.1.0:exec\n" + ++" org.codehaus.mojo:exec-maven-plugin:3.5.1:exec\n" + + " \n" + + " \n" + + " -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath ${packageClassName}\n" + +@@ -199,7 +199,7 @@ public void testJettyDebugSingle() throws Exception { // # + " \n" + + " \n" + + " process-classes\n" + +-" org.codehaus.mojo:exec-maven-plugin:3.1.0:exec\n" + ++" org.codehaus.mojo:exec-maven-plugin:3.5.1:exec\n" + + " \n" + + " \n" + + " -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath ${packageClassName}\n" + +@@ -223,7 +223,7 @@ public void testJettyDebugSingle() throws Exception { // # + RunConfig run = ActionToGoalUtils.createRunConfig("debug.single.main", (NbMavenProjectImpl) project, project.getLookup()); + assertEquals("Two goals: " + run.getGoals(), 2, run.getGoals().size()); + assertEquals("process-classes", run.getGoals().get(0)); +- assertEquals("org.codehaus.mojo:exec-maven-plugin:3.1.0:exec", run.getGoals().get(1)); ++ assertEquals("org.codehaus.mojo:exec-maven-plugin:3.5.1:exec", run.getGoals().get(1)); + assertEquals("One profile activated in action: " + run.getActivatedProfiles(), 1, run.getActivatedProfiles().size()); + assertEquals("jetty", run.getActivatedProfiles().get(0)); + } +diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecutionTestBase.java b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecutionTestBase.java +index 700b67a48ec1..fa480776502d 100644 +--- a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecutionTestBase.java ++++ b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecutionTestBase.java +@@ -188,7 +188,7 @@ protected FileObject createPom(String argsString, String propString) throws IOEx + + " \n" + + " org.codehaus.mojo\n" + + " exec-maven-plugin\n" +- + " 3.1.0\n" ++ + " 3.5.1\n" + + " \n" + + argsString + + " \n" +diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/ModelRunConfigTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/ModelRunConfigTest.java +index 612a6b57a08a..6398e3481159 100644 +--- a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/ModelRunConfigTest.java ++++ b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/ModelRunConfigTest.java +@@ -242,7 +242,7 @@ private void assertArgs(String argsString, String propString, AssertArgs a) thro + + " \n" + + " org.codehaus.mojo\n" + + " exec-maven-plugin\n" +- + " 3.1.0\n" ++ + " 3.5.1\n" + + " \n" + + " ${java.home}/bin/java\n" + + argsString +diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/runjar/nbactions-template.xml b/java/maven/test/unit/src/org/netbeans/modules/maven/runjar/nbactions-template.xml +index f3105025afe0..bea883ca7071 100644 +--- a/java/maven/test/unit/src/org/netbeans/modules/maven/runjar/nbactions-template.xml ++++ b/java/maven/test/unit/src/org/netbeans/modules/maven/runjar/nbactions-template.xml +@@ -27,7 +27,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + &runProperties; +@@ -40,7 +40,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + &debugProperties; +@@ -53,7 +53,7 @@ + + + process-classes +- org.codehaus.mojo:exec-maven-plugin:3.1.0:exec ++ org.codehaus.mojo:exec-maven-plugin:3.5.1:exec + + + &profileProperties; +diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java +index 1183cfe90e71..458d008519bb 100644 +--- a/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java ++++ b/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java +@@ -47,6 +47,7 @@ + * + * @author sdedic + */ ++@SuppressWarnings("unchecked") + public class ProvidedConfigurationsTest extends NbTestCase { + + public ProvidedConfigurationsTest(String name) { +@@ -144,7 +145,7 @@ public void testSpecificConfigurationGoalOverride() throws Exception { + RunConfig cfg = ActionToGoalUtils.createRunConfig("run", pimpl, Lookup.EMPTY); + assertEquals(Arrays.asList( + "process-classes", +- "org.codehaus.mojo:exec-maven-plugin:3.1.0:exec"), cfg.getGoals()); ++ "org.codehaus.mojo:exec-maven-plugin:3.5.1:exec"), cfg.getGoals()); + + ProjectConfigurationProvider pcp = p.getLookup().lookup(ProjectConfigurationProvider.class); + MavenConfiguration c = pcp.getConfigurations().stream().filter(x -> "Micronaut: dev mode".equals(x.getDisplayName())).findAny().get(); diff --git a/patches/8821.diff b/patches/8821.diff new file mode 100644 index 00000000..f000fe6c --- /dev/null +++ b/patches/8821.diff @@ -0,0 +1,13 @@ +diff --git a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java +index f797c28ce570..7a62d2d8dd2e 100644 +--- a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java ++++ b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NbProjectInfoBuilder.java +@@ -1705,7 +1705,7 @@ private void detectDependencies(NbProjectInfoModel model) { + model.registerPerf(depPrefix + "project", time_file_deps - time_project_deps); + Set fileDeps = new HashSet<>(); + it.getDependencies().withType(FileCollectionDependency.class).forEach(it2 -> { +- fileDeps.addAll(it2.resolve()); ++ it2.getFiles().forEach(fileDeps::add); + }); + long time_collect = System.currentTimeMillis(); + model.registerPerf(depPrefix + "file", time_collect - time_file_deps);