diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index 753fcd682a..4cf6811725 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -133,6 +133,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati
* pmd-core
* Many methods on the {% jdoc core::lang.ast.Node %} interface
and {% jdoc core::lang.ast.AbstractNode %} base class. See their javadoc for details.
+ * {% jdoc !!core::lang.ast.Node#isFindBoundary() %} is deprecated for XPath queries.
* pmd-java
* {% jdoc java::lang.java.AbstractJavaParser %}
* {% jdoc java::lang.java.AbstractJavaHandler %}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java
index c5a401fa47..e1571e8a5f 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java
@@ -12,6 +12,7 @@ import org.w3c.dom.Document;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
+import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
import net.sourceforge.pmd.lang.dfa.DataFlowNode;
/**
@@ -202,7 +203,11 @@ public interface Node {
* look past such boundaries by default, which is usually the expected thing
* to do. For example, in Java, lambdas and nested classes are considered
* find boundaries.
+ *
+ *
Note: This attribute is deprecated for XPath queries. It is not useful
+ * for XPath queries and will be removed with PMD 7.0.0.
*/
+ @DeprecatedAttribute
boolean isFindBoundary();
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
index 85cca22010..cee0734a9c 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java
@@ -16,6 +16,7 @@ import java.util.logging.Logger;
import net.sourceforge.pmd.annotation.Experimental;
import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
/**
* Represents an XPath attribute of a specific node.
@@ -31,7 +32,7 @@ public class Attribute {
private static final Logger LOG = Logger.getLogger(Attribute.class.getName());
- private static final ConcurrentMap DETECTED_DEPRECATED_ATTRIBUTES = new ConcurrentHashMap<>();
+ static final ConcurrentMap DETECTED_DEPRECATED_ATTRIBUTES = new ConcurrentHashMap<>();
private static final Object[] EMPTY_OBJ_ARRAY = new Object[0];
@@ -72,12 +73,17 @@ public class Attribute {
return method == null ? String.class : method.getReturnType();
}
+ private boolean isAttributeDeprecated() {
+ return method != null && (method.isAnnotationPresent(Deprecated.class)
+ || method.isAnnotationPresent(DeprecatedAttribute.class));
+ }
+
public Object getValue() {
if (value != null) {
return value.get(0);
}
- if (method.isAnnotationPresent(Deprecated.class) && LOG.isLoggable(Level.WARNING)
+ if (LOG.isLoggable(Level.WARNING) && isAttributeDeprecated()
&& DETECTED_DEPRECATED_ATTRIBUTES.putIfAbsent(getLoggableAttributeName(), Boolean.TRUE) == null) {
// this message needs to be kept in sync with PMDCoverageTest / BinaryDistributionIT
LOG.warning("Use of deprecated attribute '" + getLoggableAttributeName() + "' in XPath query");
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java
new file mode 100644
index 0000000000..97346d92a7
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java
@@ -0,0 +1,25 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.ast.xpath.internal;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Node attribute getter methods might be annotated with {@code DeprecatedAttribute}
+ * to mark the attribute as deprecated for XPath. Unlike {@link Deprecated}, this
+ * annotation does not deprecate the method for java usage.
+ *
+ * @since 6.21.0
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface DeprecatedAttribute {
+}
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithDeprecatedAttribute.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithDeprecatedAttribute.java
index 7f6f67d8f7..7deca9984b 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithDeprecatedAttribute.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNodeWithDeprecatedAttribute.java
@@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.ast;
+import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute;
+
/**
* @author Clément Fournier
* @since 6.3.0
@@ -20,4 +22,11 @@ public class DummyNodeWithDeprecatedAttribute extends DummyNode {
public int getSize() {
return 2;
}
+
+ // this is a attribute that is deprecated for xpath, because it will be removed.
+ // it should still be available via Java.
+ @DeprecatedAttribute
+ public String getName() {
+ return "foo";
+ }
}
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java
index 45eefbb33f..1d9e274921 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java
@@ -16,10 +16,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.hamcrest.Matchers;
import org.hamcrest.collection.IsMapContaining;
import org.junit.Assert;
+import org.junit.Rule;
import org.junit.Test;
+import net.sourceforge.pmd.junit.JavaUtilLoggingRule;
import net.sourceforge.pmd.lang.ast.DummyNode;
import net.sourceforge.pmd.lang.ast.DummyNodeWithDeprecatedAttribute;
import net.sourceforge.pmd.lang.ast.Node;
@@ -30,10 +33,30 @@ import net.sourceforge.pmd.lang.ast.Node;
*/
public class AttributeAxisIteratorTest {
+ @Rule
+ public JavaUtilLoggingRule loggingRule = new JavaUtilLoggingRule(Attribute.class.getName());
+
+ /**
+ * Verifies that attributes are returned, even if they are deprecated.
+ * Deprecated attributes are still accessible, but a warning is logged, when
+ * the value is used.
+ */
@Test
public void testAttributeDeprecation() {
+ // make sure, we log
+ Attribute.DETECTED_DEPRECATED_ATTRIBUTES.clear();
+
Node dummy = new DummyNodeWithDeprecatedAttribute(2);
- assertThat(toMap(new AttributeAxisIterator(dummy)), IsMapContaining.hasKey("Size"));
+ Map attributes = toMap(new AttributeAxisIterator(dummy));
+ assertThat(attributes, IsMapContaining.hasKey("Size"));
+ assertThat(attributes, IsMapContaining.hasKey("Name"));
+
+ assertThat(attributes.get("Size").getStringValue(), Matchers.is("2"));
+ assertThat(attributes.get("Name").getStringValue(), Matchers.is("foo"));
+
+ String log = loggingRule.getLog();
+ assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Size' in XPath query"));
+ assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Name' in XPath query"));
}
/**