diff --git a/apisupport/apisupport.ant/nbproject/project.properties b/apisupport/apisupport.ant/nbproject/project.properties index 1940d0662e01..03ab15a6f449 100644 --- a/apisupport/apisupport.ant/nbproject/project.properties +++ b/apisupport/apisupport.ant/nbproject/project.properties @@ -22,6 +22,7 @@ antsrc.cp=\ requires.nb.javac=true javac.compilerargs=-Xlint -Xlint:-serial javac.source=1.8 +javac.release=17 javadoc.arch=${basedir}/arch.xml test-unit-sys-prop.test.nbroot=${nb_all} diff --git a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/Evaluator.java b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/Evaluator.java index cf46e134d353..38f226109594 100644 --- a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/Evaluator.java +++ b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/Evaluator.java @@ -70,6 +70,7 @@ import org.openide.filesystems.FileUtil; import org.openide.modules.SpecificationVersion; import org.openide.util.ChangeSupport; +import org.openide.util.Exceptions; import org.openide.util.Mutex; import org.openide.util.RequestProcessor; import org.openide.util.Utilities; @@ -421,32 +422,43 @@ private PropertyEvaluator createEvaluator(ModuleList ml) { if (ml != null) { providers.add(PropertyUtils.fixedPropertyProvider(Collections.singletonMap("module.classpath", computeModuleClasspath(ml)))); // NOI18N providers.add(PropertyUtils.fixedPropertyProvider(Collections.singletonMap("module.run.classpath", computeRuntimeModuleClasspath(ml)))); // NOI18N + + baseEval = PropertyUtils.sequentialPropertyEvaluator(predefs, providers.toArray(new PropertyProvider[0])); + Map buildDefaults = new HashMap(); buildDefaults.put("cp.extra", ""); // NOI18N buildDefaults.put(CP, "${module.classpath}:${cp.extra}"); // NOI18N buildDefaults.put(RUN_CP, "${module.run.classpath}:${cp.extra}:${build.classes.dir}"); // NOI18N if (type == NbModuleType.NETBEANS_ORG && "true".equals(projectProperties.getProperties().get("requires.nb.javac"))) { - ModuleEntry javacLibrary = ml.getEntry(JAVACAPI_CNB); - if (javacLibrary != null) { - boolean implDependencyOnJavac = - projectDependencies().filter(dep -> JAVACAPI_CNB.equals(dependencyCNB(dep))) - .map(dep -> XMLUtil.findElement(dep, "run-dependency", NbModuleProject.NAMESPACE_SHARED)) // NOI18N - .filter(runDep -> runDep != null) - .anyMatch(runDep -> XMLUtil.findElement(runDep, "implementation-version", NbModuleProject.NAMESPACE_SHARED) != null); // NOI18N - String bootcpPrepend; - if (implDependencyOnJavac) { - bootcpPrepend = javacLibrary.getClassPathExtensions(); - } else { - bootcpPrepend = Stream.of(javacLibrary.getClassPathExtensions().split(Pattern.quote(File.pathSeparator))) - .filter(ext -> ext.endsWith("-api.jar")) - .collect(Collectors.joining(File.pathSeparator)); + String javacRelease = baseEval.getProperty(SingleModuleProperties.JAVAC_RELEASE); + if (javacRelease == null || javacRelease.isEmpty()) { + javacRelease = baseEval.getProperty(SingleModuleProperties.JAVAC_SOURCE); + } + if (javacRelease.equals("1.6") || + javacRelease.equals("1.7") || + javacRelease.equals("1.8")) { + ModuleEntry javacLibrary = ml.getEntry(JAVACAPI_CNB); + if (javacLibrary != null) { + boolean implDependencyOnJavac = + projectDependencies().filter(dep -> JAVACAPI_CNB.equals(dependencyCNB(dep))) + .map(dep -> XMLUtil.findElement(dep, "run-dependency", NbModuleProject.NAMESPACE_SHARED)) // NOI18N + .filter(runDep -> runDep != null) + .anyMatch(runDep -> XMLUtil.findElement(runDep, "implementation-version", NbModuleProject.NAMESPACE_SHARED) != null); // NOI18N + String bootcpPrepend; + if (implDependencyOnJavac) { + bootcpPrepend = javacLibrary.getClassPathExtensions(); + } else { + bootcpPrepend = Stream.of(javacLibrary.getClassPathExtensions().split(Pattern.quote(File.pathSeparator))) + .filter(ext -> ext.endsWith("-api.jar")) + .collect(Collectors.joining(File.pathSeparator)); + } + buildDefaults.put(ClassPathProviderImpl.BOOTCLASSPATH_PREPEND, bootcpPrepend); } - buildDefaults.put(ClassPathProviderImpl.BOOTCLASSPATH_PREPEND, bootcpPrepend); + } else { + buildDefaults.put(SingleModuleProperties.JAVAC_COMPILERARGS_INTERNAL_EXTRA, getLimitModules(javacRelease)); } } - baseEval = PropertyUtils.sequentialPropertyEvaluator(predefs, providers.toArray(new PropertyProvider[0])); - Map testsCPs = computeTestingClassPaths(ml, baseEval, testTypes); testTypes.addAll(testsCPs.keySet()); for (String testType : testTypes) { @@ -874,5 +886,31 @@ private String mergePaths(Set cnbs, boolean test,String testtype,File te } return cps.toString(); } - + + private static final Map limitModulesCache = new HashMap<>(); + private static String getLimitModules(String javacRelease) { + return limitModulesCache.computeIfAbsent(javacRelease, release -> { + try { + int javacReleaseValue = Integer.parseInt(release); + int javaSpecificationVersionValue = Integer.parseInt(System.getProperty("java.specification.version")); + if (javacReleaseValue > javaSpecificationVersionValue) { + release = System.getProperty("java.specification.version"); + } + } catch (NumberFormatException ex) { + //ignore + release = System.getProperty("java.specification.version"); + } + + try { + String limitModules = + SetupLimitModulesProbe.computeLimitModules(release, + "java.compiler", + "jdk.compiler"); + return "--limit-modules=" + limitModules; + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + return null; + } + }); + } } diff --git a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java index f30dc95ecbca..2814e92cea12 100644 --- a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java +++ b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/NbModuleProject.java @@ -62,6 +62,7 @@ import org.netbeans.modules.apisupport.project.queries.AntArtifactProviderImpl; import org.netbeans.modules.apisupport.project.queries.BinaryForSourceImpl; import org.netbeans.modules.apisupport.project.queries.ClassPathProviderImpl; +import org.netbeans.modules.apisupport.project.queries.CompilerOptionsQueryImpl; import org.netbeans.modules.apisupport.project.queries.FileEncodingQueryImpl; import org.netbeans.modules.apisupport.project.queries.JavadocForBinaryImpl; import org.netbeans.modules.apisupport.project.queries.ModuleProjectClassPathExtender; @@ -309,6 +310,7 @@ private Lookup createLookup(ProjectInformation info, AuxiliaryConfiguration aux, ic.add(new FileEncodingQueryImpl()); ic.add(new AnnotationProcessingQueryImpl(this)); ic.add(new PlatformJarProviderImpl()); + ic.add(new CompilerOptionsQueryImpl(this)); if (getModuleType() == NbModuleType.SUITE_COMPONENT) { ic.add(new SuiteProviderImpl()); diff --git a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/SetupLimitModulesProbe.java b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/SetupLimitModulesProbe.java new file mode 100644 index 000000000000..d501fdd41cc5 --- /dev/null +++ b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/SetupLimitModulesProbe.java @@ -0,0 +1,126 @@ +/* + * 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.apisupport.project; + +import com.sun.source.util.JavacTask; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.lang.model.element.ModuleElement; +import javax.lang.model.element.ModuleElement.RequiresDirective; +import javax.lang.model.util.ElementFilter; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +/** + * There's a copy of this class in nbbuild/antsrc/org/netbeans/nbbuild/extlibs/SetupLimitModulesProbe.java. + * Please make sure this are kept in sync. + */ +public class SetupLimitModulesProbe { + + public static void main(String[] args) throws IOException { + String release = args[0]; + + String[] excludedModules = + Arrays.stream(args) + .skip(1) + .toArray(s -> new String[s]); + + String limitModules = computeLimitModules(release, excludedModules); + + System.out.println(limitModules); + } + + public static String computeLimitModules(String release, String... excludedModulesIn) throws IOException { + Set excludedModules = new HashSet<>(List.of(excludedModulesIn)); + List options; + + if ("last".equals(release)) { + options = List.of("--add-modules", "ALL-SYSTEM", "-classpath", ""); + } else { + options = List.of("--release", release, "-classpath", ""); + } + + JavacTask task = (JavacTask) + ToolProvider.getSystemJavaCompiler() + .getTask(null, null, null, options, null, + List.of(new JFOImpl(URI.create("mem://Test.java"), ""))); + + task.analyze(); + + String limitModules = + task.getElements() + .getAllModuleElements() + .stream() + .filter(m -> !m.getQualifiedName().toString().startsWith("jdk.internal.")) + .filter(m -> !m.isUnnamed()) + .filter(m -> canInclude(m, excludedModules)) + .map(m -> m.getQualifiedName()) + .collect(Collectors.joining(",")); + + return limitModules; + } + + private static boolean canInclude(ModuleElement m, Set excludes) { + return Collections.disjoint(transitiveDependencies(m), excludes); + } + + private static Set transitiveDependencies(ModuleElement m) { + List todo = new LinkedList<>(); + Set seenModules = new HashSet<>(); + + todo.add(m); + + while (!todo.isEmpty()) { + ModuleElement current = todo.remove(0); + + if (seenModules.add(current)) { + for (RequiresDirective rd : ElementFilter.requiresIn(current.getDirectives())) { + todo.add(rd.getDependency()); + } + } + } + + return seenModules.stream() + .map(c -> c.getQualifiedName().toString()) + .collect(Collectors.toSet()); + } + + private static final class JFOImpl extends SimpleJavaFileObject { + + private final String content; + + public JFOImpl(URI uri, String content) { + super(uri, Kind.SOURCE); + this.content = content; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return content; + } + + } +} diff --git a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/queries/CompilerOptionsQueryImpl.java b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/queries/CompilerOptionsQueryImpl.java new file mode 100644 index 000000000000..5f229773c724 --- /dev/null +++ b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/queries/CompilerOptionsQueryImpl.java @@ -0,0 +1,115 @@ +/* + * 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.apisupport.project.queries; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Pattern; +import javax.swing.event.ChangeListener; +import org.netbeans.modules.apisupport.project.NbModuleProject; +import org.netbeans.modules.apisupport.project.ui.customizer.SingleModuleProperties; +import org.netbeans.spi.java.queries.CompilerOptionsQueryImplementation; +import org.netbeans.spi.project.support.ant.PropertyEvaluator; +import org.openide.filesystems.FileObject; +import org.openide.util.ChangeSupport; +import org.openide.util.WeakListeners; + +public class CompilerOptionsQueryImpl implements CompilerOptionsQueryImplementation { + + private final NbModuleProject project; + private final AtomicReference cachedResult = new AtomicReference<>(); + + public CompilerOptionsQueryImpl(NbModuleProject project) { + this.project = project; + } + + @Override + public Result getOptions(FileObject file) { + Result result = cachedResult.get(); + + if (result == null) { + result = cachedResult.updateAndGet(existing -> existing != null ? existing + : new ResultImpl(project)); + } + + return result; + } + + private static class ResultImpl extends Result implements PropertyChangeListener { + + private static final Pattern SPACE_SPLIT = Pattern.compile(" +"); + private final PropertyEvaluator evaluator; + private final ChangeSupport cs = new ChangeSupport(this); + private List cachedArguments; + + public ResultImpl(NbModuleProject project) { + this.evaluator = project.evaluator(); + this.evaluator.addPropertyChangeListener(WeakListeners.propertyChange(this, this.evaluator)); + } + + + @Override + public synchronized List getArguments() { + List result = cachedArguments; + + if (result == null) { + Map properties = evaluator.getProperties(); + String compilerArgs = properties.getOrDefault(SingleModuleProperties.JAVAC_COMPILERARGS, "") + + " " + + properties.getOrDefault(SingleModuleProperties.JAVAC_COMPILERARGS_INTERNAL_EXTRA, ""); + + compilerArgs = compilerArgs.trim(); + + if (compilerArgs.isEmpty()) { + result = Collections.emptyList(); + } else { + result = Collections.unmodifiableList(Arrays.asList(SPACE_SPLIT.split(compilerArgs))); + } + + cachedArguments = result; + } + + return result; + } + + @Override + public void addChangeListener(ChangeListener listener) { + cs.addChangeListener(listener); + } + + @Override + public void removeChangeListener(ChangeListener listener) { + cs.removeChangeListener(listener); + } + + @Override + public void propertyChange(PropertyChangeEvent pce) { + synchronized (this) { + cachedArguments = null; + } + cs.fireChange(); + } + } + +} diff --git a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/customizer/SingleModuleProperties.java b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/customizer/SingleModuleProperties.java index ed721ec071d0..ec709aab416b 100644 --- a/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/customizer/SingleModuleProperties.java +++ b/apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/customizer/SingleModuleProperties.java @@ -119,6 +119,7 @@ public final class SingleModuleProperties extends ModuleProperties { public static final String SPEC_VERSION_BASE = "spec.version.base"; // NOI18N /** @see "#66278" */ public static final String JAVAC_COMPILERARGS = "javac.compilerargs"; // NOI18N + public static final String JAVAC_COMPILERARGS_INTERNAL_EXTRA = "javac.internal.extra.compilerargs"; // NOI18N private static final Map DEFAULTS; private static final Logger LOG = Logger.getLogger(SingleModuleProperties.class.getName()); diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/SetupLimitModulesProbe.java b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/SetupLimitModulesProbe.java index 7b8117af2984..ddb585cd2147 100644 --- a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/SetupLimitModulesProbe.java +++ b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/SetupLimitModulesProbe.java @@ -35,24 +35,32 @@ import javax.tools.ToolProvider; /** - * + * There's a copy of this class in apisupport/apisupport.ant/src/org/netbeans/modules/apisupport/project/SetupLimitModulesProbe.java. + * Please make sure this are kept in sync. */ public class SetupLimitModulesProbe { public static void main(String[] args) throws IOException { String release = args[0]; - Set excludedModules = new HashSet<>(); - Arrays.stream(args) - .skip(1) - .forEach(excludedModules::add); + String[] excludedModules = + Arrays.stream(args) + .skip(1) + .toArray(s -> new String[s]); + + String limitModules = computeLimitModules(release, excludedModules); + + System.out.println(limitModules); + } + public static String computeLimitModules(String release, String... excludedModulesIn) throws IOException { + Set excludedModules = new HashSet<>(List.of(excludedModulesIn)); List options; if ("last".equals(release)) { - options = List.of("--add-modules", "ALL-SYSTEM"); + options = List.of("--add-modules", "ALL-SYSTEM", "-classpath", ""); } else { - options = List.of("--release", release); + options = List.of("--release", release, "-classpath", ""); } JavacTask task = (JavacTask) @@ -72,7 +80,7 @@ public static void main(String[] args) throws IOException { .map(m -> m.getQualifiedName()) .collect(Collectors.joining(",")); - System.out.println(limitModules); + return limitModules; } private static boolean canInclude(ModuleElement m, Set excludes) {