new property management framework - not activated yet

git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@4664 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
Brian Remedios
2006-10-15 05:05:58 +00:00
parent 4be25d55e9
commit 1c7b95bb55
23 changed files with 2041 additions and 0 deletions

View File

@ -0,0 +1,141 @@
package test.net.sourceforge.pmd.properties;
import junit.framework.TestCase;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.util.CollectionUtil;
/**
*
* @author Brian Remedios
*/
public abstract class AbstractPropertyDescriptorTester extends TestCase {
private static final int maxCardinality = 10;
public static final String punctuationChars = "!@#$%^&*()_-+=[]{}\\|;:'\",.<>/?`~";
public static final String whitespaceChars = " \t\n";
public static final String digitChars = "0123456789";
public static final String alphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmniopqrstuvwxyz";
public static final String alphaNumericChars = digitChars + alphaChars;
public static final String allChars = punctuationChars + whitespaceChars + alphaNumericChars;
protected AbstractPropertyDescriptorTester() { }
/**
* Method createValue.
* @param count int
* @return Object
*/
protected abstract Object createValue(int count);
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected abstract PropertyDescriptor createProperty(int maxCount);
public void testAsDelimitedString() {
Object testValue = createValue(maxCardinality);
PropertyDescriptor pmdProp = createProperty(maxCardinality);
String storeValue = pmdProp.asDelimitedString(testValue);
Object returnedValue = pmdProp.valueFrom(storeValue);
assertTrue(CollectionUtil.areEqual(returnedValue, testValue));
}
public void testValueFrom() {
Object testValue = createValue(1);
PropertyDescriptor pmdProp = createProperty(1);
String storeValue = pmdProp.asDelimitedString(testValue);
Object returnedValue = pmdProp.valueFrom(storeValue);
assertTrue(CollectionUtil.areEqual(returnedValue, testValue));
}
public void testErrorFor() {
Object testValue = createValue(1);
PropertyDescriptor pmdProp = createProperty(1);
String errorMsg = pmdProp.errorFor(testValue);
assertTrue(errorMsg == null);
testValue = createValue(maxCardinality);
pmdProp = createProperty(maxCardinality);
errorMsg = pmdProp.errorFor(testValue);
assertTrue(errorMsg == null);
}
public void testType() {
PropertyDescriptor pmdProp = createProperty(1);
assertTrue(pmdProp.type() != null);
}
/**
* Method randomInt.
* @return int
*/
public static int randomInt() {
int randomVal = (int) (Math.random() * 100 + 1D);
return randomVal + (int) (Math.random() * 100000D);
}
/**
* Method randomInt.
* @param min int
* @param max int
* @return int
*/
public static int randomInt(int min, int max) {
if (max < min) max = min;
int range = Math.abs(max - min);
int x = (int) ((range * Math.random()) + .5);
return x + min;
}
/**
* Method randomChar.
* @param characters char[]
* @return char
*/
public static char randomChar(char[] characters) {
return characters[randomInt(0, characters.length-1)];
}
/**
* Method randomChoice.
* @param items Object[]
* @return Object
*/
public static Object randomChoice(Object[] items) {
return items[randomInt(0, items.length-1)];
}
/**
* Method filter.
* @param chars char[]
* @param removeChar char
* @return char[]
*/
protected static final char[] filter(char[] chars, char removeChar) {
int count = 0;
for (int i=0; i<chars.length; i++) if (chars[i] == removeChar) count++;
char[] results = new char[chars.length - count];
int index = 0;
for (int i=0; i<chars.length; i++) {
if (chars[i] != removeChar) results[index++] = chars[i];
}
return results;
}
}

View File

@ -0,0 +1,40 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.BooleanProperty;
/**
* @author Brian Remedios
*/
public class BooleanPropertyTest extends AbstractPropertyDescriptorTester {
public BooleanPropertyTest() {
super();
}
/**
* Method createValue.
* @param valueCount int
* @return Object
*/
public Object createValue(int valueCount) {
if (valueCount == 1) return System.currentTimeMillis() % 1 > 0 ?
Boolean.TRUE : Boolean.FALSE;
Boolean[] values = new Boolean[valueCount];
for (int i=0; i<values.length; i++) values[i] = (Boolean)createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxValues int
* @return PropertyDescriptor
*/
public PropertyDescriptor createProperty(int maxValues) {
return maxValues == 1 ?
new BooleanProperty("testBoolean", "Test boolean property", false, 1.0f) :
new BooleanProperty("testBoolean", "Test boolean property", new boolean[] {false}, 1.0f, maxValues);
}
}

View File

@ -0,0 +1,43 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.CharacterProperty;
/**
*/
public class CharacterPropertyTest extends AbstractPropertyDescriptorTester {
private static final char delimiter = '|';
private static final char[] charSet = filter(allChars.toCharArray(), delimiter);
public CharacterPropertyTest() {
super();
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return new Character(randomChar(charSet));
Character[] values = new Character[count];
for (int i=0; i<values.length; i++) values[i] = (Character)createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new CharacterProperty("testCharacter", "Test character property", 'a', 1.0f) :
new CharacterProperty("testCharacter", "Test character property", new char[] {'a', 'b', 'c'}, 1.0f, delimiter);
}
}

View File

@ -0,0 +1,40 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.DoubleProperty;
/**
*/
public class DoublePropertyTest extends AbstractPropertyDescriptorTester {
public DoublePropertyTest() {
super();
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return new Double((int)(System.currentTimeMillis() % 100));
Double[] values = new Double[count];
for (int i=0; i<values.length; i++) values[i] = (Double)createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new DoubleProperty("testDouble", "Test double property", 9.0, 1.0f) :
new DoubleProperty("testDouble", "Test double property", new double[] {-1,0,1,2}, 1.0f, maxCount);
}
}

View File

@ -0,0 +1,50 @@
package test.net.sourceforge.pmd.properties;
import java.util.ArrayList;
import java.util.HashMap;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.EnumeratedProperty;
/**
*/
public class EnumeratedPropertyTest extends AbstractPropertyDescriptorTester {
private static final Object[][] mixedItems = new Object[][] {
{"map", new HashMap()},
{"emptyArray", new Object[0]},
{"list", new ArrayList()},
{"string", "Hello World!"},
};
public EnumeratedPropertyTest() {
super();
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return ((Object[])randomChoice(mixedItems))[1];
Object[] values = new Object[count];
for (int i=0; i<values.length; i++) values[i] = createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new EnumeratedProperty("testEnumerations", "Test enumerations with complex types", mixedItems, 1.0f) :
new EnumeratedProperty("testEnumerations", "Test enumerations with complex types", mixedItems, 1.0f, 3);
}
}

View File

@ -0,0 +1,40 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.FloatProperty;
/**
*/
public class FloatPropertyTest extends AbstractPropertyDescriptorTester {
public FloatPropertyTest() {
super();
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return new Float((int)(System.currentTimeMillis() % 100));
Float[] values = new Float[count];
for (int i=0; i<values.length; i++) values[i] = (Float)createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new FloatProperty("testFloat", "Test float property", 9.0f, 1.0f) :
new FloatProperty("testFloat", "Test float property", new float[] {-1,0,1,2}, 1.0f, maxCount);
}
}

View File

@ -0,0 +1,41 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.IntegerProperty;
/**
*/
public class IntegerPropertyTest extends AbstractPropertyDescriptorTester {
public IntegerPropertyTest() {
super();
// TODO Auto-generated constructor stub
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return new Integer((int)(System.currentTimeMillis() % 100));
Integer[] values = new Integer[count];
for (int i=0; i<values.length; i++) values[i] = (Integer)createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new IntegerProperty("testInteger", "Test integer property", 9, 1.0f) :
new IntegerProperty("testInteger", "Test integer property", new int[] {-1,0,1,2}, 1.0f, maxCount);
}
}

View File

@ -0,0 +1,52 @@
package test.net.sourceforge.pmd.properties;
import java.util.Map;
import net.sourceforge.pmd.AbstractRule;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.BooleanProperty;
import net.sourceforge.pmd.properties.CharacterProperty;
import net.sourceforge.pmd.properties.EnumeratedProperty;
import net.sourceforge.pmd.properties.FloatProperty;
import net.sourceforge.pmd.properties.IntegerProperty;
import net.sourceforge.pmd.properties.StringProperty;
import net.sourceforge.pmd.properties.TypeProperty;
class NonRuleWithAllPropertyTypes extends AbstractRule {
private static final PropertyDescriptor singleStr = new StringProperty("singleStr", "Property with a single string value", "hello world" , 3.0f);
private static final PropertyDescriptor multiStr = new StringProperty("multiStr", "Property with multiple string values", new String[] {"hello", "world"}, 5.0f, '|');
private static final PropertyDescriptor singleInt = new IntegerProperty("singleInt", "Property with a single integer value", 8 , 3.0f);
private static final PropertyDescriptor multiInt = new IntegerProperty("multiInt", "Property with multiple integer values", new int[] {1,2,3,4}, 5.0f, 5);
private static final PropertyDescriptor singleBool = new BooleanProperty("singleBool", "Property with a single boolean value", true, 6.0f);
private static final PropertyDescriptor multiBool = new BooleanProperty("multiBool", "Property with multiple boolean values", new boolean[] { true, false}, 5.0f, 2);
private static final PropertyDescriptor singleChar = new CharacterProperty("singleChar", "Property with a single character value", 'a', 5.0f);
private static final PropertyDescriptor multiChar = new CharacterProperty("multiChar", "Property with multiple character values", new char[] {'a', 'e', 'i', 'o', 'u'}, 6.0f, '|');
private static final PropertyDescriptor singleFloat = new FloatProperty("singleFloat", "Property with a single float value", 9.9f, 5.0f);
private static final PropertyDescriptor multiFloat = new FloatProperty("multiFloat", "Property with multiple float values", new float[] {1,2,3}, 6.0f, 3);
private static final PropertyDescriptor singleType = new TypeProperty("singleType", "Property with a single type value", String.class, 5.0f);
private static final PropertyDescriptor multiType = new TypeProperty("multiType", "Property with multiple type values", new Class[] {Integer.class, Object.class}, 6.0f);
private static final PropertyDescriptor enumType = new EnumeratedProperty("enumType", "Property with a enumerated choices", new Object[][] {{"String", String.class},{"Object", Object.class}}, 5.0f);
private static final Map propertyDescriptorsByName = asFixedMap(new PropertyDescriptor[] {
singleStr, multiStr, singleInt, multiInt, singleBool, multiBool,
singleChar, multiChar, singleFloat, multiFloat, singleType, multiType,
enumType
});
public NonRuleWithAllPropertyTypes() {
super();
}
protected Map propertiesByName() {
return propertyDescriptorsByName;
}
}

View File

@ -0,0 +1,131 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.AbstractRule;
import net.sourceforge.pmd.cpd.ReportException;
import net.sourceforge.pmd.util.CollectionUtil;
import test.net.sourceforge.pmd.testframework.SimpleAggregatorTst;
public class PropertyAccessorTest extends SimpleAggregatorTst {
private AbstractRule rule;
public void setUp() {
rule = new NonRuleWithAllPropertyTypes();
}
public static boolean areEqual(int[] a, int[] b) {
if (a.length != b.length) return false;
for (int i=0; i<a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
public static boolean areEqual(boolean[] a, boolean[] b) {
if (a.length != b.length) return false;
for (int i=0; i<a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
public void testIntegers() throws ReportException {
rule.setProperty("singleInt", new Integer(0));
assertTrue(rule.getIntProperty("singleInt") == 0);
rule.setProperties("multiInt", new Object[] {new Integer(0), new Integer(1)});
assertTrue(areEqual(rule.getIntProperties("multiInt"), new int[]{0, 1}));
boolean exceptionOccurred = false;
try {
rule.setProperties("singleInt", new Object[] {new Integer(0), new Integer(1)});
} catch (Exception ex) {
exceptionOccurred = true;
}
assertTrue(exceptionOccurred);
exceptionOccurred = false;
try {
rule.setProperty("multiInt", new Integer(0));
} catch (Exception ex) {
exceptionOccurred = true;
}
assertTrue(exceptionOccurred);
}
public void testBooleans() throws ReportException {
rule.setProperty("singleBool", Boolean.FALSE);
assertFalse(rule.getBooleanProperty("singleBool"));
rule.setProperties("multiBool", new Boolean[] {Boolean.TRUE, Boolean.FALSE});
assertTrue(areEqual(rule.getBooleanProperties("multiBool"), new boolean[]{true, false}));
boolean exceptionOccurred = false;
try {
rule.setProperties("singleBool", new Boolean[] {Boolean.TRUE, Boolean.FALSE});
} catch (Exception ex) {
exceptionOccurred = true;
}
assertTrue(exceptionOccurred);
exceptionOccurred = false;
try {
rule.setProperty("multiBool", Boolean.TRUE);
} catch (Exception ex) {
exceptionOccurred = true;
}
assertTrue(exceptionOccurred);
}
// public void testFloats() throws ReportException {
//
// rule.setProperty("singleFloat", new Float(0));
// assertTrue(rule.getFloatProperty("singleFloat") == 0f);
//
// rule.setProperties("multiBool", new Boolean[] {Boolean.TRUE, Boolean.FALSE});
// assertTrue(areEqual(rule.getBooleanProperties("multiBool"), new boolean[]{true, false}));
//
// boolean exceptionOccurred = false;
// try {
// rule.setProperties("singleBool", new Boolean[] {Boolean.TRUE, Boolean.FALSE});
// } catch (Exception ex) {
// exceptionOccurred = true;
// }
// assertTrue(exceptionOccurred);
//
// exceptionOccurred = false;
// try {
// rule.setProperty("multiBool", Boolean.TRUE);
// } catch (Exception ex) {
// exceptionOccurred = true;
// }
// assertTrue(exceptionOccurred);
// }
public void testStrings() throws ReportException {
rule.setProperty("singleStr", "brian");
assertEquals(rule.getStringProperty("singleStr"), "brian");
rule.setProperties("multiStr", new String[] {"hello", "world"});
assertTrue(CollectionUtil.arraysAreEqual(rule.getStringProperties("multiStr"), new String[] {"hello", "world"}));
boolean exceptionOccurred = false;
try {
rule.setProperties("singleStr", new String[] {"hello", "world"});
} catch (Exception ex) {
exceptionOccurred = true;
}
assertTrue(exceptionOccurred);
exceptionOccurred = false;
try {
rule.setProperty("multiStr", "brian");
} catch (Exception ex) {
exceptionOccurred = true;
}
assertTrue(exceptionOccurred);
}
}

View File

@ -0,0 +1,65 @@
package test.net.sourceforge.pmd.properties;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.StringProperty;
/**
*/
public class StringPropertyTest extends AbstractPropertyDescriptorTester {
private static final int maxStringLength = 52;
private static final char delimiter = '|';
private static final char[] charSet = filter(allChars.toCharArray(), delimiter);
public StringPropertyTest() {
super();
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return newString();
String[] values = new String[count];
for (int i=0; i<count; i++) values[i] = (String)createValue(1);
return values;
}
/**
* Method newString.
* @return String
*/
private String newString() {
int strLength = randomInt(0, maxStringLength);
char[] chars = new char[strLength];
for (int i=0; i<chars.length; i++) chars[i] = randomCharIn(charSet);
return new String(chars);
}
/**
* Method randomCharIn.
* @param chars char[]
* @return char
*/
private char randomCharIn(char[] chars) {
return randomChar(chars);
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new StringProperty("testString", "Test string property", "brian", 1.0f) :
new StringProperty("testString", "Test string property", new String[] {"hello", "world"}, 1.0f, delimiter);
}
}

View File

@ -0,0 +1,45 @@
package test.net.sourceforge.pmd.properties;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.properties.TypeProperty;
/**
*/
public class TypePropertyTest extends AbstractPropertyDescriptorTester {
public static final Class[] classes = new Class[] { String.class, Integer.class, int.class, HashMap.class, Map.class };
public TypePropertyTest() {
super();
}
/**
* Method createValue.
* @param count int
* @return Object
*/
protected Object createValue(int count) {
if (count == 1) return randomChoice(classes);
Object[] values = new Object[count];
for (int i=0; i<values.length; i++) values[i] = createValue(1);
return values;
}
/**
* Method createProperty.
* @param maxCount int
* @return PropertyDescriptor
*/
protected PropertyDescriptor createProperty(int maxCount) {
return maxCount == 1 ?
new TypeProperty("testType", "Test type property", Byte.class, 1.0f) :
new TypeProperty("testType", "Test type property", classes, 1.0f);
}
}

View File

@ -0,0 +1,133 @@
package net.sourceforge.pmd;
/**
* Property value descriptor that defines the use & requirements for setting
* property values for use within PMD and any associated GUIs.
*
* @author Brian Remedios
* @version $Revision$
*/
public interface PropertyDescriptor extends Comparable {
PropertyDescriptor[] emptyPropertySet = new PropertyDescriptor[0];
/**
* The name of the property without spaces as it serves
* as the key into the property map.
*
* @return String
*/
String name();
/**
* Describes the property and the role it plays within the
* rule it is specified for. Could be used in a tooltip.
*
* @return String
*/
String description();
/**
* Denotes the value datatype.
* @return Class
*/
Class type();
/**
* If the property is multi-valued, i.e. an array of strings, then this
* returns the maximum number permitted. Unary property rule properties
* normally return a value of one.
*
* @return int
*/
int maxValueCount();
/**
* Default value to use when the user hasn't specified one or when they wish
* to revert to a known-good state.
*
* @return Object
*/
Object defaultValue();
/**
* Denotes whether the value is required before the rule can be executed.
* Has no meaning for primitive types such as booleans, ints, etc.
*
* @return boolean
*/
boolean isRequired();
/**
* Validation function that returns a diagnostic error message for a sample
* property value. Returns null if the value is acceptable.
*
* @param value Object
* @return String
*/
String errorFor(Object value);
/**
* Denotes the relative order the property field should occupy if we are using
* an auto-generated UI to display and edit values. If the value returned has
* a non-zero fractional part then this is can be used to place adjacent fields
* on the same row. Example:
*
* name -> 0.0
* description 1.0
* minValue -> 2.0
* maxValue -> 2.1
*
* ..would have their fields placed like:
*
* name: [ ]
* description: [ ]
* minimum: [ ] maximum: [ ]
*
* @return float
*/
float uiOrder();
/**
* If the property is multi-valued then return the separate values after
* parsing the propertyString provided. If it isn't a multi-valued
* property then the value will be returned within an array of size[1].
*
* @param propertyString String
* @return Object
* @throws IllegalArgumentException
*/
Object valueFrom(String propertyString) throws IllegalArgumentException;
/**
* Formats the object onto a string suitable for storage within the property map.
* @param value Object
* @return String
*/
String asDelimitedString(Object value);
/**
* Returns a set of choice tuples of available, returns null if none present.
* @return Object[]
*/
Object[][] choices();
/**
* A convenience method that returns an error string if the rule holds onto a
* property value that has a problem. Returns null otherwise.
*
* @param rule Rule
* @return String
*/
String propertyErrorFor(Rule rule);
/**
* Return the character being used to delimit multiple property values within
* a single string. You must ensure that this character does not appear within
* any rule property values to avoid deserialization errors.
*
* @return char
*/
char multiValueDelimiter();
/**
* If the datatype is a String then return the preferred number of rows to
* allocate in the text widget, returns a value of one for all other types.
* Useful for multi-line XPATH editors.
*
* @return int
*/
int preferredRowCount();
}

View File

@ -0,0 +1,275 @@
package net.sourceforge.pmd.properties;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.Rule;
/**
*
* @author Brian Remedios
* @version $Revision$
*/
public abstract class AbstractPMDProperty implements PropertyDescriptor {
private String name;
private String description;
private Object defaultValue;
private boolean isRequired = false;
private int maxValueCount = 1;
private float uiOrder;
protected char multiValueDelimiter = '|';
/**
* Constructor for AbstractPMDProperty.
* @param theName String
* @param theDescription String
* @param theDefault Object
* @param theUIOrder float
*/
protected AbstractPMDProperty(String theName, String theDescription, Object theDefault, float theUIOrder) {
name = theName;
description = theDescription;
defaultValue = theDefault;
uiOrder = theUIOrder;
}
/**
* Method multiValueDelimiter.
* @param aDelimiter char
*/
protected void multiValueDelimiter(char aDelimiter) {
multiValueDelimiter = aDelimiter;
}
/**
* Method multiValueDelimiter.
* @return char
* @see net.sourceforge.pmd.PropertyDescriptor#multiValueDelimiter()
*/
public char multiValueDelimiter() {
return multiValueDelimiter;
}
/**
* Method name.
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#name()
*/
public String name() {
return name;
}
/**
* Method description.
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#description()
*/
public String description() {
return description;
}
/**
*
* @return Object
* @see net.sourceforge.pmd.PropertyDescriptor#defaultValue()
*/
public Object defaultValue() {
return defaultValue;
}
/**
* Method maxValueCount.
* @return int
* @see net.sourceforge.pmd.PropertyDescriptor#maxValueCount()
*/
public int maxValueCount() {
return maxValueCount;
}
/**
* Method maxValueCount.
* @param theCount int
* @see net.sourceforge.pmd.PropertyDescriptor#maxValueCount()
*/
protected void maxValueCount(int theCount) {
maxValueCount = theCount;
}
/**
* Method isRequired.
* @return boolean
* @see net.sourceforge.pmd.PropertyDescriptor#isRequired()
*/
public boolean isRequired() {
return isRequired;
}
/**
* Method uiOrder.
* @return float
* @see net.sourceforge.pmd.PropertyDescriptor#uiOrder()
*/
public float uiOrder() {
return uiOrder;
}
/**
* Return the value as a string that can be easily recognized and parsed
* when we see it again.
*
* @param value Object
* @return String
*/
protected String asString(Object value) {
return value == null ? "" : value.toString();
}
/**
* Method asDelimitedString.
* @param values Object
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#asDelimitedString(Object)
*/
public String asDelimitedString(Object values) {
if (values == null) return "";
if (values instanceof Object[]) {
Object[] valueSet = (Object[])values;
if (valueSet.length == 0) return "";
if (valueSet.length == 1) return asString(valueSet[0]);
StringBuffer sb = new StringBuffer();
sb.append(asString(valueSet[0]));
for (int i=1; i<valueSet.length; i++) {
sb.append(multiValueDelimiter);
sb.append(asString(valueSet[i]));
}
return sb.toString();
}
return asString(values);
}
/**
* Method compareTo.
* @param otherProperty Object
* @return int
* @see java.lang.Comparable#compareTo(Object)
*/
public int compareTo(Object otherProperty) {
float otherOrder = ((PropertyDescriptor)otherProperty).uiOrder();
return (int) (otherOrder - uiOrder);
}
/**
* Method errorFor.
* @param value Object
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#errorFor(Object)
*/
public String errorFor(Object value) {
String typeError = typeErrorFor(value);
if (typeError != null) return typeError;
return valueErrorFor(value);
}
/**
* Method valueErrorFor.
* @param value Object
* @return String
*/
protected String valueErrorFor(Object value) {
// override as required
return null;
}
/**
* Method isArray.
* @param value Object
* @return boolean
*/
protected boolean isArray(Object value) {
return value != null && value.getClass().getComponentType() != null;
}
/**
* Method typeErrorFor.
* @param value Object
* @return String
*/
protected String typeErrorFor(Object value) {
if (value == null && !isRequired) return null;
if (maxValueCount > 1) {
if (!isArray(value)) {
return "Value is not an array of type: " + type();
}
Class arrayType = value.getClass().getComponentType();
if (arrayType == null || !arrayType.isAssignableFrom(type())) {
return "Value is not an array of type: " + type();
}
return null;
}
if (!type().isAssignableFrom(value.getClass())) {
return "" + value + " is not an instance of " + type();
}
return null;
}
/**
* Method propertyErrorFor.
* @param rule Rule
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#propertyErrorFor(Rule)
*/
public String propertyErrorFor(Rule rule) {
String strValue = rule.getStringProperty(name());
if (strValue == null && !isRequired()) return null;
Object realValue = valueFrom(strValue);
return errorFor(realValue);
}
/**
* Method choices.
* @return Object[][]
* @see net.sourceforge.pmd.PropertyDescriptor#choices()
*/
public Object[][] choices() {
return null;
}
/**
* Method preferredRowCount.
* @return int
* @see net.sourceforge.pmd.PropertyDescriptor#preferredRowCount()
*/
public int preferredRowCount() {
return 1;
}
/**
* Method areEqual.
* @param value Object
* @param otherValue Object
* @return boolean
*/
public static final boolean areEqual(Object value, Object otherValue) {
if (value == otherValue) return true;
if (value == null) return false;
if (otherValue == null) return false;
return value.equals(otherValue);
}
}

View File

@ -0,0 +1,56 @@
package net.sourceforge.pmd.properties;
import net.sourceforge.pmd.util.StringUtil;
/**
* No, subclasses are not necessarily scalar per se, they're just easy to parse without error.
* If you can come up with a better name...
*
* @author Brian Remedios
* @version $Revision$
*/
public abstract class AbstractScalarProperty extends AbstractPMDProperty {
/**
* Constructor for AbstractScalarProperty.
* @param theName String
* @param theDescription String
* @param theDefault Object
* @param theUIOrder float
*/
public AbstractScalarProperty(String theName, String theDescription, Object theDefault, float theUIOrder) {
super(theName, theDescription, theDefault, theUIOrder);
}
/**
* Method createFrom.
* @param value String
* @return Object
*/
protected abstract Object createFrom(String value);
/**
* Method arrayFor.
* @param size int
* @return Object[]
*/
protected abstract Object[] arrayFor(int size);
/**
* Method valueFrom.
* @param valueString String
* @return Object[]
* @throws IllegalArgumentException
* @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String)
*/
public Object valueFrom(String valueString) throws IllegalArgumentException {
if (maxValueCount() == 1) return createFrom(valueString);
String[] strValues = StringUtil.substringsOf(valueString, multiValueDelimiter);
Object[] values = arrayFor(strValues.length);
for (int i=0; i<strValues.length; i++) values[i] = createFrom(strValues[i]);
return values;
}
}

View File

@ -0,0 +1,87 @@
package net.sourceforge.pmd.properties;
/**
* Defines a property type that supports Boolean values.
*
* @author Brian Remedios
* @version $Revision$
*/
public class BooleanProperty extends AbstractScalarProperty {
/**
* Constructor for BooleanProperty.
* @param theName String
* @param theDescription String
* @param defaultValue boolean
* @param theUIOrder float
*/
public BooleanProperty(String theName, String theDescription, boolean defaultValue, float theUIOrder) {
super(theName, theDescription, Boolean.valueOf(defaultValue), theUIOrder);
}
/**
* Constructor for BooleanProperty.
* @param theName String
* @param theDescription String
* @param defaultValues boolean[]
* @param theUIOrder float
* @param theMaxValues int
*/
public BooleanProperty(String theName, String theDescription, boolean[] defaultValues, float theUIOrder, int theMaxValues) {
this(theName, theDescription, asBooleans(defaultValues), theUIOrder, theMaxValues);
}
/**
* Constructor for BooleanProperty.
* @param theName String
* @param theDescription String
* @param defaultValues Boolean[]
* @param theUIOrder float
* @param theMaxValues int
*/
public BooleanProperty(String theName, String theDescription, Boolean[] defaultValues, float theUIOrder, int theMaxValues) {
super(theName, theDescription, defaultValues, theUIOrder);
maxValueCount(theMaxValues);
}
/**
* Method asBooleans.
* @param bools boolean[]
* @return Boolean[]
*/
private static final Boolean[] asBooleans(boolean[] bools) {
Boolean[] booleans = new Boolean[bools.length];
for (int i=0; i<bools.length; i++) booleans[i] = Boolean.valueOf(bools[i]);
return booleans;
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Boolean.class;
}
/**
* Method createFrom.
* @param value String
* @return Object
*/
protected Object createFrom(String value) {
return Boolean.valueOf(value);
}
/**
* Method arrayFor.
* @param size int
* @return Object[]
*/
protected Object[] arrayFor(int size) {
return new Boolean[size];
}
}

View File

@ -0,0 +1,103 @@
package net.sourceforge.pmd.properties;
import net.sourceforge.pmd.util.StringUtil;
/**
* Defines a property type that supports Character values.
*
* @author Brian Remedios
* @version $Revision$
*/
public class CharacterProperty extends AbstractPMDProperty {
/**
* Constructor for CharacterProperty.
* @param theName String
* @param theDescription String
* @param theDefault char
* @param theUIOrder float
*/
public CharacterProperty(String theName, String theDescription, char theDefault, float theUIOrder) {
super(theName, theDescription, new Character(theDefault), theUIOrder);
}
/**
* Constructor for CharacterProperty.
* @param theName String
* @param theDescription String
* @param theDefaults char[]
* @param theUIOrder float
* @param delimiter char
*/
public CharacterProperty(String theName, String theDescription, char[] theDefaults, float theUIOrder, char delimiter) {
this(theName, theDescription, asCharacters(theDefaults), theUIOrder, delimiter);
}
/**
* Constructor for CharacterProperty.
* @param theName String
* @param theDescription String
* @param theDefaults String
* @param theUIOrder float
* @param delimiter char
*/
public CharacterProperty(String theName, String theDescription, String theDefaults, float theUIOrder, char delimiter) {
this(theName, theDescription, theDefaults.toCharArray(), theUIOrder, delimiter);
}
/**
* Constructor for CharacterProperty.
* @param theName String
* @param theDescription String
* @param theDefaults char[]
* @param theUIOrder float
* @param delimiter char
*/
public CharacterProperty(String theName, String theDescription, Character[] theDefaults, float theUIOrder, char delimiter) {
super(theName, theDescription, theDefaults, theUIOrder);
multiValueDelimiter(delimiter);
maxValueCount(Integer.MAX_VALUE);
}
/**
* Method asCharacters.
* @param chars char[]
* @return Character[]
*/
private static final Character[] asCharacters(char[] chars) {
Character[] characters = new Character[chars.length];
for (int i=0; i<chars.length; i++) characters[i] = new Character(chars[i]);
return characters;
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Character.class;
}
/**
* Method valueFrom.
* @param valueString String
* @return Object
* @throws IllegalArgumentException
* @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String)
*/
public Object valueFrom(String valueString) throws IllegalArgumentException {
if (maxValueCount() == 1) {
if (valueString.length() > 1) throw new IllegalArgumentException(valueString);
return new Character(valueString.charAt(0));
}
String[] values = StringUtil.substringsOf(valueString, multiValueDelimiter);
Character[] chars = new Character[values.length];
for (int i=0; i<values.length; i++) chars[i] = new Character(values[i].charAt(0));
return chars;
}
}

View File

@ -0,0 +1,85 @@
package net.sourceforge.pmd.properties;
/**
* Defines a property type that support double property values.
*
* @author Brian Remedios
*/
public class DoubleProperty extends AbstractScalarProperty {
/**
* Constructor for DoubleProperty.
* @param theName String
* @param theDescription String
* @param theDefault double
* @param theUIOrder float
*/
public DoubleProperty(String theName, String theDescription, double theDefault, float theUIOrder) {
super(theName, theDescription, new Double(theDefault), theUIOrder);
}
/**
* Constructor for DoubleProperty.
* @param theName String
* @param theDescription String
* @param defaultValues boolean[]
* @param theUIOrder float
* @param theMaxValues int
*/
public DoubleProperty(String theName, String theDescription, double[] defaultValues, float theUIOrder, int theMaxValues) {
this(theName, theDescription, asDoubles(defaultValues), theUIOrder, theMaxValues);
}
/**
* Constructor for DoubleProperty.
* @param theName String
* @param theDescription String
* @param defaultValues Double[]
* @param theUIOrder float
* @param theMaxValues int
*/
public DoubleProperty(String theName, String theDescription, Double[] defaultValues, float theUIOrder, int theMaxValues) {
super(theName, theDescription, defaultValues, theUIOrder);
maxValueCount(theMaxValues);
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Double.class;
}
/**
* Method asDoubles.
* @param doubles double[]
* @return Double[]
*/
private static final Double[] asDoubles(double[] doubles) {
Double[] Doubles = new Double[doubles.length];
for (int i=0; i<doubles.length; i++) Doubles[i] = new Double(doubles[i]);
return Doubles;
}
/**
* Method createFrom.
* @param value String
* @return Object
*/
protected Object createFrom(String value) {
return new Double(value);
}
/**
* Method arrayFor.
* @param size int
* @return Object[]
*/
protected Object[] arrayFor(int size) {
return new Double[size];
}
}

View File

@ -0,0 +1,146 @@
package net.sourceforge.pmd.properties;
import java.util.Map;
import net.sourceforge.pmd.util.CollectionUtil;
import net.sourceforge.pmd.util.StringUtil;
/**
* Defines a datatype with a set of preset values of any type as held within a pair of
* maps. While the values are not serialized out, the labels are and serve as keys to
* obtain the values.
*
* @author Brian Remedios
* @version $Revision$
*/
public class EnumeratedProperty extends AbstractPMDProperty {
private Object[][] choiceTuples;
private Map choicesByLabel;
private Map labelsByChoice;
/**
* Constructor for EnumeratedProperty.
* @param theName String
* @param theDescription String
* @param theChoices Object[][]
* @param theUIOrder float
*/
public EnumeratedProperty(String theName, String theDescription, Object[][] theChoices, float theUIOrder) {
this(theName, theDescription, theChoices, theUIOrder, 1);
}
/**
* Constructor for EnumeratedProperty.
* @param theName String
* @param theDescription String
* @param theChoices Object[][]
* @param theUIOrder float
* @param maxValues int
*/
public EnumeratedProperty(String theName, String theDescription, Object[][] theChoices, float theUIOrder, int maxValues) {
super(theName, theDescription, theChoices[0][1], theUIOrder);
choiceTuples = theChoices;
choicesByLabel = CollectionUtil.mapFrom(theChoices);
labelsByChoice = CollectionUtil.invertedMapFrom(choicesByLabel);
maxValueCount(maxValues);
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Object.class;
}
/**
* Method choices.
* @return Object[][]
* @see net.sourceforge.pmd.PropertyDescriptor#choices()
*/
public Object[][] choices() {
return choiceTuples;
}
private String nonLegalValueMsgFor(Object value) {
return "" + value + " is not a legal value";
}
/**
* Method errorFor.
* @param value Object
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#errorFor(Object)
*/
public String errorFor(Object value) {
if (maxValueCount() == 1) {
return labelsByChoice.containsKey(value) ?
null : nonLegalValueMsgFor(value);
}
Object[] values = (Object[])value;
for (int i=0; i<values.length; i++) {
if (labelsByChoice.containsKey(values[i])) continue;
return nonLegalValueMsgFor(values[i]);
}
return null;
}
/**
* Method choiceFrom.
* @param label String
* @return Object
*/
private Object choiceFrom(String label) {
Object result = choicesByLabel.get(label);
if (result != null) return result;
throw new IllegalArgumentException(label);
}
/**
* Method valueFrom.
* @param value String
* @return Object
* @throws IllegalArgumentException
* @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String)
*/
public Object valueFrom(String value) throws IllegalArgumentException {
if (maxValueCount() == 1) return choiceFrom(value);
String[] strValues = StringUtil.substringsOf(value, multiValueDelimiter);
Object[] values = new Object[strValues.length];
for (int i=0;i<values.length; i++) values[i] = choiceFrom(strValues[i]);
return values;
}
/**
* Method asDelimitedString.
* @param value Object
* @return String
* @see net.sourceforge.pmd.PropertyDescriptor#asDelimitedString(Object)
*/
public String asDelimitedString(Object value) {
if (maxValueCount() == 1) return (String)labelsByChoice.get(value);
Object[] choices = (Object[])value;
StringBuffer sb = new StringBuffer();
sb.append(labelsByChoice.get(choices[0]));
for (int i=1; i<choices.length; i++) {
sb.append(multiValueDelimiter);
sb.append(labelsByChoice.get(choices[i]));
}
return sb.toString();
}
}

View File

@ -0,0 +1,85 @@
package net.sourceforge.pmd.properties;
/**
* Defines a property type that support float property values.
*
* @author Brian Remedios
*/
public class FloatProperty extends AbstractScalarProperty {
/**
* Constructor for FloatProperty.
* @param theName String
* @param theDescription String
* @param theDefault float
* @param theUIOrder float
*/
public FloatProperty(String theName, String theDescription, float theDefault, float theUIOrder) {
super(theName, theDescription, new Float(theDefault), theUIOrder);
}
/**
* Constructor for FloatProperty.
* @param theName String
* @param theDescription String
* @param defaultValues boolean[]
* @param theUIOrder float
* @param theMaxValues int
*/
public FloatProperty(String theName, String theDescription, float[] defaultValues, float theUIOrder, int theMaxValues) {
this(theName, theDescription, asFloats(defaultValues), theUIOrder, theMaxValues);
}
/**
* Constructor for FloatProperty.
* @param theName String
* @param theDescription String
* @param defaultValues Float[]
* @param theUIOrder float
* @param theMaxValues int
*/
public FloatProperty(String theName, String theDescription, Float[] defaultValues, float theUIOrder, int theMaxValues) {
super(theName, theDescription, defaultValues, theUIOrder);
maxValueCount(theMaxValues);
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Float.class;
}
/**
* Method asFloats.
* @param floats float[]
* @return Float[]
*/
private static final Float[] asFloats(float[] floats) {
Float[] Floats = new Float[floats.length];
for (int i=0; i<floats.length; i++) Floats[i] = new Float(floats[i]);
return Floats;
}
/**
* Method createFrom.
* @param value String
* @return Object
*/
protected Object createFrom(String value) {
return new Float(value);
}
/**
* Method arrayFor.
* @param size int
* @return Object[]
*/
protected Object[] arrayFor(int size) {
return new Float[size];
}
}

View File

@ -0,0 +1,86 @@
package net.sourceforge.pmd.properties;
/**
* Defines a datatype that supports the Integer property values.
*
* @author Brian Remedios
* @version $Revision$
*/
public class IntegerProperty extends AbstractScalarProperty {
/**
* Constructor for IntegerProperty.
* @param theName String
* @param theDescription String
* @param theDefault int
* @param theUIOrder float
*/
public IntegerProperty(String theName, String theDescription, int theDefault, float theUIOrder) {
super(theName, theDescription, new Integer(theDefault), theUIOrder);
}
/**
* Constructor for IntegerProperty.
* @param theName String
* @param theDescription String
* @param theDefaults int[]
* @param theUIOrder float
* @param maxCount int
*/
public IntegerProperty(String theName, String theDescription, int[] theDefaults, float theUIOrder, int maxCount) {
this(theName, theDescription, asIntegers(theDefaults), theUIOrder, maxCount);
}
/**
* Constructor for IntegerProperty.
* @param theName String
* @param theDescription String
* @param theDefaults Integer[]
* @param theUIOrder float
* @param maxCount int
*/
public IntegerProperty(String theName, String theDescription, Integer[] theDefaults, float theUIOrder, int maxCount) {
super(theName, theDescription, theDefaults, theUIOrder);
maxValueCount(maxCount);
}
/**
* Method asIntegers.
* @param ints int[]
* @return Integer[]
*/
private static final Integer[] asIntegers(int[] ints) {
Integer[] integers = new Integer[ints.length];
for (int i=0; i<ints.length; i++) integers[i] = new Integer(ints[i]);
return integers;
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Integer.class;
}
/**
* Method createFrom.
* @param value String
* @return Object
*/
protected Object createFrom(String value) {
return new Integer(value);
}
/**
* Method arrayFor.
* @param size int
* @return Object[]
*/
protected Object[] arrayFor(int size) {
return new Integer[size];
}
}

View File

@ -0,0 +1,71 @@
package net.sourceforge.pmd.properties;
import java.lang.reflect.Method;
/**
* @author Brian Remedios
*/
public class MethodProperty extends AbstractPMDProperty {
/**
* Constructor for MethodProperty.
* @param theName String
* @param theDescription String
* @param theDefault Object
* @param theUIOrder float
*/
public MethodProperty(String theName, String theDescription, Object theDefault, float theUIOrder) {
super(theName, theDescription, theDefault, theUIOrder);
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Method.class;
}
/**
* Method valueFrom.
* @param propertyString String
* @return Object
* @throws IllegalArgumentException
* @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String)
*/
public Object valueFrom(String propertyString) throws IllegalArgumentException {
Class cls = classIn(propertyString);
String methodName = methodNameIn(propertyString);
Class[] parameterTypes = parameterTypesIn(propertyString);
try {
return cls.getMethod(methodName, parameterTypes);
} catch (Exception e) {
throw new IllegalArgumentException("invalid method: " + propertyString);
}
}
private Class classIn(String propertyString) throws IllegalArgumentException {
int dotPos = propertyString.lastIndexOf('.');
String className = propertyString.substring(0, dotPos);
try {
return Class.forName(className);
} catch (Exception ex) {
throw new IllegalArgumentException("class not found: " + className);
}
}
private String methodNameIn(String propertyString) throws IllegalArgumentException {
int dotPos = propertyString.lastIndexOf('.');
return propertyString.substring(dotPos);
}
private Class[] parameterTypesIn(String propertyString) {
return null;
}
}

View File

@ -0,0 +1,121 @@
package net.sourceforge.pmd.properties;
import net.sourceforge.pmd.util.StringUtil;
/**
* Defines a datatype that supports String values.
* When capturing multiple values, all strings must be filtered by the delimiter character.
*
* @author Brian Remedios
* @version $Revision$
*/
public class StringProperty extends AbstractPMDProperty {
private int preferredRowCount;
public static final char defaultDelimiter = '|';
/**
* Constructor for StringProperty.
* @param theName String
* @param theDescription String
* @param theDefaultValue String
* @param theUIOrder float
*/
public StringProperty(String theName, String theDescription, String theDefaultValue, float theUIOrder) {
this(theName, theDescription, theDefaultValue, theUIOrder, defaultDelimiter);
maxValueCount(1);
}
/**
* Constructor for StringProperty.
* @param theName String
* @param theDescription String
* @param theValues String[]
* @param theUIOrder float
* @param aMultiValueDelimiter String
*/
public StringProperty(String theName, String theDescription, String[] theValues, float theUIOrder, char aMultiValueDelimiter) {
super(theName, theDescription, theValues, theUIOrder);
maxValueCount(Integer.MAX_VALUE);
multiValueDelimiter(aMultiValueDelimiter);
}
/**
* Constructor for StringProperty.
* @param theName String
* @param theDescription String
* @param theDefaultValue Object
* @param theUIOrder float
* @param aMultiValueDelimiter String
*/
protected StringProperty(String theName, String theDescription, Object theDefaultValue, float theUIOrder, char aMultiValueDelimiter) {
super(theName, theDescription, theDefaultValue, theUIOrder);
maxValueCount(Integer.MAX_VALUE);
multiValueDelimiter(aMultiValueDelimiter);
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return String.class;
}
/**
* Method valueFrom.
* @param valueString String
* @return Object
* @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String)
*/
public Object valueFrom(String valueString) {
if (maxValueCount() == 1) return valueString;
return StringUtil.substringsOf(valueString, multiValueDelimiter);
}
/**
* Method containsDelimiter.
* @param value String
* @return boolean
*/
private boolean containsDelimiter(String value) {
return value.indexOf(multiValueDelimiter) >= 0;
}
private final String illegalCharMsg() {
return "Value cannot contain the \"" + multiValueDelimiter + "\" character";
}
/**
*
* @param value Object
* @return String
*/
protected String valueErrorFor(Object value) {
if (maxValueCount() == 1) {
String testValue = (String)value;
if (!containsDelimiter(testValue)) return null;
return illegalCharMsg();
}
String[] values = (String[])value;
for (int i=0; i<values.length; i++) {
if (!containsDelimiter(values[i])) continue;
return illegalCharMsg();
}
return null;
}
public int preferredRowCount() {
return preferredRowCount;
}
}

View File

@ -0,0 +1,105 @@
package net.sourceforge.pmd.properties;
import net.sourceforge.pmd.util.ClassUtil;
import net.sourceforge.pmd.util.CollectionUtil;
/**
* Defines a property that supports class types, even for primitive values!
*
* @author Brian Remedios
* @version $Revision$
*/
public class TypeProperty extends StringProperty {
private static final char delimiter = '|';
/**
* Constructor for TypeProperty.
* @param theName String
* @param theDescription String
* @param theDefault Class
* @param theUIOrder float
*/
public TypeProperty(String theName, String theDescription, Class theDefault, float theUIOrder) {
super(theName, theDescription, theDefault, theUIOrder, delimiter);
maxValueCount(1);
}
/**
* Constructor for TypeProperty.
* @param theName String
* @param theDescription String
* @param theDefaults Class[]
* @param theUIOrder float
*/
public TypeProperty(String theName, String theDescription, Class[] theDefaults, float theUIOrder) {
super(theName, theDescription, theDefaults, theUIOrder, delimiter);
maxValueCount(Integer.MAX_VALUE);
}
/**
* Method type.
* @return Class
* @see net.sourceforge.pmd.PropertyDescriptor#type()
*/
public Class type() {
return Class.class;
}
/**
* Method asString.
* @param value Object
* @return String
*/
protected String asString(Object value) {
return value == null ? "" : ((Class)value).getName();
}
/**
* Method classFrom.
* @param className String
* @return Class
*/
private Class classFrom(String className) {
Class cls = ClassUtil.getTypeFor(className);
if (cls != null) return cls;
try {
return Class.forName(className);
} catch (Exception ex) {
throw new IllegalArgumentException(className);
}
}
/**
* Method valueFrom.
* @param valueString String
* @return Object
* @see net.sourceforge.pmd.PropertyDescriptor#valueFrom(String)
*/
public Object valueFrom(String valueString) {
if (maxValueCount() == 1) return classFrom(valueString);
String[] values = (String[])super.valueFrom(valueString);
Class[] classes = new Class[values.length];
for (int i=0; i<values.length; i++) classes[i] = classFrom(values[i]);
return classes;
}
/**
* Neutralize unwanted superclass functionality that will result
* in a class cast exception.
*
* @param value Object
* @return String
*/
protected String valueErrorFor(Object value) {
return null;
}
}