This is an automated email from the ASF dual-hosted git repository.
mbien 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 21510a82f5 Implement maven pom javac release option hint (JEP 247).
new d99b1939ee Merge pull request #4802 from mbien/maven-release-flag-hint
21510a82f5 is described below
commit 21510a82f5672b3247ffba0f96f8c34398571993
Author: Michael Bien <[email protected]>
AuthorDate: Mon Oct 17 12:31:35 2022 +0200
Implement maven pom javac release option hint (JEP 247).
- converts matching source/target options to the release option
- supports properties and the standard maven-compiler-plugin
- offers only hints when source/release is set to at least 9+
---
.../src/org/netbeans/modules/maven/hints/layer.xml | 3 +
.../maven/hints/pom/UseReleaseOptionHint.java | 242 +++++++++++++++++++++
.../maven/hints/pom/UseReleaseOptionHintTest.java | 153 +++++++++++++
3 files changed, 398 insertions(+)
diff --git a/java/maven.hints/src/org/netbeans/modules/maven/hints/layer.xml
b/java/maven.hints/src/org/netbeans/modules/maven/hints/layer.xml
index 765d9a70b2..ad64474723 100644
--- a/java/maven.hints/src/org/netbeans/modules/maven/hints/layer.xml
+++ b/java/maven.hints/src/org/netbeans/modules/maven/hints/layer.xml
@@ -62,6 +62,9 @@
<file
name="org-netbeans-modules-maven-hints-pom-CompilerPluginVersionError.instance">
<attr name="position" intvalue="1100"/>
</file>
+ <file
name="org-netbeans-modules-maven-hints-pom-UseReleaseOptionHint.instance">
+ <attr name="position" intvalue="1200"/>
+ </file>
</folder>
diff --git
a/java/maven.hints/src/org/netbeans/modules/maven/hints/pom/UseReleaseOptionHint.java
b/java/maven.hints/src/org/netbeans/modules/maven/hints/pom/UseReleaseOptionHint.java
new file mode 100644
index 0000000000..f99f82f9b6
--- /dev/null
+++
b/java/maven.hints/src/org/netbeans/modules/maven/hints/pom/UseReleaseOptionHint.java
@@ -0,0 +1,242 @@
+/*
+ * 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.maven.hints.pom;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.prefs.Preferences;
+import javax.swing.JComponent;
+import javax.xml.namespace.QName;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.editor.NbEditorUtilities;
+import org.netbeans.modules.maven.hints.pom.spi.Configuration;
+import org.netbeans.modules.maven.hints.pom.spi.POMErrorFixProvider;
+import org.netbeans.modules.maven.model.pom.Build;
+import org.netbeans.modules.maven.model.pom.POMComponent;
+import org.netbeans.modules.maven.model.pom.POMExtensibilityElement;
+import org.netbeans.modules.maven.model.pom.POMModel;
+import org.netbeans.modules.maven.model.pom.POMQName;
+import org.netbeans.modules.maven.model.pom.Plugin;
+import org.netbeans.modules.maven.model.pom.PluginExecution;
+import org.netbeans.modules.maven.model.pom.Properties;
+import org.netbeans.spi.editor.hints.ChangeInfo;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.editor.hints.Severity;
+import org.openide.text.Line;
+import org.openide.util.NbBundle;
+
+import static org.netbeans.modules.maven.hints.pom.Bundle.*;
+
+/**
+ * Converts source/target javac options to the release option where possible
(JEP 247).
+ * @author mbien
+ */
[email protected]({
+ "TIT_UseReleaseVersionHint=Convert matching source/target javac options to
the release option.",
+ "DESC_UseReleaseVersionHint=Matching source/target options can be replaced
with a single release option (JEP 247). This enforces API compatibility with
the chosen Java release.",
+ "FIX_UseReleaseVersionHint=Convert to release option for strict
compatibility checks."})
+public class UseReleaseOptionHint implements POMErrorFixProvider {
+
+ private static final String TARGET_TAG = "target";
+ private static final String SOURCE_TAG = "source";
+ private static final String RELEASE_TAG = "release";
+
+ private static final Configuration config = new
Configuration(UseReleaseOptionHint.class.getName(),
+ TIT_UseReleaseVersionHint(), DESC_UseReleaseVersionHint(),
true, Configuration.HintSeverity.WARNING);
+
+ @Override
+ public List<ErrorDescription> getErrorsForDocument(POMModel model, Project
prj) {
+
+ List<ErrorDescription> hints = new ArrayList<>();
+
+ Build build = model.getProject().getBuild();
+ if (build != null) {
+ for (Plugin plugin : build.getPlugins()) {
+ if ("maven-compiler-plugin".equals(plugin.getArtifactId())) {
+ if (!isPluginCompatible(plugin)) {
+ return Collections.emptyList();
+ }
+ hints.addAll(createHintsForParent("",
plugin.getConfiguration()));
+ if (plugin.getExecutions() != null) {
+ for (PluginExecution exec : plugin.getExecutions()) {
+ hints.addAll(createHintsForParent("",
exec.getConfiguration()));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ Properties properties = model.getProject().getProperties();
+ if (properties != null) {
+ hints.addAll(createHintsForParent("maven.compiler.", properties));
+ }
+
+ return hints;
+ }
+
+ private List<ErrorDescription> createHintsForParent(String prefix,
POMComponent parent) {
+
+ if (parent == null) {
+ return Collections.emptyList();
+ }
+
+ int source;
+ int target;
+
+ // property name or an int value
+ String release = null;
+
+ try {
+ String sourceText =
parent.getChildElementText(POMQName.createQName(prefix+SOURCE_TAG, true));
+ if (isProperty(sourceText)) {
+ release = sourceText;
+ sourceText = getProperty(sourceText, parent.getModel());
+ }
+
+ String targetText =
parent.getChildElementText(POMQName.createQName(prefix+TARGET_TAG, true));
+ if (isProperty(targetText)) {
+ release = targetText;
+ targetText = getProperty(targetText, parent.getModel());
+ }
+
+ source = Integer.parseInt(sourceText);
+ target = Integer.parseInt(targetText);
+ if (release == null) {
+ release = String.valueOf(target);
+ }
+ } catch (NumberFormatException ignored) {
+ // if source or target is invalid or missing
+ return Collections.emptyList();
+ }
+
+ if (source == target && source >= 9) {
+ List<ErrorDescription> hints = new ArrayList<>();
+ for (POMComponent prop : parent.getChildren()) {
+ String name = prop.getPeer().getNodeName();
+ if (name.equals(prefix+SOURCE_TAG) ||
name.equals(prefix+TARGET_TAG)) {
+ hints.add(createHintForComponent(prefix, prop,
parent.getModel(), release));
+ }
+ }
+ return hints;
+ }
+ return Collections.emptyList();
+ }
+
+ private ErrorDescription createHintForComponent(String prefix,
POMComponent component, POMModel model, String release) {
+ Line line = NbEditorUtilities.getLine(model.getBaseDocument(),
component.findPosition(), false);
+ List<Fix> fix = Collections.singletonList(new
ConvertToReleaseOptionFix(prefix, release, component));
+ return ErrorDescriptionFactory.createErrorDescription(Severity.HINT,
FIX_UseReleaseVersionHint(), fix, model.getBaseDocument(),
line.getLineNumber()+1);
+ }
+
+ /**
+ * maven-compiler-plugin version must be >= 3.6
+ */
+ private boolean isPluginCompatible(Plugin plugin) {
+ String string = plugin.getVersion();
+ if (string == null) {
+ return false;
+ }
+ String[] version = string.split("-")[0].split("\\.");
+ try {
+ int major = version.length > 0 ? Integer.parseInt(version[0]) : 0;
+ int minor = version.length > 1 ? Integer.parseInt(version[1]) : 0;
+ if (major < 3 || (major == 3 && minor < 6)) {
+ return false;
+ }
+ } catch (NumberFormatException ignored) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isProperty(String property) {
+ return property != null && property.startsWith("$");
+ }
+
+ private static String getProperty(String prop, POMModel model) {
+ if (prop.length() > 3) {
+ Properties properties = model.getProject().getProperties();
+ if (properties != null) {
+ return properties.getProperty(prop.substring(2,
prop.length()-1));
+ }
+ }
+ return null;
+ }
+
+ private static class ConvertToReleaseOptionFix implements Fix {
+
+ private final String prefix;
+ private final String release;
+ private final POMComponent component;
+
+ private ConvertToReleaseOptionFix(String prefix, String release,
POMComponent component) {
+ this.prefix = prefix;
+ this.component = component;
+ this.release = release;
+ }
+
+ @Override
+ public ChangeInfo implement() throws Exception {
+ ChangeInfo info = new ChangeInfo();
+ POMModel model = component.getModel();
+ PomModelUtils.implementInTransaction(model, () -> {
+ POMComponent parent = component.getParent();
+ for (POMComponent child : parent.getChildren()) {
+ String name = child.getPeer().getNodeName();
+ if (name.equals(prefix+SOURCE_TAG) ||
name.equals(prefix+TARGET_TAG) || name.equals(prefix+RELEASE_TAG)) {
+
parent.removeExtensibilityElement((POMExtensibilityElement) child);
+ }
+ }
+ POMExtensibilityElement element =
model.getFactory().createPOMExtensibilityElement(QName.valueOf(prefix+RELEASE_TAG));
+ element.setElementText(release);
+ parent.addExtensibilityElement(element);
+ });
+ return info;
+ }
+
+ @Override
+ public String getText() {
+ return FIX_UseReleaseVersionHint();
+ }
+
+ }
+
+ @Override
+ public void cancel() {}
+
+ @Override
+ public Configuration getConfiguration() {
+ return config;
+ }
+
+ @Override
+ public String getSavedValue(JComponent customizer, String key) {
+ return null;
+ }
+
+ @Override
+ public JComponent getCustomizer(Preferences preferences) {
+ return null;
+ }
+
+}
diff --git
a/java/maven.hints/test/unit/src/org/netbeans/modules/maven/hints/pom/UseReleaseOptionHintTest.java
b/java/maven.hints/test/unit/src/org/netbeans/modules/maven/hints/pom/UseReleaseOptionHintTest.java
new file mode 100644
index 0000000000..58aefb06cc
--- /dev/null
+++
b/java/maven.hints/test/unit/src/org/netbeans/modules/maven/hints/pom/UseReleaseOptionHintTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.maven.hints.pom;
+
+import java.util.List;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.maven.model.Utilities;
+import org.netbeans.modules.maven.model.pom.POMModel;
+import org.netbeans.modules.maven.model.pom.POMModelFactory;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.test.TestFileUtils;
+
+import static junit.framework.TestCase.assertEquals;
+
+/**
+ *
+ * @author mbien
+ */
+public class UseReleaseOptionHintTest extends NbTestCase {
+
+ private FileObject work;
+
+ public UseReleaseOptionHintTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ clearWorkDir();
+ work = FileUtil.toFileObject(getWorkDir());
+ }
+
+ public void testProperties() throws Exception {
+ FileObject pom = TestFileUtils.writeFile(work, "pom.xml",
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+ " <modelVersion>4.0.0</modelVersion>\n" +
+ " <groupId>test</groupId>\n" +
+ " <artifactId>mavenproject1</artifactId>\n" +
+ " <version>1.0-SNAPSHOT</version>\n" +
+ " <packaging>jar</packaging>\n" +
+ " <properties>\n" +
+ "
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n" +
+ "
<exec.mainClass>test.mavenproject1.Mavenproject1</exec.mainClass>\n" +
+ " <maven.compiler.source>11</maven.compiler.source>\n" +
+ " <maven.compiler.target>11</maven.compiler.target>\n" +
+ " </properties>\n" +
+ "</project>");
+
+ POMModel model =
POMModelFactory.getDefault().getModel(Utilities.createModelSource(pom));
+ Project project =
ProjectManager.getDefault().findProject(pom.getParent());
+
+ List<ErrorDescription> hints = new
UseReleaseOptionHint().getErrorsForDocument(model, project);
+ assertEquals(2, hints.size());
+ }
+
+ public void testPropertiesNegative() throws Exception {
+ FileObject pom = TestFileUtils.writeFile(work, "pom.xml",
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+ " <modelVersion>4.0.0</modelVersion>\n" +
+ " <groupId>test</groupId>\n" +
+ " <artifactId>mavenproject1</artifactId>\n" +
+ " <version>1.0-SNAPSHOT</version>\n" +
+ " <packaging>jar</packaging>\n" +
+ " <properties>\n" +
+ "
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n" +
+ "
<exec.mainClass>test.mavenproject1.Mavenproject1</exec.mainClass>\n" +
+ " <maven.compiler.source>8</maven.compiler.source>\n" +
+ " <maven.compiler.target>8</maven.compiler.target>\n" +
+ " </properties>\n" +
+ "</project>");
+
+ POMModel model =
POMModelFactory.getDefault().getModel(Utilities.createModelSource(pom));
+ Project project =
ProjectManager.getDefault().findProject(pom.getParent());
+
+ List<ErrorDescription> hints = new
UseReleaseOptionHint().getErrorsForDocument(model, project);
+ assertEquals(0, hints.size());
+ }
+
+ public void testCompilerPlugin() throws Exception {
+ FileObject pom = TestFileUtils.writeFile(work, "pom.xml",
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+ " <modelVersion>4.0.0</modelVersion>\n" +
+ " <groupId>test</groupId>\n" +
+ " <artifactId>mavenproject1</artifactId>\n" +
+ " <version>1.0-SNAPSHOT</version>\n" +
+ " <packaging>jar</packaging>\n" +
+ " <properties>\n" +
+ "
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n" +
+ "
<exec.mainClass>test.mavenproject1.Mavenproject1</exec.mainClass>\n" +
+ " <prop>11</prop>\n" +
+ " </properties>\n" +
+ " <build>\n" +
+ " <plugins>\n" +
+ " <plugin>\n" +
+ " <groupId>org.apache.maven.plugins</groupId>\n" +
+ " <artifactId>maven-compiler-plugin</artifactId>\n"
+
+ " <version>3.10.1</version>\n" +
+ " <configuration>\n" +
+ " <source>11</source>\n" +
+ " <target>11</target>\n" +
+ " </configuration>" +
+ " <executions>\n" +
+ " <execution>\n" +
+ " <id>default-compile</id>\n" +
+ " <configuration>\n" +
+ " <source>${prop}</source>\n" +
+ " <target>${prop}</target>\n" +
+ " </configuration>\n" +
+ " </execution>\n" +
+ " <execution>\n" +
+ " <id>default-testCompile</id>\n" +
+ " <configuration>\n" +
+ " <source>17</source>\n" +
+ " <target>17</target>\n" +
+ " </configuration>\n" +
+ " </execution>\n" +
+ " </executions>\n" +
+ " </plugin>\n" +
+ " </plugins>\n" +
+ " </build>\n" +
+ "</project>");
+
+ POMModel model =
POMModelFactory.getDefault().getModel(Utilities.createModelSource(pom));
+ Project project =
ProjectManager.getDefault().findProject(pom.getParent());
+
+ List<ErrorDescription> hints = new
UseReleaseOptionHint().getErrorsForDocument(model, project);
+ assertEquals(6, hints.size());
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists