This is an automated email from the ASF dual-hosted git repository.

lkishalmi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new d13f34ba74 Gradle Project shall use the Java from the tooling not 
runtime.
d13f34ba74 is described below

commit d13f34ba7422948db84075f7772e15be4274e02b
Author: Laszlo Kishalmi <laszlo.kisha...@gmail.com>
AuthorDate: Sun Feb 4 07:23:37 2024 -0800

    Gradle Project shall use the Java from the tooling not runtime.
---
 .../gradle/tooling/NbProjectInfoBuilder.java       |  23 ++
 .../modules/gradle/cache/ProjectInfoDiskCache.java |   2 +-
 java/gradle.java/apichanges.xml                    |  22 ++
 java/gradle.java/manifest.mf                       |   1 +
 java/gradle.java/nbproject/project.properties      |   3 +-
 java/gradle.java/nbproject/project.xml             |   1 +
 .../gradle/java/api/GradleJavaProjectBuilder.java  |   9 +-
 .../gradle/java/api/GradleJavaSourceSet.java       |  17 ++
 .../classpath/AbstractGradleClassPathImpl.java     |   7 +-
 .../gradle/java/classpath/BootClassPathImpl.java   |  43 ++--
 .../java/classpath/ClassPathProviderImpl.java      |   4 +-
 .../classpath/GlobalClassPathProviderImpl.java     |  44 ++--
 .../gradle/java/customizer/Bundle.properties       |   1 +
 .../gradle/java/customizer/SourceSetPanel.form     |  45 +++-
 .../gradle/java/customizer/SourceSetPanel.java     |  49 +++-
 .../gradle/java/nodes/BootCPNodeFactory.java       | 280 +++++----------------
 .../java/spi/support/JavaToolchainSupport.java     | 122 +++++++++
 17 files changed, 371 insertions(+), 302 deletions(-)

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 0362bf0e2f..332c5360d0 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
@@ -105,9 +105,13 @@ import org.gradle.api.tasks.bundling.Jar;
 import org.gradle.api.tasks.testing.Test;
 import org.gradle.internal.resolve.ArtifactResolveException;
 import org.gradle.jvm.JvmLibrary;
+import org.gradle.jvm.toolchain.JavaCompiler;
 import org.gradle.language.base.artifact.SourcesArtifact;
 import org.gradle.language.java.artifact.JavadocArtifact;
 import org.gradle.plugin.use.PluginId;
+import org.gradle.api.provider.Property;
+import org.gradle.jvm.toolchain.JavaInstallationMetadata;
+import org.gradle.jvm.toolchain.JavaLauncher;
 import org.gradle.util.GradleVersion;
 import org.netbeans.modules.gradle.tooling.internal.NbProjectInfo;
 import org.netbeans.modules.gradle.tooling.internal.NbProjectInfo.Report;
@@ -1205,6 +1209,13 @@ class NbProjectInfoBuilder {
                                         o.toString()
                                 );
                             }
+                            
+                            sinceGradle("6.7", () -> {
+                                
fetchJavaInstallationMetadata(compileTask).ifPresent(
+                                        (meta) -> model.getInfo().put(propBase 
+ lang + "_compiler_java_home", meta.getInstallationPath().getAsFile())
+                                );
+                            });
+                            
                             List<String> compilerArgs;
 
                             compilerArgs = (List<String>) 
getProperty(compileTask, "options", "allCompilerArgs");
@@ -1311,6 +1322,18 @@ class NbProjectInfoBuilder {
         }
     }
 
+    private Optional<JavaInstallationMetadata> 
fetchJavaInstallationMetadata(Task task) {
+        Property<JavaLauncher> launcherProperty = (Property<JavaLauncher>) 
getProperty(task, "javaLauncher");
+        if (launcherProperty != null && launcherProperty.isPresent()) {
+            return Optional.of(launcherProperty.get().getMetadata());
+        }
+        Property<JavaCompiler> compilerProperty = (Property<JavaCompiler>) 
getProperty(task, "javaCompiler");
+        if (compilerProperty != null && compilerProperty.isPresent()) {
+            return Optional.of(compilerProperty.get().getMetadata());
+        }
+        return Optional.empty();
+    }
+    
     private void detectArtifacts(NbProjectInfoModel model) {
         if (project.getPlugins().hasPlugin("java")) {
             model.getInfo().put("main_jar", getProperty(project, "jar", 
"archivePath"));
diff --git 
a/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java 
b/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java
index 5718378b2d..a195c37523 100644
--- 
a/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java
+++ 
b/extide/gradle/src/org/netbeans/modules/gradle/cache/ProjectInfoDiskCache.java
@@ -45,7 +45,7 @@ import org.netbeans.modules.gradle.spi.GradleFiles;
 public final class ProjectInfoDiskCache extends AbstractDiskCache<GradleFiles, 
QualifiedProjectInfo> {
 
     // Increase this number if new info is gathered from the projects.
-    private static final int COMPATIBLE_CACHE_VERSION = 24;
+    private static final int COMPATIBLE_CACHE_VERSION = 25;
     private static final String INFO_CACHE_FILE_NAME = "project-info.ser"; 
//NOI18N
     private static final Map<GradleFiles, ProjectInfoDiskCache> DISK_CACHES = 
Collections.synchronizedMap(new WeakHashMap<>());
 
diff --git a/java/gradle.java/apichanges.xml b/java/gradle.java/apichanges.xml
index dfd5b57876..55a1019a96 100644
--- a/java/gradle.java/apichanges.xml
+++ b/java/gradle.java/apichanges.xml
@@ -83,6 +83,28 @@ is the proper place.
     <!-- ACTUAL CHANGES BEGIN HERE: -->
 
     <changes>
+        <change id="sourceset-compiler-javahome">
+            <api name="gradle.java.api"/>
+            <summary>Support for per-language output directories</summary>
+            <version major="1" minor="26"/>
+            <date day="4" month="1" year="2024"/>
+            <author login="lkishalmi"/>
+            <compatibility semantic="compatible" addition="yes" 
deprecation="no"/>
+            <description>
+                <p>
+                    Gradle 6.7 introduced Java Toolchains to separate Gradle 
Java Runtime
+                    and the Java used for compilation (and other Java 
execution).
+                    <code><a 
href="@TOP@/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.html#getCompilerJavaHome-org.netbeans.modules.gradle.java.api.GradleJavaSourceSet.SourceType-">GradleJavaSourceSet.getCompilerJavaHome</a></code>
 has been added to
+                    return the Java Home of the JDK in use for compilation.
+                </p>
+                <p>
+                    In addition <code><a 
href="@TOP@/org/netbeans/modules/gradle/java/spi/support/JavaToolchainSupport.html">JavaToolchainSsupport</a></code>
+                    is provided in order to be easily work with the JDK home 
directories.
+                </p>
+            </description>
+            <class package="org.netbeans.modules.gradle.java.api" 
name="GradleJavaSourceSet"/>
+            <class package="org.netbeans.modules.gradle.java.spi.support" 
name="JavaToolchainSupport"/>
+        </change>
         <change id="sourceset-lang-output">
             <api name="gradle.java.api"/>
             <summary>Support for per-language output directories</summary>
diff --git a/java/gradle.java/manifest.mf b/java/gradle.java/manifest.mf
index e7b6d301ae..b8aecd0fda 100644
--- a/java/gradle.java/manifest.mf
+++ b/java/gradle.java/manifest.mf
@@ -3,4 +3,5 @@ AutoUpdate-Show-In-Client: false
 OpenIDE-Module: org.netbeans.modules.gradle.java
 OpenIDE-Module-Layer: org/netbeans/modules/gradle/java/layer.xml
 OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/gradle/java/Bundle.properties
+OpenIDE-Module-Java-Dependencies: Java > 17
 OpenIDE-Module-Implementation-Version: 1
diff --git a/java/gradle.java/nbproject/project.properties 
b/java/gradle.java/nbproject/project.properties
index 73520f0ec5..6d470bd837 100644
--- a/java/gradle.java/nbproject/project.properties
+++ b/java/gradle.java/nbproject/project.properties
@@ -16,7 +16,8 @@
 # under the License.
 
 is.autoload=true
-javac.source=1.8
+javac.source=17
+javac.target=17
 javac.compilerargs=-Xlint -Xlint:-serial
 nbm.module.author=Laszlo Kishalmi
 javadoc.arch=${basedir}/arch.xml
diff --git a/java/gradle.java/nbproject/project.xml 
b/java/gradle.java/nbproject/project.xml
index 80c664174f..2bc5d4e31c 100644
--- a/java/gradle.java/nbproject/project.xml
+++ b/java/gradle.java/nbproject/project.xml
@@ -389,6 +389,7 @@
                 <package>org.netbeans.modules.gradle.java.api</package>
                 <package>org.netbeans.modules.gradle.java.api.output</package>
                 <package>org.netbeans.modules.gradle.java.spi.debug</package>
+                <package>org.netbeans.modules.gradle.java.spi.support</package>
             </public-packages>
         </data>
     </configuration>
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
index 652b2eca17..e8e2c456fd 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaProjectBuilder.java
@@ -30,6 +30,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
 import org.openide.filesystems.FileUtil;
 import org.openide.util.lookup.ServiceProvider;
 import static 
org.netbeans.modules.gradle.java.api.GradleJavaSourceSet.SourceType;
@@ -47,7 +48,7 @@ final class GradleJavaProjectBuilder implements 
ProjectInfoExtractor.Result {
     final GradleJavaProject prj = new GradleJavaProject();
 
     GradleJavaProjectBuilder(Map<String, Object> info) {
-        this.info = info;
+        this.info = new TreeMap<>(info);
     }
 
     GradleJavaProjectBuilder build() {
@@ -85,6 +86,7 @@ final class GradleJavaProjectBuilder implements 
ProjectInfoExtractor.Result {
 
                 Map<SourceType, String> sourceComp = new 
EnumMap<>(SourceType.class);
                 Map<SourceType, String> targetComp = new 
EnumMap<>(SourceType.class);
+                Map<SourceType, File> javaHomes = new 
EnumMap<>(SourceType.class);
                 Map<SourceType, List<String>> compilerArgs = new 
EnumMap<>(SourceType.class);
                 for (SourceType lang : Arrays.asList(JAVA, GROOVY, SCALA, 
KOTLIN)) {
                     String sc = (String) info.get("sourceset_" + name + "_" + 
lang.name() + "_source_compatibility");
@@ -95,6 +97,10 @@ final class GradleJavaProjectBuilder implements 
ProjectInfoExtractor.Result {
                     if (tc != null) {
                         targetComp.put(lang, tc);
                     }
+                    File javaHome = (File) info.get("sourceset_" + name + "_" 
+ lang.name() + "_compiler_java_home");
+                    if (javaHome != null) {
+                        javaHomes.put(lang, javaHome);
+                    }
                     List<String> compArgs = (List<String>) 
info.get("sourceset_" + name + "_" + lang.name() + "_compiler_args");
                     if (compArgs != null) {
                         compilerArgs.put(lang, 
Collections.unmodifiableList(compArgs));
@@ -107,6 +113,7 @@ final class GradleJavaProjectBuilder implements 
ProjectInfoExtractor.Result {
                 }
                 sourceSet.sourcesCompatibility = 
Collections.unmodifiableMap(sourceComp);
                 sourceSet.targetCompatibility = 
Collections.unmodifiableMap(targetComp);
+                sourceSet.compilerJavaHomes = 
Collections.unmodifiableMap(javaHomes);
                 sourceSet.compilerArgs = 
Collections.unmodifiableMap(compilerArgs);
                 
                 for (File out : sourceSet.getOutputClassDirs()) {
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
index 9ff163e9e1..c7eb458569 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/api/GradleJavaSourceSet.java
@@ -89,6 +89,7 @@ public final class GradleJavaSourceSet implements 
Serializable {
 
     Map<SourceType, String> sourcesCompatibility = Collections.emptyMap();
     Map<SourceType, String> targetCompatibility = Collections.emptyMap();
+    Map<SourceType, File> compilerJavaHomes = Collections.emptyMap();
     Map<SourceType, List<String>> compilerArgs = Collections.emptyMap();
     boolean testSourceSet;
     Set<File> outputClassDirs;
@@ -600,6 +601,22 @@ public final class GradleJavaSourceSet implements 
Serializable {
         return null;
     }
 
+    /**
+     * Returns the JDK Home directory of the JVM what would be used during the
+     * compilation. Currently the {@linkplain SourceType#JAVA JAVA}, 
{@linkplain SourceType#GROOVY GROOVY}, and {@linkplain SourceType#SCALA SCALA}
+     * are expected to return a non {@code null} value. The home directory
+     * is determined by using the sourceSet default compile task. In Gradle 
+     * it is possible to define additional compile tasks with different Java 
Toolchain.
+     * NetBeans would ignore those.
+     * 
+     * @param type The source type of the compiler.
+     * @return The home directory of the JDK used for the default compile task.
+     * @since 1.26
+     */
+    public File getCompilerJavaHome(SourceType type) {
+        return compilerJavaHomes.get(type);
+    }
+    
     /**
      * Returns the compiler arguments for this source set defined for the given
      * language.
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/AbstractGradleClassPathImpl.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/AbstractGradleClassPathImpl.java
index 303f5c6a43..512fbca6cb 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/AbstractGradleClassPathImpl.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/AbstractGradleClassPathImpl.java
@@ -25,12 +25,12 @@ import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.io.File;
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 import org.netbeans.api.annotations.common.NonNull;
 import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.project.Project;
@@ -105,10 +105,7 @@ abstract class AbstractGradleClassPathImpl implements 
FlaggedClassPathImplementa
     @Override
     public final synchronized List<? extends PathResourceImplementation> 
getResources() {
         if (resources == null) {
-            resources = new ArrayList<>();
-            for (URL url : createPath()) {
-                resources.add(ClassPathSupport.createResource(url));
-            }
+            resources = 
createPath().stream().map(ClassPathSupport::createResource).toList();
         }
         return resources;
     }
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/BootClassPathImpl.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/BootClassPathImpl.java
index c1480d211a..9949664b03 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/BootClassPathImpl.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/BootClassPathImpl.java
@@ -19,57 +19,44 @@
 
 package org.netbeans.modules.gradle.java.classpath;
 
-import org.netbeans.modules.gradle.api.NbGradleProject;
-import org.netbeans.modules.gradle.api.execute.RunUtils;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
+import org.netbeans.modules.gradle.java.spi.support.JavaToolchainSupport;
+import java.io.File;
 import java.net.URL;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.prefs.PreferenceChangeEvent;
-import java.util.prefs.PreferenceChangeListener;
 import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.java.platform.JavaPlatform;
-import org.netbeans.api.java.platform.JavaPlatformManager;
 import org.netbeans.api.project.Project;
+import org.netbeans.modules.gradle.java.api.GradleJavaSourceSet;
+import static 
org.netbeans.modules.gradle.java.api.GradleJavaSourceSet.SourceType.JAVA;
 import org.netbeans.modules.gradle.java.execute.JavaRunUtils;
-import org.openide.util.WeakListeners;
 
 /**
  *
  * @author Laszlo Kishalmi
  */
-public final class BootClassPathImpl extends AbstractGradleClassPathImpl 
implements PropertyChangeListener {
+public final class BootClassPathImpl extends AbstractSourceSetClassPathImpl {
     private static final String PROTOCOL_NBJRT = "nbjrt";   //NOI18N
 
-    JavaPlatformManager platformManager;
     final boolean modulesOnly;
 
-    public BootClassPathImpl(Project proj) {
-        this(proj, false);
+    public BootClassPathImpl(Project proj, String group) {
+        this(proj, group, false);
     }
 
     @SuppressWarnings("LeakingThisInConstructor")
-    public BootClassPathImpl(Project proj, boolean modulesOnly) {
-        super(proj);
+    public BootClassPathImpl(Project proj, String group, boolean modulesOnly) {
+        super(proj, group);
         this.modulesOnly = modulesOnly;
-        platformManager = JavaPlatformManager.getDefault();
-        
platformManager.addPropertyChangeListener(WeakListeners.propertyChange(this, 
platformManager));
-        NbGradleProject.getPreferences(project, 
false).addPreferenceChangeListener((PreferenceChangeEvent evt) -> {
-            if (RunUtils.PROP_JDK_PLATFORM.equals(evt.getKey())) {
-                clearResourceCache();
-            }
-        });
-    }
-
-    @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        clearResourceCache();
     }
 
     @Override
     protected List<URL> createPath() {
-        JavaPlatform platform = 
JavaRunUtils.getActivePlatform(project).second();
+        JavaToolchainSupport toolchain = JavaToolchainSupport.getDefault();
+        GradleJavaSourceSet ss = getSourceSet();
+        File jh = ss != null ? ss.getCompilerJavaHome(JAVA) : null;
+        
+        JavaPlatform platform = jh != null ? toolchain.platformByHome(jh) : 
JavaRunUtils.getActivePlatform(project).second();
         List<URL> ret = new LinkedList<>();
         if (platform != null) {
             for (ClassPath.Entry entry : 
platform.getBootstrapLibraries().entries()) {
@@ -81,6 +68,4 @@ public final class BootClassPathImpl extends 
AbstractGradleClassPathImpl impleme
         }
         return ret;
     }
-
-
 }
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/ClassPathProviderImpl.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/ClassPathProviderImpl.java
index d09039ff2e..8bd0f3c9eb 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/ClassPathProviderImpl.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/ClassPathProviderImpl.java
@@ -311,7 +311,7 @@ public final class ClassPathProviderImpl extends 
ProjectOpenedHook implements Cl
 
         private synchronized ClassPath getBootClassPath() {
             if (boot == null) {
-                boot = ClassPathFactory.createClassPath(new 
BootClassPathImpl(project, false));
+                boot = ClassPathFactory.createClassPath(new 
BootClassPathImpl(project, group, false));
             }
             return boot;
         }
@@ -339,7 +339,7 @@ public final class ClassPathProviderImpl extends 
ProjectOpenedHook implements Cl
 
         private synchronized ClassPath getPlatformModulesPath() {
             if (platformModules == null) {
-                platformModules = ClassPathFactory.createClassPath(new 
BootClassPathImpl(project, true));
+                platformModules = ClassPathFactory.createClassPath(new 
BootClassPathImpl(project, group, true));
             }
             return platformModules;
         }
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/GlobalClassPathProviderImpl.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/GlobalClassPathProviderImpl.java
index 99305397d0..63a4862f52 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/GlobalClassPathProviderImpl.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/classpath/GlobalClassPathProviderImpl.java
@@ -66,20 +66,13 @@ public class GlobalClassPathProviderImpl extends 
ProjectOpenedHook implements Pr
         if (index < 0) return null;
         ClassPath cp = cache[index];
         if (cp == null) {
-            switch (type) {
-                case ClassPath.BOOT:
-                    cp = createClassPath(new BootClassPathImpl(project));
-                    break;
-                case ClassPath.SOURCE:
-                    cp = createClassPath(new 
GradleGlobalClassPathImpl.ProjectSourceClassPathImpl(project, excludeTests));
-                    break;
-                case ClassPath.COMPILE:
-                    cp = createClassPath(new 
GradleGlobalClassPathImpl.ProjectCompileClassPathImpl(project, excludeTests));
-                    break;
-                case ClassPath.EXECUTE:
-                    cp = createClassPath(new 
GradleGlobalClassPathImpl.ProjectRuntimeClassPathImpl(project, excludeTests));
-                    break;
-            }
+            cp = switch (type) {
+                case ClassPath.BOOT -> createClassPath(new 
BootClassPathImpl(project, null));
+                case ClassPath.SOURCE -> createClassPath(new 
GradleGlobalClassPathImpl.ProjectSourceClassPathImpl(project, excludeTests));
+                case ClassPath.COMPILE -> createClassPath(new 
GradleGlobalClassPathImpl.ProjectCompileClassPathImpl(project, excludeTests));
+                case ClassPath.EXECUTE -> createClassPath(new 
GradleGlobalClassPathImpl.ProjectRuntimeClassPathImpl(project, excludeTests));
+                default -> null;
+            };
             cache[index] = cp;
         }
         return cp;
@@ -87,22 +80,13 @@ public class GlobalClassPathProviderImpl extends 
ProjectOpenedHook implements Pr
 
     private static int type2Index(String type, boolean excludeTests) {
         int index;
-        switch (type) {
-            case ClassPath.BOOT:
-                index = BOOT;
-                break;
-            case ClassPath.SOURCE:
-                index = SOURCE;
-                break;
-            case ClassPath.COMPILE:
-                index = COMPILE;
-                break;
-            case ClassPath.EXECUTE:
-                index = RUNTIME;
-                break;
-            default:
-                index = -1;
-        }
+        index = switch (type) {
+            case ClassPath.BOOT -> BOOT;
+            case ClassPath.SOURCE -> SOURCE;
+            case ClassPath.COMPILE -> COMPILE;
+            case ClassPath.EXECUTE -> RUNTIME;
+            default -> -1;
+        };
 
         return (index >= 0) && excludeTests ? index + 1 : index;
     }
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/Bundle.properties
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/Bundle.properties
index 6797c79d18..9b12690db4 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/Bundle.properties
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/Bundle.properties
@@ -18,3 +18,4 @@
 SourceSetPanel.jLabel1.text=Output Classes:
 SourceSetPanel.jLabel2.text=Output Resources:
 SourceSetPanel.jLabel3.text=Source/Binary Format:
+SourceSetPanel.lbPlatform.text=Java Platform:
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.form
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.form
index 0afcb8097d..bec08b32fa 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.form
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.form
@@ -37,15 +37,10 @@
   <Layout>
     <DimensionLayout dim="0">
       <Group type="103" groupAlignment="0" attributes="0">
-          <Group type="102" alignment="0" attributes="0">
+          <Group type="102" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="0" attributes="0">
-                  <Component id="tpDetails" max="32767" attributes="0"/>
-                  <Group type="102" attributes="0">
-                      <Component id="jLabel3" min="-2" pref="169" max="-2" 
attributes="0"/>
-                      <EmptySpace max="-2" attributes="0"/>
-                      <Component id="tfSourceLevel" pref="402" max="32767" 
attributes="0"/>
-                  </Group>
+                  <Component id="tpDetails" pref="580" max="32767" 
attributes="0"/>
                   <Group type="102" alignment="0" attributes="0">
                       <Group type="103" groupAlignment="1" max="-2" 
attributes="0">
                           <Component id="jLabel1" max="32767" attributes="0"/>
@@ -57,6 +52,20 @@
                           <Component id="tfOutputClasses" max="32767" 
attributes="0"/>
                       </Group>
                   </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Group type="103" groupAlignment="0" max="-2" 
attributes="0">
+                          <Component id="jLabel3" pref="157" max="32767" 
attributes="0"/>
+                          <Component id="lbPlatform" max="32767" 
attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <Component id="tfSourceLevel" min="-2" pref="39" 
max="-2" attributes="0"/>
+                              <EmptySpace min="0" pref="0" max="32767" 
attributes="0"/>
+                          </Group>
+                          <Component id="jtPlatform" max="32767" 
attributes="0"/>
+                      </Group>
+                  </Group>
               </Group>
               <EmptySpace max="-2" attributes="0"/>
           </Group>
@@ -65,13 +74,18 @@
     <DimensionLayout dim="1">
       <Group type="103" groupAlignment="0" attributes="0">
           <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="lbPlatform" alignment="3" min="-2" max="-2" 
attributes="0"/>
+                  <Component id="jtPlatform" alignment="3" min="-2" max="-2" 
attributes="0"/>
+              </Group>
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="3" attributes="0">
                   <Component id="jLabel3" alignment="3" min="-2" max="-2" 
attributes="0"/>
                   <Component id="tfSourceLevel" alignment="3" min="-2" 
max="-2" attributes="0"/>
               </Group>
               <EmptySpace max="-2" attributes="0"/>
-              <Component id="tpDetails" pref="232" max="32767" attributes="0"/>
+              <Component id="tpDetails" pref="202" max="32767" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="0" attributes="0">
                   <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
@@ -257,5 +271,20 @@
         <Property name="editable" type="boolean" value="false"/>
       </Properties>
     </Component>
+    <Component class="javax.swing.JLabel" name="lbPlatform">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" 
editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="jtPlatform"/>
+        </Property>
+        <Property name="text" type="java.lang.String" 
editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString 
bundle="org/netbeans/modules/gradle/java/customizer/Bundle.properties" 
key="SourceSetPanel.lbPlatform.text" 
replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, 
&quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jtPlatform">
+      <Properties>
+        <Property name="editable" type="boolean" value="false"/>
+      </Properties>
+    </Component>
   </SubComponents>
 </Form>
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.java
index adbef5a63f..bc7d2fc54f 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/customizer/SourceSetPanel.java
@@ -36,6 +36,9 @@ import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.DefaultTreeCellRenderer;
 import javax.swing.tree.DefaultTreeModel;
 import javax.swing.tree.TreePath;
+import org.netbeans.api.java.platform.JavaPlatform;
+import org.netbeans.modules.gradle.java.spi.support.JavaToolchainSupport;
+import org.openide.filesystems.FileObject;
 import org.openide.util.ImageUtilities;
 import org.openide.util.NbBundle;
 import org.openide.util.NbBundle.Messages;
@@ -83,6 +86,19 @@ public class SourceSetPanel extends javax.swing.JPanel {
         this.sourceSet = sourceSet;
         relativeRoot = relativeTo.toPath();
         initComponents();
+        
+        File javaHome = 
sourceSet.getCompilerJavaHome(GradleJavaSourceSet.SourceType.JAVA);
+        JavaPlatform platform =JavaPlatform.getDefault();
+        if (javaHome != null) {
+            platform = 
JavaToolchainSupport.getDefault().platformByHome(javaHome);
+        }
+        jtPlatform.setText(platform.getDisplayName());
+        
+        if (platform.isValid()) {
+            FileObject home = platform.getInstallFolders().iterator().next();
+            jtPlatform.setToolTipText(home.getPath());
+        }
+        
         if 
(sourceSet.getSourcesCompatibility().equals(sourceSet.getTargetCompatibility()))
 {
             tfSourceLevel.setText(sourceSet.getSourcesCompatibility());
         } else {
@@ -178,6 +194,8 @@ public class SourceSetPanel extends javax.swing.JPanel {
         tfSourceLevel = new javax.swing.JTextField();
         tfOutputResources = new javax.swing.JTextField();
         tfOutputClasses = new javax.swing.JTextField();
+        lbPlatform = new javax.swing.JLabel();
+        jtPlatform = new javax.swing.JTextField();
 
         org.openide.awt.Mnemonics.setLocalizedText(jLabel1, 
org.openide.util.NbBundle.getMessage(SourceSetPanel.class, 
"SourceSetPanel.jLabel1.text")); // NOI18N
 
@@ -218,6 +236,11 @@ public class SourceSetPanel extends javax.swing.JPanel {
 
         tfOutputClasses.setEditable(false);
 
+        lbPlatform.setLabelFor(jtPlatform);
+        org.openide.awt.Mnemonics.setLocalizedText(lbPlatform, 
org.openide.util.NbBundle.getMessage(SourceSetPanel.class, 
"SourceSetPanel.lbPlatform.text")); // NOI18N
+
+        jtPlatform.setEditable(false);
+
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
         this.setLayout(layout);
         layout.setHorizontalGroup(
@@ -225,11 +248,7 @@ public class SourceSetPanel extends javax.swing.JPanel {
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
                 
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addComponent(tpDetails, 
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, 
Short.MAX_VALUE)
-                    .addGroup(layout.createSequentialGroup()
-                        .addComponent(jLabel3, 
javax.swing.GroupLayout.PREFERRED_SIZE, 169, 
javax.swing.GroupLayout.PREFERRED_SIZE)
-                        
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(tfSourceLevel, 
javax.swing.GroupLayout.DEFAULT_SIZE, 402, Short.MAX_VALUE))
+                    .addComponent(tpDetails, 
javax.swing.GroupLayout.DEFAULT_SIZE, 580, Short.MAX_VALUE)
                     .addGroup(layout.createSequentialGroup()
                         
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING,
 false)
                             .addComponent(jLabel1, 
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, 
Short.MAX_VALUE)
@@ -237,18 +256,32 @@ public class SourceSetPanel extends javax.swing.JPanel {
                         
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                         
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                             .addComponent(tfOutputResources)
-                            .addComponent(tfOutputClasses))))
+                            .addComponent(tfOutputClasses)))
+                    .addGroup(layout.createSequentialGroup()
+                        
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, 
false)
+                            .addComponent(jLabel3, 
javax.swing.GroupLayout.DEFAULT_SIZE, 157, Short.MAX_VALUE)
+                            .addComponent(lbPlatform, 
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, 
Short.MAX_VALUE))
+                        
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addGroup(layout.createSequentialGroup()
+                                .addComponent(tfSourceLevel, 
javax.swing.GroupLayout.PREFERRED_SIZE, 39, 
javax.swing.GroupLayout.PREFERRED_SIZE)
+                                .addGap(0, 0, Short.MAX_VALUE))
+                            .addComponent(jtPlatform))))
                 .addContainerGap())
         );
         layout.setVerticalGroup(
             
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, 
layout.createSequentialGroup()
                 .addContainerGap()
+                
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(lbPlatform)
+                    .addComponent(jtPlatform, 
javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, 
javax.swing.GroupLayout.PREFERRED_SIZE))
+                
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(jLabel3)
                     .addComponent(tfSourceLevel, 
javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, 
javax.swing.GroupLayout.PREFERRED_SIZE))
                 
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addComponent(tpDetails, javax.swing.GroupLayout.DEFAULT_SIZE, 
232, Short.MAX_VALUE)
+                .addComponent(tpDetails, javax.swing.GroupLayout.DEFAULT_SIZE, 
202, Short.MAX_VALUE)
                 
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addComponent(jLabel1)
@@ -318,6 +351,8 @@ public class SourceSetPanel extends javax.swing.JPanel {
     private javax.swing.JScrollPane jScrollPane3;
     private javax.swing.JScrollPane jScrollPane4;
     private javax.swing.JScrollPane jScrollPane6;
+    private javax.swing.JTextField jtPlatform;
+    private javax.swing.JLabel lbPlatform;
     private javax.swing.JList<File> lsAnnotationProcessors;
     private javax.swing.JList<File> lsCompile;
     private javax.swing.JList<File> lsRuntime;
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/nodes/BootCPNodeFactory.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/nodes/BootCPNodeFactory.java
index ecb76dcbee..a4155d2fab 100644
--- 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/nodes/BootCPNodeFactory.java
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/nodes/BootCPNodeFactory.java
@@ -19,39 +19,33 @@
 package org.netbeans.modules.gradle.java.nodes;
 
 import org.netbeans.modules.gradle.api.NbGradleProject;
-import org.netbeans.modules.gradle.api.execute.RunUtils;
-import org.netbeans.modules.gradle.java.api.ProjectSourcesClassPathProvider;
 import static 
org.netbeans.modules.gradle.java.nodes.Bundle.BootCPNode_displayName;
 import org.netbeans.modules.gradle.spi.nodes.AbstractGradleNodeList;
 import org.netbeans.modules.gradle.spi.nodes.NodeUtils;
 import java.awt.Image;
 import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.CharConversionException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.prefs.PreferenceChangeEvent;
-import java.util.prefs.PreferenceChangeListener;
-import java.util.prefs.Preferences;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
 import javax.swing.Action;
 import javax.swing.Icon;
-import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
-import org.netbeans.api.annotations.common.CheckForNull;
-import org.netbeans.api.annotations.common.NonNull;
 import org.netbeans.api.annotations.common.StaticResource;
-import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.java.platform.JavaPlatform;
-import org.netbeans.api.java.platform.JavaPlatformManager;
 import org.netbeans.api.java.project.JavaProjectConstants;
 import org.netbeans.api.project.Project;
 import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.api.project.SourceGroup;
 import org.netbeans.api.project.Sources;
+import org.netbeans.modules.gradle.java.api.GradleJavaProject;
+import org.netbeans.modules.gradle.java.api.GradleJavaSourceSet;
+import org.netbeans.modules.gradle.java.api.GradleJavaSourceSet.SourceType;
 import org.netbeans.modules.gradle.java.execute.JavaRunUtils;
+import org.netbeans.modules.gradle.java.spi.support.JavaToolchainSupport;
 import org.netbeans.spi.project.ui.PathFinder;
 import org.netbeans.spi.java.project.support.ui.PackageView;
 import org.netbeans.spi.project.ui.support.NodeFactory;
@@ -63,17 +57,12 @@ import org.openide.nodes.ChildFactory;
 import org.openide.nodes.Children;
 import org.openide.nodes.FilterNode;
 import org.openide.nodes.Node;
-import org.openide.util.ChangeSupport;
 import org.openide.util.ImageUtilities;
 import org.openide.util.Lookup;
 import org.openide.util.NbBundle;
 import org.openide.util.NbBundle.Messages;
-import org.openide.util.Pair;
-import org.openide.util.RequestProcessor;
-import org.openide.util.WeakListeners;
 import org.openide.util.lookup.Lookups;
 import org.openide.util.lookup.ProxyLookup;
-import org.openide.xml.XMLUtil;
 
 @NodeFactory.Registration(projectType = NbGradleProject.GRADLE_PROJECT_TYPE, 
position = 520)
 public class BootCPNodeFactory implements NodeFactory {
@@ -101,7 +90,7 @@ public class BootCPNodeFactory implements NodeFactory {
 
             @Override
             public Node node(Void key) {
-                return new BootCPNode(new PlatformProvider(p, null));
+                return new BootCPNode(p);
             }
 
             @Override
@@ -123,8 +112,8 @@ public class BootCPNodeFactory implements NodeFactory {
 
         @Messages("BootCPNode_displayName=Java Dependencies")
         @SuppressWarnings("OverridableMethodCallInConstructor")
-        BootCPNode(PlatformProvider pp) {
-            super(Children.create(new BootCPChildren(pp), false), 
Lookups.singleton(PathFinders.createPathFinder()));
+        BootCPNode(Project p) {
+            super(Children.create(new BootCPChildren(p), false), 
Lookups.singleton(PathFinders.createPathFinder()));
             setName("BootCPNode");
             setDisplayName(BootCPNode_displayName());
         }
@@ -142,130 +131,83 @@ public class BootCPNodeFactory implements NodeFactory {
     }
 
     // XXX PlatformNode and ActionFilterNode does some of what we want, but 
cannot be reused
-    private static class BootCPChildren extends 
ChildFactory.Detachable<FileObject> implements ChangeListener, 
PropertyChangeListener {
+    private record PlatformSourceSet(JavaPlatform platform, 
Set<GradleJavaSourceSet> sourceSets) {}
+    private static class BootCPChildren extends 
ChildFactory.Detachable<PlatformSourceSet> {
 
-        private final PlatformProvider pp;
-        private ClassPath[] endorsed;
-        private static final FileObject BOOT = 
FileUtil.createMemoryFileSystem().getRoot();
+        private final Project project;
 
-        BootCPChildren(PlatformProvider pp) {
-            this.pp = pp;
+        BootCPChildren(Project project) {
+            this.project = project;
         }
 
         @Override
         protected void addNotify() {
-            pp.addChangeListener(this);
-            ProjectSourcesClassPathProvider pvd = 
pp.project.getLookup().lookup(ProjectSourcesClassPathProvider.class);
-            endorsed = pvd != null ? pvd.getProjectClassPath(ENDORSED) : new 
ClassPath[0];
-            for (ClassPath cp : endorsed) {
-                cp.addPropertyChangeListener(this);
-            }
+            NbGradleProject.addPropertyChangeListener(project, 
this::projectChange);
         }
 
         @Override
         protected void removeNotify() {
-            pp.removeChangeListener(this);
-            for (ClassPath cp : endorsed) {
-                cp.removePropertyChangeListener(this);
-            }
-            endorsed = null;
+            NbGradleProject.removePropertyChangeListener(project, 
this::projectChange);
         }
 
         @Override
-        protected boolean createKeys(List<FileObject> roots) {
-            roots.add(BOOT);
-            for (ClassPath cp : endorsed) {
-                roots.addAll(Arrays.asList(cp.getRoots()));
+        protected boolean createKeys(List<PlatformSourceSet> keys) {
+            var toolchains = JavaToolchainSupport.getDefault();
+            var pss = new HashMap<JavaPlatform, Set<GradleJavaSourceSet>>();
+            var ss = GradleJavaProject.get(project).getSourceSets().values();
+            for (GradleJavaSourceSet s : ss) {
+                var home = s.getCompilerJavaHome(SourceType.JAVA);
+                var platform = home != null ? toolchains.platformByHome(home) 
: JavaRunUtils.getActivePlatform(project).second();
+                var groups = pss.computeIfAbsent(platform, (k) -> new 
TreeSet<GradleJavaSourceSet>((s1, s2) -> s1.getName().compareTo(s2.getName())));
+                groups.add(s);
             }
+            pss.forEach((platform, groups) -> keys.add(new 
PlatformSourceSet(platform, groups)));
             return true;
         }
 
         @Override
-        protected Node createNodeForKey(FileObject root) {
-            return  root == BOOT ? new JRENode(pp) : jarNode(new 
LibrariesSourceGroup(root, root.getNameExt()));
+        protected Node createNodeForKey(PlatformSourceSet platform) {
+            return  new JRENode(platform);
         }
 
-        @Override
-        public void propertyChange(PropertyChangeEvent evt) {
-            if (evt.getPropertyName().equals(ClassPath.PROP_ROOTS)) {
+        private void projectChange(PropertyChangeEvent evt) {
+            if 
(NbGradleProject.PROP_PROJECT_INFO.equals(evt.getPropertyName())) {
                 refresh(false);
             }
         }
 
-        @Override
-        public void stateChanged(ChangeEvent e) {
-            refresh(false);
-        }
-
     }
 
     @NbBundle.Messages({
         "# {0} - Platform Display name",
         "FMT_BrokenPlatform=Broken platform ''{0}''",
-        "TXT_BrokenPlatform=Broken platform",
-        "TXT_UnknownPlatform=Loading..."
     })
-    private static class JRENode extends AbstractNode implements 
ChangeListener {
+    private static class JRENode extends AbstractNode {
 
-        private final PlatformProvider pp;
+        private final PlatformSourceSet pss;
 
         @SuppressWarnings("OverridableMethodCallInConstructor")
-        private JRENode(PlatformProvider pp) {
+        private JRENode(PlatformSourceSet pss) {
             super(new CPChildren(), 
Lookups.singleton(PathFinders.createPathFinder()));
-            this.pp = pp;
-            pp.addChangeListener(this);
+            this.pss = pss;
             setIconBaseWithExtension(PLATFORM_ICON);
         }
 
         @Override
         public String getName() {
-            return this.getDisplayName();
+            return pss.platform().getDisplayName();
         }
 
         @Override
         public String getDisplayName() {
-            final Pair<String, JavaPlatform> platHolder = pp.getPlatform();
-            if (platHolder == null) {
-                return Bundle.TXT_UnknownPlatform();
-            }
-            String name;
-            final JavaPlatform jp = platHolder.second();
-            if (jp != null) {
-                if (jp.isValid()) {
-                    name = jp.getDisplayName();
-                } else {
-                    name = Bundle.FMT_BrokenPlatform(jp.getDisplayName());
-                }
-            } else {
-                String platformId = platHolder.first();
-                if (platformId == null) {
-                    name = Bundle.TXT_BrokenPlatform();
-                } else {
-                    name = Bundle.FMT_BrokenPlatform(platformId);
-                }
-            }
-            return name;
+            String name = pss.platform.isValid() ? 
pss.platform.getDisplayName(): 
Bundle.FMT_BrokenPlatform(pss.platform.getDisplayName());
+            String groups = 
pss.sourceSets.stream().map(GradleJavaSourceSet::getName).collect(Collectors.joining(",
 ", "[", "]"));
+            return name + " " + groups;
         }
 
         @Override
         public String getHtmlDisplayName() {
-            final Pair<String, JavaPlatform> platHolder = pp.getPlatform();
-            if (platHolder == null) {
-                return null;
-            }
-            final JavaPlatform jp = platHolder.second();
-            if (jp == null || !jp.isValid()) {
-                String displayName = this.getDisplayName();
-                try {
-                    displayName = XMLUtil.toElementContent(displayName);
-                } catch (CharConversionException ex) {
-                    // OK, no annotation in this case
-                    return null;
-                }
-                return "<font color=\"#A40000\">" + displayName + "</font>"; 
//NOI18N
-            } else {
-                return null;
-            }
+            return null;
         }
 
         @Override
@@ -274,24 +216,21 @@ public class BootCPNodeFactory implements NodeFactory {
         }
         
         @Override
+        @Messages({
+                "# {0} - The path of the Java Platform home",
+                "# {1} - The list of the sourcesets wher the platform is used",
+                "TOOLTIP_Platform=<html>Home: {0}<br/>Used in: {1}"
+        })
         public String getShortDescription() {
-            final Pair<String,JavaPlatform> platHolder = pp.getPlatform();
-            if (platHolder != null && platHolder.second() != null && 
!platHolder.second().getInstallFolders().isEmpty()) {
-                final FileObject installFolder = 
platHolder.second().getInstallFolders().iterator().next();
-                return FileUtil.getFileDisplayName(installFolder);
+            if (pss.platform.isValid()) {
+                FileObject installFolder = 
pss.platform.getInstallFolders().iterator().next();
+                String groups = 
pss.sourceSets.stream().map(GradleJavaSourceSet::getName).collect(Collectors.joining(",
 "));
+
+                return 
Bundle.TOOLTIP_Platform(FileUtil.getFileDisplayName(installFolder), groups);
             } else {
                 return super.getShortDescription();
             }
         }
-
-        @Override
-        public void stateChanged(ChangeEvent e) {
-            this.fireNameChange(null,null);
-            this.fireDisplayNameChange(null,null);
-            ((CPChildren) getChildren()).addNotify();
-        }
-
-
     }
 
     private static class CPChildren extends Children.Keys<SourceGroup> {
@@ -315,31 +254,19 @@ public class BootCPNodeFactory implements NodeFactory {
         }
 
         private List<SourceGroup> getKeys () {
-            final FileObject[] roots = 
((JRENode)this.getNode()).pp.getBootstrapLibraries();
-            if (roots.length == 0) {
-                return Collections.<SourceGroup>emptyList();
-            }
+            final FileObject[] roots = 
((JRENode)this.getNode()).pss.platform.getBootstrapLibraries().getRoots();
             final List<SourceGroup> result = new ArrayList<>(roots.length);
             for (FileObject root : roots) {
-                    FileObject file;
-                    Icon icon;
-                    Icon openedIcon;
-                    switch (root.toURL().getProtocol()) {
-                        case "jar":
-                            file = FileUtil.getArchiveFile (root);
-                            icon = openedIcon = 
ImageUtilities.loadImageIcon(ARCHIVE_ICON, false);
-                            break;
-                        case "nbjrt":
-                            file = root;
-                            icon = openedIcon = 
ImageUtilities.loadImageIcon(MODULE_ICON, false);
-                            break;
-                        default:
-                            file = root;
-                            icon = openedIcon = null;
-                    }
-                    if (file.isValid()) {
-                        result.add (new 
LibrariesSourceGroup(root,file.getNameExt(),icon, openedIcon));
-                    }
+                var protocol = root.toURL().getProtocol();
+                FileObject file = "jar".equals(protocol) ? 
FileUtil.getArchiveRoot(root) : root;
+                if (file.isValid()) {
+                    Icon icon = switch (protocol) {
+                        case "jar" -> 
ImageUtilities.loadImageIcon(ARCHIVE_ICON, false);
+                        case "nbjrt" -> 
ImageUtilities.loadImageIcon(MODULE_ICON, false);
+                        default -> null;
+                    };
+                    result.add (new 
LibrariesSourceGroup(root,file.getNameExt(), icon, icon));
+                }
             }
             return result;
         }
@@ -363,87 +290,4 @@ public class BootCPNodeFactory implements NodeFactory {
         };
 
     }
-    
-    private static final class PlatformProvider implements 
PropertyChangeListener, PreferenceChangeListener {
-
-        private static final Pair<String,JavaPlatform> BUSY = 
Pair.<String,JavaPlatform>of(null,null);
-        private static final RequestProcessor RP = new 
RequestProcessor(PlatformProvider.class);
-
-        private final Project project;
-        private final ClassPath boot;
-        private final AtomicReference<Pair<String,JavaPlatform>> platformCache 
= new AtomicReference<Pair<String,JavaPlatform>>();
-        private final ChangeSupport changeSupport = new ChangeSupport(this);
-        
-        public PlatformProvider (
-                @NonNull final Project project,
-                @NonNull final ClassPath boot) {
-            this.project = project;
-            this.boot = boot;
-            final JavaPlatformManager jps = JavaPlatformManager.getDefault();
-            jps.addPropertyChangeListener(WeakListeners.propertyChange(this, 
jps));
-            Preferences prefs = NbGradleProject.getPreferences(project, false);
-            prefs.addPreferenceChangeListener(
-                    WeakListeners.create(PreferenceChangeListener.class, this, 
prefs));
-            NbGradleProject.addPropertyChangeListener(project, 
WeakListeners.propertyChange(this, NbGradleProject.get(project)));
-            
-            if (this.boot != null) {
-                
this.boot.addPropertyChangeListener(WeakListeners.propertyChange(this, 
this.boot));
-            }
-        }
-                
-        @CheckForNull
-        public Pair<String,JavaPlatform> getPlatform () {
-            if (platformCache.compareAndSet(null, BUSY)) {
-                RP.execute(() -> {
-                    platformCache.set(JavaRunUtils.getActivePlatform(project));
-                    changeSupport.fireChange ();
-                });
-            }
-            Pair<String,JavaPlatform> res = platformCache.get();
-            return res == BUSY ? null : res;
-        }
-
-        @NonNull
-        public FileObject[] getBootstrapLibraries() {
-            final Pair<String, JavaPlatform> jp = getPlatform();
-            if (jp == null || jp.second() == null) {
-                return new FileObject[0];
-            }
-            ClassPath cp = boot;
-            if (cp == null) {
-                cp = jp.second().getBootstrapLibraries();
-            }
-            return cp.getRoots();
-        }
-        
-        public void addChangeListener (ChangeListener l) {
-            changeSupport.addChangeListener(l);
-        }
-        
-        public void removeChangeListener (ChangeListener l) {
-            changeSupport.removeChangeListener(l);
-        }
-        
-        @Override
-        public void propertyChange(PropertyChangeEvent evt) {
-            final String propName = evt.getPropertyName();
-            if (NbGradleProject.PROP_PROJECT_INFO.equals(propName) ||
-                ClassPath.PROP_ROOTS.equals(propName) ||
-                JavaPlatformManager.PROP_INSTALLED_PLATFORMS.equals(propName)) 
{
-                platformCache.set(null);
-                getPlatform();
-            }
-        }
-
-        @Override
-        public void preferenceChange(PreferenceChangeEvent evt) {
-            String prefName = evt.getKey();
-            if (RunUtils.PROP_JDK_PLATFORM.equals(prefName)) {
-                platformCache.set(null);
-                getPlatform();
-            }
-        }
-        
-    }
-
 }
diff --git 
a/java/gradle.java/src/org/netbeans/modules/gradle/java/spi/support/JavaToolchainSupport.java
 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/spi/support/JavaToolchainSupport.java
new file mode 100644
index 0000000000..eb57f6ef69
--- /dev/null
+++ 
b/java/gradle.java/src/org/netbeans/modules/gradle/java/spi/support/JavaToolchainSupport.java
@@ -0,0 +1,122 @@
+/*
+ * 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.gradle.java.spi.support;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.netbeans.api.java.platform.JavaPlatform;
+import org.netbeans.api.java.platform.JavaPlatformManager;
+import org.netbeans.modules.gradle.spi.Utils;
+import org.netbeans.modules.java.api.common.util.CommonProjectUtils;
+import org.netbeans.spi.java.platform.JavaPlatformFactory;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+
+/**
+ * Support for creating retrieving JavaPlatforms from their install location 
+ * (home directory).
+ * 
+ * @since 1.26
+ * @author Laszlo Kishalmi
+ */
+public final class JavaToolchainSupport {
+
+    private final Map<File, JavaPlatform> platformCache;
+
+    private static JavaToolchainSupport instance;
+    
+    private JavaToolchainSupport() {
+        platformCache = new HashMap<>();
+    }
+    
+    public static JavaToolchainSupport getDefault() {
+        if (instance == null) {
+            instance = new JavaToolchainSupport();
+        }
+        return instance;
+    }
+    
+    /**
+     * Tries to locate a registered {@linkplain JavaPlatform} from its install
+     * location. If it is not registered among the NetBeans usual Java 
Platforms
+     * then a new non-registered one will be created.
+     * 
+     * @param home The home directory of a Java installation
+     * @return the {@linkplain JavaPlatform} representing the given directory.
+     */
+    public JavaPlatform platformByHome(File home) {
+        return platformCache.computeIfAbsent(home, this::detectPlatform);
+    }
+    
+    private JavaPlatform detectPlatform(File home) {
+        FileObject h = FileUtil.toFileObject(home);
+        for (JavaPlatform platform : 
JavaPlatformManager.getDefault().getInstalledPlatforms()) {
+            if (platform.isValid()) {
+                FileObject ph = platform.getInstallFolders().iterator().next();
+                if (ph.equals(h)) {
+                    return platform;
+                }
+            }
+        }
+        for (JavaPlatformFactory.Provider pvd : 
Lookup.getDefault().lookupAll(JavaPlatformFactory.Provider.class)) {
+            JavaPlatformFactory factory = 
pvd.forType(CommonProjectUtils.J2SE_PLATFORM_TYPE);
+            if (factory != null) {
+                try {
+                    JavaPlatform ret = factory.create(h, toolchainName(home), 
false);
+                    return ret;
+                } catch (IOException ex) {
+                    
+                }
+            }
+        }
+        return null;
+    }
+    
+    private static final Pattern GRADLE_JDK_DIST = 
Pattern.compile("(\\w+)-(\\d+)-(\\w+)-(\\w+)");
+    @NbBundle.Messages({
+        "# {0} - JDK Vendor",
+        "# {1} - Java Feature Version",
+        "# {2} - JDK Architecture",
+        "# {3} - JDK OS",
+        "GRADLE_INSTALLED_JDK_NAME=Java {1} {0} (from Java Toolchain)",
+        "# {0} - JDK Install folder name",
+        "# {1} - JDK Install folder path",
+        "OTHER_JDK_NAME=JDK {0} from {1}"
+    })
+    private static String toolchainName(File home) {
+        File distDir = home.getParentFile();
+        if (distDir != null) {
+            Matcher m = GRADLE_JDK_DIST.matcher(distDir.getName());
+            if (m.matches()) {
+                String vendor = Utils.capitalize(m.group(1).replace('_', ' '));
+                String version = m.group(2);
+                String arch = m.group(3);
+                String os = m.group(4);
+                return Bundle.GRADLE_INSTALLED_JDK_NAME(vendor, version, arch, 
os);
+            }
+        }
+        return Bundle.OTHER_JDK_NAME(home.getName(), home.getAbsolutePath());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to