Modularized numeric and packaged properties

This commit is contained in:
oowekyala
2017-07-13 21:43:18 +02:00
parent 282cf5bd66
commit 879a7d375c
47 changed files with 1012 additions and 924 deletions

View File

@ -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<T> implements PropertyDe
}
@Override
public final PropertyDescriptor<T> createWith(Map<PropertyDescriptorField, String> valuesById) {
return createWith(valuesById, false);
}
/**
* Parses a string into a list of values of type {@literal <U>}.
* 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 <U>}
* @param <U> 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 <U> List<U> parsePrimitives(String toParse, char delimiter, ValueParser<U> extractor) {
String[] values = StringUtil.substringsOf(toParse, delimiter);
List<U> result = new ArrayList<>();
for (String s : values) {
result.add(extractor.valueOf(s));
}
return result;
protected abstract PropertyDescriptor<T> createWith(Map<PropertyDescriptorField, String> 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<T> createExternalWith(Map<PropertyDescriptorField, String> valuesById) {
return createWith(valuesById, true);
}
@ -185,9 +195,11 @@ public abstract class AbstractPropertyDescriptorFactory<T> 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<PropertyDescriptorField, Boolean> expectedFieldTypesWith(PropertyDescriptorField[] otherKeys,
@ -202,37 +214,4 @@ public abstract class AbstractPropertyDescriptorFactory<T> implements PropertyDe
}
@Override
public final PropertyDescriptor<T> createWith(Map<PropertyDescriptorField, String> 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<T> createExternalWith(Map<PropertyDescriptorField, String> 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<T> createWith(Map<PropertyDescriptorField, String> valuesById, boolean isExternallyDefined);
}

View File

@ -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<T> extends PropertyDescriptor<T> {
Map<PropertyDescriptorField, Boolean> 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.
*

View File

@ -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<T> extends PropertyDescriptor<T> {
/** Required additional fields. */
Map<PropertyDescriptorField, Boolean> 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.
*

View File

@ -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<T extends Number> extends AbstractMultiValueProperty<T>
implements NumericPropertyDescriptor<List<T>> {
private final T lowerLimit;
private final T upperLimit;
private final NumericPropertyModule<T> 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<T> 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<PropertyDescriptorField, String> attributes) {
super.addAttributesTo(attributes);
attributes.put(MIN, lowerLimit.toString());
attributes.put(MAX, upperLimit.toString());
module.addAttributesTo(attributes);
}
}

View File

@ -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<T> extends AbstractMultiValueProperty<T>
implements PackagedPropertyDescriptor<List<T>>{
implements PackagedPropertyDescriptor<List<T>> {
/** Delimiter between values. */
protected static final char DELIMITER = '|';
/** Required keys in the map. */
protected static final Map<PropertyDescriptorField, Boolean> 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<T> 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<T> theDefault,
String[] theLegalPackageNames, float theUIOrder,
boolean isDefinedExternally) {
super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally);
checkValidPackages(theDefault, theLegalPackageNames);
legalPackageNames = theLegalPackageNames;
float theUIOrder, boolean isDefinedExternally,
PackagedPropertyModule<T> 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<T> items, String[] legalNamePrefixes) {
Set<String> nameSet = new HashSet<>();
for (T item : items) {
nameSet.add(packageNameOf(item));
}
Set<String> 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<PropertyDescriptorField, String> 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<PropertyDescriptorField, String> params) {
// TODO
return null;
protected String[] packageNamesIn(Map<PropertyDescriptorField, String> params) {
return module.packageNamesIn(params);
}
}

View File

@ -27,7 +27,6 @@ import net.sourceforge.pmd.util.StringUtil;
implements MultiValuePropertyDescriptor<V> {
/** The default value. */
private final List<V> defaultValue;
private final char multiValueDelimiter;

View File

@ -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<T extends Number> extends AbstractSingleValueProperty<T>
implements NumericPropertyDescriptor<T> {
public static final Map<PropertyDescriptorField, Boolean> NUMBER_FIELD_TYPES_BY_KEY
= AbstractPropertyDescriptorFactory.expectedFieldTypesWith(new PropertyDescriptorField[] {MIN, MAX},
new Boolean[] {true, true});
private T lowerLimit;
private T upperLimit;
private final NumericPropertyModule<T> 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<PropertyDescriptorField, String> attributes) {
super.addAttributesTo(attributes);
attributes.put(MIN, lowerLimit.toString());
attributes.put(MAX, upperLimit.toString());
module.addAttributesTo(attributes);
}

View File

@ -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<T> extends AbstractSingleValueProperty<T>
implements PackagedPropertyDescriptor<T> {
/** Required keys in the map. */
protected static final Map<PropertyDescriptorField, Boolean> 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<T> 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<T> 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<PropertyDescriptorField, String> 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<PropertyDescriptorField, String> 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<PropertyDescriptorField, String> params) {
return module.packageNamesIn(params);
}
}

View File

@ -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<Boole
char delimiter = delimiterIn(valuesById);
return new BooleanMultiProperty(nameIn(valuesById),
descriptionIn(valuesById),
parsePrimitives(defaultValueIn(valuesById), delimiter, BOOLEAN_PARSER),
Companion.parsePrimitives(defaultValueIn(valuesById), delimiter, BOOLEAN_PARSER),
0f,
isDefinedExternally);
}
@ -48,6 +49,13 @@ public final class BooleanMultiProperty extends AbstractMultiValueProperty<Boole
}
/** Master constructor. */
private BooleanMultiProperty(String theName, String theDescription, List<Boolean> 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<Boole
}
private BooleanMultiProperty(String theName, String theDescription, List<Boolean> defaultValues,
float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, defaultValues, theUIOrder, isDefinedExternally);
}
@Override
protected Boolean createFrom(String toParse) {
return BOOLEAN_PARSER.valueOf(toParse);

View File

@ -49,6 +49,12 @@ public final class BooleanProperty extends AbstractSingleValueProperty<Boolean>
}
/** 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<Boolean>
}
private BooleanProperty(String theName, String theDescription, boolean defaultValue, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally);
}
@Override
public Class<Boolean> type() {
return Boolean.class;

View File

@ -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<Cha
char delimiter = delimiterIn(valuesById);
return new CharacterMultiProperty(nameIn(valuesById),
descriptionIn(valuesById),
parsePrimitives(defaultValueIn(valuesById), delimiter, ValueParser.CHARACTER_PARSER),
Companion.parsePrimitives(defaultValueIn(valuesById), delimiter, ValueParser.CHARACTER_PARSER),
0.0f,
delimiter,
isDefinedExternally);
@ -53,6 +54,7 @@ public final class CharacterMultiProperty extends AbstractMultiValueProperty<Cha
}
/** Master constructor. */
private CharacterMultiProperty(String theName, String theDescription, List<Character> defaultValues, float theUIOrder,
char delimiter, boolean isDefinedExternally) {
super(theName, theDescription, defaultValues, theUIOrder, delimiter, isDefinedExternally);

View File

@ -49,19 +49,7 @@ public final class CharacterProperty extends AbstractSingleValueProperty<Charact
}
/**
* Constructor.
*
* @param theName Name
* @param theDescription Description
* @param theDefault Default value
* @param theUIOrder UI order
*/
public CharacterProperty(String theName, String theDescription, Character theDefault, float theUIOrder) {
this(theName, theDescription, theDefault, theUIOrder, false);
}
/** Master constructor. */
private CharacterProperty(String theName, String theDescription, Character theDefault, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally);
}
@ -81,6 +69,19 @@ public final class CharacterProperty extends AbstractSingleValueProperty<Charact
}
/**
* Constructor.
*
* @param theName Name
* @param theDescription Description
* @param theDefault Default value
* @param theUIOrder UI order
*/
public CharacterProperty(String theName, String theDescription, Character theDefault, float theUIOrder) {
this(theName, theDescription, theDefault, theUIOrder, false);
}
@Override
public Class<Character> type() {
return Character.class;

View File

@ -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<Doub
public DoubleMultiProperty createWith(Map<PropertyDescriptorField, String> valuesById, boolean isDefinedExternally) {
String[] minMax = minMaxFrom(valuesById);
char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER);
List<Double> defaultValues = parsePrimitives(numericDefaultValueIn(valuesById), delimiter, DOUBLE_PARSER);
List<Double> 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<Doub
}
/** Master constructor. */
private DoubleMultiProperty(String theName, String theDescription, Double min, Double max,
List<Double> 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<Doub
this(theName, theDescription, min, max, defaultValues, theUIOrder, false);
}
private DoubleMultiProperty(String theName, String theDescription, Double min, Double max,
List<Double> defaultValues, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally);
}
@Override
public Class<Double> type() {

View File

@ -57,6 +57,25 @@ public final class DoubleProperty extends AbstractNumericProperty<Double> {
}
/** 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<Double> {
}
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<Double> type() {
return Double.class;

View File

@ -64,20 +64,6 @@ public final class EnumeratedMultiProperty<E> 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<String, E> choices,
List<E> defaultValues, Class<E> valueType, float theUIOrder) {
this(theName, theDescription, choices, defaultValues, valueType, theUIOrder, false);
}
private EnumeratedMultiProperty(String theName, String theDescription, Map<String, E> choices,
List<E> defaultValues, Class<E> valueType, float theUIOrder,
@ -113,6 +99,21 @@ public final class EnumeratedMultiProperty<E> 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<String, E> choices,
List<E> defaultValues, Class<E> valueType, float theUIOrder) {
this(theName, theDescription, choices, defaultValues, valueType, theUIOrder, false);
}
@Override
public Map<String, E> mappings() {
return choicesByLabel; // unmodifiable

View File

@ -71,6 +71,16 @@ public final class EnumeratedProperty<E> extends AbstractSingleValueProperty<E>
}
private EnumeratedProperty(String theName, String theDescription, Map<String, E> labelsToChoices,
E defaultValue, Class<E> 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<E> extends AbstractSingleValueProperty<E>
}
private EnumeratedProperty(String theName, String theDescription, Map<String, E> labelsToChoices,
E defaultValue, Class<E> 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<E> type() {
return valueType;

View File

@ -46,10 +46,12 @@ public final class FileProperty extends AbstractSingleValueProperty<File> {
}
/** Master constructor. */
private FileProperty(String theName, String theDescription, File theDefault, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally);
}
@Override
public Class<File> type() {
return File.class;

View File

@ -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<Float
boolean isDefinedExternally) {
String[] minMax = minMaxFrom(valuesById);
char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER);
List<Float> defaultValues = parsePrimitives(numericDefaultValueIn(valuesById), delimiter, FLOAT_PARSER);
List<Float> 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<Float
}
/** Master constructor. */
private FloatMultiProperty(String theName, String theDescription, Float min, Float max,
List<Float> 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<Float
}
private FloatMultiProperty(String theName, String theDescription, Float min, Float max,
List<Float> defaultValues, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally);
}
@Override
public Class<Float> type() {
return Float.class;

View File

@ -57,6 +57,13 @@ public final class FloatProperty extends AbstractNumericProperty<Float> {
}
/** 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<Float> {
}
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<Float> type() {
return Float.class;

View File

@ -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<Int
isDefinedExternally) {
String[] minMax = minMaxFrom(valuesById);
char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER);
List<Integer> defaultValues = parsePrimitives(numericDefaultValueIn(valuesById), delimiter, INTEGER_PARSER);
List<Integer> 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<Int
}
/** Master constructor. */
private IntegerMultiProperty(String theName, String theDescription, Integer min, Integer max,
List<Integer> 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<Int
}
private IntegerMultiProperty(String theName, String theDescription, Integer min, Integer max,
List<Integer> defaultValues, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally);
}
@Override
public Class<Integer> type() {
return Integer.class;

View File

@ -53,8 +53,9 @@ public final class IntegerProperty extends AbstractNumericProperty<Integer> {
}
/** 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);
}

View File

@ -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<Long>
public LongMultiProperty createWith(Map<PropertyDescriptorField, String> valuesById, boolean isDefinedExternally) {
String[] minMax = minMaxFrom(valuesById);
char delimiter = delimiterIn(valuesById, DEFAULT_NUMERIC_DELIMITER);
List<Long> defaultValues = parsePrimitives(defaultValueIn(valuesById), delimiter, LONG_PARSER);
List<Long> 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<Long>
}
/** Master constructor. */
private LongMultiProperty(String theName, String theDescription, Long min, Long max,
List<Long> 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<Long>
}
private LongMultiProperty(String theName, String theDescription, Long min, Long max,
List<Long> defaultValues, float theUIOrder, boolean isDefinedExternally) {
super(theName, theDescription, min, max, defaultValues, theUIOrder, isDefinedExternally);
}
@Override
public Class<Long> type() {
return Long.class;

View File

@ -58,6 +58,13 @@ public final class LongProperty extends AbstractNumericProperty<Long> {
}
/** 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<Long> {
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<Long> type() {

View File

@ -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<Met
0f,
isDefinedExternally);
}
}; // @formatter:on
@ -66,9 +68,11 @@ public final class MethodMultiProperty extends AbstractMultiPackagedProperty<Met
}
/** Master constructor. */
private MethodMultiProperty(String theName, String theDescription, List<Method> 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<Met
* @param theUIOrder float
*
* @throws IllegalArgumentException
* @deprecated will be removed in 7.O.O
*/
public MethodMultiProperty(String theName, String theDescription, String methodDefaults,
String[] legalPackageNames, float theUIOrder) {
this(theName, theDescription, methodsFrom(methodDefaults), legalPackageNames, theUIOrder, false);
this(theName, theDescription,
methodsFrom(methodDefaults),
legalPackageNames, theUIOrder,
false);
}
public static List<Method> methodsFrom(String methodsStr) {
String[] values = StringUtil.substringsOf(methodsStr, DELIMITER);
List<Method> 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<Method> 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);
}

View File

@ -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<Method> {
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<Method> FACTORY // @formatter:off
= new SingleValuePropertyDescriptorFactory<Method>(Method.class, PACKAGED_FIELD_TYPES_BY_KEY) {
@Override
@ -37,22 +36,37 @@ public final class MethodProperty extends AbstractPackagedProperty<Method> {
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<Class<?>, 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<Method> {
* @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<Method> {
@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.:
*
* <p>"String#isEmpty()" "String#indexOf(int)" "String#substring(int,int)"
*
* <p>If a method isn't part of the specified class we will walk up any
* superclasses to Object to try and find it.
*
* <p>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.
*
* <p>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);
}
}

View File

@ -34,7 +34,7 @@ public abstract class MultiValuePropertyDescriptorFactory<T> extends AbstractPro
@Override
protected abstract MultiValuePropertyDescriptor<T> createWith(Map<PropertyDescriptorField, String> valuesById,
boolean isDefinedExternally);
boolean isDefinedExternally);
@Override

View File

@ -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<String, PropertyDescriptorFactory<?>> DESCRIPTOR_FACTORIES_BY_TYPE;
@ -38,8 +41,8 @@ public class PropertyDescriptorUtil {
temp.put("Double", DoubleProperty.FACTORY);
temp.put("List<Double>", DoubleMultiProperty.FACTORY);
// temp.put("Enum", EnumeratedProperty.FACTORY);
// temp.put("List<Enum>", EnumeratedMultiProperty.FACTORY);
// temp.put("Enum", EnumeratedProperty.FACTORY); // TODO:cf implement that
// temp.put("List<Enum>", EnumeratedMultiProperty.FACTORY);
temp.put("Class", TypeProperty.FACTORY);
temp.put("List<Class>", 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<String, PropertyDescriptorFactory<?>> entry : DESCRIPTOR_FACTORIES_BY_TYPE.entrySet()) {
if (entry.getValue().valueType() == valueType && entry.getValue().isMultiValue() == multiValue) {
return entry.getKey();

View File

@ -20,13 +20,13 @@ import net.sourceforge.pmd.SingleValuePropertyDescriptor;
*/
public abstract class SingleValuePropertyDescriptorFactory<T> extends AbstractPropertyDescriptorFactory<T> {
public SingleValuePropertyDescriptorFactory(Class<T> theValueType) {
/* default */ SingleValuePropertyDescriptorFactory(Class<T> theValueType) {
super(theValueType);
}
public SingleValuePropertyDescriptorFactory(Class<T> theValueType,
Map<PropertyDescriptorField, Boolean> additionalFieldTypesByKey) {
/* default */ SingleValuePropertyDescriptorFactory(Class<T> theValueType,
Map<PropertyDescriptorField, Boolean> additionalFieldTypesByKey) {
super(theValueType, additionalFieldTypesByKey);
}

View File

@ -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<String
char delimiter = delimiterIn(valuesById);
return new StringMultiProperty(nameIn(valuesById),
descriptionIn(valuesById),
parsePrimitives(defaultValueIn(valuesById), delimiter, STRING_PARSER),
Companion.parsePrimitives(defaultValueIn(valuesById), delimiter, STRING_PARSER),
0.0f,
delimiter,
isDefinedExternally);
@ -75,7 +76,7 @@ public final class StringMultiProperty extends AbstractMultiValueProperty<String
}
/** For external defition. */
/** Master constructor. */
private StringMultiProperty(String theName, String theDescription, List<String> defaultValues, float theUIOrder,
char delimiter, boolean isDefinedExternally) {
super(theName, theDescription, defaultValues, theUIOrder, delimiter, isDefinedExternally);

View File

@ -44,6 +44,7 @@ public final class StringProperty extends AbstractSingleValueProperty<String> {
}
/** Master constructor. */
private StringProperty(String theName, String theDescription, String defaultValue, float theUIOrder, boolean
isDefinedExternally) {
super(theName, theDescription, defaultValue, theUIOrder, isDefinedExternally);

Some files were not shown because too many files have changed in this diff Show More