From 1f2835f96e2f2c1bc880f2abbdf989d7753c4013 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 17 Jan 2020 14:01:40 +0100 Subject: [PATCH 1/2] [core] Deprecated Node#isFindBoundary for XPath Refs #2218 --- docs/pages/release_notes.md | 1 + .../net/sourceforge/pmd/lang/ast/Node.java | 5 ++++ .../pmd/lang/ast/xpath/Attribute.java | 9 +++++-- .../lang/ast/xpath/DeprecatedAttribute.java | 25 +++++++++++++++++++ .../ast/DummyNodeWithDeprecatedAttribute.java | 9 +++++++ .../ast/xpath/AttributeAxisIteratorTest.java | 25 ++++++++++++++++++- 6 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DeprecatedAttribute.java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 63fa0942f2..24def78ce6 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -119,6 +119,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 d203ee6b1c..8bc5fabbe6 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.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..9cf3a30f04 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 @@ -31,7 +31,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 +72,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/DeprecatedAttribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DeprecatedAttribute.java new file mode 100644 index 0000000000..30eb49df05 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/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; + +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..1eaa4f0486 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.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")); } /** From c3b7db042b0ec627376b8eb9f769f4f6ca8faee2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 17 Jan 2020 15:17:27 +0100 Subject: [PATCH 2/2] Move DeprecatedAttribute annotation to internal package --- pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java | 2 +- .../main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java | 1 + .../pmd/lang/ast/xpath/{ => internal}/DeprecatedAttribute.java | 2 +- .../pmd/lang/ast/DummyNodeWithDeprecatedAttribute.java | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) rename pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/{ => internal}/DeprecatedAttribute.java (92%) 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 8bc5fabbe6..e38a046263 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,7 +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.DeprecatedAttribute; +import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.dfa.DataFlowNode; /** 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 9cf3a30f04..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. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DeprecatedAttribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java similarity index 92% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DeprecatedAttribute.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java index 30eb49df05..97346d92a7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DeprecatedAttribute.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath; +package net.sourceforge.pmd.lang.ast.xpath.internal; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; 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 1eaa4f0486..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,7 +4,7 @@ package net.sourceforge.pmd.lang.ast; -import net.sourceforge.pmd.lang.ast.xpath.DeprecatedAttribute; +import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; /** * @author Clément Fournier