Update the defining properties page
This commit is contained in:
@@ -28,12 +28,12 @@
|
||||
{% elsif fun.params_are_same_as %}
|
||||
(Same as for `{{ fun.params_are_same_as }}`)
|
||||
{% elsif fun.parameters.size == 1 %}
|
||||
0: {{ fun.parameters[0].description }}
|
||||
1: {{ fun.parameters[0].description }}
|
||||
{% else %}
|
||||
<ul>
|
||||
{% for i in 0..fun.parameters.size %}
|
||||
{{ assign param = fun.parameters[i] }}
|
||||
<li>{{ i }} : {{ param.description }}</li>
|
||||
<li>{{ i + 1 }} : {{ param.description }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
@@ -9,6 +9,7 @@ author: Hooper Bloob <hooperbloob@users.sourceforge.net>, Romain Pelisse <rpelis
|
||||
---
|
||||
|
||||
{% jdoc_nspace :props core::properties %}
|
||||
{% jdoc_nspace :PF props::PropertyFactory %}
|
||||
|
||||
Rule properties are a way to make your rules configurable directly from the
|
||||
ruleset XML. Their usage is described on the [Configuring Rules](pmd_userdocs_configuring_rules.html#rule-properties) page.
|
||||
@@ -28,31 +29,28 @@ The basic thing you need to do as a developer is to define a **property descript
|
||||
|
||||
Don't worry, all of these attributes can be specified in a single Java statement (or xml element for XPath rules).
|
||||
|
||||
Without further ado, here is the list of available (single-value) properties:
|
||||
Without further ado, here is the list of available (single-value) property types:
|
||||
|
||||
|Class name|Value type|
|
||||
|----------|----------|
|
||||
|IntegerProperty | int
|
||||
|DoubleProperty | double
|
||||
|FloatProperty | float
|
||||
|LongProperty | long
|
||||
|EnumeratedProperty\<*E*\>| *E*
|
||||
|StringProperty|String
|
||||
|BooleanProperty|boolean
|
||||
|CharacterProperty|char
|
||||
|FileProperty|java.io.File
|
||||
|MethodProperty|java.lang.reflect.Method
|
||||
|TypeProperty|java.lang.Class\<?\>
|
||||
|RegexProperty|java.util.regex.Pattern
|
||||
|Value type|Factory method|
|
||||
|----------|--------------|
|
||||
| int |{% jdoc :PF#intProperty(java.lang.String) %}|
|
||||
| double |{% jdoc :PF#doubleProperty(java.lang.String) %}|
|
||||
| long |{% jdoc :PF#longProperty(java.lang.String) %}|
|
||||
| char |{% jdoc :PF#charProperty(java.lang.String) %}|
|
||||
| boolean |{% jdoc :PF#booleanProperty(java.lang.String) %}|
|
||||
| String |{% jdoc :PF#stringProperty(java.lang.String) %}|
|
||||
| java.util.regex.Pattern |{% jdoc :PF#regexProperty(java.lang.String) %}|
|
||||
| *anything* |{% jdoc :PF#enumProperty(java.lang.String,java.util.Map) %}|
|
||||
|
||||
Each of these is complemented by a multivalued variant, whose name ends with "MultiProperty", and which returns a list of values, e.g.
|
||||
Each of these is complemented by a multivalued variant, whose value is a list, e.g.
|
||||
|
||||
|Class name|Value type|
|
||||
|----------|----------|
|
||||
|LongMultiProperty | List\<Long\>
|
||||
|EnumeratedMultiProperty\<*E*\>| List\<*E*\>
|
||||
|Value type|Factory method|
|
||||
|----------|--------------|
|
||||
| List\<Integer\> |{% jdoc :PF#intListProperty(java.lang.String) %}|
|
||||
| List\<*E*\> |{% jdoc :PF#enumListProperty(java.lang.String,java.util.Map) %}|
|
||||
|
||||
Note that RegexProperty doesn't have a multivalued variant, since the delimiters could be part of a specific value.
|
||||
Note that no multivalue property is available for regex properties, since the
|
||||
delimiters could be part of a specific value.
|
||||
|
||||
## For Java rules
|
||||
|
||||
@@ -64,28 +62,45 @@ You can then retrieve the value of the property at any time using {% jdoc !a!pro
|
||||
|
||||
### Creating a descriptor
|
||||
|
||||
From version 6.0.0 on, properties can be built using specific **builders**. For example, to build a string property, you'd call
|
||||
Properties can be built using type-specific **builders**, which can be obtained
|
||||
from the factory methods of {% jdoc :PF %}. For example, to build a
|
||||
string property, you'd call
|
||||
```java
|
||||
StringProperty.named("myProperty")
|
||||
.desc("This is my property")
|
||||
.defaultValue("foo")
|
||||
.build();
|
||||
PropertyFactory.stringProperty("myProperty")
|
||||
.desc("This is my property")
|
||||
.defaultValue("foo")
|
||||
.build();
|
||||
```
|
||||
|
||||
This is fairly more readable than a constructor call, but keep in mind the description and the default value are not optional.
|
||||
|
||||
{%include note.html content="The constructors may be deprecated in a future release, so please use the builders instead." %}
|
||||
{%include note.html
|
||||
content='As of version 6.10.0, all property concrete classes are deprecated for
|
||||
removal in 7.0.0. See the <a href="pmd_next_major_development.html#properties-framework">detailed list of planned removals</a> for
|
||||
information about how to migrate.' %}
|
||||
|
||||
For **numeric properties**, you'd add a call to `range` to define the range of acceptable values, e.g.
|
||||
|
||||
For **numeric properties**, you can add constraints on the range of acceptable values, e.g.
|
||||
```java
|
||||
IntegerProperty.named("myIntProperty")
|
||||
PropertyFactory.intProperty("myIntProperty")
|
||||
.desc("This is my property")
|
||||
.defaultValue(3)
|
||||
.require(positive())
|
||||
.range(0, 100)
|
||||
.build();
|
||||
```
|
||||
|
||||
**Enumerated properties** are a bit less straightforward to define, though they are arguably more powerful. These properties don't have a specific value type, instead, you can choose any type of value, provided the values are from a closed set. To make that actionable, you give string labels to each of the acceptable values, and the user will provide one of those labels as a value in the XML. The property will give you back the associated value, not the label. Here's an example:
|
||||
The {% jdoc props::constraints.NumericConstraints#positive() %} method is part of
|
||||
the {% jdoc props::constraints.NumericConstraints %} class, which provides some
|
||||
other constraints. The constraint mechanism will be completely unlocked with 7.0.0,
|
||||
since we'll be migrating our API to Java 8.
|
||||
|
||||
**Enumerated properties** are a bit less straightforward to define, though they are
|
||||
arguably more powerful. These properties don't have a specific value type, instead,
|
||||
you can choose any type of value, provided the values are from a closed set. To make
|
||||
that actionable, you give string labels to each of the acceptable values, and the user
|
||||
will provide one of those labels as a value in the XML. The property will give you back
|
||||
the associated value, not the label. Here's an example:
|
||||
```java
|
||||
static Map<String, ModeStrategy> map = new HashMap<>();
|
||||
|
||||
@@ -94,24 +109,25 @@ static {
|
||||
map.put("hardMode", new HardStrategy());
|
||||
}
|
||||
|
||||
static EnumeratedProperty<ModeStrategy> modeProperty
|
||||
= EnumeratedProperty.<ModeStrategy>named("modeProperty")
|
||||
.desc("This is my property")
|
||||
.defaultValue(new EasyStrategy())
|
||||
.mappings(map)
|
||||
.type(ModeStrategy.class)
|
||||
.build();
|
||||
static PropertyDescriptor<ModeStrategy> modeProperty
|
||||
= PropertyFactory.enumProperty("modeProperty", map)
|
||||
.desc("This is my property")
|
||||
.defaultValue(new EasyStrategy())
|
||||
.build();
|
||||
```
|
||||
|
||||
Note that you're required to fill in the type of the values too, using `type()`.
|
||||
|
||||
### Example
|
||||
|
||||
You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/ac2ff0f6af8d16f739584ba8d00b7ea1a6311ccc/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java#L17).
|
||||
You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/5d86217871f086f8223da327099d1d67a6e45dab/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java#L41-L42).
|
||||
There are several things to notice here:
|
||||
* The property descriptor is declared `static final`, which should generally be the case, as descriptors are immutable and can be shared between instances of the same rule;
|
||||
* The property is declared using `definePropertyDescriptor` *in the constructor*, which ensures the property gets recognised by PMD;
|
||||
* The value of the property is *not retrieved in the constructor*, but in one of the `visit` methods (typically on the highest node in the tree, since the property doesn't change).
|
||||
* The property descriptors are declared `static final`, which should generally be
|
||||
the case, as descriptors are immutable and can be shared between instances of the same rule;
|
||||
* The property is declared using {% jdoc props::PropertySource#definePropertyDescriptor(props::PropertyDescriptor) %}` *in the constructor*,
|
||||
which ensures the property gets recognised by PMD at the time the properties
|
||||
are overridden (which happens before rule execution);
|
||||
* The value of the property is *not retrieved in the constructor*, but in one of
|
||||
the `visit` methods (typically on the highest node in the tree, since the property
|
||||
doesn't change).
|
||||
|
||||
|
||||
|
||||
@@ -119,21 +135,28 @@ There are several things to notice here:
|
||||
|
||||
XPath rules can also define their own properties. To do so, you must add a `property` element in the `properties` element of your rule, which **declares the `type` attribute**. This attribute conditions what type the underlying property has, and can have the following values:
|
||||
|
||||
| `type` attribute | Property type|
|
||||
| `type` attribute | XSD type
|
||||
|----------|----------|
|
||||
|Integer|IntegerProperty
|
||||
|Double | DoubleProperty
|
||||
|Float|FloatProperty
|
||||
|Long| LongProperty
|
||||
|String|StringProperty
|
||||
|Character|CharacterProperty
|
||||
|Boolean|BooleanProperty
|
||||
|Class|TypeProperty
|
||||
|Regex|RegexProperty
|
||||
|Integer | xs:integer
|
||||
|Long | xs:integer
|
||||
|Double | xs:decimal
|
||||
|Boolean | xs:boolean
|
||||
|String | xs:string
|
||||
|Character| xs:string
|
||||
|Regex | xs:string
|
||||
|
||||
{% include note.html
|
||||
content="In XPath 1.0 mode, all values are actually represented as
|
||||
string values, which is mostly fine as there is no type
|
||||
checking. This is a problem when [migrating from XPath 1.0
|
||||
to 2.0](pmd_userdocs_extending_writing_xpath_rules.html#migrating-from-10-to-20) though" %}
|
||||
|
||||
|
||||
Note that enumerated properties are not available in XPath rules (yet?).
|
||||
|
||||
Properties defined in XPath also *must* declare the `description` attribute. Numeric properties also expect the `min` and `max` attributes. Here are a few examples to sum it up:
|
||||
Properties defined in XPath also *must* declare the `description` attribute.
|
||||
Numeric properties also expect the `min` and `max` attributes for now. Here are
|
||||
a few examples to sum it up:
|
||||
|
||||
```xml
|
||||
<property name="stringProp" type="Boolean" value="true" description="A BooleanProperty."/>
|
||||
@@ -157,7 +180,12 @@ You can then use the property in XPath with the syntax `$propertyName`, for exam
|
||||
|
||||
### Multivalued properties
|
||||
|
||||
Multivalued properties are also allowed and their `type` attribute has the form `List[Boolean]` or `List[Character]`, with every above type allowed. These properties **require XPath 2.0** to work properly, and make use of the **sequence datatype** provided by that language. You thus need to set the `version` property to `2.0` to use them. Properties can also declare the `delimiter` attribute.
|
||||
Multivalued properties are also allowed and their `type` attribute has the form
|
||||
`List[Boolean]` or `List[Character]`, with every above type allowed. These
|
||||
properties **require XPath 2.0** to work properly, and make use of the
|
||||
**sequence datatype** provided by that language. You thus need to set the
|
||||
`version` property to `2.0` to use them. Properties can also declare the
|
||||
`delimiter` attribute.
|
||||
|
||||
|
||||
|
||||
@@ -176,5 +204,9 @@ Multivalued properties are also allowed and their `type` attribute has the form
|
||||
</rule>
|
||||
```
|
||||
|
||||
Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test `@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether the sequence *contains* `@Image`. That is, the above rule will report all variables named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported.
|
||||
Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test
|
||||
`@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether
|
||||
the sequence *contains* `@Image`. That is, the above rule will report all variables
|
||||
named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions)
|
||||
are supported.
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ also [the tutorial about how to write an XPath rule](pmd_userdocs_extending_desi
|
||||
|
||||
<!-- Later we can document the specific subset of XPath features our wrappers support -->
|
||||
|
||||
<!-- TODO describe value representation quirks -->
|
||||
|
||||
## XPath version
|
||||
|
||||
PMD supports three XPath versions for now: 1.0, 2.0, and 1.0 compatibility mode.
|
||||
@@ -86,8 +88,8 @@ On XPath 2.0, the namespace of custom PMD function must be explicitly mentioned.
|
||||
{% include custom/xpath_fun_doc.html %}
|
||||
{% endrender %}
|
||||
|
||||
There is also a `typeOf` function which is deprecated and whose usages
|
||||
should be replaced with uses of `typeIs` or `typeIsExactly`. That one will
|
||||
be removed with PMD 7.0.0.
|
||||
{% include note.html content='There is also a `typeOf` function which is
|
||||
deprecated and whose usages should be replaced with uses of `typeIs` or
|
||||
`typeIsExactly`. That one will be removed with PMD 7.0.0.' %}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user