From 879a7d375cb88d997b32fff84b810e97b216bbb1 Mon Sep 17 00:00:00 2001 From: oowekyala Date: Thu, 13 Jul 2017 21:43:18 +0200 Subject: [PATCH] Modularized numeric and packaged properties --- .../AbstractPropertyDescriptorFactory.java | 79 +++--- .../pmd/NumericPropertyDescriptor.java | 10 + .../pmd/PackagedPropertyDescriptor.java | 15 ++ .../AbstractMultiNumericProperty.java | 46 +--- .../AbstractMultiPackagedProperty.java | 138 ++-------- .../AbstractMultiValueProperty.java | 1 - .../properties/AbstractNumericProperty.java | 79 +----- .../properties/AbstractPackagedProperty.java | 137 ++-------- .../rule/properties/BooleanMultiProperty.java | 16 +- .../lang/rule/properties/BooleanProperty.java | 10 +- .../properties/CharacterMultiProperty.java | 4 +- .../rule/properties/CharacterProperty.java | 27 +- .../rule/properties/DoubleMultiProperty.java | 16 +- .../lang/rule/properties/DoubleProperty.java | 37 +-- .../properties/EnumeratedMultiProperty.java | 29 ++- .../rule/properties/EnumeratedProperty.java | 20 +- .../lang/rule/properties/FileProperty.java | 2 + .../rule/properties/FloatMultiProperty.java | 17 +- .../lang/rule/properties/FloatProperty.java | 13 +- .../rule/properties/IntegerMultiProperty.java | 19 +- .../lang/rule/properties/IntegerProperty.java | 3 +- .../rule/properties/LongMultiProperty.java | 17 +- .../lang/rule/properties/LongProperty.java | 12 +- .../rule/properties/MethodMultiProperty.java | 44 ++-- .../lang/rule/properties/MethodProperty.java | 241 +++--------------- .../MultiValuePropertyDescriptorFactory.java | 2 +- .../properties/PropertyDescriptorUtil.java | 25 +- .../SingleValuePropertyDescriptorFactory.java | 6 +- .../rule/properties/StringMultiProperty.java | 5 +- .../lang/rule/properties/StringProperty.java | 1 + .../rule/properties/TypeMultiProperty.java | 51 ++-- .../lang/rule/properties/TypeProperty.java | 66 +---- .../pmd/lang/rule/properties/ValueParser.java | 184 ++++++++++++- .../modules/MethodPropertyModule.java | 110 ++++++++ .../modules/NumericPropertyModule.java | 93 +++++++ .../modules/PackagedPropertyModule.java | 155 +++++++++++ .../modules/TypePropertyModule.java | 30 +++ .../AbstractPropertyDescriptorTester.java | 4 +- .../pmd/properties/BooleanPropertyTest.java | 7 + .../pmd/properties/CharacterPropertyTest.java | 12 +- .../pmd/properties/DoublePropertyTest.java | 6 + .../pmd/properties/FloatPropertyTest.java | 72 +++--- .../pmd/properties/MethodPropertyTest.java | 19 +- .../pmd/properties/PropertyAccessorTest.java | 5 + .../SimpleEnumeratedPropertyTest.java | 21 +- .../pmd/properties/StringPropertyTest.java | 18 +- .../pmd/properties/TypePropertyTest.java | 12 +- 47 files changed, 1012 insertions(+), 924 deletions(-) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/MethodPropertyModule.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/NumericPropertyModule.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/PackagedPropertyModule.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/TypePropertyModule.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/AbstractPropertyDescriptorFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/AbstractPropertyDescriptorFactory.java index ae8c6d836c..f8153253ea 100755 --- a/pmd-core/src/main/java/net/sourceforge/pmd/AbstractPropertyDescriptorFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/AbstractPropertyDescriptorFactory.java @@ -12,13 +12,10 @@ import static net.sourceforge.pmd.PropertyDescriptorField.MAX; import static net.sourceforge.pmd.PropertyDescriptorField.MIN; import static net.sourceforge.pmd.PropertyDescriptorField.NAME; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; -import net.sourceforge.pmd.lang.rule.properties.ValueParser; import net.sourceforge.pmd.util.CollectionUtil; import net.sourceforge.pmd.util.StringUtil; @@ -91,23 +88,36 @@ public abstract class AbstractPropertyDescriptorFactory implements PropertyDe } + @Override + public final PropertyDescriptor createWith(Map valuesById) { + return createWith(valuesById, false); + } + + /** - * Parses a string into a list of values of type {@literal }. + * Creates a new property descriptor specifying whether the descriptor is externally defined or not. This is + * meant to be implemented by subclasses. * - * @param toParse The string to parse - * @param delimiter The delimiter to use - * @param extractor The function mapping a string to an instance of {@code } - * @param The type of the values to parse + * @param valuesById The map of values + * @param isExternallyDefined Whether the descriptor is externally defined * - * @return A list of values + * @return A new and initialized {@link PropertyDescriptor} */ - protected static List parsePrimitives(String toParse, char delimiter, ValueParser extractor) { - String[] values = StringUtil.substringsOf(toParse, delimiter); - List result = new ArrayList<>(); - for (String s : values) { - result.add(extractor.valueOf(s)); - } - return result; + protected abstract PropertyDescriptor createWith(Map valuesById, boolean isExternallyDefined); + + + /** + * Creates a new property descriptor which was defined externally. + * + * @param valuesById The map of values + * + * @return A new and initialized {@link PropertyDescriptor} + * + * @see PropertyDescriptor#isDefinedExternally() + */ + /* default */ + final PropertyDescriptor createExternalWith(Map valuesById) { + return createWith(valuesById, true); } @@ -185,9 +195,11 @@ public abstract class AbstractPropertyDescriptorFactory implements PropertyDe /** - * Returns a map of mappings of property descriptor fields + * Returns a map describing which fields are required to build an + * * @param otherKeys * @param otherValues + * * @return */ public static Map expectedFieldTypesWith(PropertyDescriptorField[] otherKeys, @@ -202,37 +214,4 @@ public abstract class AbstractPropertyDescriptorFactory implements PropertyDe } - @Override - public final PropertyDescriptor createWith(Map valuesById) { - return createWith(valuesById, false); - } - - - /** - * Creates a new property descriptor which was defined externally. - * - * @param valuesById The map of values - * - * @return A new and initialized {@link PropertyDescriptor} - * - * @see PropertyDescriptor#isDefinedExternally() - */ - /* default */ - final PropertyDescriptor createExternalWith(Map valuesById) { - return createWith(valuesById, true); - } - - - /** - * Creates a new property descriptor specifying whether the descriptor is externally defined or not. This is - * meant to be implemented by subclasses. - * - * @param valuesById The map of values - * @param isExternallyDefined Whether the descriptor is externally defined - * - * @return A new and initialized {@link PropertyDescriptor} - */ - protected abstract PropertyDescriptor createWith(Map valuesById, boolean isExternallyDefined); - - } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/NumericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/NumericPropertyDescriptor.java index cb4cd948a7..66e1f57fe1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/NumericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/NumericPropertyDescriptor.java @@ -4,6 +4,11 @@ package net.sourceforge.pmd; +import static net.sourceforge.pmd.PropertyDescriptorField.MAX; +import static net.sourceforge.pmd.PropertyDescriptorField.MIN; + +import java.util.Map; + /** * Defines a descriptor type whose instance values are required to lie within * specified upper and lower limits. @@ -14,6 +19,11 @@ package net.sourceforge.pmd; */ public interface NumericPropertyDescriptor extends PropertyDescriptor { + Map NUMBER_FIELD_TYPES_BY_KEY + = AbstractPropertyDescriptorFactory.expectedFieldTypesWith(new PropertyDescriptorField[] {MIN, MAX}, + new Boolean[] {true, true}); + + /** * Returns the maximum value that instances of the property can have. * diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PackagedPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/PackagedPropertyDescriptor.java index d13ce719c9..c3baaaea6c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PackagedPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PackagedPropertyDescriptor.java @@ -4,6 +4,10 @@ package net.sourceforge.pmd; +import static net.sourceforge.pmd.PropertyDescriptorField.LEGAL_PACKAGES; + +import java.util.Map; + /** * Defines a property descriptor type whose values can be described by qualified names and thus restricted to only some * packages. These typically use values such as {@link Class} and {@link java.lang.reflect.Method}. @@ -14,6 +18,17 @@ package net.sourceforge.pmd; */ public interface PackagedPropertyDescriptor extends PropertyDescriptor { + /** Required additional fields. */ + Map PACKAGED_FIELD_TYPES_BY_KEY + = AbstractPropertyDescriptorFactory.expectedFieldTypesWith(new PropertyDescriptorField[] {LEGAL_PACKAGES}, + new Boolean[] {false}); + + /** Delimiter used to separate package names. */ + char PACKAGE_NAME_DELIMITER = ' '; + /** Delimiter used to separate multiple values if this descriptor is multi valued. */ + char MULTI_VALUE_DELIMITER = '|'; + + /** * Returns the legal package names. * diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiNumericProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiNumericProperty.java index 7945bdc1f0..b6365ab62b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiNumericProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiNumericProperty.java @@ -4,14 +4,12 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.PropertyDescriptorField.MAX; -import static net.sourceforge.pmd.PropertyDescriptorField.MIN; - import java.util.List; import java.util.Map; import net.sourceforge.pmd.NumericPropertyDescriptor; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.modules.NumericPropertyModule; /** * Base class for multi-valued numeric properties. @@ -24,8 +22,7 @@ import net.sourceforge.pmd.PropertyDescriptorField; /* default */ abstract class AbstractMultiNumericProperty extends AbstractMultiValueProperty implements NumericPropertyDescriptor> { - private final T lowerLimit; - private final T upperLimit; + private final NumericPropertyModule module; /** @@ -39,65 +36,38 @@ import net.sourceforge.pmd.PropertyDescriptorField; * @param theUIOrder UI order * * @throws IllegalArgumentException if lower > upper, or one of them is null, or one of the defaults is not between - * the bounds + * the bounds */ AbstractMultiNumericProperty(String theName, String theDescription, T lower, T upper, List theDefault, float theUIOrder, boolean isDefinedExternally) { super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally); - lowerLimit = lower; - upperLimit = upper; - - checkNumber(lower); - checkNumber(upper); - - if (lower.doubleValue() > upper.doubleValue()) { - throw new IllegalArgumentException("Lower limit cannot be greater than the upper limit"); - } - - - } - - - private void checkNumber(T number) { - String error = valueErrorFor(number); - if (error != null) { - throw new IllegalArgumentException(error); - } + module = new NumericPropertyModule<>(lower, upper); } @Override protected String valueErrorFor(T value) { - - double number = value.doubleValue(); - - if (number > upperLimit.doubleValue() || number < lowerLimit.doubleValue()) { - return value + " is out of range " + AbstractNumericProperty.rangeString(lowerLimit, upperLimit); - } - - return null; + return module.valueErrorFor(value); } @Override public Number lowerLimit() { - return lowerLimit; + return module.getLowerLimit(); } @Override public Number upperLimit() { - return upperLimit; + return module.getUpperLimit(); } @Override protected void addAttributesTo(Map attributes) { super.addAttributesTo(attributes); - attributes.put(MIN, lowerLimit.toString()); - attributes.put(MAX, upperLimit.toString()); + module.addAttributesTo(attributes); } - } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiPackagedProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiPackagedProperty.java index 0ea1ab7060..a313c52db3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiPackagedProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiPackagedProperty.java @@ -4,17 +4,12 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.PropertyDescriptorField.LEGAL_PACKAGES; - -import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; -import net.sourceforge.pmd.AbstractPropertyDescriptorFactory; import net.sourceforge.pmd.PackagedPropertyDescriptor; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.modules.PackagedPropertyModule; /** * Multi-valued property restricting the type of its values to some packages. @@ -25,116 +20,40 @@ import net.sourceforge.pmd.PropertyDescriptorField; * @version Refactored June 2017 (6.0.0) */ /* default */ abstract class AbstractMultiPackagedProperty extends AbstractMultiValueProperty - implements PackagedPropertyDescriptor>{ + implements PackagedPropertyDescriptor> { - /** Delimiter between values. */ - protected static final char DELIMITER = '|'; - /** Required keys in the map. */ - protected static final Map PACKAGED_FIELD_TYPES_BY_KEY - = AbstractPropertyDescriptorFactory.expectedFieldTypesWith(new PropertyDescriptorField[] {LEGAL_PACKAGES}, - new Boolean[] {false}); - private static final char PACKAGE_NAME_DELIMITER = ' '; - private String[] legalPackageNames; + + protected final PackagedPropertyModule module; /** * Create a packaged property. * - * @param theName Name - * @param theDescription Description - * @param theDefault Default value - * @param theLegalPackageNames Legal package names - * @param theUIOrder UI order + * @param theName Name + * @param theDescription Description + * @param theDefault Default value + * @param theUIOrder UI order + * @param module * * @throws IllegalArgumentException */ protected AbstractMultiPackagedProperty(String theName, String theDescription, List theDefault, - String[] theLegalPackageNames, float theUIOrder, - boolean isDefinedExternally) { - super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally); - - checkValidPackages(theDefault, theLegalPackageNames); - - legalPackageNames = theLegalPackageNames; + float theUIOrder, boolean isDefinedExternally, + PackagedPropertyModule module) { + super(theName, theDescription, theDefault, theUIOrder, MULTI_VALUE_DELIMITER, isDefinedExternally); + this.module = module; } - /** - * Evaluates the names of the items against the allowable name prefixes. If - * one or more do not have valid prefixes then an exception will be thrown. - * - * @param items Items to check - * @param legalNamePrefixes Legal name prefixes - * - * @throws IllegalArgumentException if some items are not allowed - */ - private void checkValidPackages(List items, String[] legalNamePrefixes) { - - Set nameSet = new HashSet<>(); - - for (T item : items) { - nameSet.add(packageNameOf(item)); - } - - Set notAllowed = new HashSet<>(nameSet); - - - for (String name : nameSet) { - for (String prefix : legalNamePrefixes) { - if (name.startsWith(prefix)) { - notAllowed.remove(name); - break; - } - } - } - - if (notAllowed.isEmpty()) { - return; - } - - throw new IllegalArgumentException("Invalid items: " + notAllowed); - } - - - /** - * Returns the package name of the item. - * - * @param item Item - * - * @return Package name of the item - */ - protected abstract String packageNameOf(T item); - - @Override protected void addAttributesTo(Map attributes) { super.addAttributesTo(attributes); - - attributes.put(LEGAL_PACKAGES, delimitedPackageNames()); - } - - - private String delimitedPackageNames() { - - if (legalPackageNames == null || legalPackageNames.length == 0) { - return ""; - } - if (legalPackageNames.length == 1) { - return legalPackageNames[0]; - } - - StringBuilder sb = new StringBuilder(); - sb.append(legalPackageNames[0]); - for (int i = 1; i < legalPackageNames.length; i++) { - sb.append(PACKAGE_NAME_DELIMITER).append(legalPackageNames[i]); - } - return sb.toString(); + module.addAttributesTo(attributes); } @Override protected String valueErrorFor(T value) { - if (value == null) { String err = super.valueErrorFor(null); if (err != null) { @@ -142,38 +61,17 @@ import net.sourceforge.pmd.PropertyDescriptorField; } } - if (legalPackageNames == null) { - return null; // no restriction - } - - String name = packageNameOf(value); - - for (int i = 0; i < legalPackageNames.length; i++) { - if (name.startsWith(legalPackageNames[i])) { - return null; - } - } - - return "Disallowed " + itemTypeName() + ": " + name; + return module.valueErrorFor(value); } - /** - * Returns the name of the type of item. - * - * @return The name of the type of item - */ - protected abstract String itemTypeName(); - - @Override public String[] legalPackageNames() { - return Arrays.copyOf(legalPackageNames, legalPackageNames.length); + return module.legalPackageNames(); } - protected static String[] packageNamesIn(Map params) { - // TODO - return null; + protected String[] packageNamesIn(Map params) { + return module.packageNamesIn(params); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiValueProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiValueProperty.java index c5a646f176..8332e6355e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiValueProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractMultiValueProperty.java @@ -27,7 +27,6 @@ import net.sourceforge.pmd.util.StringUtil; implements MultiValuePropertyDescriptor { - /** The default value. */ private final List defaultValue; private final char multiValueDelimiter; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractNumericProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractNumericProperty.java index 3b115a0116..128cb81f13 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractNumericProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractNumericProperty.java @@ -4,14 +4,11 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.PropertyDescriptorField.MAX; -import static net.sourceforge.pmd.PropertyDescriptorField.MIN; - import java.util.Map; -import net.sourceforge.pmd.AbstractPropertyDescriptorFactory; import net.sourceforge.pmd.NumericPropertyDescriptor; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.modules.NumericPropertyModule; /** * Maintains a pair of boundary limit values between which all values managed by @@ -25,12 +22,8 @@ import net.sourceforge.pmd.PropertyDescriptorField; /* default */ abstract class AbstractNumericProperty extends AbstractSingleValueProperty implements NumericPropertyDescriptor { - public static final Map NUMBER_FIELD_TYPES_BY_KEY - = AbstractPropertyDescriptorFactory.expectedFieldTypesWith(new PropertyDescriptorField[] {MIN, MAX}, - new Boolean[] {true, true}); - private T lowerLimit; - private T upperLimit; + private final NumericPropertyModule module; /** @@ -50,92 +43,34 @@ import net.sourceforge.pmd.PropertyDescriptorField; float theUIOrder, boolean isDefinedExternally) { super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally); - lowerLimit = lower; - upperLimit = upper; - - checkNumber(lower); - checkNumber(upper); - - if (lower.doubleValue() > upper.doubleValue()) { - throw new IllegalArgumentException("Lower limit cannot be greater than the upper limit"); - } + module = new NumericPropertyModule<>(lower, upper); } - private void checkNumber(T number) { - if (valueErrorFor(number) != null) { - throw new IllegalArgumentException(valueErrorFor(number)); - } - } - - - /** - * Returns a string describing any error the value may have when - * characterized by the receiver. - * - * @param value Object - * - * @return String - */ @Override protected String valueErrorFor(T value) { - - if (value == null) { - return "Missing value"; - } - - double number = value.doubleValue(); - - if (number > upperLimit.doubleValue() || number < lowerLimit.doubleValue()) { - return value + " is out of range " + rangeString(lowerLimit, upperLimit); - } - - return null; + return module.valueErrorFor(value); } - /** - * Returns a string representing the range defined by the two bounds. - * - * @param low Lower bound - * @param up Upper bound - * - * @return String - */ - /* default */ static String rangeString(Number low, Number up) { - return "(" + low + " -> " + up + ")"; - } - - - /** - * Returns the minimum value that instances of the property can have - * - * @return The minimum value - */ @Override public Number lowerLimit() { - return lowerLimit; + return module.getLowerLimit(); } - /** - * Returns the maximum value that instances of the property can have - * - * @return The maximum value. - */ @Override public Number upperLimit() { - return upperLimit; + return module.getUpperLimit(); } @Override protected void addAttributesTo(Map attributes) { super.addAttributesTo(attributes); - attributes.put(MIN, lowerLimit.toString()); - attributes.put(MAX, upperLimit.toString()); + module.addAttributesTo(attributes); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractPackagedProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractPackagedProperty.java index 250122e8b0..f8f5f344f6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractPackagedProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/AbstractPackagedProperty.java @@ -4,16 +4,11 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.PropertyDescriptorField.LEGAL_PACKAGES; - -import java.util.Arrays; import java.util.Map; -import java.util.regex.Pattern; -import net.sourceforge.pmd.AbstractPropertyDescriptorFactory; import net.sourceforge.pmd.PackagedPropertyDescriptor; import net.sourceforge.pmd.PropertyDescriptorField; -import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.lang.rule.properties.modules.PackagedPropertyModule; /** * Property which restricts the type of its values to some packages. If @@ -27,151 +22,49 @@ import net.sourceforge.pmd.util.StringUtil; /* default */ abstract class AbstractPackagedProperty extends AbstractSingleValueProperty implements PackagedPropertyDescriptor { - /** Required keys in the map. */ - protected static final Map PACKAGED_FIELD_TYPES_BY_KEY - = AbstractPropertyDescriptorFactory.expectedFieldTypesWith(new PropertyDescriptorField[] {LEGAL_PACKAGES}, - new Boolean[] {false}); - private static final char PACKAGE_NAME_DELIMITER = ' '; - private static Pattern packageNamePattern = Pattern.compile("(\\w+)(\\.\\w+)*"); - - private String[] legalPackageNames; + protected final PackagedPropertyModule module; /** * Create a packaged property. * - * @param theName Name - * @param theDescription Description - * @param theDefault Default value - * @param theLegalPackageNames Legal package names - * @param theUIOrder UI order + * @param theName Name + * @param theDescription Description + * @param theDefault Default value + * @param theUIOrder UI order + * @param module * * @throws IllegalArgumentException */ protected AbstractPackagedProperty(String theName, String theDescription, T theDefault, - String[] theLegalPackageNames, float theUIOrder, boolean isDefinedExternally) { + float theUIOrder, boolean isDefinedExternally, + PackagedPropertyModule module) { super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally); - - checkValidPackages(theDefault, theLegalPackageNames); - - legalPackageNames = theLegalPackageNames; + this.module = module; } - /** - * Evaluates the names of the items against the allowable name prefixes. If - * one or more do not have valid prefixes then an exception will be thrown. - * - * @param item The item to check - * @param legalNamePrefixes The legal name prefixes - * - * @throws IllegalArgumentException If the item's package is not whitelisted. - */ - private void checkValidPackages(T item, String[] legalNamePrefixes) { - if (item == null) { - return; - } - - String name = packageNameOf(item); - - for (String legalNamePrefixe : legalNamePrefixes) { - if (name.startsWith(legalNamePrefixe)) { - return; - } - } - - throw new IllegalArgumentException("Invalid item: " + item); - } - - - /** - * Returns the package name of the item. - * - * @param item Item - * - * @return Package name of the item - */ - protected abstract String packageNameOf(T item); - - @Override protected void addAttributesTo(Map attributes) { super.addAttributesTo(attributes); - - attributes.put(LEGAL_PACKAGES, delimitedPackageNames()); - } - - - private String delimitedPackageNames() { - - if (legalPackageNames == null || legalPackageNames.length == 0) { - return ""; - } - - if (legalPackageNames.length == 1) { - return legalPackageNames[0]; - } - - StringBuilder sb = new StringBuilder(); - sb.append(legalPackageNames[0]); - for (int i = 1; i < legalPackageNames.length; i++) { - sb.append(PACKAGE_NAME_DELIMITER).append(legalPackageNames[i]); - } - return sb.toString(); + module.addAttributesTo(attributes); } @Override protected String valueErrorFor(T value) { - - if (value == null) { - String err = super.valueErrorFor(null); - if (err != null) { - return err; - } - } - - if (legalPackageNames == null) { - return null; // no restriction - } - - String name = packageNameOf(value); - - for (int i = 0; i < legalPackageNames.length; i++) { - if (name.startsWith(legalPackageNames[i])) { - return null; - } - } - - return "Disallowed " + itemTypeName() + ": " + name; + return module.valueErrorFor(value); } - /** - * Returns the name of the type of item. - * - * @return The name of the type of item - */ - protected abstract String itemTypeName(); - - @Override public String[] legalPackageNames() { - return Arrays.copyOf(legalPackageNames, legalPackageNames.length); // defensive copy + return module.legalPackageNames(); } - protected static String[] packageNamesIn(Map params) { - String[] packageNames = StringUtil.substringsOf(params.get(LEGAL_PACKAGES), - PACKAGE_NAME_DELIMITER); - - for (String name : packageNames) { - if (!packageNamePattern.matcher(name).matches()) { - throw new IllegalArgumentException("One name is not a package: '" + name + "'"); - } - } - - return packageNames; + protected String[] packageNamesIn(Map params) { + return module.packageNamesIn(params); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java index 997855fe29..792d417670 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanMultiProperty.java @@ -12,6 +12,7 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.ValueParser.Companion; /** * Defines a property type that supports multiple Boolean values. @@ -28,7 +29,7 @@ public final class BooleanMultiProperty extends AbstractMultiValueProperty defaultValues, + float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, defaultValues, theUIOrder, isDefinedExternally); + } + + /** * Constructor using a list of defaults. * @@ -61,12 +69,6 @@ public final class BooleanMultiProperty extends AbstractMultiValueProperty defaultValues, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, defaultValues, theUIOrder, isDefinedExternally); - } - - @Override protected Boolean createFrom(String toParse) { return BOOLEAN_PARSER.valueOf(toParse); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanProperty.java index ffbb43a3cd..3520e4918f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/BooleanProperty.java @@ -49,6 +49,12 @@ public final class BooleanProperty extends AbstractSingleValueProperty } + /** Master constructor. */ + private BooleanProperty(String theName, String theDescription, boolean defaultValue, float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally); + } + + /** * Constructor. * @@ -62,10 +68,6 @@ public final class BooleanProperty extends AbstractSingleValueProperty } - private BooleanProperty(String theName, String theDescription, boolean defaultValue, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally); - } - @Override public Class type() { return Boolean.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java index 5b2ef644db..331cfce5f1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterMultiProperty.java @@ -11,6 +11,7 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.ValueParser.Companion; import net.sourceforge.pmd.util.StringUtil; /** @@ -29,7 +30,7 @@ public final class CharacterMultiProperty extends AbstractMultiValueProperty defaultValues, float theUIOrder, char delimiter, boolean isDefinedExternally) { super(theName, theDescription, defaultValues, theUIOrder, delimiter, isDefinedExternally); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterProperty.java index 6c2426acab..ad97abbc85 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/CharacterProperty.java @@ -49,19 +49,7 @@ public final class CharacterProperty extends AbstractSingleValueProperty type() { return Character.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java index f33868ce2c..b6dbb8e1c0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleMultiProperty.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.lang.rule.properties.AbstractNumericProperty.NUMBER_FIELD_TYPES_BY_KEY; import static net.sourceforge.pmd.lang.rule.properties.ValueParser.DOUBLE_PARSER; import java.util.Arrays; @@ -29,7 +28,8 @@ public final class DoubleMultiProperty extends AbstractMultiNumericProperty valuesById, boolean isDefinedExternally) { String[] minMax = minMaxFrom(valuesById); char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); - List defaultValues = parsePrimitives(numericDefaultValueIn(valuesById), delimiter, DOUBLE_PARSER); + List defaultValues = ValueParser.Companion.parsePrimitives(numericDefaultValueIn(valuesById), + delimiter, DOUBLE_PARSER); return new DoubleMultiProperty(nameIn(valuesById), descriptionIn(valuesById), DOUBLE_PARSER.valueOf(minMax[0]), @@ -59,6 +59,13 @@ public final class DoubleMultiProperty extends AbstractMultiNumericProperty defaultValues, float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); + } + + /** * Constructor using a list of defaults. * @@ -76,11 +83,6 @@ public final class DoubleMultiProperty extends AbstractMultiNumericProperty defaultValues, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); - } - @Override public Class type() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleProperty.java index a2650ad8c8..900a83d618 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/DoubleProperty.java @@ -57,6 +57,25 @@ public final class DoubleProperty extends AbstractNumericProperty { } + /** Master constructor. */ + private DoubleProperty(String theName, String theDescription, Double min, Double max, Double theDefault, + float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); + } + + + /** + * Parses a String into a Double. + * + * @param numberString String to parse + * + * @return Parsed Double + */ + public static Double doubleFrom(String numberString) { + return Double.valueOf(numberString); + } + + /** * Constructor that limits itself to a single value within the specified limits. * @@ -75,24 +94,6 @@ public final class DoubleProperty extends AbstractNumericProperty { } - private DoubleProperty(String theName, String theDescription, Double min, Double max, Double theDefault, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); - } - - - /** - * Parses a String into a Double. - * - * @param numberString String to parse - * - * @return Parsed Double - */ - public static Double doubleFrom(String numberString) { - return Double.valueOf(numberString); - } - - @Override public Class type() { return Double.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java index b81b55aeed..f511e94f6e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedMultiProperty.java @@ -64,20 +64,6 @@ public final class EnumeratedMultiProperty extends AbstractMultiValueProperty selection(choiceIndices, theChoices), valueType, theUIOrder, false); } - /** - * Constructor using a map to define the label-value mappings. The default values are specified with a list. - * - * @param theName Name - * @param theDescription Description - * @param choices Map of labels to values - * @param defaultValues List of default values - * @param theUIOrder UI order - */ - public EnumeratedMultiProperty(String theName, String theDescription, Map choices, - List defaultValues, Class valueType, float theUIOrder) { - this(theName, theDescription, choices, defaultValues, valueType, theUIOrder, false); - } - private EnumeratedMultiProperty(String theName, String theDescription, Map choices, List defaultValues, Class valueType, float theUIOrder, @@ -113,6 +99,21 @@ public final class EnumeratedMultiProperty extends AbstractMultiValueProperty } + /** + * Constructor using a map to define the label-value mappings. The default values are specified with a list. + * + * @param theName Name + * @param theDescription Description + * @param choices Map of labels to values + * @param defaultValues List of default values + * @param theUIOrder UI order + */ + public EnumeratedMultiProperty(String theName, String theDescription, Map choices, + List defaultValues, Class valueType, float theUIOrder) { + this(theName, theDescription, choices, defaultValues, valueType, theUIOrder, false); + } + + @Override public Map mappings() { return choicesByLabel; // unmodifiable diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedProperty.java index 70ef645d49..0bfc785d87 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/EnumeratedProperty.java @@ -71,6 +71,16 @@ public final class EnumeratedProperty extends AbstractSingleValueProperty } + private EnumeratedProperty(String theName, String theDescription, Map labelsToChoices, + E defaultValue, Class valueType, float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally); + + this.valueType = valueType; + choicesByLabel = Collections.unmodifiableMap(labelsToChoices); + labelsByChoice = Collections.unmodifiableMap(CollectionUtil.invertedMapFrom(choicesByLabel)); + } + + /** * Constructor using a map to define the label-value mappings. * @@ -86,16 +96,6 @@ public final class EnumeratedProperty extends AbstractSingleValueProperty } - private EnumeratedProperty(String theName, String theDescription, Map labelsToChoices, - E defaultValue, Class valueType, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally); - - this.valueType = valueType; - choicesByLabel = Collections.unmodifiableMap(labelsToChoices); - labelsByChoice = Collections.unmodifiableMap(CollectionUtil.invertedMapFrom(choicesByLabel)); - } - - @Override public Class type() { return valueType; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FileProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FileProperty.java index a1055fdfe5..58527a6a25 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FileProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FileProperty.java @@ -46,10 +46,12 @@ public final class FileProperty extends AbstractSingleValueProperty { } + /** Master constructor. */ private FileProperty(String theName, String theDescription, File theDefault, float theUIOrder, boolean isDefinedExternally) { super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally); } + @Override public Class type() { return File.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java index 6ba7af0bbc..25dc7badfa 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatMultiProperty.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.lang.rule.properties.AbstractNumericProperty.NUMBER_FIELD_TYPES_BY_KEY; import static net.sourceforge.pmd.lang.rule.properties.ValueParser.FLOAT_PARSER; import java.util.Arrays; @@ -13,6 +12,7 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.ValueParser.Companion; /** * Multi-valued float property. @@ -30,7 +30,7 @@ public final class FloatMultiProperty extends AbstractMultiNumericProperty defaultValues = parsePrimitives(numericDefaultValueIn(valuesById), delimiter, FLOAT_PARSER); + List defaultValues = Companion.parsePrimitives(numericDefaultValueIn(valuesById), delimiter, FLOAT_PARSER); return new FloatMultiProperty(nameIn(valuesById), descriptionIn(valuesById), FLOAT_PARSER.valueOf(minMax[0]), @@ -60,6 +60,13 @@ public final class FloatMultiProperty extends AbstractMultiNumericProperty defaultValues, float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); + } + + /** * Constructor using a list of defaults. * @@ -78,12 +85,6 @@ public final class FloatMultiProperty extends AbstractMultiNumericProperty defaultValues, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); - } - - @Override public Class type() { return Float.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatProperty.java index 4240e88138..0861deb897 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/FloatProperty.java @@ -57,6 +57,13 @@ public final class FloatProperty extends AbstractNumericProperty { } + /** Master constructor. */ + private FloatProperty(String theName, String theDescription, Float min, Float max, Float theDefault, + float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); + } + + /** * Constructor that limits itself to a single value within the specified limits. * @@ -75,12 +82,6 @@ public final class FloatProperty extends AbstractNumericProperty { } - private FloatProperty(String theName, String theDescription, Float min, Float max, Float theDefault, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); - } - - @Override public Class type() { return Float.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java index a6ce64db55..1a4e529362 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerMultiProperty.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.lang.rule.properties.AbstractNumericProperty.NUMBER_FIELD_TYPES_BY_KEY; import static net.sourceforge.pmd.lang.rule.properties.ValueParser.INTEGER_PARSER; import java.util.Arrays; @@ -13,6 +12,7 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.ValueParser.Companion; /** * Multi-valued integer property. @@ -30,7 +30,7 @@ public final class IntegerMultiProperty extends AbstractMultiNumericProperty defaultValues = parsePrimitives(numericDefaultValueIn(valuesById), delimiter, INTEGER_PARSER); + List defaultValues = Companion.parsePrimitives(numericDefaultValueIn(valuesById), delimiter, INTEGER_PARSER); return new IntegerMultiProperty(nameIn(valuesById), descriptionIn(valuesById), INTEGER_PARSER.valueOf(minMax[0]), @@ -60,6 +60,14 @@ public final class IntegerMultiProperty extends AbstractMultiNumericProperty defaultValues, float theUIOrder, boolean isDefinedExternally) { + + super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); + } + + /** * Constructor using a list of defaults. * @@ -79,13 +87,6 @@ public final class IntegerMultiProperty extends AbstractMultiNumericProperty defaultValues, float theUIOrder, boolean isDefinedExternally) { - - super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); - } - - @Override public Class type() { return Integer.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerProperty.java index 694349e9d7..35322bcd48 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/IntegerProperty.java @@ -53,8 +53,9 @@ public final class IntegerProperty extends AbstractNumericProperty { } + /** Master constructor. */ private IntegerProperty(String theName, String theDescription, Integer min, Integer max, Integer theDefault, - float theUIOrder, boolean isDefinedExternally) { + float theUIOrder, boolean isDefinedExternally) { super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java index 8eaf0af35d..0611c52ab6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongMultiProperty.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.rule.properties; -import static net.sourceforge.pmd.lang.rule.properties.AbstractNumericProperty.NUMBER_FIELD_TYPES_BY_KEY; import static net.sourceforge.pmd.lang.rule.properties.ValueParser.LONG_PARSER; import java.util.Arrays; @@ -13,6 +12,7 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.ValueParser.Companion; /** * Multi-valued long property. @@ -29,7 +29,7 @@ public final class LongMultiProperty extends AbstractMultiNumericProperty public LongMultiProperty createWith(Map valuesById, boolean isDefinedExternally) { String[] minMax = minMaxFrom(valuesById); char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER); - List defaultValues = parsePrimitives(defaultValueIn(valuesById), delimiter, LONG_PARSER); + List defaultValues = Companion.parsePrimitives(defaultValueIn(valuesById), delimiter, LONG_PARSER); return new LongMultiProperty(nameIn(valuesById), descriptionIn(valuesById), LONG_PARSER.valueOf(minMax[0]), @@ -59,6 +59,13 @@ public final class LongMultiProperty extends AbstractMultiNumericProperty } + /** Master constructor. */ + private LongMultiProperty(String theName, String theDescription, Long min, Long max, + List defaultValues, float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); + } + + /** * Constructor using a list of defaults. * @@ -77,12 +84,6 @@ public final class LongMultiProperty extends AbstractMultiNumericProperty } - private LongMultiProperty(String theName, String theDescription, Long min, Long max, - List defaultValues, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally); - } - - @Override public Class type() { return Long.class; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java index 2683d0c86a..138651c2b3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/LongProperty.java @@ -58,6 +58,13 @@ public final class LongProperty extends AbstractNumericProperty { } + /** Master constructor. */ + private LongProperty(String theName, String theDescription, Long min, Long max, Long theDefault, + float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); + } + + /** * Constructor that limits itself to a single value within the specified limits. * @@ -74,11 +81,6 @@ public final class LongProperty extends AbstractNumericProperty { this(theName, theDescription, min, max, theDefault, theUIOrder, false); } - private LongProperty(String theName, String theDescription, Long min, Long max, Long theDefault, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, min, max, theDefault, theUIOrder, isDefinedExternally); - } - @Override public Class type() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java index 71e01afb9c..a0af6ed34c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodMultiProperty.java @@ -4,15 +4,16 @@ package net.sourceforge.pmd.lang.rule.properties; +import static net.sourceforge.pmd.lang.rule.properties.ValueParser.METHOD_PARSER; + import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; -import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule; /** * Defines a property type that can specify multiple methods to use as part of a @@ -40,6 +41,7 @@ public final class MethodMultiProperty extends AbstractMultiPackagedProperty theDefaults, String[] legalPackageNames, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theDefaults, legalPackageNames, theUIOrder, isDefinedExternally); + super(theName, theDescription, theDefaults, theUIOrder, isDefinedExternally, + new MethodPropertyModule(legalPackageNames, theDefaults)); } @@ -82,47 +86,31 @@ public final class MethodMultiProperty extends AbstractMultiPackagedProperty methodsFrom(String methodsStr) { - String[] values = StringUtil.substringsOf(methodsStr, DELIMITER); - - List methods = new ArrayList<>(values.length); - for (String name : values) { - methods.add(MethodProperty.methodFrom(name, MethodProperty.CLASS_METHOD_DELIMITER, - MethodProperty.METHOD_ARG_DELIMITER)); - } - return methods; + private static List methodsFrom(String valueString) { + return ValueParser.Companion.parsePrimitives(valueString, MULTI_VALUE_DELIMITER, METHOD_PARSER); } @Override public String asString(Method value) { - return value == null ? "" : MethodProperty.asStringFor(value); + return MethodPropertyModule.asString(value); } @Override protected Method createFrom(String toParse) { - return MethodProperty.methodFrom(toParse, MethodProperty.CLASS_METHOD_DELIMITER, - MethodProperty.METHOD_ARG_DELIMITER); - } - - - @Override - protected String packageNameOf(Method item) { - return item.getDeclaringClass().getName() + '.' + item.getName(); - } - - - @Override - protected String itemTypeName() { - return "method"; + return METHOD_PARSER.valueOf(toParse); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodProperty.java index 4f6022e6bb..f2488a1ff2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MethodProperty.java @@ -4,14 +4,16 @@ package net.sourceforge.pmd.lang.rule.properties; -import java.lang.reflect.Array; + +import static net.sourceforge.pmd.lang.rule.properties.ValueParser.METHOD_PARSER; + import java.lang.reflect.Method; +import java.util.Collections; import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; -import net.sourceforge.pmd.util.ClassUtil; -import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule; /** * Defines a property type that can specify a single method to use as part of a @@ -26,10 +28,7 @@ import net.sourceforge.pmd.util.StringUtil; */ public final class MethodProperty extends AbstractPackagedProperty { - - public static final char CLASS_METHOD_DELIMITER = '#'; - public static final char METHOD_ARG_DELIMITER = ','; - public static final char[] METHOD_GROUP_DELIMITERS = {'(', ')'}; + /** Factory. */ public static final PropertyDescriptorFactory FACTORY // @formatter:off = new SingleValuePropertyDescriptorFactory(Method.class, PACKAGED_FIELD_TYPES_BY_KEY) { @Override @@ -37,22 +36,37 @@ public final class MethodProperty extends AbstractPackagedProperty { char delimiter = delimiterIn(valuesById); return new MethodProperty(nameIn(valuesById), descriptionIn(valuesById), - methodFrom(defaultValueIn(valuesById)), + METHOD_PARSER.valueOf(defaultValueIn(valuesById)), legalPackageNamesIn(valuesById, delimiter), 0f, isDefinedExternally); } }; // @formatter:on - private static final String ARRAY_FLAG = "[]"; - private static final Map, String> TYPE_SHORTCUTS = ClassUtil.getClassShortNames(); + /** + * Constructor for MethodProperty. + * + * @param theName Name of the property + * @param theDescription Description + * @param theDefault Default value + * @param legalPackageNames Legal packages + * @param theUIOrder UI order + */ public MethodProperty(String theName, String theDescription, Method theDefault, String[] legalPackageNames, float theUIOrder) { this(theName, theDescription, theDefault, legalPackageNames, theUIOrder, false); } + /** Master constructor. */ + private MethodProperty(String theName, String theDescription, Method theDefault, String[] legalPackageNames, + float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally, + new MethodPropertyModule(legalPackageNames, Collections.singletonList(theDefault))); + } + + /** * Constructor for MethodProperty using a string as a default value. * @@ -61,104 +75,19 @@ public final class MethodProperty extends AbstractPackagedProperty { * @param defaultMethodStr Default value, that will be parsed into a Method object * @param legalPackageNames Legal packages * @param theUIOrder UI order + * + * @deprecated will be removed in 7.0.0 */ public MethodProperty(String theName, String theDescription, String defaultMethodStr, String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, methodFrom(defaultMethodStr), legalPackageNames, theUIOrder, false); + this(theName, theDescription, METHOD_PARSER.valueOf(defaultMethodStr), + legalPackageNames, theUIOrder, false); } - /** - * Constructor for MethodProperty. - * - * @param theName Name of the property - * @param theDescription Description - * @param theDefault Default value - * @param legalPackageNames Legal packages - * @param theUIOrder UI order - */ - private MethodProperty(String theName, String theDescription, Method theDefault, String[] legalPackageNames, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theDefault, legalPackageNames, theUIOrder, isDefinedExternally); - } @Override protected String asString(Method value) { - return value == null ? "" : asStringFor(value); - } - - - /** - * Return the value of `method' as a string that can be easily recognized - * and parsed when we see it again. - * - * @param method the method to convert - * - * @return the string value - */ - public static String asStringFor(Method method) { - StringBuilder sb = new StringBuilder(); - asStringOn(method, sb); - return sb.toString(); - } - - - /** - * Serializes the method signature onto the specified buffer. - * - * @param method Method - * @param sb StringBuilder - */ - public static void asStringOn(Method method, StringBuilder sb) { - - Class clazz = method.getDeclaringClass(); - - sb.append(shortestNameFor(clazz)); - sb.append(CLASS_METHOD_DELIMITER); - sb.append(method.getName()); - - sb.append(METHOD_GROUP_DELIMITERS[0]); - - Class[] argTypes = method.getParameterTypes(); - if (argTypes.length == 0) { - sb.append(METHOD_GROUP_DELIMITERS[1]); - return; - } - - serializedTypeIdOn(argTypes[0], sb); - for (int i = 1; i < argTypes.length; i++) { - sb.append(METHOD_ARG_DELIMITER); - serializedTypeIdOn(argTypes[i], sb); - } - sb.append(METHOD_GROUP_DELIMITERS[1]); - } - - - private static String shortestNameFor(Class cls) { - String compactName = TYPE_SHORTCUTS.get(cls); - return compactName == null ? cls.getName() : compactName; - } - - - private static void serializedTypeIdOn(Class type, StringBuilder sb) { - - Class arrayType = type.getComponentType(); - if (arrayType == null) { - sb.append(shortestNameFor(type)); - return; - } - sb.append(shortestNameFor(arrayType)).append(ARRAY_FLAG); - } - - - @Override - protected String packageNameOf(Method method) { - return method == null ? null : method.getDeclaringClass().getName() + '.' + method.getName(); - } - - - @Override - protected String itemTypeName() { - return "method"; + return MethodPropertyModule.asString(value); } @@ -170,118 +99,8 @@ public final class MethodProperty extends AbstractPackagedProperty { @Override public Method createFrom(String valueString) throws IllegalArgumentException { - return methodFrom(valueString); + return METHOD_PARSER.valueOf(valueString); } - private static Class typeFor(String typeName) { - - Class type; - - if (typeName.endsWith(ARRAY_FLAG)) { - String arrayTypeName = typeName.substring(0, typeName.length() - ARRAY_FLAG.length()); - type = typeFor(arrayTypeName); // recurse - return Array.newInstance(type, 0).getClass(); // TODO is there a - // better way to get - // an array type? - } - - type = ClassUtil.getTypeFor(typeName); // try shortcut first - if (type != null) { - return type; - } - - try { - return Class.forName(typeName); - } catch (Exception ex) { - return null; - } - } - - - /** - * Returns the method specified within the string argument after parsing out - * its source class and any optional arguments. Callers need to specify the - * delimiters expected between the various elements. I.e.: - * - *

"String#isEmpty()" "String#indexOf(int)" "String#substring(int,int)" - * - *

If a method isn't part of the specified class we will walk up any - * superclasses to Object to try and find it. - * - *

If the classes are listed in the ClassUtil class within in Typemaps then - * you likely can avoid specifying fully-qualified class names per the above - * example. - * - *

Returns null if a matching method cannot be found. - * - * @param methodNameAndArgTypes Method name (with its declaring class and arguments) - * @param classMethodDelimiter Delimiter between the class and method names - * @param methodArgDelimiter Method arguments delimiter - * - * @return Method - */ - public static Method methodFrom(String methodNameAndArgTypes, char classMethodDelimiter, char methodArgDelimiter) { - - // classname#methodname(arg1,arg2) - // 0 1 2 - - int delimPos0 = -1; - if (methodNameAndArgTypes != null) { - delimPos0 = methodNameAndArgTypes.indexOf(classMethodDelimiter); - } else { - return null; - } - - if (delimPos0 < 0) { - return null; - } - - String className = methodNameAndArgTypes.substring(0, delimPos0); - Class type = ClassUtil.getTypeFor(className); - if (type == null) { - return null; - } - - int delimPos1 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[0]); - if (delimPos1 < 0) { - String methodName = methodNameAndArgTypes.substring(delimPos0 + 1); - return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY); - } - - String methodName = methodNameAndArgTypes.substring(delimPos0 + 1, delimPos1); - if (StringUtil.isEmpty(methodName)) { - return null; - } // missing method name? - - int delimPos2 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[1]); - if (delimPos2 < 0) { - return null; - } // error! - - String argTypesStr = methodNameAndArgTypes.substring(delimPos1 + 1, delimPos2); - if (StringUtil.isEmpty(argTypesStr)) { - return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY); - } // no arg(s) - - String[] argTypeNames = StringUtil.substringsOf(argTypesStr, methodArgDelimiter); - Class[] argTypes = new Class[argTypeNames.length]; - for (int i = 0; i < argTypes.length; i++) { - argTypes[i] = typeFor(argTypeNames[i]); - } - - return ClassUtil.methodFor(type, methodName, argTypes); - } - - - /** - * Parses a String into a Method. - * - * @param methodStr String to parse - * - * @return Parsed Method - */ - public static Method methodFrom(String methodStr) { - return methodFrom(methodStr, CLASS_METHOD_DELIMITER, METHOD_ARG_DELIMITER); - } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MultiValuePropertyDescriptorFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MultiValuePropertyDescriptorFactory.java index e256ae0ad7..03c85b24b7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MultiValuePropertyDescriptorFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/MultiValuePropertyDescriptorFactory.java @@ -34,7 +34,7 @@ public abstract class MultiValuePropertyDescriptorFactory extends AbstractPro @Override protected abstract MultiValuePropertyDescriptor createWith(Map valuesById, - boolean isDefinedExternally); + boolean isDefinedExternally); @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorUtil.java index fa3e9c8ae4..43e1514332 100755 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/PropertyDescriptorUtil.java @@ -11,9 +11,12 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; /** + * Utility class allowing to find the factory of a specific type of descriptor. That's used to define descriptors in + * the xml, eg for xpath rules. + * * @author Brian Remedios */ -public class PropertyDescriptorUtil { +public final class PropertyDescriptorUtil { private static final Map> DESCRIPTOR_FACTORIES_BY_TYPE; @@ -38,8 +41,8 @@ public class PropertyDescriptorUtil { temp.put("Double", DoubleProperty.FACTORY); temp.put("List", DoubleMultiProperty.FACTORY); - // temp.put("Enum", EnumeratedProperty.FACTORY); - // temp.put("List", EnumeratedMultiProperty.FACTORY); + // temp.put("Enum", EnumeratedProperty.FACTORY); // TODO:cf implement that + // temp.put("List", EnumeratedMultiProperty.FACTORY); temp.put("Class", TypeProperty.FACTORY); temp.put("List", TypeMultiProperty.FACTORY); @@ -55,14 +58,28 @@ public class PropertyDescriptorUtil { private PropertyDescriptorUtil() { } + /** + * Gets the factory for the descriptor identified by the string id. + * + * @param typeId The identifier of the type + * + * @return The factory used to build new instances of a descriptor + */ public static PropertyDescriptorFactory factoryFor(String typeId) { return DESCRIPTOR_FACTORIES_BY_TYPE.get(typeId); } + /** + * Gets the string representation of this type, as it should be given when defining a descriptor in the xml. + * + * @param valueType The type to look for + * @param multiValue Whether the descriptor is multivalued or not + * + * @return The type id + */ public static String typeIdFor(Class valueType, boolean multiValue) { - // a reverse lookup, not very efficient but fine for now for (Map.Entry> entry : DESCRIPTOR_FACTORIES_BY_TYPE.entrySet()) { if (entry.getValue().valueType() == valueType && entry.getValue().isMultiValue() == multiValue) { return entry.getKey(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/SingleValuePropertyDescriptorFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/SingleValuePropertyDescriptorFactory.java index c04b829170..92935f2df1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/SingleValuePropertyDescriptorFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/SingleValuePropertyDescriptorFactory.java @@ -20,13 +20,13 @@ import net.sourceforge.pmd.SingleValuePropertyDescriptor; */ public abstract class SingleValuePropertyDescriptorFactory extends AbstractPropertyDescriptorFactory { - public SingleValuePropertyDescriptorFactory(Class theValueType) { + /* default */ SingleValuePropertyDescriptorFactory(Class theValueType) { super(theValueType); } - public SingleValuePropertyDescriptorFactory(Class theValueType, - Map additionalFieldTypesByKey) { + /* default */ SingleValuePropertyDescriptorFactory(Class theValueType, + Map additionalFieldTypesByKey) { super(theValueType, additionalFieldTypesByKey); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java index e1eb927dff..e07406ce1e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringMultiProperty.java @@ -12,6 +12,7 @@ import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.lang.rule.properties.ValueParser.Companion; import net.sourceforge.pmd.util.StringUtil; /** @@ -31,7 +32,7 @@ public final class StringMultiProperty extends AbstractMultiValueProperty defaultValues, float theUIOrder, char delimiter, boolean isDefinedExternally) { super(theName, theDescription, defaultValues, theUIOrder, delimiter, isDefinedExternally); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringProperty.java index 58f94d757c..83a9fe91ca 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/StringProperty.java @@ -44,6 +44,7 @@ public final class StringProperty extends AbstractSingleValueProperty { } + /** Master constructor. */ private StringProperty(String theName, String theDescription, String defaultValue, float theUIOrder, boolean isDefinedExternally) { super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java index 7db4f1be85..8b913c42c4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/TypeMultiProperty.java @@ -4,13 +4,12 @@ package net.sourceforge.pmd.lang.rule.properties; -import java.util.ArrayList; import java.util.List; import java.util.Map; import net.sourceforge.pmd.PropertyDescriptorFactory; import net.sourceforge.pmd.PropertyDescriptorField; -import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.lang.rule.properties.modules.TypePropertyModule; /** * Defines a property that supports multiple class types, even for primitive @@ -55,6 +54,14 @@ public final class TypeMultiProperty extends AbstractMultiPackagedProperty theTypeDefaults, + String[] legalPackageNames, float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, theTypeDefaults, theUIOrder, isDefinedExternally, + new TypePropertyModule(legalPackageNames, theTypeDefaults)); + } + + /** * Constructor for TypeProperty. * @@ -68,37 +75,15 @@ public final class TypeMultiProperty extends AbstractMultiPackagedProperty theTypeDefaults, - String[] legalPackageNames, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theTypeDefaults, legalPackageNames, theUIOrder, isDefinedExternally); - } - - /** - * Returns a list of Class objects parsed from the input string. - * - * @param classesStr String to parse - * - * @return A list of class objects - */ - private static List typesFrom(String classesStr) { - String[] values = StringUtil.substringsOf(classesStr, DELIMITER); - - List classes = new ArrayList<>(values.length); - for (int i = 0; i < values.length; i++) { - classes.add(TypeProperty.classFrom(values[i])); - } - return classes; - } - - - @Override - protected String packageNameOf(Class item) { - return ((Class) item).getName(); + private static List typesFrom(String valueString) { + return ValueParser.Companion.parsePrimitives(valueString, MULTI_VALUE_DELIMITER, ValueParser.CLASS_PARSER); } @@ -108,12 +93,6 @@ public final class TypeMultiProperty extends AbstractMultiPackagedProperty { char delimiter = delimiterIn(valuesById); return new TypeProperty(nameIn(valuesById), descriptionIn(valuesById), - classFrom(defaultValueIn(valuesById)), + ValueParser.CLASS_PARSER.valueOf(defaultValueIn(valuesById)), legalPackageNamesIn(valuesById, delimiter), 0f, isDefinedExternally); @@ -51,7 +51,15 @@ public final class TypeProperty extends AbstractPackagedProperty { */ public TypeProperty(String theName, String theDescription, String defaultTypeStr, String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, classFrom(defaultTypeStr), legalPackageNames, theUIOrder, false); + this(theName, theDescription, ValueParser.CLASS_PARSER.valueOf(defaultTypeStr), legalPackageNames, theUIOrder, false); + } + + + /** Master constructor. */ + private TypeProperty(String theName, String theDescription, Class theDefault, String[] legalPackageNames, + float theUIOrder, boolean isDefinedExternally) { + super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally, + new TypePropertyModule(legalPackageNames, Collections.singletonList(theDefault))); } @@ -63,7 +71,6 @@ public final class TypeProperty extends AbstractPackagedProperty { * @param theDefault Class * @param legalPackageNames String[] * @param theUIOrder float - * */ public TypeProperty(String theName, String theDescription, Class theDefault, String[] legalPackageNames, float theUIOrder) { @@ -71,59 +78,12 @@ public final class TypeProperty extends AbstractPackagedProperty { } - private TypeProperty(String theName, String theDescription, Class theDefault, String[] legalPackageNames, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theDefault, legalPackageNames, theUIOrder, isDefinedExternally); - } - - - static Class classFrom(String className) { - if (StringUtil.isEmpty(className)) { - return null; - } - - Class cls = ClassUtil.getTypeFor(className); - if (cls != null) { - return cls; - } - - try { - return Class.forName(className); - } catch (Exception ex) { - throw new IllegalArgumentException(className); - } - } - - - /** - * Deprecated constructor. - * - * @deprecated - */ - public TypeProperty(String theName, String theDescription, String defaultTypeStr, Map otherParams, - float theUIOrder) { - this(theName, theDescription, classFrom(defaultTypeStr), packageNamesIn(otherParams), theUIOrder); - } - - - @Override - protected String packageNameOf(Class item) { - return item.getName(); - } - - @Override public Class type() { return Class.class; } - @Override - protected String itemTypeName() { - return "type"; - } - - @Override protected String asString(Class value) { return value == null ? "" : value.getName(); @@ -132,6 +92,6 @@ public final class TypeProperty extends AbstractPackagedProperty { @Override public Class createFrom(String valueString) { - return classFrom(valueString); + return ValueParser.CLASS_PARSER.valueOf(valueString); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/ValueParser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/ValueParser.java index d66f9370e4..ce7d633a54 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/ValueParser.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/ValueParser.java @@ -4,6 +4,19 @@ package net.sourceforge.pmd.lang.rule.properties; +import static net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule.ARRAY_FLAG; +import static net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule.CLASS_METHOD_DELIMITER; +import static net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule.METHOD_ARG_DELIMITER; +import static net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule.METHOD_GROUP_DELIMITERS; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.util.ClassUtil; +import net.sourceforge.pmd.util.StringUtil; + /** * Parses a value from a string. * @@ -12,7 +25,6 @@ package net.sourceforge.pmd.lang.rule.properties; // FUTURE @FunctionalInterface public interface ValueParser { - /** Extracts characters. */ ValueParser CHARACTER_PARSER = new ValueParser() { @Override @@ -24,7 +36,6 @@ public interface ValueParser { } }; - /** Extracts strings. That's a dummy used to return a list in StringMultiProperty. */ ValueParser STRING_PARSER = new ValueParser() { @Override @@ -33,7 +44,6 @@ public interface ValueParser { } }; - // FUTURE Integer::valueOf /** Extracts integers. */ ValueParser INTEGER_PARSER = new ValueParser() { @Override @@ -42,7 +52,7 @@ public interface ValueParser { } }; - // FUTURE Boolean::valueOf + // FUTURE Integer::valueOf /** Extracts booleans. */ ValueParser BOOLEAN_PARSER = new ValueParser() { @Override @@ -51,7 +61,7 @@ public interface ValueParser { } }; - // FUTURE Float::valueOf + // FUTURE Boolean::valueOf /** Extracts floats. */ ValueParser FLOAT_PARSER = new ValueParser() { @Override @@ -60,7 +70,7 @@ public interface ValueParser { } }; - // FUTURE Long::valueOf + // FUTURE Float::valueOf /** Extracts longs. */ ValueParser LONG_PARSER = new ValueParser() { @Override @@ -69,7 +79,7 @@ public interface ValueParser { } }; - // FUTURE Double::valueOf + // FUTURE Long::valueOf /** Extracts doubles. */ ValueParser DOUBLE_PARSER = new ValueParser() { @Override @@ -78,6 +88,137 @@ public interface ValueParser { } }; + /** Extract classes. */ + ValueParser CLASS_PARSER = new ValueParser() { + @Override + public Class valueOf(String value) throws IllegalArgumentException { + if (StringUtil.isEmpty(value)) { + return null; + } + + Class cls = ClassUtil.getTypeFor(value); + if (cls != null) { + return cls; + } + + try { + return Class.forName(value); + } catch (Exception ex) { + throw new IllegalArgumentException(value); + } + } + }; + + + /** Extracts methods. */ + ValueParser METHOD_PARSER = new ValueParser() { + @Override + public Method valueOf(String value) throws IllegalArgumentException { + return methodFrom(value, CLASS_METHOD_DELIMITER, METHOD_ARG_DELIMITER); + } + + + /** + * Returns the method specified within the string argument after parsing out + * its source class and any optional arguments. Callers need to specify the + * delimiters expected between the various elements. I.e.: + * + *

"String#isEmpty()" "String#indexOf(int)" "String#substring(int,int)" + * + *

If a method isn't part of the specified class we will walk up any + * superclasses to Object to try and find it. + * + *

If the classes are listed in the ClassUtil class within in Typemaps then + * you likely can avoid specifying fully-qualified class names per the above + * example. + * + *

Returns null if a matching method cannot be found. + * + * @param methodNameAndArgTypes Method name (with its declaring class and arguments) + * @param classMethodDelimiter Delimiter between the class and method names + * @param methodArgDelimiter Method arguments delimiter + * + * @return Method + */ + public Method methodFrom(String methodNameAndArgTypes, char classMethodDelimiter, char methodArgDelimiter) { + + // classname#methodname(arg1,arg2) + // 0 1 2 + + int delimPos0 = -1; + if (methodNameAndArgTypes != null) { + delimPos0 = methodNameAndArgTypes.indexOf(classMethodDelimiter); + } else { + return null; + } + + if (delimPos0 < 0) { + return null; + } + + String className = methodNameAndArgTypes.substring(0, delimPos0); + Class type = ClassUtil.getTypeFor(className); + if (type == null) { + return null; + } + + int delimPos1 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[0]); + if (delimPos1 < 0) { + String methodName = methodNameAndArgTypes.substring(delimPos0 + 1); + return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY); + } + + String methodName = methodNameAndArgTypes.substring(delimPos0 + 1, delimPos1); + if (StringUtil.isEmpty(methodName)) { + return null; + } // missing method name? + + int delimPos2 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[1]); + if (delimPos2 < 0) { + return null; + } // error! + + String argTypesStr = methodNameAndArgTypes.substring(delimPos1 + 1, delimPos2); + if (StringUtil.isEmpty(argTypesStr)) { + return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY); + } // no arg(s) + + String[] argTypeNames = StringUtil.substringsOf(argTypesStr, methodArgDelimiter); + Class[] argTypes = new Class[argTypeNames.length]; + for (int i = 0; i < argTypes.length; i++) { + argTypes[i] = typeFor(argTypeNames[i]); + } + + return ClassUtil.methodFor(type, methodName, argTypes); + } + + + private Class typeFor(String typeName) { + + Class type; + + if (typeName.endsWith(ARRAY_FLAG)) { + String arrayTypeName = typeName.substring(0, typeName.length() - ARRAY_FLAG.length()); + type = typeFor(arrayTypeName); // recurse + return Array.newInstance(type, 0).getClass(); // TODO is there a + // better way to get + // an array type? + } + + type = ClassUtil.getTypeFor(typeName); // try shortcut first + if (type != null) { + return type; + } + + try { + return Class.forName(typeName); + } catch (Exception ex) { + return null; + } + } + + }; + /** * Extracts a primitive from a string. @@ -90,4 +231,33 @@ public interface ValueParser { */ U valueOf(String value) throws IllegalArgumentException; + + /** Companion object. */ + class Companion { + + private Companion() { + + } + + + /** + * Parses a string into a list of values of type {@literal }. + * + * @param toParse The string to parse + * @param delimiter The delimiter to use + * @param extractor The function mapping a string to an instance of {@code } + * @param The type of the values to parse + * + * @return A list of values + */ + public static List parsePrimitives(String toParse, char delimiter, ValueParser extractor) { + String[] values = StringUtil.substringsOf(toParse, delimiter); + List result = new ArrayList<>(); + for (String s : values) { + result.add(extractor.valueOf(s)); + } + return result; + } + } + } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/MethodPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/MethodPropertyModule.java new file mode 100644 index 0000000000..5df4007eb8 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/MethodPropertyModule.java @@ -0,0 +1,110 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties.modules; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +import net.sourceforge.pmd.util.ClassUtil; + +/** + * @author Clément Fournier + */ +public class MethodPropertyModule extends PackagedPropertyModule { + + public static final char CLASS_METHOD_DELIMITER = '#'; + public static final char METHOD_ARG_DELIMITER = ','; + public static final char[] METHOD_GROUP_DELIMITERS = {'(', ')'}; + public static final String ARRAY_FLAG = "[]"; + private static final Map, String> TYPE_SHORTCUTS = ClassUtil.getClassShortNames(); + + + public MethodPropertyModule(String[] legalPackageNames, List defaults) { + super(legalPackageNames, defaults); + } + + + @Override + protected String packageNameOf(Method method) { + return method == null ? null : method.getDeclaringClass().getName() + '.' + method.getName(); + } + + + @Override + protected String itemTypeName() { + return "method"; + } + + + public static String asString(Method method) { + return method == null ? "" : asStringFor(method); + } + + + /** + * Return the value of `method' as a string that can be easily recognized + * and parsed when we see it again. + * + * @param method the method to convert + * + * @return the string value + */ + private static String asStringFor(Method method) { // TODO:cf we could replace that with a QualifiedName's toString + StringBuilder sb = new StringBuilder(); // once it can parse Class and Method + asStringOn(method, sb); + return sb.toString(); + } + + + /** + * Serializes the method signature onto the specified buffer. + * + * @param method Method + * @param sb StringBuilder + */ + private static void asStringOn(Method method, StringBuilder sb) { + + Class clazz = method.getDeclaringClass(); + + sb.append(shortestNameFor(clazz)); + sb.append(CLASS_METHOD_DELIMITER); + sb.append(method.getName()); + + sb.append(METHOD_GROUP_DELIMITERS[0]); + + Class[] argTypes = method.getParameterTypes(); + if (argTypes.length == 0) { + sb.append(METHOD_GROUP_DELIMITERS[1]); + return; + } + + serializedTypeIdOn(argTypes[0], sb); + for (int i = 1; i < argTypes.length; i++) { + sb.append(METHOD_ARG_DELIMITER); + serializedTypeIdOn(argTypes[i], sb); + } + sb.append(METHOD_GROUP_DELIMITERS[1]); + } + + + private static String shortestNameFor(Class cls) { + String compactName = TYPE_SHORTCUTS.get(cls); + return compactName == null ? cls.getName() : compactName; + } + + + private static void serializedTypeIdOn(Class type, StringBuilder sb) { + + Class arrayType = type.getComponentType(); + if (arrayType == null) { + sb.append(shortestNameFor(type)); + return; + } + sb.append(shortestNameFor(arrayType)).append(ARRAY_FLAG); + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/NumericPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/NumericPropertyModule.java new file mode 100644 index 0000000000..e8555cd2ba --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/NumericPropertyModule.java @@ -0,0 +1,93 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties.modules; + +import static net.sourceforge.pmd.PropertyDescriptorField.MAX; +import static net.sourceforge.pmd.PropertyDescriptorField.MIN; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptorField; + +/** + * Common utilities for implementations of numeric property descriptors. + * + * @author Clément Fournier + */ +public class NumericPropertyModule { + + private final T lowerLimit; + private final T upperLimit; + + + public NumericPropertyModule(T lowerLimit, T upperLimit) { + this.lowerLimit = lowerLimit; + this.upperLimit = upperLimit; + + checkNumber(lowerLimit); + checkNumber(upperLimit); + + if (lowerLimit.doubleValue() > upperLimit.doubleValue()) { + throw new IllegalArgumentException("Lower limit cannot be greater than the upper limit"); + } + + + } + + + private void checkNumber(T number) { + String error = valueErrorFor(number); + if (error != null) { + throw new IllegalArgumentException(error); + } + } + + + public String valueErrorFor(T value) { + + if (value == null) { + return "Missing value"; + } + + double number = value.doubleValue(); + + if (number > upperLimit.doubleValue() || number < lowerLimit.doubleValue()) { + return value + " is out of range " + rangeString(lowerLimit, upperLimit); + } + + return null; + } + + + /** + * Returns a string representing the range defined by the two bounds. + * + * @param low Lower bound + * @param up Upper bound + * + * @return String + */ + private static String rangeString(Number low, Number up) { + return "(" + low + " -> " + up + ")"; + } + + + public T getLowerLimit() { + return lowerLimit; + } + + + public T getUpperLimit() { + return upperLimit; + } + + + public void addAttributesTo(Map attributes) { + attributes.put(MIN, lowerLimit.toString()); + attributes.put(MAX, upperLimit.toString()); + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/PackagedPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/PackagedPropertyModule.java new file mode 100644 index 0000000000..5e36bc8202 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/PackagedPropertyModule.java @@ -0,0 +1,155 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties.modules; + +import static net.sourceforge.pmd.PackagedPropertyDescriptor.PACKAGE_NAME_DELIMITER; +import static net.sourceforge.pmd.PropertyDescriptorField.LEGAL_PACKAGES; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import net.sourceforge.pmd.PropertyDescriptorField; +import net.sourceforge.pmd.util.StringUtil; + +/** + * @author Clément Fournier + */ +public abstract class PackagedPropertyModule { + + private static final Pattern PACKAGE_NAME_PATTERN = Pattern.compile("(\\w+)(\\.\\w+)*"); + + private final String[] legalPackageNames; + + + public PackagedPropertyModule(String[] legalPackageNames, List defaults) { + + checkValidPackages(defaults, legalPackageNames); + + this.legalPackageNames = legalPackageNames; + } + + + /** + * Evaluates the names of the items against the allowable name prefixes. If + * one or more do not have valid prefixes then an exception will be thrown. + * + * @param items Items to check + * @param legalNamePrefixes Legal name prefixes + * + * @throws IllegalArgumentException if some items are not allowed + */ + private void checkValidPackages(List items, String[] legalNamePrefixes) { + + if (legalNamePrefixes == null) { + return; + } + + Set nameSet = new HashSet<>(); + + for (T item : items) { + nameSet.add(packageNameOf(item)); + } + + Set notAllowed = new HashSet<>(nameSet); + + + for (String name : nameSet) { + for (String prefix : legalNamePrefixes) { + if (name.startsWith(prefix)) { + notAllowed.remove(name); + break; + } + } + } + + if (notAllowed.isEmpty()) { + return; + } + + throw new IllegalArgumentException("Invalid items: " + notAllowed); + } + + + /** + * Returns the package name of the item. + * + * @param item Item + * + * @return Package name of the item + */ + protected abstract String packageNameOf(T item); + + + public String valueErrorFor(T value) { + + if (legalPackageNames == null) { + return null; // no restriction + } + + String name = packageNameOf(value); + + for (int i = 0; i < legalPackageNames.length; i++) { + if (name.startsWith(legalPackageNames[i])) { + return null; + } + } + + return "Disallowed " + itemTypeName() + ": " + name; + } + + + /** + * Returns the name of the type of item. + * + * @return The name of the type of item + */ + protected abstract String itemTypeName(); + + + public String[] legalPackageNames() { + return Arrays.copyOf(legalPackageNames, legalPackageNames.length); + } + + + public void addAttributesTo(Map attributes) { + attributes.put(LEGAL_PACKAGES, delimitedPackageNames()); + } + + + private String delimitedPackageNames() { + + if (legalPackageNames == null || legalPackageNames.length == 0) { + return ""; + } + if (legalPackageNames.length == 1) { + return legalPackageNames[0]; + } + + StringBuilder sb = new StringBuilder(); + sb.append(legalPackageNames[0]); + for (int i = 1; i < legalPackageNames.length; i++) { + sb.append(PACKAGE_NAME_DELIMITER).append(legalPackageNames[i]); + } + return sb.toString(); + } + + + public String[] packageNamesIn(Map params) { + String[] packageNames = StringUtil.substringsOf(params.get(LEGAL_PACKAGES), PACKAGE_NAME_DELIMITER); + + for (String name : packageNames) { + if (!PACKAGE_NAME_PATTERN.matcher(name).matches()) { + throw new IllegalArgumentException("One name is not a package: '" + name + "'"); + } + } + + return packageNames; + } + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/TypePropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/TypePropertyModule.java new file mode 100644 index 0000000000..232a20635a --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/properties/modules/TypePropertyModule.java @@ -0,0 +1,30 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.properties.modules; + +import java.util.List; + +/** + * @author Clément Fournier + */ +public class TypePropertyModule extends PackagedPropertyModule { + + public TypePropertyModule(String[] legalPackageNames, List defaults) { + super(legalPackageNames, defaults); + } + + + @Override + protected String packageNameOf(Class item) { + return item.getName(); + } + + + @Override + protected String itemTypeName() { + return "type"; + } + +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java index de20923523..600f739169 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java @@ -251,12 +251,14 @@ public abstract class AbstractPropertyDescriptorTester { return res; } + @Test public void testIsMultiValue() { assertFalse(createProperty().isMultiValue()); assertTrue(createMultiProperty().isMultiValue()); } + @Test public void testAddAttributes() { Map atts = createProperty().attributeValuesById(); @@ -273,8 +275,6 @@ public abstract class AbstractPropertyDescriptorTester { } - - @Test public void testType() { assertNotNull(createMultiProperty().type()); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java index 69652d3066..c8a65a4db7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java @@ -27,39 +27,46 @@ public class BooleanPropertyTest extends AbstractPropertyDescriptorTester 0 ? Boolean.TRUE : Boolean.FALSE; } + @Override @Test public void testErrorForBadSingle() { // override, cannot create a 'bad' boolean per se } + @Override @Test public void testErrorForBadMulti() { // override, cannot create a 'bad' boolean per se } + @Override protected Boolean createBadValue() { return null; } + @Override protected PropertyDescriptor createProperty() { return new BooleanProperty("testBoolean", "Test boolean property", false, 1.0f); } + @Override protected PropertyDescriptor> createMultiProperty() { return new BooleanMultiProperty("testBoolean", "Test boolean property", new Boolean[] {false, true, true}, 1.0f); } + @Override protected PropertyDescriptor> createBadMultiProperty() { return new BooleanMultiProperty("", "Test boolean property", new Boolean[] {false, true, true}, 1.0f); } + @Override protected PropertyDescriptor createBadProperty() { return new BooleanProperty("testBoolean", "", false, 1.0f); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/CharacterPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/CharacterPropertyTest.java index 57e36fe616..fa4c4bd34d 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/CharacterPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/CharacterPropertyTest.java @@ -24,6 +24,7 @@ public class CharacterPropertyTest extends AbstractPropertyDescriptorTester createProperty() { return new CharacterProperty("testCharacter", "Test character property", 'a', 1.0f); } + @Override protected PropertyDescriptor> createMultiProperty() { return new CharacterMultiProperty("testCharacter", "Test character property", - new Character[] { 'a', 'b', 'c' }, 1.0f, DELIMITER); + new Character[] {'a', 'b', 'c'}, 1.0f, DELIMITER); } + @Override protected PropertyDescriptor createBadProperty() { return new CharacterProperty("", "Test character property", 'a', 1.0f); } + @Override protected PropertyDescriptor> createBadMultiProperty() { return new CharacterMultiProperty("testCharacter", "Test character property", - new Character[] { 'a', 'b', 'c' }, 1.0f, DELIMITER); + new Character[] {'a', 'b', 'c'}, 1.0f, DELIMITER); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java index 91de40b395..024954bbea 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java @@ -24,6 +24,7 @@ public class DoublePropertyTest extends AbstractNumericPropertyDescriptorTester< private static final double MAX = 100.0; private static final double SHIFT = 5.0; + public DoublePropertyTest() { super("Double"); } @@ -34,28 +35,33 @@ public class DoublePropertyTest extends AbstractNumericPropertyDescriptorTester< return randomDouble(MIN, MAX); } + @Override protected Double createBadValue() { return randomBool() ? randomDouble(MIN - SHIFT, MIN - 0.01) : randomDouble(MAX + 0.01, MAX + SHIFT); } + @Override protected PropertyDescriptor createProperty() { return new DoubleProperty("testDouble", "Test double property", MIN, MAX, 9.0, 1.0f); } + @Override protected PropertyDescriptor> createMultiProperty() { return new DoubleMultiProperty("testDouble", "Test double property", MIN, MAX, new Double[] {-1d, 0d, 1d, 2d}, 1.0f); } + @Override protected PropertyDescriptor createBadProperty() { return new DoubleProperty("testDouble", "Test double property", MAX, MIN, 9.0, 1.0f); } + @Override protected PropertyDescriptor> createBadMultiProperty() { return new DoubleMultiProperty("testDouble", "Test double property", MIN, MAX, diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java index 137be50b4b..879c8fcb6a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java @@ -24,10 +24,50 @@ public class FloatPropertyTest extends AbstractPropertyDescriptorTester { private static final float MAX = 11.0f; private static final float SHIFT = 3.0f; + public FloatPropertyTest() { super("Float"); } + + @Override + protected Float createValue() { + return randomFloat(MIN, MAX); + } + + + @Override + protected Float createBadValue() { + return randomBool() ? randomFloat(MIN - SHIFT, MIN) : randomFloat(MAX, MAX + SHIFT); + } + + + @Override + protected PropertyDescriptor createProperty() { + return new FloatProperty("testFloat", "Test float property", MIN, MAX, 9.0f, 1.0f); + } + + + @Override + protected PropertyDescriptor> createMultiProperty() { + return new FloatMultiProperty("testFloat", "Test float property", MIN, MAX, + new Float[] {-1f, 0f, 1f, 2f}, 1.0f); + } + + + @Override + protected PropertyDescriptor createBadProperty() { + return new FloatProperty("testFloat", "Test float property", 5f, 4f, 9.0f, 1.0f); + } + + + @Override + protected PropertyDescriptor> createBadMultiProperty() { + return new FloatMultiProperty("testFloat", "Test float property", 0f, 5f, + new Float[] {-1f, 0f, 1f, 2f}, 1.0f); + } + + public static FloatProperty randomProperty(int nameLength, int descLength, boolean multiValue) { float defalt = randomFloat(0, 1000f); @@ -35,36 +75,4 @@ public class FloatPropertyTest extends AbstractPropertyDescriptorTester { return new FloatProperty(randomString(nameLength), randomString(descLength), defalt - 1000f, defalt + 1000, defalt, 0f); } - - @Override - protected Float createValue() { - return randomFloat(MIN, MAX); - } - - @Override - protected Float createBadValue() { - return randomBool() ? randomFloat(MIN - SHIFT, MIN) : randomFloat(MAX, MAX + SHIFT); - } - - @Override - protected PropertyDescriptor createProperty() { - return new FloatProperty("testFloat", "Test float property", MIN, MAX, 9.0f, 1.0f); - } - - @Override - protected PropertyDescriptor> createMultiProperty() { - return new FloatMultiProperty("testFloat", "Test float property", MIN, MAX, - new Float[] {-1f, 0f, 1f, 2f}, 1.0f); - } - - @Override - protected PropertyDescriptor createBadProperty() { - return new FloatProperty("testFloat", "Test float property", 5f, 4f, 9.0f, 1.0f); - } - - @Override - protected PropertyDescriptor> createBadMultiProperty() { - return new FloatMultiProperty("testFloat", "Test float property", 0f, 5f, - new Float[] {-1f, 0f, 1f, 2f}, 1.0f); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java index 9b5e3652ba..d4cada806c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java @@ -16,6 +16,8 @@ import org.junit.Test; import net.sourceforge.pmd.PropertyDescriptor; import net.sourceforge.pmd.lang.rule.properties.MethodMultiProperty; import net.sourceforge.pmd.lang.rule.properties.MethodProperty; +import net.sourceforge.pmd.lang.rule.properties.ValueParser; +import net.sourceforge.pmd.lang.rule.properties.modules.MethodPropertyModule; import net.sourceforge.pmd.util.ClassUtil; /** @@ -37,69 +39,76 @@ public class MethodPropertyTest extends AbstractPropertyDescriptorTester "java.lang.String#substring(int,int)", "Integer#parseInt(String)", "java.util.HashMap#put(Object,Object)", "HashMap#containsKey(Object)", }; + public MethodPropertyTest() { super("Method"); } + @Test public void testAsStringOn() { Method method = null; for (int i = 0; i < METHOD_SIGNATURES.length; i++) { - method = MethodProperty.methodFrom(METHOD_SIGNATURES[i], MethodProperty.CLASS_METHOD_DELIMITER, - MethodProperty.METHOD_ARG_DELIMITER); + method = ValueParser.METHOD_PARSER.valueOf(METHOD_SIGNATURES[i]); assertNotNull("Unable to identify method: " + METHOD_SIGNATURES[i], method); } } + @Test public void testAsMethodOn() { Method[] methods = new Method[METHOD_SIGNATURES.length]; for (int i = 0; i < METHOD_SIGNATURES.length; i++) { - methods[i] = MethodProperty.methodFrom(METHOD_SIGNATURES[i], MethodProperty.CLASS_METHOD_DELIMITER, - MethodProperty.METHOD_ARG_DELIMITER); + methods[i] = ValueParser.METHOD_PARSER.valueOf(METHOD_SIGNATURES[i]); assertNotNull("Unable to identify method: " + METHOD_SIGNATURES[i], methods[i]); } String translatedMethod = null; for (int i = 0; i < methods.length; i++) { - translatedMethod = MethodProperty.asStringFor(methods[i]); + translatedMethod = MethodPropertyModule.asString(methods[i]); assertTrue("Translated method does not match", ClassUtil.withoutPackageName(METHOD_SIGNATURES[i]) .equals(ClassUtil.withoutPackageName(translatedMethod))); } } + @Override protected Method createValue() { return randomChoice(ALL_METHODS); } + @Override protected Method createBadValue() { return randomChoice(HashMap.class.getDeclaredMethods()); } + @Override protected PropertyDescriptor createProperty() { return new MethodProperty("methodProperty", "asdf", ALL_METHODS[1], new String[] {"java.lang", "org.apache"}, 1.0f); } + @Override protected PropertyDescriptor> createMultiProperty() { return new MethodMultiProperty("methodProperty", "asdf", new Method[] {ALL_METHODS[2], ALL_METHODS[3]}, new String[] {"java.lang"}, 1.0f); } + @Override protected PropertyDescriptor createBadProperty() { return new MethodProperty("methodProperty", "asdf", ALL_METHODS[1], new String[] {"java.util"}, 1.0f); } + @Override protected PropertyDescriptor> createBadMultiProperty() { return new MethodMultiProperty("methodProperty", "asdf", new Method[] {ALL_METHODS[2], ALL_METHODS[3]}, diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyAccessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyAccessorTest.java index 338e37eaf4..624a27f926 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyAccessorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyAccessorTest.java @@ -25,11 +25,13 @@ public class PropertyAccessorTest { private Rule rule; + @Before public void setUpSingleRule() { rule = new NonRuleWithAllPropertyTypes(); } + @Test public void testIntegers() { rule.setProperty(NonRuleWithAllPropertyTypes.SINGLE_INT, NumericConstants.ZERO); @@ -40,6 +42,7 @@ public class PropertyAccessorTest { assertEquals(rule.getProperty(NonRuleWithAllPropertyTypes.MULTI_INT), Arrays.asList(0, 1)); } + @Test public void testBooleans() { @@ -50,6 +53,7 @@ public class PropertyAccessorTest { assertEquals(rule.getProperty(NonRuleWithAllPropertyTypes.MULTI_BOOL), Arrays.asList(true, false)); } + @Ignore @Test public void testFloats() throws ReportException { @@ -73,6 +77,7 @@ public class PropertyAccessorTest { */ } + @Test public void testStrings() { rule.setProperty(NonRuleWithAllPropertyTypes.SINGLE_STR, "brian"); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java index 89424bc6c8..dcb3c2f5f3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java @@ -52,7 +52,16 @@ public class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTest } + @Test + public void testMappings() { + EnumeratedPropertyDescriptor prop + = (EnumeratedPropertyDescriptor) createProperty(); + EnumeratedPropertyDescriptor> multi + = (EnumeratedPropertyDescriptor>) createMultiProperty(); + assertEquals(MAPPINGS, prop.mappings()); + assertEquals(MAPPINGS, multi.mappings()); + } @Override @@ -75,18 +84,6 @@ public class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTest } - @Test - public void testMappings() { - EnumeratedPropertyDescriptor prop - = (EnumeratedPropertyDescriptor) createProperty(); - EnumeratedPropertyDescriptor> multi - = (EnumeratedPropertyDescriptor>) createMultiProperty(); - - assertEquals(MAPPINGS, prop.mappings()); - assertEquals(MAPPINGS, multi.mappings()); - } - - @Test public void testDefaultIndexOutOfBounds() { try { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java index dc6c743317..4e62f80594 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java @@ -24,10 +24,18 @@ public class StringPropertyTest extends AbstractPropertyDescriptorTester private static final char DELIMITER = '|'; private static final char[] CHARSET = filter(ALL_CHARS.toCharArray(), DELIMITER); + public StringPropertyTest() { super("String"); } + + @Override + protected String createValue() { + return newString(); + } + + /** * Method newString. * @@ -44,6 +52,7 @@ public class StringPropertyTest extends AbstractPropertyDescriptorTester return new String(chars); } + /** * Method randomCharIn. * @@ -56,32 +65,31 @@ public class StringPropertyTest extends AbstractPropertyDescriptorTester } - @Override - protected String createValue() { - return newString(); - } - @Override protected String createBadValue() { return null; } + @Override protected PropertyDescriptor createProperty() { return new StringProperty("testString", "Test string property", "brian", 1.0f); } + @Override protected PropertyDescriptor> createMultiProperty() { return new StringMultiProperty("testString", "Test string property", new String[] {"hello", "world"}, 1.0f, DELIMITER); } + @Override protected PropertyDescriptor createBadProperty() { return new StringProperty("", "Test string property", "brian", 1.0f); } + @Override protected PropertyDescriptor> createBadMultiProperty() { return new StringMultiProperty("testString", "Test string property", diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java index 852011c584..873cb7ad71 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java @@ -42,12 +42,6 @@ public class TypePropertyTest extends AbstractPropertyDescriptorTester { } - @Override - protected Class createValue() { - return JAVA_LANG_CLASSES.get(randomInt(0, JAVA_LANG_CLASSES.size())); - } - - @Override protected Class createBadValue() { return JAVA_UTIL_CLASSES.get(randomInt(0, JAVA_UTIL_CLASSES.size())); @@ -61,6 +55,12 @@ public class TypePropertyTest extends AbstractPropertyDescriptorTester { } + @Override + protected Class createValue() { + return JAVA_LANG_CLASSES.get(randomInt(0, JAVA_LANG_CLASSES.size())); + } + + @Override protected PropertyDescriptor> createMultiProperty() { return new TypeMultiProperty("testType", "Test type property", JAVA_LANG_CLASSES, new String[] {"java.lang"},