r1958 - in trunk/commons-beanutils: . branches branches/upstream branches/upstream/current branches/upstream/current/optional branches/upstream/current/optional/bean-collections branches/upstream/current/optional/bean-collections/src branches/upstream/current/optional/bean-collections/src/conf branches/upstream/current/optional/bean-collections/src/java branches/upstream/current/optional/bean-collections/src/java/org branches/upstream/current/optional/bean-collections/src/java/org/apache branches/upstream/current/optional/bean-collections/src/java/org/apache/commons branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils branches/upstream/current/optional/bean-collections/src/test branches/upstream/current/optional/bean-collections/src/test/org branches/upstream/current/optional/bean-collections/src/test/org/apache branches/upstream/current/optional/bean-collections/src/test/org/apache/commons branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils branches/upstream/current/optional/bean-collections/xdocs branches/upstream/current/src branches/upstream/current/src/conf branches/upstream/current/src/java branches/upstream/current/src/java/org branches/upstream/current/src/java/org/apache branches/upstream/current/src/java/org/apache/commons branches/upstream/current/src/java/org/apache/commons/beanutils branches/upstream/current/src/java/org/apache/commons/beanutils/converters branches/upstream/current/src/java/org/apache/commons/beanutils/locale branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters branches/upstream/current/src/java/org/apache/commons/collections branches/upstream/current/src/media branches/upstream/current/src/test branches/upstream/current/src/test/org branches/upstream/current/src/test/org/apache branches/upstream/current/src/test/org/apache/commons branches/upstream/current/src/test/org/apache/commons/beanutils branches/upstream/current/src/test/org/apache/commons/beanutils/converters branches/upstream/current/src/test/org/apache/commons/beanutils/locale branches/upstream/current/src/test/org/apache/commons/beanutils/locale/converters branches/upstream/current/src/test/org/apache/commons/beanutils/priv branches/upstream/current/src/test/org/apache/commons/collections branches/upstream/current/src/test/org/apache/commons/collections/keyvalue branches/upstream/current/xdocs branches/upstream/current/xdocs/images branches/upstream/current/xdocs/style

Arnaud Vandyck avdyk at costa.debian.org
Thu Mar 9 22:05:12 UTC 2006


Author: avdyk
Date: 2006-03-09 22:04:21 +0000 (Thu, 09 Mar 2006)
New Revision: 1958

Added:
   trunk/commons-beanutils/branches/
   trunk/commons-beanutils/branches/upstream/
   trunk/commons-beanutils/branches/upstream/current/
   trunk/commons-beanutils/branches/upstream/current/.cvsignore
   trunk/commons-beanutils/branches/upstream/current/LICENSE.txt
   trunk/commons-beanutils/branches/upstream/current/NOTICE.txt
   trunk/commons-beanutils/branches/upstream/current/PROPOSAL.html
   trunk/commons-beanutils/branches/upstream/current/README.txt
   trunk/commons-beanutils/branches/upstream/current/RELEASE-NOTES.txt
   trunk/commons-beanutils/branches/upstream/current/STATUS.html
   trunk/commons-beanutils/branches/upstream/current/build.properties.sample
   trunk/commons-beanutils/branches/upstream/current/build.xml
   trunk/commons-beanutils/branches/upstream/current/maven.xml
   trunk/commons-beanutils/branches/upstream/current/optional/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/.cvsignore
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/LICENSE.txt
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.properties.sample
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.xml
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/project.xml
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/conf/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/conf/MANIFEST.MF
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanComparator.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanMap.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPredicate.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueChangeClosure.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicate.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanToPropertyValueTransformer.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/overview.html
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AbstractParent.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AlphaBean.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanCollectionsTestSuite.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanComparatorTestCase.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPredicateTestCase.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueChangeClosureTest.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicateTest.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanToPropertyValueTransformerTest.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/Child.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBean.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBeanMap.java
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/index.xml
   trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/navigation.xml
   trunk/commons-beanutils/branches/upstream/current/project.properties
   trunk/commons-beanutils/branches/upstream/current/project.xml
   trunk/commons-beanutils/branches/upstream/current/src/
   trunk/commons-beanutils/branches/upstream/current/src/conf/
   trunk/commons-beanutils/branches/upstream/current/src/conf/MANIFEST.MF
   trunk/commons-beanutils/branches/upstream/current/src/java/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanAccessLanguageException.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtilsBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConstructorUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ContextClassLoaderLocal.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConversionException.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtilsBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/Converter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertingWrapDynaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaProperty.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/JDBCDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaMap.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MethodUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MutableDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/NestedNullException.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetIterator.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/RowSetDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaClass.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/AbstractArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigDecimalConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigIntegerConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ClassConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FileConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlDateConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimeConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimestampConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringArrayConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/URLConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/package.html
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/BaseLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtilsBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtils.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtilsBean.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ByteLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlDateLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/StringLocaleConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/package.html
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/package.html
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/package.html
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/ArrayStack.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/Buffer.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/BufferUnderflowException.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/FastHashMap.java
   trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/package.html
   trunk/commons-beanutils/branches/upstream/current/src/java/overview.html
   trunk/commons-beanutils/branches/upstream/current/src/media/
   trunk/commons-beanutils/branches/upstream/current/src/media/logo.xcf
   trunk/commons-beanutils/branches/upstream/current/src/test/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/A.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractChild.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractParent.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AlphaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BasicDynaBeanTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsBenchCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanWithInnerBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanificationTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BenchBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BetaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/Child.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConstructorUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConvertUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaBeanUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaPropertyUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaResultSetTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaRowSetTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ExtendMapBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaBeanTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaClassTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaMapTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MappedPropertyTestBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/NestedTestBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PassTestException.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PrimitiveBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsBenchCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/SonOfAlphaBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPackageSubclass.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPublicSubclass.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSet.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSetMetaData.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ThrowExceptionConverter.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/WrapDynaBeanTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ByteConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ConverterTestSuite.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/DoubleConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FileConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FloatConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/IntegerConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/LongConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/NumberConverterTestBase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ShortConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/StringArrayConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/URLConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleBeanificationTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertTestSuite.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertUtilsTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/converters/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/converters/DateLocaleConverterTestCase.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PackageBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanFactory.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanSubclass.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateDirect.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateIndirect.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PublicSubBean.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/ReferenceMap.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractKeyValue.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractMapEntry.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/DefaultMapEntry.java
   trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/KeyValue.java
   trunk/commons-beanutils/branches/upstream/current/xdocs/
   trunk/commons-beanutils/branches/upstream/current/xdocs/.cvsignore
   trunk/commons-beanutils/branches/upstream/current/xdocs/images/
   trunk/commons-beanutils/branches/upstream/current/xdocs/images/logo.png
   trunk/commons-beanutils/branches/upstream/current/xdocs/index.xml
   trunk/commons-beanutils/branches/upstream/current/xdocs/navigation.xml
   trunk/commons-beanutils/branches/upstream/current/xdocs/proposal.xml
   trunk/commons-beanutils/branches/upstream/current/xdocs/style/
   trunk/commons-beanutils/branches/upstream/current/xdocs/style/project.css
   trunk/commons-beanutils/tags/
Log:
[svn-inject] Installing original source of commons-beanutils

Added: trunk/commons-beanutils/branches/upstream/current/.cvsignore
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/.cvsignore	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/.cvsignore	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,8 @@
+build.properties
+dist
+target
+beanutils.ipr
+maven.log
+velocity.log
+.classpath
+.project

Added: trunk/commons-beanutils/branches/upstream/current/LICENSE.txt
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/LICENSE.txt	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/LICENSE.txt	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

Added: trunk/commons-beanutils/branches/upstream/current/NOTICE.txt
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/NOTICE.txt	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/NOTICE.txt	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,2 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).

Added: trunk/commons-beanutils/branches/upstream/current/PROPOSAL.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/PROPOSAL.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/PROPOSAL.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,128 @@
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<title>Proposal for BeanUtils Package</title>
+</head>
+<body bgcolor="white">
+
+<div align="center">
+<h1>Proposal for <em>BeanUtils</em> Package</h1>
+</div>
+
+<h3>(0) Rationale</h3>
+
+<p>Most Java developers are used to creating Java classes that conform to the
+JavaBeans naming patterns for property getters and setters.  It is natural to
+then access these methods directly, using calls to the corresponding
+<code>getXxx</code> and <code>setXxx</code> methods.  However, there are some
+occasions where dynamic access to Java object properties (without compiled-in
+knowledge of the property getter and setter methods to be called) is needed.
+Example use cases include:</p>
+<ul>
+<li>Building scripting languages that interact with the Java object model
+    (such as the Bean Scripting Framework).</li>
+<li>Building template language processors for web presentation and similar
+    uses (such as JSP or Velocity).</li>
+<li>Building custom tag libraries for JSP and XSP environments (such as Jakarta
+    Taglibs, Struts, Cocoon).</li>
+<li>Consuming XML-based configuration resources (such as Ant build scripts, web
+    application deployment descriptors, Tomcat's <code>server.xml</code>
+    file).</li>
+</ul>
+
+<p>The Java language provides <em>Reflection</em> and <em>Introspection</em>
+APIs (see the <code>java.lang.reflect</code> and <code>java.beans</code>
+packages in the JDK Javadocs).  However, these APIs can be quite complex to
+understand and utilize.  The proposed <em>BeanUtils</em> component provides
+easy-to-use wrappers around these capabilities.</p>
+
+
+<h3>(1) Scope of the Package</h3>
+
+<p>This proposal is to create a package of Java utility methods for accessing
+and modifying the properties of arbitrary JavaBeans.  No dependencies outside
+of the JDK are required, so the use of this package is very lightweight.</p>
+
+<p>In addition to wrapping the reflection and introspection APIs of the
+standard JDK, <em>BeanUtils</em> components shall support a syntax for directly
+accessing <strong>nested</strong> and <strong>indexed</strong> properties, in a
+manner that will be familar to users of scripting languages like JavaScript.
+For example, the following property accessor expressions are supported:</p>
+<ul>
+<li><strong>customer</strong> - Equivalent to <code>getCustomer()</code>.</li>
+<li><strong>customer.address</strong> - Equivalent to
+    <code>getCustomer().getAddress()</code>.</li>
+<li><strong>customer.address[2].street</strong> - Equivalent to
+    <code>getCustomer().getAddress(2).getStreet()</code> (access to indexed
+    properties also works if the underlying property is an array rather than
+    providing indexed getter and setter methods).</li>
+</ul>
+
+
+<h3>(1.5) Interaction With Other Packages</h3>
+
+<p><em>BeanUtils</em> relies only on standard JDK 1.2 (or later) APIs for
+production deployment.  It utilizes the JUnit unit testing framework for
+developing and executing unit tests, but this is of interest only to
+developers of the component.  BeanUtils will also be a dependency for
+several future proposed components for the Jakarta Commons subproject.</p>
+
+<p>No external configuration files are utilized.</p>
+
+
+<h3>(2) Initial Source of the Package</h3>
+
+<p>The three original Java classes (<code>BeanUtils</code>,
+<code>ConvertUtils</code>, and <code>PropertyUtils</code>) are an integral
+part of the <a href="http://jakarta.apache.org/struts">Struts Framework</a>.
+However, they have very few dependencies on other aspects of Struts, and
+those dependencies have been removed in the proposed code base.
+Once accepted and released as a Jakarta Commons component, Struts will
+be modified to use the Commons version of these classes, and its internal
+versions will be deprecated.</p>
+
+<p>The proposed package name for the new component is
+<code>org.apache.commons.beanutils</code>.</p>
+
+
+<h3>(3)  Required Jakarta-Commons Resources</h3>
+
+<ul>
+<li>CVS Repository - New directory <code>beanutils</code> in the
+    <code>jakarta-commons</code> CVS repository.  All initial committers
+    are already committers on <code>jakarta-commons</code>, so no
+    additional user setups are required.</li>
+<li>Mailing List - Discussions will take place on the general
+    <em>jakarta-commons at jakarta.apache.org</em> mailing list.  To help
+    list subscribers identify messages of interest, it is suggested that
+    the message subject of messages about this component be prefixed with
+    [BeanUtils].</li>
+<li>Bugzilla - New component "BeanUtils" under the "Commons" product
+    category, with appropriate version identifiers as needed.</li>
+<li>Jyve FAQ - New category "commons-beanutils" (when available). </li>
+</ul>
+
+
+<h3>(4) Initial Committers</h3>
+
+<p>The initial committers on the BeanUtils component shall be Craig
+McClanahan and Geir Magnusson Jr.</p>
+
+
+
+</body>
+</html>


Property changes on: trunk/commons-beanutils/branches/upstream/current/PROPOSAL.html
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/README.txt
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/README.txt	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/README.txt	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,26 @@
+README
+======
+
+Jars
+----
+
+BeanUtils now comes packaged (into jars) in two different ways: 
+
+    an all-in-one jar (commons-beanutils.jar);
+    and as modular component jars:
+	commons-beanutils-core.jar (core classes)
+	commons-beanutils-bean-collections.jar (additional dependency on commons-collections 3.0)
+
+Those who want it all should grab the all-in-one jar (and the optional dependencies) 
+whereas those who need minimal dependencies should use commons-beanutils-core.jar
+plus any optional jars they plan to use.
+
+All classes that were in the last release are in commons-beanutils-core except for BeanComparator. 
+
+Commons-Collections
+-------------------
+BeanUtils now ships with a small number of commons collections classes. 
+This is a temporary measure intended to allow BeanUtils core to be used with 
+either commons-collections 2 or commons-collections-3 without a dependency on either.
+It is intended that soon BeanUtils core will have no dependency on any commons collection
+packaged classes.
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/RELEASE-NOTES.txt
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/RELEASE-NOTES.txt	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/RELEASE-NOTES.txt	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,90 @@
+$Id: RELEASE-NOTES.txt,v 1.11.2.3 2004/08/01 20:15:19 rdonkin Exp $
+
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                          Commons BeanUtils Package
+                             Version 1.7.0
+                               Release Notes
+
+INTRODUCTION:
+============
+
+Beanutils 1.7.0 is a service release aimed at providing compatibility
+with both the commons collections 2.x series of releases 
+and the commons collections 3.x series of releases
+
+CHANGES:
+========
+
+Upgraded License To Apache License 2.0
+--------------------------------------
+Beanutils is now released under the Apache License 2.0. 
+See http://www.apache.org/licenses/LICENSE-2.0.
+
+Beanification
+-------------
+Creation of objects to back the static utility classes. These object are 
+per-context-classloader pseudo-singletons. Each web or enterprise application 
+is therefore isolated from changes made to the state of others suing the
+static facades. Greater flexibility of implementation is encourage since users
+can subclass and then set their own implementations. Calls to the static facades 
+will then be passed to that implementation.
+
+Removal Of Commons Collections Dependency
+-----------------------------------------
+The commons collections dependency is in the process of being removed
+from core beanutils. This will reduce the number of dependencies for
+the core beanutils and also will allow beanutils to used with both
+collection 2.x and collection 3.x releases.
+
+Documentation Improvements
+--------------------------
+Many thanks to all those kind souls who've contributed documentation :)
+
+ 
+ENHANCEMENTS:
+=============
+
+BeanAccessLanguageException & NestNullException
+-----------------------------------------------
+Added new subclasses of RuntimeException so that bean access language
+exceptions can be trapped by users.
+
+BeanComparator
+--------------
+Added no-argument constructor for use in bean-centric environments.
+
+ConvertUtilsBean
+----------------
+Added a File converter and registered the File and URL converters by default
+
+
+BUG REPORTS ADDRESSED:
+=====================
+   #14848 Converted localized versions of beanutils and convert utils to use 
+          delegated singletons. Now instances with the functionality in these 
+          classes can be created.  
+          Added public constructors for the utility objects (BeanUtilsBean, 
+          PropertyUtilsBean and ConvertUtilsBean). Add public accessor properties
+          for the ConvertUtilsBean and PropertyUtilsBean instances used by a 
+          BeanUtilsBean. This allows BeanUtilsBean objects to be created with 
+          independent registered converters and independent caches.  Also added
+          test cases. 
+   #17663 Made BeanUtils.getArrayProperty conversions use ConvertUtils 
+          (rather than just toString)
+   #18918 This bug prevented converters from being correctly deregistered
+   #19850 Now cloneBean will deal successfully with DynaBeans.
+

Added: trunk/commons-beanutils/branches/upstream/current/STATUS.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/STATUS.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/STATUS.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,131 @@
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<title>Status File for Jakarta Commons "BeanUtils" Component</title>
+<head>
+<body bgcolor="white">
+
+
+<div align="center">
+<h1>The Jakarta Commons <em>BeanUtils</em> Component</h1>
+$Id: STATUS.html,v 1.16 2004/02/29 21:17:51 scolebourne Exp $<br>
+<a href="#Introduction">[Introduction]</a>
+<a href="#Dependencies">[Dependencies]</a>
+<a href="#Release Info">[Release Info]</a>
+<a href="#Committers">[Committers]</a>
+<a href="#Action Items">[Action Items]</a>
+<br><br>
+</div>
+
+
+<a name="Introduction"></a>
+<h3>1.  INTRODUCTION</h3>
+
+<p>The <em>BeanUtils</em> Component contains a set of Java classes that provide
+static utility methods useful in manipulating Java classes that conform to the
+JavaBeans Specification naming patterns for bean properties in a dynamic
+fashion.  The following classes are included:</p>
+<ul>
+<li><strong>BeanUtils</strong> - Higher level getters and setters that deal
+    with automatic conversion of String-represented property values to the
+    corresponding data types of the underlying property setters (and vice
+    versa), using the capabilities of the ConvertUtils and PropertyUtils
+    classes.</li>
+<li><strong>ConvertUtils</strong> - Utility methods to convert String arguments
+    to native Java types (and vice versa)</li>.
+<li><strong>PropertyUtils</strong> - Low level getters and setters for bean
+    properties that perform no type conversions at all.  Works on
+    <code>List</code> objects as well (Not JavaBeans standard).</li>
+</ul>
+
+<p>An innovative and unique feature of this component is the syntax for
+accessing nested and indexed bean properties.  See the Javadocs
+<a href="http://jakarta.apache.org/commons/beanutils/api/">PropertyUtils</a>
+for more information about this feature.</p>
+
+
+<a name="Dependencies"></a>
+<h3>2.  DEPENDENCIES</h3>
+
+<p>The <em>BeanUtils</em> component is dependent upon the following external
+components for development and use:</p>
+<ul>
+<li><a href="http://java.sun.com/j2se">Java Development Kit</a>
+    (Version 1.2 or later)</li>
+<li><a href="http://jakarta.apache.org/commons">Collections Classes</a>
+    from the Jakarta Commons Subproject</li>
+<li><a href="http://jakarta.apache.org/commons">Logging Classes</a>
+    from the Jakarta Commons Subproject</li>
+<li><a href="http://www.junit.org">JUnit Testing Framework</a>
+    (Version 3.7 or later) - for unit tests only, not required
+    for deployment</li>
+</ul>
+
+
+<a name="Release Info"></a>
+<h3>3.  RELEASE INFO</h3>
+
+<p>Current Release: Version 1.6.1</p>
+
+<p>Planned Next Release: 1.7</p>
+
+
+<a name="Committers"></a>
+<h3>4.  COMMITTERS</h3>
+
+<p>The following individuals are the primary developers and maintainers of this
+component.  Developers who plan to use <em>BeanUtils</em> in their own
+projects are encouraged to collaborate on the future development of this
+component to ensure that it continues to meet a variety of needs.</p>
+<ul>
+<li><a href="mailto:craigmcc at apache.org">Craig McClanahan</a></li>
+<li><a href="mailto:geirm at apache.org">Geir Magnusson Jr.</a></li>
+<li><a href="mailto:sanders at apache.org">Scott Sanders</a></li>
+<li><a href="mailto:rdonkin at apache.org">Robert Burrell Donkin</a></li>
+<li><a href="mailto:dion at apache.org">dIon Gillard</a></li>
+<li><a href="mailto:jstrachan at apache.org">James Strachan</a></li>
+<li><a href="mailto:yoavs at apache.org">Yoav Shapira</a></li>
+</ul>
+
+
+<a name="Action Items"></a>
+<h3>5.  ACTION ITEMS</h3>
+
+<p>The following action items need to be completed prior to the next
+release of this component:</p>
+
+<table border="1">
+
+  <tr>
+    <th width="80%">Action Item</th>
+    <th width="20%">Volunteer</th>
+  </tr>
+
+  <tr>
+    <td><strong>Finish locale-sensitive beans and converters.</strong>.
+    <td align="center">All</td>
+  </tr>
+
+  <tr>
+    <td><strong>Add test cases</strong>.  Especially for i18n classes.</td>
+    <td align="center">All</td>
+  </tr>
+
+</table>
+
+</body>
+</html>


Property changes on: trunk/commons-beanutils/branches/upstream/current/STATUS.html
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/build.properties.sample
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/build.properties.sample	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/build.properties.sample	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,38 @@
+#   Copyright 2001-2004 The Apache Software Foundation
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+# The home directory for the Commons collection classes distribution
+commons-collections.home = ../collections/dist
+
+# The pathname of the collections classes JAR file
+commons-collections.jar = ${commons-collections.home}/commons-collections.jar
+
+# The home directory for the Commons logging classes distribution
+commons-logging.home = ../logging/dist
+
+# The pathname of the Commons Logging JAR file
+commons-logging.jar = ${commons-logging.home}/commons-logging.jar
+
+# The directory containing your binary distribution of JUnit, 
+# version 3.7 or later
+junit.home = /usr/local/junit3.7
+
+# The pathname of the "junit.jar" JAR file
+junit.jar = ${junit.home}/junit.jar
+
+
+# Maven properties (for web site build)
+# Those committers using agents may like to use
+#maven.username=rdonkin
+#beanutils.cvs=lserver:rdonkin at cvs.apache.org:/home/cvs
\ No newline at end of file


Property changes on: trunk/commons-beanutils/branches/upstream/current/build.properties.sample
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/build.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/build.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/build.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,575 @@
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="Bean Utilities" default="compile" basedir=".">
+
+
+<!--
+        "Bean Utilities" component of the Jakarta Commons Subproject
+        $Id: build.xml,v 1.59.2.3 2004/07/27 21:59:14 rdonkin Exp $
+-->
+
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+  <property file="build.properties"/>                <!-- Component local   -->
+  <property file="../build.properties"/>             <!-- Commons local     -->
+  <property file="${user.home}/build.properties"/>   <!-- User local        -->
+
+
+<!-- ========== External Dependencies ===================================== -->
+
+  <!-- The home directory for the Commons collection classes distribution -->
+  <property name="commons-logging.home" value="../logging/dist"/>
+
+  <!-- The directory containing your binary distribution of JUnit,
+       version 3.7 or later -->
+  <property name="junit.home"              value="/usr/local/junit3.7"/>
+
+
+<!-- ========== Derived Values ============================================ -->
+
+  <!-- The pathname of the "junit.jar" JAR file -->
+  <property name="junit.jar"               value="${junit.home}/junit.jar"/>
+
+
+<!-- ========== Component Declarations ==================================== -->
+
+
+  <!-- The name of this component -->
+  <property name="component.name"          value="beanutils"/>
+
+  <!-- The primary package name of this component -->
+  <property name="component.package"       value="org.apache.commons.beanutils"/>
+
+  <!-- The title of this component -->
+  <property name="component.title"         value="Bean Introspection Utilities"/>
+
+  <!-- The current version number of this component -->
+  <property name="component.version"       value="1.7"/>
+
+  <!-- The base directory for compilation targets -->
+  <property name="build.home"              value="target"/>
+
+  <!-- The base directory for component configuration files -->
+  <property name="conf.home"               value="src/conf"/>
+
+  <!-- The base directory for distribution targets -->
+  <property name="dist.home"               value="dist"/>
+
+  <!-- The base directory for component sources -->
+  <property name="source.home"             value="src/java"/>
+
+  <!-- The base directory for unit test sources -->
+  <property name="test.home"               value="src/test"/>
+
+
+<!-- ========== Compiler Defaults ========================================= -->
+
+
+  <!-- Should Java compilations set the 'debug' compiler option? -->
+  <property name="compile.debug"           value="true"/>
+
+  <!-- Should Java compilations set the 'deprecation' compiler option? -->
+  <property name="compile.deprecation"     value="false"/>
+
+  <!-- Should Java compilations set the 'optimize' compiler option? -->
+  <property name="compile.optimize"        value="true"/>
+
+  <!-- Construct compile classpath -->
+  <path id="compile.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${commons-logging.jar}"/>
+  </path>
+
+
+<!-- ========== Test Execution Defaults =================================== -->
+
+
+  <!-- Construct unit test classpath -->
+  <path id="test.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${build.home}/tests"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${junit.jar}"/>
+  </path>
+
+  <!-- Should all tests fail if one does? -->
+  <property name="test.failonerror"        value="true"/>
+
+  <!-- The test runner to execute -->
+  <property name="test.runner"             value="junit.textui.TestRunner"/>
+
+  <!-- The Commons Logger LogFactory implementation to use -->
+  <property name="test.factory"
+           value="org.apache.commons.logging.impl.LogFactoryImpl"/>
+
+  <!-- The Commons Logger Log implementation to use (standard factory) -->
+  <property name="test.log"
+           value="org.apache.commons.logging.impl.SimpleLog"/>
+
+  <!-- The Commons Logger SimpleLog level for testing -->
+  <property name="test.level"               value="error"/>
+
+  <!-- Loop counter for microbenchmarks -->
+  <property name="bench.counter"            value="100000"/>
+
+
+<!-- ========== Executable Targets ======================================== -->
+
+
+  <target name="init"
+   description="Initialize and evaluate conditionals">
+    <echo message="-------- ${component.name} ${component.version} --------"/>
+    <filter  token="name"                  value="${component.name}"/>
+    <filter  token="package"               value="${component.package}"/>
+    <filter  token="version"               value="${component.version}"/>
+  </target>
+
+
+  <target name="prepare" depends="init"
+   description="Prepare build directory">
+    <mkdir dir="${build.home}"/>
+    <mkdir dir="${build.home}/classes"/>
+    <mkdir dir="${build.home}/conf"/>
+    <mkdir dir="${build.home}/tests"/>
+  </target>
+
+
+  <target name="static" depends="prepare"
+   description="Copy static files to build directory">
+    <tstamp/>
+    <copy  todir="${build.home}/conf" filtering="on">
+      <fileset dir="${conf.home}" includes="*.MF"/>
+    </copy>
+  </target>
+
+
+  <target name="compile" depends="static"
+   description="Compile shareable components">
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="compile.tests" depends="compile"
+   description="Compile unit test cases">
+    <javac  srcdir="${test.home}"
+           destdir="${build.home}/tests"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="test.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/tests" filtering="on">
+      <fileset dir="${test.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="clean"
+   description="Clean build and distribution directories">
+    <delete    dir="${build.home}"/>
+    <delete    dir="${dist.home}"/>
+  </target>
+
+
+  <target name="all" depends="clean,compile"
+   description="Clean and compile all components"/>
+
+
+  <target name="javadoc" depends="compile"
+   description="Create component Javadoc documentation">
+    <mkdir      dir="${dist.home}"/>
+    <mkdir      dir="${dist.home}/docs"/>
+    <mkdir      dir="${dist.home}/docs/api"/>
+    <javadoc sourcepath="${source.home}"
+                destdir="${dist.home}/docs/api"
+           packagenames="org.apache.commons.*"
+                 author="true"
+                private="true"
+                version="true"
+               overview="src/java/overview.html"
+               doctitle="&lt;h1&gt;${component.title} (Version ${component.version})&lt;/h1&gt;"
+            windowtitle="${component.title} (Version ${component.version})"
+                 bottom="Copyright (c) 2001-2004 - Apache Software Foundation">
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+  </target>
+
+
+  <target name="dist" depends="compile,javadoc"
+   description="Create binary distribution">
+    <mkdir      dir="${dist.home}"/>
+    <copy      file="LICENSE.txt"
+              todir="${dist.home}"/>
+    <copy      file="NOTICE.txt"
+              todir="${dist.home}"/>
+    <copy      file="RELEASE-NOTES.txt"
+              todir="${dist.home}"/>
+    <copy      file="README.txt"
+              todir="${dist.home}"/>
+    <antcall target="jar"/>
+    <antcall target="bean-collections-dist"/>
+  </target>
+
+
+  <target name="jar" depends="compile"
+   description="Create jar">
+    <mkdir      dir="${dist.home}"/>
+    <mkdir      dir="${build.home}/classes/META-INF"/>
+    <copy      file="LICENSE.txt"
+             tofile="${build.home}/classes/META-INF/LICENSE.txt"/>
+    <copy      file="NOTICE.txt"
+             tofile="${build.home}/classes/META-INF/NOTICE.txt"/>
+    <jar    jarfile="${dist.home}/commons-beanutils.jar"
+            basedir="${build.home}/classes"
+           manifest="${build.home}/conf/MANIFEST.MF"/>
+    <copy tofile='${dist.home}/commons-beanutils-core.jar' file='${dist.home}/commons-beanutils.jar'/>
+  </target>
+
+
+  <target name="install-jar" depends="jar"
+   description="--> Installs jar file in ${lib.repo}">
+    <copy todir="${lib.repo}" filtering="no">
+      <fileset dir="${dist.home}">
+        <include name="commons-${component.name}.jar"/>
+      </fileset>
+    </copy>
+  </target>
+
+<!-- ========== Sub Component Targets ===================================== -->
+
+  <target name='bean-collections-dist'>
+    <ant antfile='optional/bean-collections/build.xml' target='dist' inheritAll='false'/>
+  </target>
+
+<!-- ========== Unit Test Targets ========================================= -->
+
+
+  <target name="test"  depends="compile.tests,
+                                test.basic.dynabean,
+                                test.wrap.dynabean,
+                                test.dyna.property,
+                                test.property,
+                                test.dyna.bean,
+                                test.bean,
+                                test.convert,
+                                test.method,
+                                test.dyna.result,
+                                test.dyna.row,
+                                test.locale.convert,
+                                test.converters,
+                                test.beanification,
+                                test.lazy.dynaclass,
+                                test.lazy.dynabean,
+                                test.lazy.dynamap
+                                "
+   description="Run all unit test cases">
+  </target>
+
+
+  <target name="test.basic.dynabean" depends="compile.tests">
+    <echo message="Running BasicDynaBean tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.BasicDynaBeanTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.wrap.dynabean" depends="compile.tests">
+    <echo message="Running WrapDynaBean tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.WrapDynaBeanTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.dyna.property" depends="compile.tests">
+    <echo message="Running DynaBean PropertyUtils tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.DynaPropertyUtilsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.property" depends="compile.tests">
+    <echo message="Running PropertyUtils tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.PropertyUtilsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.dyna.bean" depends="compile.tests">
+    <echo message="Running DynaBean BeanUtils tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.DynaBeanUtilsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+ <target name="test.bean" depends="compile.tests">
+    <echo message="Running BeanUtils tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.BeanUtilsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+ <target name="test.convert" depends="compile.tests">
+    <echo message="Running ConvertUtils tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.ConvertUtilsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.method" depends="compile.tests">
+    <echo message="Running MethodUtils tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.MethodUtilsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.dyna.result" depends="compile.tests">
+    <echo message="Running DynaBean ResultSet tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.DynaResultSetTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.dyna.row" depends="compile.tests">
+    <echo message="Running DynaBean RowSet tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.DynaRowSetTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+  
+  <target name="test.locale.convert" depends="compile.tests">
+    <echo message="Running Locale converters tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.locale.LocaleConvertTestSuite"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+  
+  
+  <target name="test.converters" depends="compile.tests">
+    <echo message="Running Converters tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.converters.ConverterTestSuite"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.lazy.dynaclass" depends="compile.tests">
+    <echo message="Running LazyDynaClass tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.LazyDynaClassTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.lazy.dynabean" depends="compile.tests">
+    <echo message="Running LazyDynaBean tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.LazyDynaBeanTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="test.lazy.dynamap" depends="compile.tests">
+    <echo message="Running LazyDynaMap tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.LazyDynaMapTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+  
+  <target name="test.beanification" depends="compile.tests">
+    <echo message="Running Beanification tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <arg value="org.apache.commons.beanutils.BeanificationTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+
+  <!-- ========== Microbenchmark Cases ===================================== -->
+
+
+  <target name="bench"  depends="compile.tests,
+                                 bench.BeanUtils,
+                                 bench.PropertyUtils
+                                "
+   description="Execute microbenchmark cases"/>
+
+
+  <target name="bench.BeanUtils" depends="compile.tests">
+    <echo message="Running BeanUtils microbenchmarks"/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="counter"
+                 value="${bench.counter}"/>
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.BeanUtilsBenchCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+  <target name="bench.PropertyUtils" depends="compile.tests">
+    <echo message="Running PropertyUtils microbenchmarks"/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="counter"
+                 value="${bench.counter}"/>
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.PropertyUtilsBenchCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+
+
+
+</project>


Property changes on: trunk/commons-beanutils/branches/upstream/current/build.xml
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/maven.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/maven.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/maven.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,19 @@
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="java:jar"
+  xmlns:j="jelly:core">
+
+</project>

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/.cvsignore
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/.cvsignore	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/.cvsignore	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,4 @@
+*.log
+*.properties
+target
+dist

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/LICENSE.txt
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/LICENSE.txt	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/LICENSE.txt	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.properties.sample
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.properties.sample	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.properties.sample	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,39 @@
+#   Copyright 2001-2004 The Apache Software Foundation
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+# The home directory for the Commons collection classes distribution
+commons-collections.home= ../collections/dist
+
+# The pathname of the collections classes JAR file
+commons-collections.jar = ${commons-collections.home}/commons-collections.jar
+commons-collections-testframework.jar = ${commons-collections.home}/commons-collections-testframework-3.0-dev.jar
+
+# The home directory for the Commons logging classes distribution
+commons-logging.home = ../logging/dist
+
+# The pathname of the Commons Logging JAR file
+commons-logging.jar = ${commons-logging.home}/commons-logging.jar
+
+# The directory containing your binary distribution of JUnit, 
+# version 3.7 or later
+junit.home = /usr/local/junit3.7
+
+# The pathname of the "junit.jar" JAR file
+junit.jar = ${junit.home}/junit.jar
+
+
+# Maven properties (for web site build)
+# Those committers using agents may like to use
+#maven.username=rdonkin
+#beanutils.cvs=lserver:rdonkin at cvs.apache.org:/home/cvs
\ No newline at end of file


Property changes on: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.properties.sample
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,301 @@
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="Bean Utilities Bean Collections" default="dist" basedir=".">
+
+
+<!--
+        "Bean Utilities" component of the Jakarta Commons Subproject
+        $Id: build.xml,v 1.2.2.3 2004/07/27 21:59:14 rdonkin Exp $
+-->
+
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+  <property file="build.properties"/>                <!-- Component local   -->
+  <property file="../build.properties"/>             <!-- Commons local     -->
+  <property file="${user.home}/build.properties"/>   <!-- User local        -->
+
+<!-- ========== External Dependencies ===================================== -->
+
+  <!-- The home directory for the Commons collection classes distribution -->
+  <property name="commons-collections.home" value="../../../collections/dist"/>
+
+  <!-- The home directory for the Commons collection classes distribution -->
+  <property name="commons-logging.home" value="../logging/dist"/>
+
+  <!-- The directory containing your binary distribution of JUnit,
+       version 3.7 or later -->
+  <property name="junit.home"              value="/usr/local/junit3.7"/>
+  
+  <!-- The pathname of the beanutils core JAR file -->
+  <property name="commons-beanutils-core.jar" value="../../dist/commons-beanutils.jar"/>
+
+
+<!-- ========== Derived Values ============================================ -->
+
+  <!-- The pathname of the collections classes JAR file -->
+  <property name="commons-collections.jar" value="${commons-collections.home}/commons-collections-3.0-dev.jar"/>
+
+  <!-- The pathname of the collections testframework classes JAR file -->
+  <property name="commons-collections-testframework.jar" value="${commons-collections.home}/commons-collections-testframework-3.0-dev.jar"/>
+
+
+  <!-- The pathname of the logging classes JAR file -->
+  <property name="commons-logging.jar" value="${commons-logging.home}/commons-logging.jar"/>
+
+  <!-- The pathname of the "junit.jar" JAR file -->
+  <property name="junit.jar"               value="${junit.home}/junit.jar"/>
+
+
+<!-- ========== Component Declarations ==================================== -->
+
+
+  <!-- The name of this component -->
+  <property name="component.name"          value="beanutils"/>
+
+  <!-- The primary package name of this component -->
+  <property name="component.package"       value="org.apache.commons.beanutils"/>
+
+  <!-- The title of this component -->
+  <property name="component.title"         value="Bean Utilities Bean Collections"/>
+
+  <!-- The current version number of this component -->
+  <property name="component.version"       value="1.7"/>
+
+  <!-- The base directory for compilation targets -->
+  <property name="build.home"              value="target"/>
+
+  <!-- The base directory for component configuration files -->
+  <property name="conf.home"               value="src/conf"/>
+
+  <!-- The base directory for distribution targets -->
+  <property name="dist.home"               value="dist"/>
+
+  <!-- The base directory for component sources -->
+  <property name="source.home"             value="src/java"/>
+
+  <!-- The base directory for unit test sources -->
+  <property name="test.home"               value="src/test"/>
+
+
+<!-- ========== Compiler Defaults ========================================= -->
+
+
+  <!-- Should Java compilations set the 'debug' compiler option? -->
+  <property name="compile.debug"           value="true"/>
+
+  <!-- Should Java compilations set the 'deprecation' compiler option? -->
+  <property name="compile.deprecation"     value="false"/>
+
+  <!-- Should Java compilations set the 'optimize' compiler option? -->
+  <property name="compile.optimize"        value="true"/>
+
+  <!-- Construct compile classpath -->
+  <path id="compile.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${commons-beanutils-core.jar}"/>
+  </path>
+
+
+<!-- ========== Test Execution Defaults =================================== -->
+
+
+  <!-- Construct unit test classpath -->
+  <path id="test.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${build.home}/tests"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${commons-collections-testframework.jar}"/>
+    <pathelement location="${commons-beanutils-core.jar}"/>
+    <pathelement location="${junit.jar}"/>
+  </path>
+
+  <!-- Should all tests fail if one does? -->
+  <property name="test.failonerror"        value="true"/>
+
+  <!-- The test runner to execute -->
+  <property name="test.runner"             value="junit.textui.TestRunner"/>
+
+  <!-- The Commons Logger LogFactory implementation to use -->
+  <property name="test.factory"
+           value="org.apache.commons.logging.impl.LogFactoryImpl"/>
+
+  <!-- The Commons Logger Log implementation to use (standard factory) -->
+  <property name="test.log"
+           value="org.apache.commons.logging.impl.SimpleLog"/>
+
+  <!-- The Commons Logger SimpleLog level for testing -->
+  <property name="test.level"               value="error"/>
+
+  <!-- Loop counter for microbenchmarks -->
+  <property name="bench.counter"            value="100000"/>
+
+
+<!-- ========== Executable Targets ======================================== -->
+
+
+  <target name="init"
+   description="Initialize and evaluate conditionals">
+    <echo message="-------- ${component.name} ${component.version} --------"/>
+    <filter  token="name"                  value="${component.name}"/>
+    <filter  token="package"               value="${component.package}"/>
+    <filter  token="version"               value="${component.version}"/>
+  </target>
+
+
+  <target name="prepare" depends="init"
+   description="Prepare build directory">
+    <mkdir dir="${build.home}"/>
+    <mkdir dir="${build.home}/classes"/>
+    <mkdir dir="${build.home}/conf"/>
+    <mkdir dir="${build.home}/tests"/>
+  </target>
+
+
+  <target name="static" depends="prepare"
+   description="Copy static files to build directory">
+    <tstamp/>
+    <copy  todir="${build.home}/conf" filtering="on">
+      <fileset dir="${conf.home}" includes="*.MF"/>
+    </copy>
+  </target>
+
+
+  <target name="compile" depends="static"
+   description="Compile shareable components">
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="compile.tests" depends="compile"
+   description="Compile unit test cases">
+    <javac  srcdir="${test.home}"
+           destdir="${build.home}/tests"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="test.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/tests" filtering="on">
+      <fileset dir="${test.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="clean"
+   description="Clean build and distribution directories">
+    <delete    dir="${build.home}"/>
+    <delete    dir="${dist.home}"/>
+  </target>
+
+
+  <target name="all" depends="clean,compile"
+   description="Clean and compile all components"/>
+
+  <target name="dist" depends="clean,compile,javadoc,jar"
+   description="Clean, compile and jar">
+    <copy todir='../../dist' file= '${dist.home}/commons-beanutils-bean-collections.jar'/>
+  </target>
+   
+  <target name="jar" depends="compile"
+   description="Create jar">
+    <mkdir      dir="${dist.home}"/>
+    <mkdir      dir="${build.home}/classes/META-INF"/>
+    <copy      file="../../LICENSE.txt"
+             tofile="${build.home}/classes/META-INF/LICENSE.txt"/>
+    <copy      file="../../NOTICE.txt"
+             tofile="${build.home}/classes/META-INF/NOTICE.txt"/>
+    <jar    jarfile="${dist.home}/commons-beanutils-bean-collections.jar"
+            basedir="${build.home}/classes"
+           manifest="${build.home}/conf/MANIFEST.MF"/>
+    <jar    jarfile="../../dist/commons-beanutils.jar"
+            basedir="${build.home}/classes"
+            update='true'/>
+  </target>
+
+
+  <target name="javadoc" depends="compile"
+   description="Create component Javadoc documentation">
+    <mkdir      dir="${dist.home}"/>
+    <mkdir      dir="${dist.home}/docs"/>
+    <mkdir      dir="${dist.home}/docs/api"/>
+    <mkdir      dir="../../dist/docs/"/>
+    <mkdir      dir="../../dist/docs/bean-collections"/>
+    <javadoc sourcepath="${source.home}"
+                destdir="${dist.home}/docs/api"
+           packagenames="org.apache.commons.*"
+                 author="true"
+                private="true"
+                version="true"
+               overview="src/java/overview.html"
+               doctitle="&lt;h1&gt;${component.title} (Version ${component.version})&lt;/h1&gt;"
+            windowtitle="${component.title} (Version ${component.version})"
+                 bottom="Copyright (c) 2001-2004 - Apache Software Foundation">
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+    <copy 
+        todir='../../dist/docs/bean-collections'>
+        <fileset dir='${dist.home}/docs/api'/>
+    </copy>
+  </target>
+
+  <target name="install-jar" depends="jar"
+   description="--> Installs jar file in ${lib.repo}">
+    <copy todir="${lib.repo}" filtering="no">
+      <fileset dir="${dist.home}">
+        <include name="commons-${component.name}.jar"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+<!-- ========== Unit Test Targets ========================================= -->
+
+
+  <target name="test"  depends="compile.tests,
+                                test.bean.collections"
+   description="Run all unit test cases">
+  </target>
+  
+  <target name="test.bean.collections" depends="compile.tests">
+    <echo message="Running bean collection utilities tests ..."/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="org.apache.commons.logging.LogFactory"
+                 value="${test.factory}"/>
+      <sysproperty key="org.apache.commons.logging.Log"
+                 value="${test.log}"/>
+      <sysproperty key="org.apache.commons.logging.simplelog.defaultlog"
+                 value="${test.level}"/>
+      <arg value="org.apache.commons.beanutils.BeanCollectionsTestSuite"/>
+      <classpath refid="test.classpath"/>
+    </java>
+  </target>
+  
+</project>


Property changes on: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/build.xml
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/project.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/project.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/project.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project>
+  <extend>../../project.xml</extend>
+  <pomVersion>3</pomVersion>
+  <id>commons-beanutils-bean-collections</id>
+  <name>BeanUtils Bean Collections</name>
+  <currentVersion>1.7</currentVersion>
+  <inceptionYear>2000</inceptionYear>
+  <shortDescription>Commons BeanUtils Bean Collections</shortDescription>
+  <description>Extensions of commons collections focussing on collections of beans</description>
+  
+  <siteDirectory>/www/jakarta.apache.org/commons/beanutils/bean-collections</siteDirectory>
+      
+  <dependencies>
+    <dependency>
+      <id>commons-logging</id>
+      <version>1.0.3</version>
+    </dependency>
+    <dependency>
+      <id>commons-collections</id>
+      <version>3.0</version>
+    </dependency>
+    <dependency>
+      <id>commons-beanutils</id>
+      <version>1.6</version>
+    </dependency>
+    <!-- Test Only -->
+    <dependency>
+        <artifactId>commons-collections-testframework</artifactId> 
+        <groupId>commons-collections</groupId>
+        <version>SNAPSHOT</version> 
+    </dependency>
+    
+  </dependencies>
+</project>

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/conf/MANIFEST.MF
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/conf/MANIFEST.MF	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/conf/MANIFEST.MF	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,7 @@
+Extension-Name: org.apache.commons.beanutils-bean-collections
+Specification-Title: Jakarta Commons Beanutils
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 1.6
+Implementation-Title: org.apache.commons.beanutils-bean-collections
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: 1.6

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanComparator.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanComparator.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanComparator.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.collections.comparators.ComparableComparator;
+
+/**
+ * <p>
+ * This comparator compares two beans by the specified bean property. 
+ * It is also possible to compare beans based on nested, indexed, 
+ * combined, mapped bean properties. Please see the {@link PropertyUtilsBean} 
+ * documentation for all property name possibilities. 
+ *
+ * </p><p>
+ * <strong>Note:</strong> The BeanComparator passes the values of the specified 
+ * bean property to a ComparableComparator, if no comparator is 
+ * specified in the constructor. If you are comparing two beans based 
+ * on a property that could contain "null" values, a suitable <code>Comparator</code> 
+ * or <code>ComparatorChain</code> should be supplied in the constructor. 
+ * </p>
+ *
+ * @author     <a href"mailto:epugh at upstate.com">Eric Pugh</a>
+ * @author Tim O'Brien 
+ */
+public class BeanComparator implements Comparator, Serializable {
+
+    private String property;
+    private Comparator comparator;
+
+    /** 
+     * <p>Constructs a Bean Comparator without a property set.
+     * </p><p>
+     * <strong>Note</strong> that this is intended to be used 
+     * only in bean-centric environments.
+     * </p><p>
+     * Until {@link #setProperty} is called with a non-null value.
+     * this comparator will compare the Objects only.
+     * </p>
+     */
+    public BeanComparator() {
+        this( null );
+    }
+
+    /**
+     * <p>Constructs a property-based comparator for beans.
+     * This compares two beans by the property 
+     * specified in the property parameter. This constructor creates 
+     * a <code>BeanComparator</code> that uses a <code>ComparableComparator</code>
+     * to compare the property values. 
+     * </p>
+     * 
+     * <p>Passing "null" to this constructor will cause the BeanComparator 
+     * to compare objects based on natural order, that is 
+     * <code>java.lang.Comparable</code>. 
+     * </p>
+     *
+     * @param property String Name of a bean property, which may contain the 
+     * name of a simple, nested, indexed, mapped, or combined 
+     * property. See {@link PropertyUtilsBean} for property query language syntax. 
+     * If the property passed in is null then the actual objects will be compared
+     */
+    public BeanComparator( String property ) {
+        this( property, ComparableComparator.getInstance() );
+    }
+
+    /**
+     * Constructs a property-based comparator for beans.
+     * This constructor creates 
+     * a BeanComparator that uses the supplied Comparator to compare 
+     * the property values. 
+     * 
+     * @param property Name of a bean property, can contain the name 
+     * of a simple, nested, indexed, mapped, or combined 
+     * property. See {@link PropertyUtilsBean} for property query language  
+     * syntax. 
+     * @param comparator BeanComparator will pass the values of the 
+     * specified bean property to this Comparator. 
+     * If your bean property is not a comparable or 
+     * contains null values, a suitable comparator 
+     * may be supplied in this constructor.
+     */
+    public BeanComparator( String property, Comparator comparator ) {
+        setProperty( property );
+        this.comparator = comparator;
+    }
+
+    /**
+     * Sets the method to be called to compare two JavaBeans
+     *
+     * @param property String method name to call to compare 
+     * If the property passed in is null then the actual objects will be compared
+     */
+    public void setProperty( String property ) {
+        this.property = property;
+    }
+
+
+    /**
+     * Gets the property attribute of the BeanComparator
+     *
+     * @return String method name to call to compare. 
+     * A null value indicates that the actual objects will be compared
+     */
+    public String getProperty() {
+        return property;
+    }
+
+
+    /**
+     * Gets the Comparator being used to compare beans.
+     */
+    public Comparator getComparator() {
+        return comparator;
+    }
+
+
+    /**
+     * Compare two JavaBeans by their shared property.
+     * If {@link #getProperty} is null then the actual objects will be compared.
+     *
+     * @param  o1 Object The first bean to get data from to compare against
+     * @param  o2 Object The second bean to get data from to compare
+     * @return int negative or positive based on order
+     */
+    public int compare( Object o1, Object o2 ) {
+        
+        if ( property == null ) {
+            // compare the actual objects
+            return comparator.compare( o1, o2 );
+        }
+        
+        try {
+            Object value1 = PropertyUtils.getProperty( o1, property );
+            Object value2 = PropertyUtils.getProperty( o2, property );
+            return comparator.compare( value1, value2 );
+        }
+        catch ( Exception e ) {
+            throw new ClassCastException( e.toString() );
+        }
+    }
+    
+    /**
+     * Two <code>BeanComparator</code>'s are equals if and only if
+     * the wrapped comparators and the property names to be compared
+     * are equal.
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof BeanComparator)) return false;
+
+        final BeanComparator beanComparator = (BeanComparator) o;
+
+        if (!comparator.equals(beanComparator.comparator)) return false;
+        if (property != null)
+        {
+            if (!property.equals(beanComparator.property)) return false;
+        }
+        else
+        {
+            return (beanComparator.property == null);
+        }
+
+        return true;
+    }
+
+    /**
+     * Hashcode compatible with equals.
+     */ 
+    public int hashCode() {
+        int result;
+        result = comparator.hashCode();
+        return result;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanMap.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanMap.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanMap.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,803 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.collections.list.UnmodifiableList;
+import org.apache.commons.collections.keyvalue.AbstractMapEntry;
+import org.apache.commons.collections.set.UnmodifiableSet;
+import org.apache.commons.collections.Transformer;
+
+/** 
+ * An implementation of Map for JavaBeans which uses introspection to
+ * get and put properties in the bean.
+ * <p>
+ * If an exception occurs during attempts to get or set a property then the
+ * property is considered non existent in the Map
+ *
+ * @version $Revision: 1.2.2.2 $ $Date: 2004/06/22 21:07:02 $
+ * 
+ * @author James Strachan
+ * @author Stephen Colebourne
+ */
+public class BeanMap extends AbstractMap implements Cloneable {
+
+    private transient Object bean;
+
+    private transient HashMap readMethods = new HashMap();
+    private transient HashMap writeMethods = new HashMap();
+    private transient HashMap types = new HashMap();
+
+    /**
+     * An empty array.  Used to invoke accessors via reflection.
+     */
+    public static final Object[] NULL_ARGUMENTS = {};
+
+    /**
+     * Maps primitive Class types to transformers.  The transformer
+     * transform strings into the appropriate primitive wrapper.
+     */
+    public static HashMap defaultTransformers = new HashMap();
+    
+    static {
+        defaultTransformers.put( 
+            Boolean.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Boolean.valueOf( input.toString() );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Character.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return new Character( input.toString().charAt( 0 ) );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Byte.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Byte.valueOf( input.toString() );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Short.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Short.valueOf( input.toString() );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Integer.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Integer.valueOf( input.toString() );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Long.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Long.valueOf( input.toString() );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Float.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Float.valueOf( input.toString() );
+                }
+            }
+        );
+        defaultTransformers.put( 
+            Double.TYPE, 
+            new Transformer() {
+                public Object transform( Object input ) {
+                    return Double.valueOf( input.toString() );
+                }
+            }
+        );
+    }
+    
+    
+    // Constructors
+    //-------------------------------------------------------------------------
+
+    /**
+     * Constructs a new empty <code>BeanMap</code>.
+     */
+    public BeanMap() {
+    }
+
+    /**
+     * Constructs a new <code>BeanMap</code> that operates on the 
+     * specified bean.  If the given bean is <code>null</code>, then
+     * this map will be empty.
+     *
+     * @param bean  the bean for this map to operate on
+     */
+    public BeanMap(Object bean) {
+        this.bean = bean;
+        initialise();
+    }
+
+    // Map interface
+    //-------------------------------------------------------------------------
+
+    /**
+     * Renders a string representation of this object.
+     * @return a <code>String</code> representation of this object
+     */
+    public String toString() {
+        return "BeanMap<" + String.valueOf(bean) + ">";
+    }
+    
+    /**
+     * Clone this bean map using the following process: 
+     *
+     * <ul>
+     * <li>If there is no underlying bean, return a cloned BeanMap without a
+     * bean.
+     *
+     * <li>Since there is an underlying bean, try to instantiate a new bean of
+     * the same type using Class.newInstance().
+     * 
+     * <li>If the instantiation fails, throw a CloneNotSupportedException
+     *
+     * <li>Clone the bean map and set the newly instantiated bean as the
+     * underlying bean for the bean map.
+     *
+     * <li>Copy each property that is both readable and writable from the
+     * existing object to a cloned bean map.  
+     *
+     * <li>If anything fails along the way, throw a
+     * CloneNotSupportedException.
+     *
+     * <ul>
+     */
+    public Object clone() throws CloneNotSupportedException {
+        BeanMap newMap = (BeanMap)super.clone();
+
+        if(bean == null) {
+            // no bean, just an empty bean map at the moment.  return a newly
+            // cloned and empty bean map.
+            return newMap;
+        }
+
+        Object newBean = null;            
+        Class beanClass = null;
+        try {
+            beanClass = bean.getClass();
+            newBean = beanClass.newInstance();
+        } catch (Exception e) {
+            // unable to instantiate
+            throw new CloneNotSupportedException
+                ("Unable to instantiate the underlying bean \"" +
+                 beanClass.getName() + "\": " + e);
+        }
+            
+        try {
+            newMap.setBean(newBean);
+        } catch (Exception exception) {
+            throw new CloneNotSupportedException
+                ("Unable to set bean in the cloned bean map: " + 
+                 exception);
+        }
+            
+        try {
+            // copy only properties that are readable and writable.  If its
+            // not readable, we can't get the value from the old map.  If
+            // its not writable, we can't write a value into the new map.
+            Iterator readableKeys = readMethods.keySet().iterator();
+            while(readableKeys.hasNext()) {
+                Object key = readableKeys.next();
+                if(getWriteMethod(key) != null) {
+                    newMap.put(key, get(key));
+                }
+            }
+        } catch (Exception exception) {
+            throw new CloneNotSupportedException
+                ("Unable to copy bean values to cloned bean map: " +
+                 exception);
+        }
+
+        return newMap;
+    }
+
+    /**
+     * Puts all of the writable properties from the given BeanMap into this
+     * BeanMap. Read-only and Write-only properties will be ignored.
+     *
+     * @param map  the BeanMap whose properties to put
+     */
+    public void putAllWriteable(BeanMap map) {
+        Iterator readableKeys = map.readMethods.keySet().iterator();
+        while (readableKeys.hasNext()) {
+            Object key = readableKeys.next();
+            if (getWriteMethod(key) != null) {
+                this.put(key, map.get(key));
+            }
+        }
+    }
+
+
+    /**
+     * This method reinitializes the bean map to have default values for the
+     * bean's properties.  This is accomplished by constructing a new instance
+     * of the bean which the map uses as its underlying data source.  This
+     * behavior for <code>clear()</code> differs from the Map contract in that
+     * the mappings are not actually removed from the map (the mappings for a
+     * BeanMap are fixed).
+     */
+    public void clear() {
+        if(bean == null) return;
+
+        Class beanClass = null;
+        try {
+            beanClass = bean.getClass();
+            bean = beanClass.newInstance();
+        }
+        catch (Exception e) {
+            throw new UnsupportedOperationException( "Could not create new instance of class: " + beanClass );
+        }
+    }
+
+    /**
+     * Returns true if the bean defines a property with the given name.
+     * <p>
+     * The given name must be a <code>String</code>; if not, this method
+     * returns false. This method will also return false if the bean
+     * does not define a property with that name.
+     * <p>
+     * Write-only properties will not be matched as the test operates against
+     * property read methods.
+     *
+     * @param name  the name of the property to check
+     * @return false if the given name is null or is not a <code>String</code>;
+     *   false if the bean does not define a property with that name; or
+     *   true if the bean does define a property with that name
+     */
+    public boolean containsKey(Object name) {
+        Method method = getReadMethod(name);
+        return method != null;
+    }
+
+    /**
+     * Returns true if the bean defines a property whose current value is
+     * the given object.
+     *
+     * @param value  the value to check
+     * @return false  true if the bean has at least one property whose 
+     *   current value is that object, false otherwise
+     */
+    public boolean containsValue(Object value) {
+        // use default implementation
+        return super.containsValue(value);
+    }
+
+    /**
+     * Returns the value of the bean's property with the given name.
+     * <p>
+     * The given name must be a {@link String} and must not be 
+     * null; otherwise, this method returns <code>null</code>.
+     * If the bean defines a property with the given name, the value of
+     * that property is returned.  Otherwise, <code>null</code> is 
+     * returned.
+     * <p>
+     * Write-only properties will not be matched as the test operates against
+     * property read methods.
+     *
+     * @param name  the name of the property whose value to return
+     * @return  the value of the property with that name
+     */
+    public Object get(Object name) {
+        if ( bean != null ) {
+            Method method = getReadMethod( name );
+            if ( method != null ) {
+                try {
+                    return method.invoke( bean, NULL_ARGUMENTS );
+                }
+                catch (  IllegalAccessException e ) {
+                    logWarn( e );
+                }
+                catch ( IllegalArgumentException e ) {
+                    logWarn(  e );
+                }
+                catch ( InvocationTargetException e ) {
+                    logWarn(  e );
+                }
+                catch ( NullPointerException e ) {
+                    logWarn(  e );
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the bean property with the given name to the given value.
+     *
+     * @param name  the name of the property to set
+     * @param value  the value to set that property to
+     * @return  the previous value of that property
+     * @throws IllegalArgumentException  if the given name is null;
+     *   if the given name is not a {@link String}; if the bean doesn't
+     *   define a property with that name; or if the bean property with
+     *   that name is read-only
+     */
+    public Object put(Object name, Object value) throws IllegalArgumentException, ClassCastException {
+        if ( bean != null ) {
+            Object oldValue = get( name );
+            Method method = getWriteMethod( name );
+            if ( method == null ) {
+                throw new IllegalArgumentException( "The bean of type: "+ bean.getClass().getName() + " has no property called: " + name );
+            }
+            try {
+                Object[] arguments = createWriteMethodArguments( method, value );
+                method.invoke( bean, arguments );
+
+                Object newValue = get( name );
+                firePropertyChange( name, oldValue, newValue );
+            }
+            catch ( InvocationTargetException e ) {
+                logInfo( e );
+                throw new IllegalArgumentException( e.getMessage() );
+            }
+            catch ( IllegalAccessException e ) {
+                logInfo( e );
+                throw new IllegalArgumentException( e.getMessage() );
+            }
+            return oldValue;
+        }
+        return null;
+    }
+                    
+    /**
+     * Returns the number of properties defined by the bean.
+     *
+     * @return  the number of properties defined by the bean
+     */
+    public int size() {
+        return readMethods.size();
+    }
+
+    
+    /**
+     * Get the keys for this BeanMap.
+     * <p>
+     * Write-only properties are <b>not</b> included in the returned set of
+     * property names, although it is possible to set their value and to get 
+     * their type.
+     * 
+     * @return BeanMap keys.  The Set returned by this method is not
+     *        modifiable.
+     */
+    public Set keySet() {
+        return UnmodifiableSet.decorate(readMethods.keySet());
+    }
+
+    /**
+     * Gets a Set of MapEntry objects that are the mappings for this BeanMap.
+     * <p>
+     * Each MapEntry can be set but not removed.
+     * 
+     * @return the unmodifiable set of mappings
+     */
+    public Set entrySet() {
+        return UnmodifiableSet.decorate(new AbstractSet() {
+            public Iterator iterator() {
+                return entryIterator();
+            }
+            public int size() {
+              return BeanMap.this.readMethods.size();
+            }
+        });
+    }
+
+    /**
+     * Returns the values for the BeanMap.
+     * 
+     * @return values for the BeanMap.  The returned collection is not
+     *        modifiable.
+     */
+    public Collection values() {
+        ArrayList answer = new ArrayList( readMethods.size() );
+        for ( Iterator iter = valueIterator(); iter.hasNext(); ) {
+            answer.add( iter.next() );
+        }
+        return UnmodifiableList.decorate(answer);
+    }
+
+
+    // Helper methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Returns the type of the property with the given name.
+     *
+     * @param name  the name of the property
+     * @return  the type of the property, or <code>null</code> if no such
+     *  property exists
+     */
+    public Class getType(String name) {
+        return (Class) types.get( name );
+    }
+
+    /**
+     * Convenience method for getting an iterator over the keys.
+     * <p>
+     * Write-only properties will not be returned in the iterator.
+     *
+     * @return an iterator over the keys
+     */
+    public Iterator keyIterator() {
+        return readMethods.keySet().iterator();
+    }
+
+    /**
+     * Convenience method for getting an iterator over the values.
+     *
+     * @return an iterator over the values
+     */
+    public Iterator valueIterator() {
+        final Iterator iter = keyIterator();
+        return new Iterator() {            
+            public boolean hasNext() {
+                return iter.hasNext();
+            }
+            public Object next() {
+                Object key = iter.next();
+                return get(key);
+            }
+            public void remove() {
+                throw new UnsupportedOperationException( "remove() not supported for BeanMap" );
+            }
+        };
+    }
+
+    /**
+     * Convenience method for getting an iterator over the entries.
+     *
+     * @return an iterator over the entries
+     */
+    public Iterator entryIterator() {
+        final Iterator iter = keyIterator();
+        return new Iterator() {            
+            public boolean hasNext() {
+                return iter.hasNext();
+            }            
+            public Object next() {
+                Object key = iter.next();
+                Object value = get(key);
+                return new Entry( BeanMap.this, key, value );
+            }            
+            public void remove() {
+                throw new UnsupportedOperationException( "remove() not supported for BeanMap" );
+            }
+        };
+    }
+
+
+    // Properties
+    //-------------------------------------------------------------------------
+
+    /**
+     * Returns the bean currently being operated on.  The return value may
+     * be null if this map is empty.
+     *
+     * @return the bean being operated on by this map
+     */
+    public Object getBean() {
+        return bean;
+    }
+
+    /**
+     * Sets the bean to be operated on by this map.  The given value may
+     * be null, in which case this map will be empty.
+     *
+     * @param newBean  the new bean to operate on
+     */
+    public void setBean( Object newBean ) {
+        bean = newBean;
+        reinitialise();
+    }
+
+    /**
+     * Returns the accessor for the property with the given name.
+     *
+     * @param name  the name of the property 
+     * @return the accessor method for the property, or null
+     */
+    public Method getReadMethod(String name) {
+        return (Method) readMethods.get(name);
+    }
+
+    /**
+     * Returns the mutator for the property with the given name.
+     *
+     * @param name  the name of the property
+     * @return the mutator method for the property, or null
+     */
+    public Method getWriteMethod(String name) {
+        return (Method) writeMethods.get(name);
+    }
+
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Returns the accessor for the property with the given name.
+     *
+     * @param name  the name of the property 
+     * @return null if the name is null; null if the name is not a 
+     * {@link String}; null if no such property exists; or the accessor
+     *  method for that property
+     */
+    protected Method getReadMethod( Object name ) {
+        return (Method) readMethods.get( name );
+    }
+
+    /**
+     * Returns the mutator for the property with the given name.
+     *
+     * @param name  the name of the 
+     * @return null if the name is null; null if the name is not a 
+     * {@link String}; null if no such property exists; null if the 
+     * property is read-only; or the mutator method for that property
+     */
+    protected Method getWriteMethod( Object name ) {
+        return (Method) writeMethods.get( name );
+    }
+
+    /**
+     * Reinitializes this bean.  Called during {@link #setBean(Object)}.
+     * Does introspection to find properties.
+     */
+    protected void reinitialise() {
+        readMethods.clear();
+        writeMethods.clear();
+        types.clear();
+        initialise();
+    }
+
+    private void initialise() {
+        if(getBean() == null) return;
+
+        Class  beanClass = getBean().getClass();
+        try {
+            //BeanInfo beanInfo = Introspector.getBeanInfo( bean, null );
+            BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
+            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+            if ( propertyDescriptors != null ) {
+                for ( int i = 0; i < propertyDescriptors.length; i++ ) {
+                    PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
+                    if ( propertyDescriptor != null ) {
+                        String name = propertyDescriptor.getName();
+                        Method readMethod = propertyDescriptor.getReadMethod();
+                        Method writeMethod = propertyDescriptor.getWriteMethod();
+                        Class aType = propertyDescriptor.getPropertyType();
+
+                        if ( readMethod != null ) {
+                            readMethods.put( name, readMethod );
+                        }
+                        if ( writeMethods != null ) {
+                            writeMethods.put( name, writeMethod );
+                        }
+                        types.put( name, aType );
+                    }
+                }
+            }
+        }
+        catch ( IntrospectionException e ) {
+            logWarn(  e );
+        }
+    }
+
+    /**
+     * Called during a successful {@link #put(Object,Object)} operation.
+     * Default implementation does nothing.  Override to be notified of
+     * property changes in the bean caused by this map.
+     *
+     * @param key  the name of the property that changed
+     * @param oldValue  the old value for that property
+     * @param newValue  the new value for that property
+     */
+    protected void firePropertyChange( Object key, Object oldValue, Object newValue ) {
+    }
+
+    // Implementation classes
+    //-------------------------------------------------------------------------
+
+    /**
+     * Map entry used by {@link BeanMap}.
+     */
+    protected static class Entry extends AbstractMapEntry {        
+        private BeanMap owner;
+        
+        /**
+         * Constructs a new <code>Entry</code>.
+         *
+         * @param owner  the BeanMap this entry belongs to
+         * @param key  the key for this entry
+         * @param value  the value for this entry
+         */
+        protected Entry( BeanMap owner, Object key, Object value ) {
+            super( key, value );
+            this.owner = owner;
+        }
+
+        /**
+         * Sets the value.
+         *
+         * @param value  the new value for the entry
+         * @return the old value for the entry
+         */
+        public Object setValue(Object value) {
+            Object key = getKey();
+            Object oldValue = owner.get( key );
+
+            owner.put( key, value );
+            Object newValue = owner.get( key );
+            super.setValue( newValue );
+            return oldValue;
+        }
+    }
+
+    /**
+     * Creates an array of parameters to pass to the given mutator method.
+     * If the given object is not the right type to pass to the method 
+     * directly, it will be converted using {@link #convertType(Class,Object)}.
+     *
+     * @param method  the mutator method
+     * @param value  the value to pass to the mutator method
+     * @return an array containing one object that is either the given value
+     *   or a transformed value
+     * @throws IllegalAccessException if {@link #convertType(Class,Object)}
+     *   raises it
+     * @throws IllegalArgumentException if any other exception is raised
+     *   by {@link #convertType(Class,Object)}
+     */
+    protected Object[] createWriteMethodArguments( Method method, Object value ) throws IllegalAccessException, ClassCastException {            
+        try {
+            if ( value != null ) {
+                Class[] types = method.getParameterTypes();
+                if ( types != null && types.length > 0 ) {
+                    Class paramType = types[0];
+                    if ( ! paramType.isAssignableFrom( value.getClass() ) ) {
+                        value = convertType( paramType, value );
+                    }
+                }
+            }
+            Object[] answer = { value };
+            return answer;
+        }
+        catch ( InvocationTargetException e ) {
+            logInfo( e );
+            throw new IllegalArgumentException( e.getMessage() );
+        }
+        catch ( InstantiationException e ) {
+            logInfo( e );
+            throw new IllegalArgumentException( e.getMessage() );
+        }
+    }
+
+    /**
+     * Converts the given value to the given type.  First, reflection is
+     * is used to find a public constructor declared by the given class 
+     * that takes one argument, which must be the precise type of the 
+     * given value.  If such a constructor is found, a new object is
+     * created by passing the given value to that constructor, and the
+     * newly constructed object is returned.<P>
+     *
+     * If no such constructor exists, and the given type is a primitive
+     * type, then the given value is converted to a string using its 
+     * {@link Object#toString() toString()} method, and that string is
+     * parsed into the correct primitive type using, for instance, 
+     * {@link Integer#valueOf(String)} to convert the string into an
+     * <code>int</code>.<P>
+     *
+     * If no special constructor exists and the given type is not a 
+     * primitive type, this method returns the original value.
+     *
+     * @param newType  the type to convert the value to
+     * @param value  the value to convert
+     * @return the converted value
+     * @throws NumberFormatException if newType is a primitive type, and 
+     *  the string representation of the given value cannot be converted
+     *  to that type
+     * @throws InstantiationException  if the constructor found with 
+     *  reflection raises it
+     * @throws InvocationTargetException  if the constructor found with
+     *  reflection raises it
+     * @throws IllegalAccessException  never
+     * @throws IllegalArgumentException  never
+     */
+    protected Object convertType( Class newType, Object value ) 
+        throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        
+        // try call constructor
+        Class[] types = { value.getClass() };
+        try {
+            Constructor constructor = newType.getConstructor( types );        
+            Object[] arguments = { value };
+            return constructor.newInstance( arguments );
+        }
+        catch ( NoSuchMethodException e ) {
+            // try using the transformers
+            Transformer transformer = getTypeTransformer( newType );
+            if ( transformer != null ) {
+                return transformer.transform( value );
+            }
+            return value;
+        }
+    }
+
+    /**
+     * Returns a transformer for the given primitive type.
+     *
+     * @param aType  the primitive type whose transformer to return
+     * @return a transformer that will convert strings into that type,
+     *  or null if the given type is not a primitive type
+     */
+    protected Transformer getTypeTransformer( Class aType ) {
+        return (Transformer) defaultTransformers.get( aType );
+    }
+
+    /**
+     * Logs the given exception to <code>System.out</code>.  Used to display
+     * warnings while accessing/mutating the bean.
+     *
+     * @param ex  the exception to log
+     */
+    protected void logInfo(Exception ex) {
+        // Deliberately do not use LOG4J or Commons Logging to avoid dependencies
+        System.out.println( "INFO: Exception: " + ex );
+    }
+
+    /**
+     * Logs the given exception to <code>System.err</code>.  Used to display
+     * errors while accessing/mutating the bean.
+     *
+     * @param ex  the exception to log
+     */
+    protected void logWarn(Exception ex) {
+        // Deliberately do not use LOG4J or Commons Logging to avoid dependencies
+        System.out.println( "WARN: Exception: " + ex );
+        ex.printStackTrace();
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPredicate.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPredicate.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPredicate.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.beanutils;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * <p>Predicate implementation that applies the given <code>Predicate</code>
+ * to the result of calling the given property getter.
+ * </p>
+ */
+public class BeanPredicate implements Predicate {
+   
+    private final Log log = LogFactory.getLog(this.getClass());
+    
+    /** Name of the property whose value will be predicated */
+    private String propertyName;
+    /** <code>Predicate</code> to be applied to the property value */
+    private Predicate predicate;
+
+    /**
+     * Constructs a <code>BeanPredicate</code> that applies the given
+     * <code>Predicate</code> to the named property value.
+     * @param propertyName the name of the property whose value is to be predicated,
+     * not null
+     * @param predicate the <code>Predicate</code> to be applied,
+     * not null
+     */
+    public BeanPredicate(String propertyName, Predicate predicate) {
+        this.propertyName = propertyName;
+        this.predicate = predicate;
+    }
+
+    /**
+     * Evaluates the given object by applying the {@link #getPredicate()}
+     * to a property value named by {@link #getPropertyName()}.
+     * @throws IllegalAccessException when the property cannot be evaluated
+     */
+    public boolean evaluate(Object object) {
+       
+        boolean evaluation = false;
+
+        try {
+            Object propValue = PropertyUtils.getProperty( object, propertyName );
+            evaluation = predicate.evaluate(propValue);
+        } catch (IllegalArgumentException e) {
+            final String errorMsg = "Problem during evaluation.";
+            log.error("ERROR: " + errorMsg, e);
+            throw e;
+        } catch (IllegalAccessException e) {
+            final String errorMsg = "Unable to access the property provided.";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (InvocationTargetException e) {
+            final String errorMsg = "Exception occurred in property's getter";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (NoSuchMethodException e) {
+            final String errorMsg = "Property not found.";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        }
+
+        return evaluation;
+    }
+
+    /**
+     * Gets the name of the property whose value is to be predicated.
+     * in the evaluation.
+     * @return the property name, not null
+     */ 
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    /** 
+     * Sets the name of the property whose value is to be predicated.
+     * @param propertyName the name of the property whose value is to be predicated,
+     * not null
+     */
+    public void setPropertyName(String propertyName) {
+        this.propertyName = propertyName;
+    }
+
+    /**
+     * Gets the <code>Predicate</code> to be applied to the value of the named property
+     * during {@link #evaluate}.
+     * @return <code>Predicate</code>, not null
+     */
+    public Predicate getPredicate() {
+        return predicate;
+    }
+
+    /** 
+     * Sets the <code>Predicate</code> to be applied to the value of the named property
+     * during {@link evaluate}.
+     * @param predicate <code>Predicate</code>, not null
+     */
+    public void setPredicate(Predicate predicate) {
+        this.predicate = predicate;
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueChangeClosure.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueChangeClosure.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueChangeClosure.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import org.apache.commons.collections.Closure;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * <p><code>Closure</code> that sets a property.</p>
+ * <p>
+ * An implementation of <code>org.apache.commons.collections.Closure</code> that updates
+ * a specified property on the object provided with a specified value.
+ * The <code>BeanPropertyValueChangeClosure</code> constructor takes two parameters which determine
+ * what property will be updated and with what value.
+ * <dl>
+ *    <dt>
+ *       <b><code><pre>public BeanPropertyValueChangeClosure( String propertyName, Object propertyValue )</pre></code></b>
+ *    </dt>
+ *    <dd>
+ *       Will create a <code>Closure</code> that will update an object by setting the property
+ *       specified by <code>propertyName</code> to the value specified by <code>propertyValue</code>.
+ *    </dd>
+ * </dl>
+ *
+ * <p/>
+ * <strong>Note:</strong> Property names can be a simple, nested, indexed, or mapped property as defined by
+ * <code>org.apache.commons.beanutils.PropertyUtils</code>.  If any object in the property path
+ * specified by <code>propertyName</code> is <code>null</code> then the outcome is based on the
+ * value of the <code>ignoreNull</code> attribute.
+ *
+ * <p/>
+ * A typical usage might look like:
+ * <code><pre>
+ * // create the closure
+ * BeanPropertyValueChangeClosure closure =
+ *    new BeanPropertyValueChangeClosure( "activeEmployee", Boolean.TRUE );
+ *
+ * // update the Collection
+ * CollectionUtils.forAllDo( peopleCollection, closure );
+ * </pre></code>
+ * <p/>
+ *
+ * This would take a <code>Collection</code> of person objects and update the
+ * <code>activeEmployee</code> property of each object in the <code>Collection</code> to
+ * <code>true</code>. Assuming...
+ * <ul>
+ *    <li>
+ *       The top level object in the <code>peopleCollection</code> is an object which represents a
+ *       person.
+ *    </li>
+ *    <li>
+ *       The person object has a <code>setActiveEmployee( boolean )</code> method which updates
+ *       the value for the object's <code>activeEmployee</code> property.
+ *    </li>
+ * </ul>
+ *
+ * @author Norm Deane
+ * @see org.apache.commons.beanutils.PropertyUtils
+ * @see org.apache.commons.collections.Closure
+ */
+public class BeanPropertyValueChangeClosure implements Closure {
+   
+    /** For logging. */
+    private final Log log = LogFactory.getLog(this.getClass());
+
+    /**
+     * The name of the property which will be updated when this <code>Closure</code> executes.
+     */
+    private String propertyName;
+
+    /**
+     * The value that the property specified by <code>propertyName</code>
+     * will be updated to when this <code>Closure</code> executes.
+     */
+    private Object propertyValue;
+
+    /**
+     * Determines whether <code>null</code> objects in the property path will genenerate an
+     * <code>IllegalArgumentException</code> or not. If set to <code>true</code> then if any objects
+     * in the property path leading up to the target property evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
+     * not rethrown.  If set to <code>false</code> then if any objects in the property path leading
+     * up to the target property evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
+     * rethrown.
+     */
+    private boolean ignoreNull;
+
+    /**
+     * Constructor which takes the name of the property to be changed, the new value to set
+     * the property to, and assumes <code>ignoreNull</code> to be <code>false</code>.
+     *
+     * @param propertyName The name of the property that will be updated with the value specified by
+     * <code>propertyValue</code>.
+     * @param propertyValue The value that <code>propertyName</code> will be set to on the target
+     * object.
+     * @throws IllegalArgumentException If the propertyName provided is null or empty.
+     */
+    public BeanPropertyValueChangeClosure(String propertyName, Object propertyValue) {
+        this(propertyName, propertyValue, false);
+    }
+
+    /**
+     * Constructor which takes the name of the property to be changed, the new value to set
+     * the property to and a boolean which determines whether <code>null</code> objects in the
+     * property path will genenerate an <code>IllegalArgumentException</code> or not.
+     *
+     * @param propertyName The name of the property that will be updated with the value specified by
+     * <code>propertyValue</code>.
+     * @param propertyValue The value that <code>propertyName</code> will be set to on the target
+     * object.
+     * @param ignoreNull Determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     * @throws IllegalArgumentException If the propertyName provided is null or empty.
+     */
+    public BeanPropertyValueChangeClosure(String propertyName, Object propertyValue, boolean ignoreNull) {
+        super();
+
+        if ((propertyName != null) && (propertyName.length() > 0)) {
+            this.propertyName = propertyName;
+            this.propertyValue = propertyValue;
+            this.ignoreNull = ignoreNull;
+        } else {
+            throw new IllegalArgumentException("propertyName cannot be null or empty");
+        }
+    }
+
+    /**
+     * Updates the target object provided using the property update criteria provided when this
+     * <code>BeanPropertyValueChangeClosure</code> was constructed.  If any object in the property
+     * path leading up to the target property is <code>null</code> then the outcome will be based on
+     * the value of the <code>ignoreNull</code> attribute. By default, <code>ignoreNull</code> is
+     * <code>false</code> and would result in an <code>IllegalArgumentException</code> if an object
+     * in the property path leading up to the target property is <code>null</code>.
+     *
+     * @param object The object to be updated.
+     * @throws IllegalArgumentException If an IllegalAccessException, InvocationTargetException, or
+     * NoSuchMethodException is thrown when trying to access the property specified on the object
+     * provided. Or if an object in the property path provided is <code>null</code> and
+     * <code>ignoreNull</code> is set to <code>false</code>.
+     */
+    public void execute(Object object) {
+       
+        try {
+            PropertyUtils.setProperty(object, propertyName, propertyValue);
+        } catch (IllegalArgumentException e) {
+            final String errorMsg = "Unable to execute Closure. Null value encountered in property path...";
+
+            if (ignoreNull) {
+                log.warn("WARNING: " + errorMsg, e);
+            } else {
+                log.error("ERROR: " + errorMsg, e);
+                throw e;
+            }
+        } catch (IllegalAccessException e) {
+            final String errorMsg = "Unable to access the property provided.";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (InvocationTargetException e) {
+            final String errorMsg = "Exception occurred in property's getter";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (NoSuchMethodException e) {
+            final String errorMsg = "Property not found";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        }
+    }
+
+    /**
+     * Returns the name of the property which will be updated when this <code>Closure</code> executes.
+     *
+     * @return The name of the property which will be updated when this <code>Closure</code> executes.
+     */
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    /**
+     * Returns the value that the property specified by <code>propertyName</code>
+     * will be updated to when this <code>Closure</code> executes.
+     *
+     * @return The value that the property specified by <code>propertyName</code>
+     * will be updated to when this <code>Closure</code> executes.
+     */
+    public Object getPropertyValue() {
+        return propertyValue;
+    }
+
+    /**
+     * Returns the flag that determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not. If set to <code>true</code> then
+     * if any objects in the property path leading up to the target property evaluate to
+     * <code>null</code> then the <code>IllegalArgumentException</code> throw by
+     * <code>PropertyUtils</code> will be logged but not rethrown.  If set to <code>false</code> then
+     * if any objects in the property path leading up to the target property evaluate to
+     * <code>null</code> then the <code>IllegalArgumentException</code> throw by
+     * <code>PropertyUtils</code> will be logged and rethrown.
+     *
+     * @return The flag that determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     */
+    public boolean isIgnoreNull() {
+        return ignoreNull;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicate.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicate.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicate.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * <p><code>Predicate</code> that evaluates a property value against a specified value.</p>
+ * <p>
+ * An implementation of <code>org.apache.commons.collections.Predicate</code> that evaluates a
+ * property value on the object provided against a specified value and returns <code>true</code>
+ * if equal; <code>false</code> otherwise.
+ * The <code>BeanPropertyValueEqualsPredicate</code> constructor takes two parameters which
+ * determine what property will be evaluated on the target object and what its expected value should
+ * be.
+ * <dl>
+ *    <dt>
+ *       <strong><code><pre>public BeanPropertyValueEqualsPredicate( String propertyName, Object propertyValue )</pre></code></strong>
+ *    </dt>
+ *    <dd>
+ *       Will create a <code>Predicate</code> that will evaluate the target object and return
+ *       <code>true</code> if the property specified by <code>propertyName</code> has a value which
+ *       is equal to the the value specified by <code>propertyValue</code>. Or return
+ *       <code>false</code> otherwise.
+ *    </dd>
+ * </dl>
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Property names can be a simple, nested, indexed, or mapped property as defined by
+ * <code>org.apache.commons.beanutils.PropertyUtils</code>.  If any object in the property path
+ * specified by <code>propertyName</code> is <code>null</code> then the outcome is based on the
+ * value of the <code>ignoreNull</code> attribute.
+ * </p>
+ * <p>
+ * A typical usage might look like:
+ * <code><pre>
+ * // create the closure
+ * BeanPropertyValueEqualsPredicate predicate =
+ *    new BeanPropertyValueEqualsPredicate( "activeEmployee", Boolean.FALSE );
+ *
+ * // filter the Collection
+ * CollectionUtils.filter( peopleCollection, predicate );
+ * </pre></code>
+ * </p>
+ * <p>
+ * This would take a <code>Collection</code> of person objects and filter out any people whose
+ * <code>activeEmployee</code> property is <code>false</code>. Assuming...
+ * <ul>
+ *    <li>
+ *       The top level object in the <code>peeopleCollection</code> is an object which represents a
+ *       person.
+ *    </li>
+ *    <li>
+ *       The person object has a <code>getActiveEmployee()</code> method which returns
+ *       the boolean value for the object's <code>activeEmployee</code> property.
+ *    </li>
+ * </ul>
+ * </p>
+ * <p>
+ * Another typical usage might look like:
+ * <code><pre>
+ * // create the closure
+ * BeanPropertyValueEqualsPredicate predicate =
+ *    new BeanPropertyValueEqualsPredicate( "personId", "456-12-1234" );
+ *
+ * // search the Collection
+ * CollectionUtils.find( peopleCollection, predicate );
+ * </pre><code>
+ * </p>
+ * <p>
+ * This would search a <code>Collection</code> of person objects and return the first object whose
+ * <code>personId</code> property value equals <code>456-12-1234</code>. Assuming...
+ * <ul>
+ *    <li>
+ *       The top level object in the <code>peeopleCollection</code> is an object which represents a
+ *       person.
+ *    </li>
+ *    <li>
+ *       The person object has a <code>getPersonId()</code> method which returns
+ *       the value for the object's <code>personId</code> property.
+ *    </li>
+ * </ul>
+ * </p>
+ *
+ * @author Norm Deane
+ * @see org.apache.commons.beanutils.PropertyUtils
+ * @see org.apache.commons.collections.Predicate
+ */
+public class BeanPropertyValueEqualsPredicate implements Predicate {
+   
+    /** For logging. */
+    private final Log log = LogFactory.getLog(this.getClass());
+
+    /**
+     * The name of the property which will be evaluated when this <code>Predicate</code> is executed.
+     */
+    private String propertyName;
+
+    /**
+     * The value that the property specified by <code>propertyName</code>
+     * will be compared to when this <code>Predicate</code> executes.
+     */
+    private Object propertyValue;
+
+    /**
+     * <p>Should <code>null</code> objects in the property path be ignored?</p>
+     * <p>
+     * Determines whether <code>null</code> objects in the property path will genenerate an
+     * <code>IllegalArgumentException</code> or not. If set to <code>true</code> then if any objects
+     * in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
+     * not rethrown and <code>false</code> will be returned.  If set to <code>false</code> then if
+     * any objects in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
+     * rethrown.
+     * </p>
+     */
+    private boolean ignoreNull;
+
+    /**
+     * Constructor which takes the name of the property, its expected value to be used in evaluation,
+     * and assumes <code>ignoreNull</code> to be <code>false</code>.
+     *
+     * @param propertyName The name of the property that will be evaluated against the expected value.
+     * @param propertyValue The value to use in object evaluation.
+     * @throws IllegalArgumentException If the property name provided is null or empty.
+     */
+    public BeanPropertyValueEqualsPredicate(String propertyName, Object propertyValue) {
+        this(propertyName, propertyValue, false);
+    }
+
+    /**
+     * Constructor which takes the name of the property, its expected value
+     * to be used in evaluation, and a boolean which determines whether <code>null</code> objects in
+     * the property path will genenerate an <code>IllegalArgumentException</code> or not.
+     *
+     * @param propertyName The name of the property that will be evaluated against the expected value.
+     * @param propertyValue The value to use in object evaluation.
+     * @param ignoreNull Determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     * @throws IllegalArgumentException If the property name provided is null or empty.
+     */
+    public BeanPropertyValueEqualsPredicate(String propertyName, Object propertyValue, boolean ignoreNull) {
+        super();
+
+        if ((propertyName != null) && (propertyName.length() > 0)) {
+            this.propertyName = propertyName;
+            this.propertyValue = propertyValue;
+            this.ignoreNull = ignoreNull;
+        } else {
+            throw new IllegalArgumentException("propertyName cannot be null or empty");
+        }
+    }
+
+    /**
+     * Evaulates the object provided against the criteria specified when this
+     * <code>BeanPropertyValueEqualsPredicate</code> was constructed.  Equality is based on
+     * either reference or logical equality as defined by the property object's equals method. If
+     * any object in the property path leading up to the target property is <code>null</code> then
+     * the outcome will be based on the value of the <code>ignoreNull</code> attribute. By default,
+     * <code>ignoreNull</code> is <code>false</code> and would result in an
+     * <code>IllegalArgumentException</code> if an object in the property path leading up to the
+     * target property is <code>null</code>.
+     *
+     * @param object The object to be evaluated.
+     * @return True if the object provided meets all the criteria for this <code>Predicate</code>;
+     * false otherwise.
+     * @throws IllegalArgumentException If an IllegalAccessException, InvocationTargetException, or
+     * NoSuchMethodException is thrown when trying to access the property specified on the object
+     * provided. Or if an object in the property path provided is <code>null</code> and
+     * <code>ignoreNull</code> is set to <code>false</code>.
+     */
+    public boolean evaluate(Object object) {
+       
+        boolean evaluation = false;
+
+        try {
+            evaluation = evaluateValue(propertyValue,
+                    PropertyUtils.getProperty(object, propertyName));
+        } catch (IllegalArgumentException e) {
+            final String errorMsg = "Problem during evaluation. Null value encountered in property path...";
+
+            if (ignoreNull) {
+                log.warn("WARNING: " + errorMsg, e);
+            } else {
+                log.error("ERROR: " + errorMsg, e);
+                throw e;
+            }
+        } catch (IllegalAccessException e) {
+            final String errorMsg = "Unable to access the property provided.";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (InvocationTargetException e) {
+            final String errorMsg = "Exception occurred in property's getter";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (NoSuchMethodException e) {
+            final String errorMsg = "Property not found.";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        }
+
+        return evaluation;
+    }
+
+    /**
+     * Utility method which evaluates whether the actual property value equals the expected property
+     * value.
+     *
+     * @param expected The expected value.
+     * @param actual The actual value.
+     * @return True if they are equal; false otherwise.
+     */
+    private boolean evaluateValue(Object expected, Object actual) {
+        return (expected == actual) || ((expected != null) && expected.equals(actual));
+    }
+
+    /**
+     * Returns the name of the property which will be evaluated when this <code>Predicate</code> is
+     * executed.
+     *
+     * @return The name of the property which will be evaluated when this <code>Predicate</code> is
+     * executed.
+     */
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    /**
+     * Returns the value that the property specified by <code>propertyName</code> will be compared to
+     * when this <code>Predicate</code> executes.
+     *
+     * @return The value that the property specified by <code>propertyName</code> will be compared to
+     * when this <code>Predicate</code> executes.
+     */
+    public Object getPropertyValue() {
+        return propertyValue;
+    }
+
+    /**
+     * Returns the flag which determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not. If set to <code>true</code> then
+     * if any objects in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
+     * not rethrown and <code>false</code> will be returned.  If set to <code>false</code> then if
+     * any objects in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
+     * rethrown.
+     *
+     * @return The flag which determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     */
+    public boolean isIgnoreNull() {
+        return ignoreNull;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanToPropertyValueTransformer.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanToPropertyValueTransformer.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/org/apache/commons/beanutils/BeanToPropertyValueTransformer.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * <p><code>Transformer</code> that outputs a property value.</p>
+ *
+ * <p>An implementation of <code>org.apache.commons.collections.Transformer</code> that transforms
+ * the object provided by returning the value of a specified property of the object.  The
+ * constructor for <code>BeanToPropertyValueTransformer</code> requires the name of the property
+ * that will be used in the transformation.  The property can be a simple, nested, indexed, or
+ * mapped property as defined by <code>org.apache.commons.beanutils.PropertyUtils</code>. If any
+ * object in the property path specified by <code>propertyName</code> is <code>null</code> then the
+ * outcome is based on the value of the <code>ignoreNull</code> attribute.
+ * </p>
+ *
+ * <p>
+ * A typical usage might look like:
+ * <code><pre>
+ * // create the transformer
+ * BeanToPropertyValueTransformer transformer = new BeanToPropertyValueTransformer( "person.address.city" );
+ *
+ * // transform the Collection
+ * Collection peoplesCities = CollectionUtils.collect( peopleCollection, transformer );
+ * </pre></code>
+ * </p>
+ *
+ * <p>
+ * This would take a <code>Collection</code> of person objects and return a <code>Collection</code>
+ * of objects which represents the cities in which each person lived. Assuming...
+ * <ul>
+ *    <li>
+ *       The top level object in the <code>peeopleCollection</code> is an object which represents a
+ *       person.
+ *    </li>
+ *    <li>
+ *       The person object has a <code>getAddress()</code> method which returns an object which
+ *       represents a person's address.
+ *    </li>
+ *    <li>
+ *       The address object has a <code>getCity()</code> method which returns an object which
+ *       represents the city in which a person lives.
+ *    </li>
+ * </ul>
+ *
+ * @author Norm Deane
+ * @see org.apache.commons.beanutils.PropertyUtils
+ * @see org.apache.commons.collections.Transformer
+ */
+public class BeanToPropertyValueTransformer implements Transformer {
+   
+    /** For logging. */
+    private final Log log = LogFactory.getLog(this.getClass());
+
+    /** The name of the property that will be used in the transformation of the object. */
+    private String propertyName;
+
+    /**
+     * <p>Should null objects on the property path throw an <code>IllegalArgumentException</code>?</p>
+     * <p>
+     * Determines whether <code>null</code> objects in the property path will genenerate an
+     * <code>IllegalArgumentException</code> or not. If set to <code>true</code> then if any objects
+     * in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
+     * not rethrown and <code>null</code> will be returned.  If set to <code>false</code> then if any
+     * objects in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
+     * rethrown.
+     * </p>
+     */
+    private boolean ignoreNull;
+
+    /**
+     * Constructs a Transformer which does not ignore nulls.
+     * Constructor which takes the name of the property that will be used in the transformation and
+     * assumes <code>ignoreNull</code> to be <code>false</code>.
+     *
+     * @param propertyName The name of the property that will be used in the transformation.
+     * @throws IllegalArgumentException If the <code>propertyName</code> is <code>null</code> or
+     * empty.
+     */
+    public BeanToPropertyValueTransformer(String propertyName) {
+        this(propertyName, false);
+    }
+
+    /**
+     * Constructs a Transformer and sets ignoreNull.
+     * Constructor which takes the name of the property that will be used in the transformation and
+     * a boolean which determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     *
+     * @param propertyName The name of the property that will be used in the transformation.
+     * @param ignoreNull Determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     * @throws IllegalArgumentException If the <code>propertyName</code> is <code>null</code> or
+     * empty.
+     */
+    public BeanToPropertyValueTransformer(String propertyName, boolean ignoreNull) {
+        super();
+
+        if ((propertyName != null) && (propertyName.length() > 0)) {
+            this.propertyName = propertyName;
+            this.ignoreNull = ignoreNull;
+        } else {
+            throw new IllegalArgumentException(
+                "propertyName cannot be null or empty");
+        }
+    }
+
+    /**
+     * Returns the value of the property named in the transformer's constructor for
+     * the object provided. If any object in the property path leading up to the target property is
+     * <code>null</code> then the outcome will be based on the value of the <code>ignoreNull</code>
+     * attribute. By default, <code>ignoreNull</code> is <code>false</code> and would result in an
+     * <code>IllegalArgumentException</code> if an object in the property path leading up to the
+     * target property is <code>null</code>.
+     *
+     * @param object The object to be transformed.
+     * @return The value of the property named in the transformer's constructor for the object
+     * provided.
+     * @throws IllegalArgumentException If an IllegalAccessException, InvocationTargetException, or
+     * NoSuchMethodException is thrown when trying to access the property specified on the object
+     * provided. Or if an object in the property path provided is <code>null</code> and
+     * <code>ignoreNull</code> is set to <code>false</code>.
+     */
+    public Object transform(Object object) {
+       
+        Object propertyValue = null;
+
+        try {
+            propertyValue = PropertyUtils.getProperty(object, propertyName);
+        } catch (IllegalArgumentException e) {
+            final String errorMsg = "Problem during transformation. Null value encountered in property path...";
+
+            if (ignoreNull) {
+                log.warn("WARNING: " + errorMsg, e);
+            } else {
+                log.error("ERROR: " + errorMsg, e);
+                throw e;
+            }
+        } catch (IllegalAccessException e) {
+            final String errorMsg = "Unable to access the property provided.";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (InvocationTargetException e) {
+            final String errorMsg = "Exception occurred in property's getter";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        } catch (NoSuchMethodException e) {
+            final String errorMsg = "No property found for name [" +
+                propertyName + "]";
+            log.error(errorMsg, e);
+            throw new IllegalArgumentException(errorMsg);
+        }
+
+        return propertyValue;
+    }
+
+    /**
+     * Returns the name of the property that will be used in the transformation of the bean.
+     *
+     * @return The name of the property that will be used in the transformation of the bean.
+     */
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    /**
+     * Returns the flag which determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not. If set to <code>true</code> then
+     * if any objects in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged but
+     * not rethrown and <code>null</code> will be returned.  If set to <code>false</code> then if any
+     * objects in the property path evaluate to <code>null</code> then the
+     * <code>IllegalArgumentException</code> throw by <code>PropertyUtils</code> will be logged and
+     * rethrown.
+     *
+     * @return The flag which determines whether <code>null</code> objects in the property path will
+     * genenerate an <code>IllegalArgumentException</code> or not.
+     */
+    public boolean isIgnoreNull() {
+        return ignoreNull;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/overview.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/overview.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/java/overview.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<title>Overview Documentation for COMMONS-BEANUTILS BEAN COLLECTIONS</title>
+</head>
+<body bgcolor="white">
+<p>The <em>Bean Introspection Utilities</em> component of the Jakarta Commons
+subproject offers low-level utility classes that assist in getting and setting
+property values on Java classes that follow the naming design patterns outlined
+in the JavaBeans Specification, as well as mechanisms for dynamically defining
+and accessing bean properties.</p>
+<p>
+The Bean-Collections optional distribution contains objects which apply these 
+techniques to collections. They rely on commons-collections 3.0 (or higher).
+</p>
+
+<p>The documentation for this optional package is included with the core Beanutils
+documentation.</p>
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AbstractParent.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AbstractParent.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AbstractParent.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+public abstract class AbstractParent {
+    
+    private Child child;
+    
+    public Child getChild()
+    {
+        return child;
+    }
+
+    /**
+     * Method which matches signature but which has wrong parameters 
+     */
+    public String testAddChild(String badParameter) {
+        return null;
+    }
+
+    /**
+     * Method which matches signature but which has wrong parameters 
+     */
+    public String testAddChild2(String ignore, String badParameter) {
+        return null;
+    }
+    
+    public String testAddChild(Child child) {
+        this.child = child;
+        return child.getName();
+    }
+    
+
+    public String testAddChild2(String ignore, Child child) {
+        this.child = child;
+        return child.getName();
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AlphaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AlphaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/AlphaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+public class AlphaBean extends AbstractParent implements Child {
+    
+    private String name;
+    
+    public AlphaBean() {}
+    
+    public AlphaBean(String name) {
+        setName(name);
+    }
+    
+    public String getName() {
+        return name;
+    }    
+    
+    public void setName(String name) {
+        this.name = name;
+    }	
+    
+    /**
+     * Used for testing that correct exception is thrown.
+     */
+    public void bogus(String badParameter){}
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanCollectionsTestSuite.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanCollectionsTestSuite.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanCollectionsTestSuite.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>Test suite which runs all the test cases application to beans in collections.
+ *
+ * @author <a href="mailto:epugh at upstate.com">Eric Pugh</a>
+ * @version $Revision: 1.2 $
+ */
+
+public class BeanCollectionsTestSuite extends TestCase {
+
+    public BeanCollectionsTestSuite(java.lang.String testName) {
+        super(testName);
+    }
+
+    public static void main(java.lang.String[] args) {
+        junit.textui.TestRunner.run(suite());
+    }
+
+    public static junit.framework.Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(BeanComparatorTestCase.class);
+        suite.addTestSuite(BeanToPropertyValueTransformerTest.class);
+        suite.addTestSuite(BeanPropertyValueEqualsPredicateTest.class);
+        suite.addTestSuite(BeanPropertyValueChangeClosureTest.class);
+        suite.addTestSuite(TestBeanMap.class);
+
+        return suite;
+    }
+}
+
+

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanComparatorTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanComparatorTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanComparatorTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>
+ *  Test Case for the BeanComparator class.
+ *
+ * @author <a href="mailto:epugh at upstate.com">Eric Pugh</a>
+ * @version $Revision: 1.1 $
+ */
+
+public class BeanComparatorTestCase extends TestCase {
+
+    // ---------------------------------------------------- Instance Variables
+
+    /**
+     * The test beans for each test.
+     */
+    protected TestBean bean = null;
+    protected AlphaBean alphaBean1 = null;
+    protected AlphaBean alphaBean2 = null;
+
+    // The test BeanComparator
+    protected BeanComparator beanComparator = null;
+
+
+
+
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public BeanComparatorTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+        bean = new TestBean();
+        alphaBean1 = new AlphaBean("alphaBean1");
+        alphaBean2 = new AlphaBean("alphaBean2");
+
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(BeanComparatorTestCase.class));
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        bean = null;
+        alphaBean1 = null;
+        alphaBean2 = null;
+        beanComparator = null;
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     *  tests comparing two beans via their name using the default Comparator
+     */
+    public void testSimpleCompare() {
+        try {
+          beanComparator = new BeanComparator("name");
+          int result = beanComparator.compare(alphaBean1, alphaBean2);
+          assertTrue("Comparator did not sort properly.  Result:" + result,result==-1);
+
+        }
+        catch (Exception e) {
+            fail("Exception");
+        }
+    }
+
+    /**
+     *  tests comparing two beans via their name using the default Comparator, but the inverse
+     */
+    public void testSimpleCompareInverse() {
+        try {
+          beanComparator = new BeanComparator("name");
+          int result = beanComparator.compare(alphaBean2, alphaBean1);
+          assertTrue("Comparator did not sort properly.  Result:" + result,result==1);
+
+        }
+        catch (Exception e) {
+            fail("Exception" + e);
+        }
+    }
+
+    /**
+     *  tests comparing two beans via their name using the default Comparator where they have the same value.
+     */
+    public void testCompareIdentical() {
+        try {
+          alphaBean1 = new AlphaBean("alphabean");
+          alphaBean2 = new AlphaBean("alphabean");
+          beanComparator = new BeanComparator("name");
+          int result = beanComparator.compare(alphaBean1, alphaBean2);
+          assertTrue("Comparator did not sort properly.  Result:" + result,result==0);
+
+        }
+        catch (Exception e) {
+            fail("Exception");
+        }
+    }
+
+    /**
+     *  tests comparing one bean against itself.
+     */
+    public void testCompareBeanAgainstSelf() {
+        try {
+          beanComparator = new BeanComparator("name");
+          int result = beanComparator.compare(alphaBean1, alphaBean1);
+          assertTrue("Comparator did not sort properly.  Result:" + result,result==0);
+
+        }
+        catch (Exception e) {
+            fail("Exception");
+        }
+    }
+
+    /**
+     *  tests comparing two beans via their name using the default Comparator, but with one of the beans
+     *  being null.
+     */
+    public void testCompareWithNulls() {
+        try {
+          beanComparator = new BeanComparator("name");
+          beanComparator.compare(alphaBean2, null);
+
+          // DEP not sure if this is the best way to test an exception?
+          fail("Should not be able to compare a null value.");
+
+        }
+        catch (Exception e) {
+
+        }
+    }
+
+    /**
+     *  tests comparing two beans who don't have a property
+     */
+    public void testCompareOnMissingProperty() {
+        try {
+          beanComparator = new BeanComparator("bogusName");
+          beanComparator.compare(alphaBean2, alphaBean1);
+          fail("should not be able to compare");
+
+
+        }
+        catch (ClassCastException cce){
+          assertTrue("Wrong exception was thrown.",cce.toString().indexOf("Unknown property") > -1);
+        }
+        catch (Exception e) {
+            fail("Exception" + e);
+        }
+    }
+
+    /**
+     *  tests comparing two beans on a boolean property, which is not possible.
+     */
+    public void testCompareOnBooleanProperty() {
+        try {
+          TestBean testBeanA = new TestBean();
+          TestBean testBeanB = new TestBean();
+
+          testBeanA.setBooleanProperty(true);
+          testBeanB.setBooleanProperty(false);
+
+          beanComparator = new BeanComparator("booleanProperty");
+          beanComparator.compare(testBeanA, testBeanB);
+
+          fail("BeanComparator should throw an exception when comparing two booleans.");
+
+        }
+        catch (ClassCastException cce){
+          ; // Expected result
+        }
+        catch (Exception e) {
+            fail("Exception" + e);
+        }
+    }
+
+    /**
+     *  tests comparing two beans on a boolean property, then changing the property and testing
+     */
+    public void testSetProperty() {
+        try {
+          TestBean testBeanA = new TestBean();
+          TestBean testBeanB = new TestBean();
+
+          testBeanA.setDoubleProperty(5.5);
+          testBeanB.setDoubleProperty(1.0);
+
+          beanComparator = new BeanComparator("doubleProperty");
+          int result = beanComparator.compare(testBeanA, testBeanB);
+
+          assertTrue("Comparator did not sort properly.  Result:" + result,result==1);
+
+          testBeanA.setStringProperty("string 1");
+          testBeanB.setStringProperty("string 2");
+
+          beanComparator.setProperty("stringProperty");
+
+          result = beanComparator.compare(testBeanA, testBeanB);
+
+          assertTrue("Comparator did not sort properly.  Result:" + result,result==-1);
+
+        }
+        catch (ClassCastException cce){
+          fail("ClassCaseException " + cce.toString());
+        }
+        catch (Exception e) {
+          fail("Exception" + e);
+        }
+    }
+}
+
+

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPredicateTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPredicateTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPredicateTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.collections.functors.EqualPredicate;
+import org.apache.commons.collections.functors.InstanceofPredicate;
+import org.apache.commons.collections.functors.NotPredicate;
+import org.apache.commons.collections.functors.NullPredicate;
+
+public class BeanPredicateTestCase extends TestCase {
+   
+    public BeanPredicateTestCase(String name) {
+        super(name);
+    }
+
+    public void testEqual() {
+        BeanPredicate predicate = 
+            new BeanPredicate("stringProperty",new EqualPredicate("foo"));
+        assertTrue(predicate.evaluate(new TestBean("foo")));
+        assertTrue(!predicate.evaluate(new TestBean("bar")));
+    }
+
+    public void testNotEqual() {
+        BeanPredicate predicate = 
+            new BeanPredicate("stringProperty",new NotPredicate( new EqualPredicate("foo")));
+        assertTrue(!predicate.evaluate(new TestBean("foo")));
+        assertTrue(predicate.evaluate(new TestBean("bar")));
+    }
+
+    public void testInstanceOf() {
+        BeanPredicate predicate = 
+            new BeanPredicate("stringProperty",new InstanceofPredicate( String.class ));
+        assertTrue(predicate.evaluate(new TestBean("foo")));
+        assertTrue(predicate.evaluate(new TestBean("bar")));
+    }
+
+    public void testNull() {
+        BeanPredicate predicate = 
+            new BeanPredicate("stringProperty", NullPredicate.INSTANCE);
+        String nullString = null;
+        assertTrue(predicate.evaluate(new TestBean(nullString)));
+        assertTrue(!predicate.evaluate(new TestBean("bar")));
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueChangeClosureTest.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueChangeClosureTest.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueChangeClosureTest.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Test cases for <code>BeanPropertyValueChangeClosure</code>.
+ *
+ * @author Norm Deane
+ */
+public class BeanPropertyValueChangeClosureTest extends TestCase {
+   
+    private static final Integer expectedIntegerValue = new Integer(123);
+    private static final Float expectedFloatValue = new Float(123.123f);
+    private static final Double expectedDoubleValue = new Double(567879.12344d);
+    private static final Boolean expectedBooleanValue = Boolean.TRUE;
+    private static final Byte expectedByteValue = new Byte("12");
+
+    /**
+     * Constructor for BeanPropertyValueChangeClosureTest.
+     *
+     * @param name Name of this test case.
+     */
+    public BeanPropertyValueChangeClosureTest(String name) {
+        super(name);
+    }
+    
+    /**
+     * Test execute with simple float property and Float value.
+     */
+    public void testExecuteWithSimpleFloatPropertyAndFloatValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("floatProperty", expectedFloatValue).execute(testBean);
+        assertTrue(expectedFloatValue.floatValue() == testBean.getFloatProperty());
+    }
+
+    /**
+     * Test execute with simple float property and String value.
+     */
+    public void testExecuteWithSimpleFloatPropertyAndStringValue() {
+        try {
+            new BeanPropertyValueChangeClosure("floatProperty", "123").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple float property and Double value.
+     */
+    public void testExecuteWithSimpleFloatPropertyAndDoubleValue() {
+        try {
+            new BeanPropertyValueChangeClosure("floatProperty", expectedDoubleValue).execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple float property and Integer value.
+     */
+    public void testExecuteWithSimpleFloatPropertyAndIntegerValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("floatProperty", expectedIntegerValue).execute(testBean);
+        assertTrue(expectedIntegerValue.floatValue() == testBean.getFloatProperty());
+    }
+
+    /**
+     * Test execute with simple double property and Double value.
+     */
+    public void testExecuteWithSimpleDoublePropertyAndDoubleValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("doubleProperty", expectedDoubleValue).execute(testBean);
+        assertTrue(expectedDoubleValue.doubleValue() == testBean.getDoubleProperty());
+    }
+
+    /**
+     * Test execute with simple double property and String value.
+     */
+    public void testExecuteWithSimpleDoublePropertyAndStringValue() {
+        try {
+            new BeanPropertyValueChangeClosure("doubleProperty", "123").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple double property and Float value.
+     */
+    public void testExecuteWithSimpleDoublePropertyAndFloatValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("doubleProperty", expectedFloatValue).execute(testBean);
+        assertTrue(expectedFloatValue.doubleValue() == testBean.getDoubleProperty());
+    }
+
+    /**
+     * Test execute with simple double property and Integer value.
+     */
+    public void testExecuteWithSimpleDoublePropertyAndIntegerValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("doubleProperty", expectedIntegerValue).execute(testBean);
+        assertTrue(expectedIntegerValue.doubleValue() == testBean.getDoubleProperty());
+    }
+
+    /**
+     * Test execute with simple int property and Double value.
+     */
+    public void testExecuteWithSimpleIntPropertyAndDoubleValue() {
+        try {
+            new BeanPropertyValueChangeClosure("intProperty", expectedDoubleValue).execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple int property and String value.
+     */
+    public void testExecuteWithSimpleIntPropertyAndStringValue() {
+        try {
+            new BeanPropertyValueChangeClosure("intProperty", "123").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple int property and Float value.
+     */
+    public void testExecuteWithSimpleIntPropertyAndFloatValue() {
+        try {
+            new BeanPropertyValueChangeClosure("intProperty", expectedFloatValue).execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple int property and Integer value.
+     */
+    public void testExecuteWithSimpleIntPropertyAndIntegerValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("intProperty", expectedIntegerValue).execute(testBean);
+        assertTrue(expectedIntegerValue.intValue() == testBean.getIntProperty());
+    }
+
+    /**
+     * Test execute with simple boolean property and Boolean value.
+     */
+    public void testExecuteWithSimpleBooleanPropertyAndBooleanValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("booleanProperty", expectedBooleanValue).execute(testBean);
+        assertTrue(expectedBooleanValue.booleanValue() == testBean.getBooleanProperty());
+    }
+
+    /**
+     * Test execute with simple boolean property and String value.
+     */
+    public void testExecuteWithSimpleBooleanPropertyAndStringValue() {
+        try {
+            new BeanPropertyValueChangeClosure("booleanProperty", "true").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple byte property and Byte value.
+     */
+    public void testExecuteWithSimpleBytePropertyAndByteValue() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("byteProperty", expectedByteValue).execute(testBean);
+        assertTrue(expectedByteValue.byteValue() == testBean.getByteProperty());
+    }
+
+    /**
+     * Test execute with simple boolean property and String value.
+     */
+    public void testExecuteWithSimpleBytePropertyAndStringValue() {
+        try {
+            new BeanPropertyValueChangeClosure("byteProperty", "foo").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with simple primitive property and null value.
+     */
+    public void testExecuteWithSimplePrimitivePropertyAndNullValue() {
+        try {
+            new BeanPropertyValueChangeClosure("intProperty", null).execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (NullPointerException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with read only property.
+     */
+    public void testExecuteWithReadOnlyProperty() {
+        try {
+            new BeanPropertyValueChangeClosure("readOnlyProperty", "foo").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with write only property.
+     */
+    public void testExecuteWithWriteOnlyProperty() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("writeOnlyProperty", "foo").execute(testBean);
+        assertEquals("foo", testBean.getWriteOnlyPropertyValue());
+    }
+
+    /**
+     * Test execute with a nested property.
+     */
+    public void testExecuteWithNestedProperty() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("nested.stringProperty", "bar").execute(testBean);
+        assertEquals("bar", testBean.getNested().getStringProperty());
+    }
+
+    /**
+     * Test execute with a nested property and null in the property path.
+     */
+    public void testExecuteWithNullInPropertyPath() {
+        try {
+            new BeanPropertyValueChangeClosure("anotherNested.stringProperty", "foo").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+
+    /**
+     * Test execute with a nested property and null in the property path and ignoreNull = true.
+     */
+    public void testExecuteWithNullInPropertyPathAngIgnoreTrue() {
+        TestBean testBean = new TestBean();
+
+        // create a closure that will attempt to set a property on the null bean in the path
+        BeanPropertyValueChangeClosure closure = new BeanPropertyValueChangeClosure("anotherNested.stringProperty",
+                "Should ignore exception", true);
+
+        try {
+            closure.execute(testBean);
+        } catch (IllegalArgumentException e) {
+            fail("Should have ignored the exception.");
+        }
+    }
+
+    /**
+     * Test execute with indexed property.
+     */
+    public void testExecuteWithIndexedProperty() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("intIndexed[0]", expectedIntegerValue).execute(testBean);
+        assertTrue(expectedIntegerValue.intValue() == testBean.getIntIndexed(0));
+    }
+
+    /**
+     * Test execute with mapped property.
+     */
+    public void testExecuteWithMappedProperty() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("mappedProperty(fred)", "barney").execute(testBean);
+        assertEquals("barney", testBean.getMappedProperty("fred"));
+    }
+
+    /**
+     * Test execute with a simple String property.
+     */
+    public void testExecuteWithSimpleStringProperty() {
+        TestBean testBean = new TestBean();
+        new BeanPropertyValueChangeClosure("stringProperty", "barney").execute(testBean);
+        assertEquals("barney", testBean.getStringProperty());
+    }
+
+    /**
+     * Test execute with an invalid property name.
+     */
+    public void testExecuteWithInvalidPropertyName() {
+        try {
+            new BeanPropertyValueChangeClosure("bogusProperty", "foo").execute(new TestBean());
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* this is what we expect */
+        }
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicateTest.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicateTest.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanPropertyValueEqualsPredicateTest.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Test cases for <code>BeanPropertyValueEqualsPredicateTest</code>.
+ *
+ * @author Norm Deane
+ */
+public class BeanPropertyValueEqualsPredicateTest extends TestCase {
+   
+    private static final Integer expectedIntegerValue = new Integer(123);
+    private static final Float expectedFloatValue = new Float(123.123f);
+    private static final Double expectedDoubleValue = new Double(567879.12344d);
+    private static final Boolean expectedBooleanValue = Boolean.TRUE;
+    private static final Byte expectedByteValue = new Byte("12");
+
+    /**
+     * Constructor for BeanPropertyValueEqualsPredicateTest.
+     *
+     * @param name Name of this test case.
+     */
+    public BeanPropertyValueEqualsPredicateTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test evaluate with simple String property.
+     */
+    public void testEvaluateWithSimpleStringProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("stringProperty","foo");
+        assertTrue(predicate.evaluate(new TestBean("foo")));
+        assertTrue(!predicate.evaluate(new TestBean("bar")));
+    }
+
+    /**
+     * Test evaluate with simple String property and null values.
+     */
+    public void testEvaluateWithSimpleStringPropertyWithNullValues() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("stringProperty",null);
+        assertTrue(predicate.evaluate(new TestBean((String) null)));
+        assertTrue(!predicate.evaluate(new TestBean("bar")));
+    }
+
+    /**
+     * Test evaluate with nested property.
+     */
+    public void testEvaluateWithNestedProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("anotherNested.stringProperty","match");
+        TestBean testBean = new TestBean();
+        TestBean nestedBean = new TestBean("match");
+        testBean.setAnotherNested(nestedBean);
+        assertTrue(predicate.evaluate(testBean));
+        testBean.setAnotherNested(new TestBean("no-match"));
+        assertTrue(!predicate.evaluate(testBean));
+    }
+
+    /**
+     * Test evaluate with null in property path and ignore=false.
+     */
+    public void testEvaluateWithNullInPath() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("anotherNested.stringProperty","foo");
+        try {
+            // try to evaluate the predicate
+            predicate.evaluate(new TestBean());
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* ignore this is what should happen */
+        }
+    }
+
+    /**
+     * Test evaluate with null in property path and ignore=true.
+     */
+    public void testEvaluateWithNullInPathAndIgnoreTrue() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("anotherNested.stringProperty","foo", true);
+        try {
+            assertTrue(!predicate.evaluate(new TestBean()));
+        } catch (IllegalArgumentException e) {
+            fail("Should not have throw IllegalArgumentException");
+        }
+    }
+
+    /**
+     * Test evaluate with int property.
+     */
+    public void testEvaluateWithIntProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("intProperty",expectedIntegerValue);
+        assertTrue(predicate.evaluate(new TestBean(expectedIntegerValue.intValue())));
+        assertTrue(!predicate.evaluate(new TestBean(expectedIntegerValue.intValue() - 1)));
+    }
+
+    /**
+     * Test evaluate with float property.
+     */
+    public void testEvaluateWithFloatProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("floatProperty",expectedFloatValue);
+        assertTrue(predicate.evaluate(new TestBean(expectedFloatValue.floatValue())));
+        assertTrue(!predicate.evaluate(new TestBean(expectedFloatValue.floatValue() - 1)));
+    }
+
+    /**
+     * Test evaluate with double property.
+     */
+    public void testEvaluateWithDoubleProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("doubleProperty",expectedDoubleValue);
+        assertTrue(predicate.evaluate(new TestBean(expectedDoubleValue.doubleValue())));
+        assertTrue(!predicate.evaluate(new TestBean(expectedDoubleValue.doubleValue() - 1)));
+    }
+
+    /**
+     * Test evaluate with boolean property.
+     */
+    public void testEvaluateWithBooleanProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("booleanProperty",expectedBooleanValue);
+        assertTrue(predicate.evaluate(new TestBean(expectedBooleanValue.booleanValue())));
+        assertTrue(!predicate.evaluate(new TestBean(!expectedBooleanValue.booleanValue())));
+    }
+
+    /**
+     * Test evaluate with byte property.
+     */
+    public void testEvaluateWithByteProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("byteProperty",expectedByteValue);
+        TestBean testBean = new TestBean();
+        testBean.setByteProperty(expectedByteValue.byteValue());
+        assertTrue(predicate.evaluate(testBean));
+        testBean.setByteProperty((byte) (expectedByteValue.byteValue() - 1));
+        assertTrue(!predicate.evaluate(testBean));
+    }
+
+    /**
+     * Test evaluate with mapped property.
+     */
+    public void testEvaluateWithMappedProperty() {
+        // try a key that is in the map
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("mappedProperty(test-key)","match");
+        TestBean testBean = new TestBean();
+        testBean.setMappedProperty("test-key", "match");
+        assertTrue(predicate.evaluate(testBean));
+        testBean.setMappedProperty("test-key", "no-match");
+        assertTrue(!predicate.evaluate(testBean));
+
+        // try a key that isn't in the map
+        predicate = new BeanPropertyValueEqualsPredicate("mappedProperty(invalid-key)", "match");
+        assertTrue(!predicate.evaluate(testBean));
+    }
+
+    /**
+     * Test evaluate with indexed property.
+     */
+    public void testEvaluateWithIndexedProperty() {
+        // try a valid index
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("intIndexed[0]",expectedIntegerValue);
+        TestBean testBean = new TestBean();
+        testBean.setIntIndexed(0, expectedIntegerValue.intValue());
+        assertTrue(predicate.evaluate(testBean));
+        testBean.setIntIndexed(0, expectedIntegerValue.intValue() - 1);
+        assertTrue(!predicate.evaluate(testBean));
+
+        // try an invalid index
+        predicate = new BeanPropertyValueEqualsPredicate("intIndexed[999]", "exception-ahead");
+
+        try {
+            assertTrue(!predicate.evaluate(testBean));
+        } catch (ArrayIndexOutOfBoundsException e) { 
+            /* this is what should happen */
+        }
+    }
+
+    /**
+     * Test evaluate with primitive property and null value.
+     */
+    public void testEvaluateWithPrimitiveAndNull() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("intProperty",null);
+        assertTrue(!predicate.evaluate(new TestBean(0)));
+
+        predicate = new BeanPropertyValueEqualsPredicate("booleanProperty", null);
+        assertTrue(!predicate.evaluate(new TestBean(true)));
+
+        predicate = new BeanPropertyValueEqualsPredicate("floatProperty", null);
+        assertTrue(!predicate.evaluate(new TestBean(expectedFloatValue.floatValue())));
+    }
+
+    /**
+     * Test evaluate with nested mapped property.
+     */
+    public void testEvaluateWithNestedMappedProperty() {
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("anotherNested.mappedProperty(test-key)","match");
+        TestBean testBean = new TestBean();
+        TestBean nestedBean = new TestBean();
+        nestedBean.setMappedProperty("test-key", "match");
+        testBean.setAnotherNested(nestedBean);
+        assertTrue(predicate.evaluate(testBean));
+        nestedBean.setMappedProperty("test-key", "no-match");
+        assertTrue(!predicate.evaluate(testBean));
+    }
+
+    /**
+     * Test evaluate with write only property.
+     */
+    public void testEvaluateWithWriteOnlyProperty() {
+        try {
+            new BeanPropertyValueEqualsPredicate("writeOnlyProperty", null).evaluate(new TestBean());
+        } catch (IllegalArgumentException e) { 
+            /* This is what should happen */
+        }
+    }
+
+    /**
+     * Test evaluate with read only property.
+     */
+    public void testEvaluateWithReadOnlyProperty() {
+        TestBean testBean = new TestBean();
+        BeanPropertyValueEqualsPredicate predicate = 
+            new BeanPropertyValueEqualsPredicate("readOnlyProperty",testBean.getReadOnlyProperty());
+        assertTrue(predicate.evaluate(new TestBean()));
+    }
+
+    /**
+     * Test evaluate with an invalid property name.
+     */
+    public void testEvaluateWithInvalidPropertyName() {
+        try {
+            new BeanPropertyValueEqualsPredicate("bogusProperty", null).evaluate(new TestBean());
+        } catch (IllegalArgumentException e) { 
+            /* This is what should happen */
+        }
+    }
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanToPropertyValueTransformerTest.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanToPropertyValueTransformerTest.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/BeanToPropertyValueTransformerTest.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Test cases for <code>BeanToPropertyValueTransformer</code>.
+ *
+ * @author Norm Deane
+ */
+public class BeanToPropertyValueTransformerTest extends TestCase {
+   
+    private static final Integer expectedIntegerValue = new Integer(123);
+    private static final Long expectedLongValue = new Long(123);
+    private static final Float expectedFloatValue = new Float(123.123f);
+    private static final Double expectedDoubleValue = new Double(567879.12344d);
+    private static final Boolean expectedBooleanValue = Boolean.TRUE;
+    private static final Byte expectedByteValue = new Byte("12");
+
+    /**
+     * Constructor for BeanToPropertyValueTransformerTest.
+     *
+     * @param name Name of this test case.
+     */
+    public BeanToPropertyValueTransformerTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test transform with simple String property.
+     */
+    public void testTransformWithSimpleStringProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("stringProperty");
+        TestBean testBean = new TestBean("foo");
+        assertEquals("foo", transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple String property and null value.
+     *
+     */
+    public void testTransformWithSimpleStringPropertyAndNullValue() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("stringProperty");
+        TestBean testBean = new TestBean((String) null);
+        assertNull(transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple int property.
+     */
+    public void testTransformWithSimpleIntProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("intProperty");
+        TestBean testBean = new TestBean(expectedIntegerValue.intValue());
+        assertEquals(expectedIntegerValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple long property.
+     */
+    public void testTransformWithSimpleLongProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("longProperty");
+        TestBean testBean = new TestBean();
+        testBean.setLongProperty(expectedLongValue.longValue());
+        assertEquals(expectedLongValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple float property.
+     */
+    public void testTransformWithSimpleFloatProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("floatProperty");
+        TestBean testBean = new TestBean(expectedFloatValue.floatValue());
+        assertEquals(expectedFloatValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple double property.
+     */
+    public void testTransformWithSimpleDoubleProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("doubleProperty");
+        TestBean testBean = new TestBean(expectedDoubleValue.doubleValue());
+        assertEquals(expectedDoubleValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple byte property.
+     */
+    public void testTransformWithSimpleByteProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("byteProperty");
+        TestBean testBean = new TestBean();
+        testBean.setByteProperty(expectedByteValue.byteValue());
+        assertEquals(expectedByteValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with simple boolean property.
+     */
+    public void testTransformWithSimpleBooleanProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("booleanProperty");
+        TestBean testBean = new TestBean(expectedBooleanValue.booleanValue());
+        assertEquals(expectedBooleanValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with write only property.
+     */
+    public void testTransformWithWriteOnlyProperty() {
+        try {
+            new BeanToPropertyValueTransformer("writeOnlyProperty").transform(new TestBean());
+        } catch (IllegalArgumentException e) { 
+            /* This is what should happen */
+        }
+    }
+
+    /**
+     * Test transform with read only property.
+     */
+    public void testTransformWithReadOnlyProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("readOnlyProperty");
+        TestBean testBean = new TestBean();
+        assertEquals(testBean.getReadOnlyProperty(), transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with invalid property.
+     */
+    public void testTransformWithInvalidProperty() {
+        try {
+            new BeanToPropertyValueTransformer("bogusProperty").transform(new TestBean());
+        } catch (IllegalArgumentException e) { 
+            /* This is what should happen */
+        }
+    }
+
+    /**
+     * Test transform with nested property.
+     */
+    public void testTransformWithNestedProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("anotherNested.stringProperty");
+        TestBean testBean = new TestBean();
+        TestBean nestedBean = new TestBean("foo");
+        testBean.setAnotherNested(nestedBean);
+        assertEquals("foo", transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with mapped property.
+     */
+    public void testTransformWithMappedProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("mappedProperty(test-key)");
+        TestBean testBean = new TestBean();
+
+        // try a valid key
+        testBean.setMappedProperty("test-key", "test-value");
+        assertEquals("test-value", transformer.transform(testBean));
+
+        // now try an invalid key
+        transformer = new BeanToPropertyValueTransformer("mappedProperty(bogus-key)");
+        assertEquals(null, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with indexed property.
+     */
+    public void testTransformWithIndexedProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("intIndexed[0]");
+        TestBean testBean = new TestBean();
+        testBean.setIntIndexed(0, expectedIntegerValue.intValue());
+        assertEquals(expectedIntegerValue, transformer.transform(testBean));
+
+        // test index out of range
+        transformer = new BeanToPropertyValueTransformer("intIndexed[9999]");
+
+        try {
+            transformer.transform(testBean);
+            fail("Should have thrown an ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException e) { 
+            /* this is what should happen */
+        }
+    }
+
+    /**
+     * Test transform with nested indexed property.
+     */
+    public void testTransformWithNestedIndexedProperty() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("anotherNested.intIndexed[0]");
+        TestBean testBean = new TestBean();
+        TestBean nestedBean = new TestBean();
+        nestedBean.setIntIndexed(0, expectedIntegerValue.intValue());
+        testBean.setAnotherNested(nestedBean);
+        assertEquals(expectedIntegerValue, transformer.transform(testBean));
+    }
+
+    /**
+     * Test transform with null in property path.
+     */
+    public void testTransformWithNullInPath() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("anotherNested.stringProperty");
+
+        try {
+            transformer.transform(new TestBean());
+            fail("Should have throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) { 
+            /* ignore this is what should happen */
+        }
+    }
+
+    /**
+     * Test transform with null in property path and ignore = true.
+     */
+    public void testTransformWithNullInPathAndIgnoreTrue() {
+        BeanToPropertyValueTransformer transformer = 
+            new BeanToPropertyValueTransformer("anotherNested.stringProperty",true);
+        assertEquals(null, transformer.transform(new TestBean()));
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/Child.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/Child.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/Child.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+public interface Child {
+    
+    public String getName();
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * General purpose test bean for JUnit tests for the "beanutils" component.
+ *
+ * @author Craig R. McClanahan
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 20:01:16 $
+ */
+
+public class TestBean {
+
+    // ----------------------------------------------------------- Constructors
+
+    public TestBean() {
+    }
+
+    public TestBean(String stringProperty) {
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(float floatProperty) {
+        setFloatProperty(floatProperty);
+    }
+
+    public TestBean(boolean booleanProperty) {
+        setBooleanProperty(booleanProperty);
+    }
+
+    public TestBean(Boolean booleanSecond) {
+        setBooleanSecond(booleanSecond.booleanValue());
+    }
+
+    public TestBean(float floatProperty, String stringProperty) {
+        setFloatProperty(floatProperty);
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(boolean booleanProperty, String stringProperty) {
+        setBooleanProperty(booleanProperty);
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(Boolean booleanSecond, String stringProperty) {
+        setBooleanSecond(booleanSecond.booleanValue());
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(Integer intProperty) {
+        setIntProperty(intProperty.intValue());
+    }
+
+   public TestBean(double doubleProperty) {
+       setDoubleProperty(doubleProperty);
+   }
+   
+    TestBean(int intProperty) {
+        setIntProperty(intProperty);
+    }
+
+    protected TestBean(boolean booleanProperty, boolean booleanSecond, String stringProperty) {
+        setBooleanProperty(booleanProperty);
+        setBooleanSecond(booleanSecond);
+        setStringProperty(stringProperty);
+    }
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A boolean property.
+     */
+    private boolean booleanProperty = true;
+
+    public boolean getBooleanProperty() {
+        return (booleanProperty);
+    }
+
+    public void setBooleanProperty(boolean booleanProperty) {
+        this.booleanProperty = booleanProperty;
+    }
+
+
+    /**
+     * A boolean property that uses an "is" method for the getter.
+     */
+    private boolean booleanSecond = true;
+
+    public boolean isBooleanSecond() {
+        return (booleanSecond);
+    }
+
+    public void setBooleanSecond(boolean booleanSecond) {
+        this.booleanSecond = booleanSecond;
+    }
+
+
+    /**
+     * A byte property.
+     */
+    private byte byteProperty = (byte) 121;
+
+    public byte getByteProperty() {
+        return (this.byteProperty);
+    }
+
+    public void setByteProperty(byte byteProperty) {
+        this.byteProperty = byteProperty;
+    }
+
+
+    /**
+     * A double property.
+     */
+    private double doubleProperty = 321.0;
+
+    public double getDoubleProperty() {
+        return (this.doubleProperty);
+    }
+
+    public void setDoubleProperty(double doubleProperty) {
+        this.doubleProperty = doubleProperty;
+    }
+
+
+    /**
+     * An "indexed property" accessible via both array and subscript
+     * based getters and setters.
+     */
+    private String dupProperty[] =
+    { "Dup 0", "Dup 1", "Dup 2", "Dup 3", "Dup 4" };
+
+    public String[] getDupProperty() {
+        return (this.dupProperty);
+    }
+
+    public String getDupProperty(int index) {
+        return (this.dupProperty[index]);
+    }
+
+    public void setDupProperty(int index, String value) {
+        this.dupProperty[index] = value;
+    }
+
+    public void setDupProperty(String dupProperty[]) {
+        this.dupProperty = dupProperty;
+    }
+
+
+    /**
+     * A float property.
+     */
+    private float floatProperty = (float) 123.0;
+
+    public float getFloatProperty() {
+        return (this.floatProperty);
+    }
+
+    public void setFloatProperty(float floatProperty) {
+        this.floatProperty = floatProperty;
+    }
+
+
+    /**
+     * An integer array property accessed as an array.
+     */
+    private int intArray[] = { 0, 10, 20, 30, 40 };
+
+    public int[] getIntArray() {
+        return (this.intArray);
+    }
+
+    public void setIntArray(int intArray[]) {
+        this.intArray = intArray;
+    }
+
+
+    /**
+     * An integer array property accessed as an indexed property.
+     */
+    private int intIndexed[] = { 0, 10, 20, 30, 40 };
+
+    public int getIntIndexed(int index) {
+        return (intIndexed[index]);
+    }
+
+    public void setIntIndexed(int index, int value) {
+        intIndexed[index] = value;
+    }
+
+
+    /**
+     * An integer property.
+     */
+    private int intProperty = 123;
+
+    public int getIntProperty() {
+        return (this.intProperty);
+    }
+
+    public void setIntProperty(int intProperty) {
+        this.intProperty = intProperty;
+    }
+
+
+    /**
+     * A List property accessed as an indexed property.
+     */
+    private static List listIndexed = new ArrayList();
+
+    static {
+        listIndexed.add("String 0");
+        listIndexed.add("String 1");
+        listIndexed.add("String 2");
+        listIndexed.add("String 3");
+        listIndexed.add("String 4");
+    }
+
+    public List getListIndexed() {
+        return (listIndexed);
+    }
+
+
+    /**
+     * A long property.
+     */
+    private long longProperty = 321;
+
+    public long getLongProperty() {
+        return (this.longProperty);
+    }
+
+    public void setLongProperty(long longProperty) {
+        this.longProperty = longProperty;
+    }
+
+
+    /**
+     * A mapped property with only a getter and setter for a Map.
+     */
+    private Map mapProperty = null;
+
+    public Map getMapProperty() {
+        // Create the map the very first time
+        if (mapProperty == null) {
+            mapProperty = new HashMap();
+            mapProperty.put("First Key", "First Value");
+            mapProperty.put("Second Key", "Second Value");
+        }
+        return (mapProperty);
+    }
+
+    public void setMapProperty(Map mapProperty) {
+        // Create the map the very first time
+        if (mapProperty == null) {
+            mapProperty = new HashMap();
+            mapProperty.put("First Key", "First Value");
+            mapProperty.put("Second Key", "Second Value");
+        }
+        this.mapProperty = mapProperty;
+    }
+
+
+    /**
+     * A mapped property that has String keys and Object values.
+     */
+    private HashMap mappedObjects = null;
+
+    public Object getMappedObjects(String key) {
+        // Create the map the very first time
+        if (mappedObjects == null) {
+            mappedObjects = new HashMap();
+            mappedObjects.put("First Key", "First Value");
+            mappedObjects.put("Second Key", "Second Value");
+        }
+        return (mappedObjects.get(key));
+    }
+
+    public void setMappedObjects(String key, Object value) {
+        // Create the map the very first time
+        if (mappedObjects == null) {
+            mappedObjects = new HashMap();
+            mappedObjects.put("First Key", "First Value");
+            mappedObjects.put("Second Key", "Second Value");
+        }
+        mappedObjects.put(key, value);
+    }
+
+
+    /**
+     * A mapped property that has String keys and String values.
+     */
+    private HashMap mappedProperty = null;
+
+    public String getMappedProperty(String key) {
+        // Create the map the very first time
+        if (mappedProperty == null) {
+            mappedProperty = new HashMap();
+            mappedProperty.put("First Key", "First Value");
+            mappedProperty.put("Second Key", "Second Value");
+        }
+        return ((String) mappedProperty.get(key));
+    }
+
+    public void setMappedProperty(String key, String value) {
+        // Create the map the very first time
+        if (mappedProperty == null) {
+            mappedProperty = new HashMap();
+            mappedProperty.put("First Key", "First Value");
+            mappedProperty.put("Second Key", "Second Value");
+        }
+        mappedProperty.put(key, value);
+    }
+
+
+    /**
+     * A mapped property that has String keys and int values.
+     */
+    private HashMap mappedIntProperty = null;
+
+    public int getMappedIntProperty(String key) {
+        // Create the map the very first time
+        if (mappedProperty == null) {
+            mappedProperty = new HashMap();
+            mappedProperty.put("One", new Integer(1));
+            mappedProperty.put("Two", new Integer(2));
+        }
+        Integer x = (Integer) mappedIntProperty.get(key);
+        return ((x == null) ? 0 : x.intValue());
+    }
+
+    public void setMappedIntProperty(String key, int value) {
+        mappedIntProperty.put(key, new Integer(value));
+    }
+
+
+    /**
+     * A nested reference to another test bean (populated as needed).
+     */
+    private TestBean nested = null;
+
+    public TestBean getNested() {
+        if (nested == null)
+            nested = new TestBean();
+        return (nested);
+    }
+
+   /**
+    * Another nested reference to another test bean,
+    */
+   private TestBean anotherNested = null;
+    
+   public TestBean getAnotherNested() {
+      return anotherNested;
+   }
+    
+   public void setAnotherNested( TestBean anotherNested ) {
+      this.anotherNested = anotherNested;
+   }
+   
+    /*
+     * Another nested reference to a bean containing mapp properties
+     */
+    class MappedTestBean {
+        public void setValue(String key,String val) { }
+        public String getValue(String key) { return "Mapped Value"; }
+    }
+
+    private MappedTestBean mappedNested = null;
+
+    public MappedTestBean getMappedNested() {
+        if (mappedNested == null)
+        {
+            mappedNested = new MappedTestBean();
+        }
+        return mappedNested;
+    }
+
+    /**
+     * A String property with an initial value of null.
+     */
+    private String nullProperty = null;
+
+    public String getNullProperty() {
+        return (this.nullProperty);
+    }
+
+    public void setNullProperty(String nullProperty) {
+        this.nullProperty = nullProperty;
+    }
+
+
+    /**
+     * A read-only String property.
+     */
+    private String readOnlyProperty = "Read Only String Property";
+
+    public String getReadOnlyProperty() {
+        return (this.readOnlyProperty);
+    }
+
+
+    /**
+     * A short property.
+     */
+    private short shortProperty = (short) 987;
+
+    public short getShortProperty() {
+        return (this.shortProperty);
+    }
+
+    public void setShortProperty(short shortProperty) {
+        this.shortProperty = shortProperty;
+    }
+
+
+    /**
+     * A String array property accessed as a String.
+     */
+    private String stringArray[] =
+            { "String 0", "String 1", "String 2", "String 3", "String 4" };
+
+    public String[] getStringArray() {
+        return (this.stringArray);
+    }
+
+    public void setStringArray(String stringArray[]) {
+        this.stringArray = stringArray;
+    }
+
+
+    /**
+     * A String array property accessed as an indexed property.
+     */
+    private String stringIndexed[] =
+            { "String 0", "String 1", "String 2", "String 3", "String 4" };
+
+    public String getStringIndexed(int index) {
+        return (stringIndexed[index]);
+    }
+
+    public void setStringIndexed(int index, String value) {
+        stringIndexed[index] = value;
+    }
+
+
+    /**
+     * A String property.
+     */
+    private String stringProperty = "This is a string";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+    /**
+     * A write-only String property.
+     */
+    private String writeOnlyProperty = "Write Only String Property";
+
+    public String getWriteOnlyPropertyValue() {
+        return (this.writeOnlyProperty);
+    }
+
+    public void setWriteOnlyProperty(String writeOnlyProperty) {
+        this.writeOnlyProperty = writeOnlyProperty;
+    }
+
+
+    // ------------------------------------------------------ Invalid Properties
+
+
+    /**
+     * <p>An invalid property that has two boolean getters (getInvalidBoolean
+     * and isInvalidBoolean) plus a String setter (setInvalidBoolean).  By the
+     * rules described in the JavaBeans Specification, this will be considered
+     * a read-only boolean property, using isInvalidBoolean() as the getter.</p>
+     */
+    private boolean invalidBoolean = false;
+
+    public boolean getInvalidBoolean() {
+	return (this.invalidBoolean);
+    }
+
+    public boolean isInvalidBoolean() {
+	return (this.invalidBoolean);
+    }
+
+    public void setInvalidBoolean(String invalidBoolean) {
+	if ("true".equalsIgnoreCase(invalidBoolean) ||
+	    "yes".equalsIgnoreCase(invalidBoolean) ||
+	    "1".equalsIgnoreCase(invalidBoolean)) {
+	    this.invalidBoolean = true;
+	} else {
+	    this.invalidBoolean = false;
+	}
+    }
+
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * A static variable that is accessed and updated via static methods
+     * for MethodUtils testing.
+     */
+    private static int counter = 0;
+
+
+    /**
+     * Return the current value of the counter.
+     */
+    public static int currentCounter() {
+
+        return (counter);
+
+    }
+
+
+    /**
+     * Increment the current value of the counter by 1.
+     */
+    public static void incrementCounter() {
+
+        incrementCounter(1);
+
+    }
+
+
+    /**
+     * Increment the current value of the counter by the specified amount.
+     *
+     * @param amount Amount to be added to the current counter
+     */
+    public static void incrementCounter(int amount) {
+
+        counter += amount;
+
+    }
+
+
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBean.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBeanMap.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBeanMap.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/src/test/org/apache/commons/beanutils/TestBeanMap.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,344 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
+import org.apache.commons.collections.map.AbstractTestMap;
+import org.apache.commons.collections.BulkTest;
+
+/**
+ * Test cases for BeanMap
+ * 
+ * @version $Revision: 1.1 $ $Date: 2004/05/11 22:46:26 $
+ * 
+ * @author Morgan Delagrange
+ * @author Stephen Colebourne
+ */
+public class TestBeanMap extends AbstractTestMap {
+
+    public TestBeanMap(String testName) {
+        super(testName);
+    }
+    
+    public static void main(String[] args) {
+        TestRunner.run(suite());
+    }
+
+    public static Test suite() {
+        return BulkTest.makeSuite(TestBeanMap.class);
+    }
+
+/*
+  note to self.  The getter and setter methods were generated by copying the
+  field declarations and using the following regular expression search and
+  replace:
+
+  From:
+        private \(.*\) some\(.*\);
+  To:
+        public \1 getSome\2Value() {
+            return some\2;
+        }
+        public void setSome\2Value(\1 value) {
+            some\2 = value;
+        } 
+
+  Also note:  The sample keys and mappings were generated manually.
+*/
+
+
+    public static class BeanWithProperties implements Serializable {
+        private int someInt;
+        private long someLong;
+        private double someDouble;
+        private float someFloat;
+        private short someShort;
+        private byte someByte;
+        private char someChar;
+        private Integer someInteger;
+        private String someString;
+        private Object someObject;
+
+        public int getSomeIntValue() {
+            return someInt;
+        }
+        public void setSomeIntValue(int value) {
+            someInt = value;
+        }
+
+        public long getSomeLongValue() {
+            return someLong;
+        }
+        public void setSomeLongValue(long value) {
+            someLong = value;
+        }
+
+        public double getSomeDoubleValue() {
+            return someDouble;
+        }
+        public void setSomeDoubleValue(double value) {
+            someDouble = value;
+        }
+
+        public float getSomeFloatValue() {
+            return someFloat;
+        }
+        public void setSomeFloatValue(float value) {
+            someFloat = value;
+        }
+
+        public short getSomeShortValue() {
+            return someShort;
+        }
+        public void setSomeShortValue(short value) {
+            someShort = value;
+        }
+
+        public byte getSomeByteValue() {
+            return someByte;
+        }
+        public void setSomeByteValue(byte value) {
+            someByte = value;
+        }
+
+        public char getSomeCharValue() {
+            return someChar;
+        }
+        public void setSomeCharValue(char value) {
+            someChar = value;
+        }
+
+        public String getSomeStringValue() {
+            return someString;
+        }
+        public void setSomeStringValue(String value) {
+            someString = value;
+        }
+
+        public Integer getSomeIntegerValue() {
+            return someInteger;
+        }
+        public void setSomeIntegerValue(Integer value) {
+            someInteger = value;
+        }
+
+        public Object getSomeObjectValue() {
+            return someObject;
+        }
+        public void setSomeObjectValue(Object value) {
+            someObject = value;
+        }
+    }
+    
+    // note to self.  The Sample keys were generated by copying the field
+    // declarations and using the following regular expression search and replace:
+    //
+    // From:
+    //    private \(.*\) some\(.*\);
+    // To:
+    //    "some\2Value",
+    //
+    // Then, I manually added the "class" key, which is a property that exists for
+    // all beans (and all objects for that matter.
+    public Object[] getSampleKeys() {
+        Object[] keys = new Object[] {
+            "someIntValue",
+            "someLongValue",
+            "someDoubleValue",
+            "someFloatValue",
+            "someShortValue",
+            "someByteValue",
+            "someCharValue",
+            "someIntegerValue",
+            "someStringValue",
+            "someObjectValue",
+            "class",
+        };
+        return keys;
+    }
+
+    /**
+     *  An object value that will be stored in the bean map as a value.  Need
+     *  to save this externally so that we can make sure the object instances
+     *  are equivalent since getSampleValues() would otherwise construct a new
+     *  and different Object each time.
+     **/
+    private Object objectInFullMap = new Object();
+
+    // note to self: the sample values were created manually
+    public Object[] getSampleValues() {
+        Object[] values = new Object[] {
+            new Integer(1234),
+            new Long(1298341928234L),
+            new Double(123423.34),
+            new Float(1213332.12f),
+            new Short((short)134),
+            new Byte((byte)10),
+            new Character('a'),
+            new Integer(1432),
+            "SomeStringValue",
+            objectInFullMap,
+            BeanWithProperties.class,
+        };
+        return values;
+    }
+
+    public Object[] getNewSampleValues() {
+        Object[] values = new Object[] {
+            new Integer(223),
+            new Long(23341928234L),
+            new Double(23423.34),
+            new Float(213332.12f),
+            new Short((short)234),
+            new Byte((byte)20),
+            new Character('b'),
+            new Integer(232),
+            "SomeNewStringValue",
+            new Object(),
+            null,
+        };
+        return values;
+    }
+
+    /**
+     * Values is a dead copy in BeanMap, so refresh each time.
+     */
+    public void verifyValues() {
+        values = map.values();
+        super.verifyValues();
+    }
+
+    /**
+     * The mappings in a BeanMap are fixed on the properties the underlying
+     * bean has.  Adding and removing mappings is not possible, thus this
+     * method is overridden to return false.
+     */
+    public boolean isPutAddSupported() {
+        return false;
+    }
+
+    /**
+     * The mappings in a BeanMap are fixed on the properties the underlying
+     * bean has.  Adding and removing mappings is not possible, thus this
+     * method is overridden to return false.
+     */
+    public boolean isRemoveSupported() {
+        return false;
+    }
+
+    public Map makeFullMap() {
+        // note: These values must match (i.e. .equals() must return true)
+        // those returned from getSampleValues().
+        BeanWithProperties bean = new BeanWithProperties();
+        bean.setSomeIntValue(1234);
+        bean.setSomeLongValue(1298341928234L);
+        bean.setSomeDoubleValue(123423.34);
+        bean.setSomeFloatValue(1213332.12f);
+        bean.setSomeShortValue((short)134);
+        bean.setSomeByteValue((byte)10);
+        bean.setSomeCharValue('a');
+        bean.setSomeIntegerValue(new Integer(1432));
+        bean.setSomeStringValue("SomeStringValue");
+        bean.setSomeObjectValue(objectInFullMap);
+        return new BeanMap(bean);
+    }
+
+    public Map makeEmptyMap() {
+        return new BeanMap();
+    }
+
+    public String[] ignoredTests() {
+        // Ignore the serialization tests on collection views.
+        return new String[] {
+         "TestBeanMap.bulkTestMapEntrySet.testCanonicalEmptyCollectionExists",
+         "TestBeanMap.bulkTestMapEntrySet.testCanonicalFullCollectionExists",
+         "TestBeanMap.bulkTestMapKeySet.testCanonicalEmptyCollectionExists",
+         "TestBeanMap.bulkTestMapKeySet.testCanonicalFullCollectionExists",
+         "TestBeanMap.bulkTestMapValues.testCanonicalEmptyCollectionExists",
+         "TestBeanMap.bulkTestMapValues.testCanonicalFullCollectionExists",
+         "TestBeanMap.bulkTestMapEntrySet.testSimpleSerialization",
+         "TestBeanMap.bulkTestMapKeySet.testSimpleSerialization",
+         "TestBeanMap.bulkTestMapEntrySet.testSerializeDeserializeThenCompare",
+         "TestBeanMap.bulkTestMapKeySet.testSerializeDeserializeThenCompare"
+        };
+    }
+
+    /**
+     * Need to override this method because the "clear()" method on the bean
+     * map just returns the bean properties to their default states.  It does
+     * not actually remove the mappings as per the map contract.  The default
+     * testClear() methods checks that the clear method throws an
+     * UnsupportedOperationException since this class is not add/remove
+     * modifiable.  In our case though, we do not always throw that exception.
+     */
+    public void testMapClear() {
+        //TODO: make sure a call to BeanMap.clear returns the bean to its
+        //default initialization values.
+    }
+
+    /**
+     * Need to override this method because the "put()" method on the bean
+     * doesn't work for this type of Map.
+     */
+    public void testMapPut() {
+        // see testBeanMapPutAllWriteable
+    }
+
+    public void testBeanMapClone() {
+        BeanMap map = (BeanMap)makeFullMap();
+        try {
+            BeanMap map2 = (BeanMap)((BeanMap)map).clone();
+
+            // make sure containsKey is working to verify the bean was cloned
+            // ok, and the read methods were properly initialized
+            Object[] keys = getSampleKeys();
+            for(int i = 0; i < keys.length; i++) {
+                assertTrue("Cloned BeanMap should contain the same keys",
+                           map2.containsKey(keys[i]));
+            }
+        } catch (CloneNotSupportedException exception) {
+            fail("BeanMap.clone() should not throw a " +
+                 "CloneNotSupportedException when clone should succeed.");
+        }
+    }
+
+    public void testBeanMapPutAllWriteable() {
+        BeanMap map1 = (BeanMap)makeFullMap();
+        BeanMap map2 = (BeanMap)makeFullMap();
+        map2.put("someIntValue", new Integer(0));
+        map1.putAllWriteable(map2);
+        assertEquals(map1.get("someIntValue"), new Integer(0));
+    }
+
+    public void testMethodAccessor() throws Exception {
+        BeanMap map = (BeanMap) makeFullMap();
+        Method method = BeanWithProperties.class.getDeclaredMethod("getSomeIntegerValue", null);
+        assertEquals(method, map.getReadMethod("someIntegerValue"));
+    }
+    
+    public void testMethodMutator() throws Exception {
+        BeanMap map = (BeanMap) makeFullMap();
+        Method method = BeanWithProperties.class.getDeclaredMethod("setSomeIntegerValue", new Class[] {Integer.class});
+        assertEquals(method, map.getWriteMethod("someIntegerValue"));
+    }
+    
+}

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/index.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/index.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/index.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<document>
+
+ <properties>
+  <title>Commons</title>
+  <author email="commons-dev at jakarta.apache.org">Commons Documentation Team</author>
+ </properties>
+
+ <body>
+
+<section name="Commons BeanUtils Bean Collections">
+
+<p>
+Dealing with collections of beans is a common feature of development in Java.
+A lot of time is spent creating bean-specific implementations 
+for standard collection manipulators such as functors and comparators.
+</p>
+
+<p>
+<code>BeanUtils Bean collections</code> is a library intended to 
+improve developer productivity by using sophisticated bean introspection 
+(from <code>BeanUtils</code>) 
+to allow general library classes to be used (rather than creating bean specific
+implementation classes).
+</p>
+
+<p>
+But won't this be slower? Yes, reflection is slower than direct references
+but in real life applications, this is typically insignificant. So why not use 
+these classes to speed development and then substitute faster implementations only
+where the profiler indicates there is a problem :) 
+</p>
+    <subsection name='Quick-Quick Guide To Functors'>
+        <p>
+Many of the classes in <code>bean-collections</code> are functor implementations
+specialized for bean properties. This is a very quick guide (aimed to let java developer
+know why functors make for elegant code).
+        </p>
+        <p>
+The word <code>functor</code> is mathematical in origin but comes into object oriented
+development from functional and logic coding. In Java terms, a functor 
+is a function that is encapsulated as an object (and so can be manipulated as an object).
+This allows elegant, concise and powerful techniques to be used. For example, 
+<a href='http://jakarta.apache.org/commons/collections'>Commons Collections</a>
+contains utilities that allow functions (as functors) to be easily applied to 
+Collections.
+        </p>
+        <p>
+This is actually pretty useful when it comes to collections of beans. It's a common 
+problem to want to extract information from a collection of beans or to change all properties
+to a particular value. Functors can be a particularly elegant way to do this. So try them!
+You might just like them!
+        </p>
+        <p>
+For more information about functors, please read the introduction to the
+<a href='http://jakarta.apache.org/commons/sandbox/functor/'>Commons Functor component</a>.
+        </p>
+    </subsection>
+</section>
+<section name='Releases'>
+        <p>
+BeanUtils Bean-Collections is distributed as an optional jar within the main 
+beanutils distribution. For details, see the 
+<a href='http://jakarta.apache.org/commons/beanutils/index.html'>main BeanUtils website</a>
+        </p>
+</section>
+
+</body>
+</document>

Added: trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/navigation.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/navigation.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/optional/bean-collections/xdocs/navigation.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE org.apache.commons.menus SYSTEM '../../../../commons-build/menus/menus.dtd'>
+<project name="BeanUtils Bean Collections">
+
+  <title>BeanUtils Bean Collections</title>
+  <organizationLogo href="/images/jakarta-logo-blue.gif">
+   Jakarta
+  </organizationLogo>
+
+  <body>
+    <links>
+      <item name="BeanUtils Core"                   
+            href="http://jakarta.apache.org/commons/beanutils"/>
+      <item name="Jakarta Commons"                   
+            href="http://jakarta.apache.org/commons/"/>
+    </links>
+
+    <menu name="Commons BeanUtils Bean Collections">
+      <item name="Overview" href="/index.html"/>
+    </menu>
+    
+    &common-menus;
+
+  </body>
+</project>

Added: trunk/commons-beanutils/branches/upstream/current/project.properties
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/project.properties	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/project.properties	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,23 @@
+#   Copyright 2001-2004 The Apache Software Foundation
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+# documentation properties
+maven.xdoc.jsl=../commons-build/commons-site.jsl
+maven.xdoc.date=left
+maven.xdoc.version=${pom.currentVersion}
+maven.xdoc.developmentProcessUrl=http://jakarta.apache.org/commons/charter.html
+maven.xdoc.poweredby.image=maven-feather.png
+
+
+beanutils.cvs=pserver:anoncvs at cvs.apache.org:/home/cvspublic
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/project.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/project.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/project.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project>
+  <pomVersion>3</pomVersion>
+  <id>commons-beanutils</id>
+  <name>BeanUtils</name>
+  <currentVersion>1.7</currentVersion>
+  <inceptionYear>2000</inceptionYear>
+  <shortDescription>Commons BeanUtils</shortDescription>
+  <description>BeanUtils provides an easy-to-use but flexible wrapper around reflection and introspection.</description>
+  <logo>/images/logo.png</logo>
+  
+  <package>org.apache.commons.beanutils.*</package>
+  <url>http://jakarta.apache.org/commons/beanutils/index.html</url>
+
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://jakarta.apache.org</url>
+    <logo>http://jakarta.apache.org/images/original-jakarta-logo.gif</logo>
+  </organization>
+  
+  <licenses>
+	<license>
+    	<name>The Apache Software License, Version 2.0</name>
+    	<url>/LICENSE.txt</url>
+    	<distribution>repo</distribution>
+	</license>
+  </licenses>
+  
+  <gumpRepositoryId>jakarta</gumpRepositoryId>
+  <issueTrackingUrl>http://issues.apache.org/bugzilla/</issueTrackingUrl>
+  <siteAddress>jakarta.apache.org</siteAddress>
+  <siteDirectory>/www/jakarta.apache.org/commons/${pom.artifactId.substring(8)}/</siteDirectory>
+  <distributionDirectory>/www/jakarta.apache.org/builds/jakarta-commons/${pom.artifactId.substring(8)}/</distributionDirectory>
+  
+  <repository>
+    <connection>scm:cvs:pserver:anoncvs at cvs.apache.org:/home/cvspublic:jakarta-commons/${pom.artifactId.substring(8)}</connection>
+    <url>http://cvs.apache.org/viewcvs/jakarta-commons/${pom.artifactId.substring(8)}/</url>
+  </repository>
+  
+  <mailingLists>
+    <mailingList>
+      <name>Commons Dev List</name>
+      <subscribe>commons-dev-subscribe at jakarta.apache.org</subscribe>
+      <unsubscribe>commons-dev-unsubscribe at jakarta.apache.org</unsubscribe>
+      <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+    </mailingList>
+    <mailingList>
+      <name>Commons User List</name>
+      <subscribe>commons-user-subscribe at jakarta.apache.org</subscribe>
+      <unsubscribe>commons-user-unsubscribe at jakarta.apache.org</unsubscribe>
+      <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+    </mailingList>
+  </mailingLists>
+   
+  <developers>
+    <developer>
+      <name>Robert Burrell Donkin</name>
+      <id>rdonkin</id>
+      <email>rdonkin at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>dIon Gillard</name>
+      <id>dion</id>
+      <email>dion at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>Craig McClanahan</name>
+      <id>craigmcc</id>
+      <email>craigmcc at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>Geir Magnusson Jr.</name>
+      <id>geirm</id>
+      <email>geirm at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>Scott Sanders</name>
+      <id>sanders</id>
+      <email>sanders at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>James Strachan</name>
+      <id>jstrachan</id>
+      <email>jstrachan at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>Rodney Waldhoff</name>
+      <id>rwaldhoff</id>
+      <email>rwaldhoff at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>Martin van den Bemt</name>
+      <id>mvdb</id>
+      <email>mvdb at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <name>Yoav Shapira</name>
+      <id>yoavs</id>
+      <email>yoavs at apache.org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+  </developers>
+
+  <contributors>
+    <contributor>
+      <name>Paul Jack</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Stephen Colebourne</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Berin Loritsch</name>
+      <email></email>
+    </contributor>    
+  </contributors>
+  
+  <dependencies>
+    <dependency>
+      <id>commons-logging</id>
+      <version>1.0.3</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    	<nagEmailAddress>commons-dev at jakarta.apache.org</nagEmailAddress>
+    	<sourceDirectory>src/java</sourceDirectory>
+    	<unitTestSourceDirectory>src/test</unitTestSourceDirectory>
+    	<integrationUnitTestSourceDirectory/>
+    	<aspectSourceDirectory/>
+
+    	<!-- Unit test classes -->
+    	<unitTest>
+	      	<includes>
+	        	<include>**/*TestCase.java</include>
+            </includes>
+            <resources>
+                <resource>
+                    <directory>${pom.build.unitTestSourceDirectory}</directory>
+                    <includes>
+                        <include>**/*.xml</include>
+                    </includes>
+                </resource>
+            </resources>
+   		</unitTest>
+
+    	<!-- Integration unit test classes -->
+    	<integrationUnitTestPatterns></integrationUnitTestPatterns>
+    
+    	<resources>
+      		<includes>
+       			<include>**/*.properties</include>
+      		</includes>
+    	</resources>
+    	<jars/>
+  	</build>
+
+  <reports>
+  	<report>maven-changelog-plugin</report>
+   	<report>maven-changes-plugin</report>
+    <report>maven-developer-activity-plugin</report>
+    <report>maven-file-activity-plugin</report>
+    <report>maven-javadoc-plugin</report>
+    <report>maven-jdepend-plugin</report>
+    <report>maven-junit-report-plugin</report>
+    <report>maven-jxr-plugin</report>
+    <report>maven-license-plugin</report>
+    <report>maven-tasklist-plugin</report>
+  </reports>
+</project>

Added: trunk/commons-beanutils/branches/upstream/current/src/conf/MANIFEST.MF
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/conf/MANIFEST.MF	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/conf/MANIFEST.MF	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,7 @@
+Extension-Name: org.apache.commons.beanutils
+Specification-Title: Jakarta Commons Beanutils
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 1.6
+Implementation-Title: org.apache.commons.beanutils
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: 1.6

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>Minimal implementation of the <code>DynaBean</code> interface.  Can be
+ * used as a convenience base class for more sophisticated implementations.</p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - Instances of this class that are
+ * accessed from multiple threads simultaneously need to be synchronized.</p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - Instances of this class can be
+ * successfully serialized and deserialized <strong>ONLY</strong> if all
+ * property values are <code>Serializable</code>.</p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 1.11 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public class BasicDynaBean implements DynaBean, Serializable {
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new <code>DynaBean</code> associated with the specified
+     * <code>DynaClass</code> instance.
+     *
+     * @param dynaClass The DynaClass we are associated with
+     */
+    public BasicDynaBean(DynaClass dynaClass) {
+
+        super();
+        this.dynaClass = dynaClass;
+
+    }
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    /**
+     * The <code>DynaClass</code> "base class" that this DynaBean
+     * is associated with.
+     */
+    protected DynaClass dynaClass = null;
+
+
+    /**
+     * The set of property values for this DynaBean, keyed by property name.
+     */
+    protected HashMap values = new HashMap();
+
+
+    // ------------------------------------------------------ DynaBean Methods
+
+
+    /**
+     * Does the specified mapped property contain a value for the specified
+     * key value?
+     *
+     * @param name Name of the property to check
+     * @param key Name of the key to check
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public boolean contains(String name, String key) {
+
+        Object value = values.get(name);
+        if (value == null) {
+            throw new NullPointerException
+                    ("No mapped value for '" + name + "(" + key + ")'");
+        } else if (value instanceof Map) {
+            return (((Map) value).containsKey(key));
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-mapped property for '" + name + "(" + key + ")'");
+        }
+
+    }
+
+
+    /**
+     * Return the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public Object get(String name) {
+
+        // Return any non-null value for the specified property
+        Object value = values.get(name);
+        if (value != null) {
+            return (value);
+        }
+
+        // Return a null value for a non-primitive property
+        Class type = getDynaProperty(name).getType();
+        if (!type.isPrimitive()) {
+            return (value);
+        }
+
+        // Manufacture default values for primitive properties
+        if (type == Boolean.TYPE) {
+            return (Boolean.FALSE);
+        } else if (type == Byte.TYPE) {
+            return (new Byte((byte) 0));
+        } else if (type == Character.TYPE) {
+            return (new Character((char) 0));
+        } else if (type == Double.TYPE) {
+            return (new Double((double) 0.0));
+        } else if (type == Float.TYPE) {
+            return (new Float((float) 0.0));
+        } else if (type == Integer.TYPE) {
+            return (new Integer((int) 0));
+        } else if (type == Long.TYPE) {
+            return (new Long((int) 0));
+        } else if (type == Short.TYPE) {
+            return (new Short((short) 0));
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param index Index of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     * @exception NullPointerException if no array or List has been
+     *  initialized for this property
+     */
+    public Object get(String name, int index) {
+
+        Object value = values.get(name);
+        if (value == null) {
+            throw new NullPointerException
+                    ("No indexed value for '" + name + "[" + index + "]'");
+        } else if (value.getClass().isArray()) {
+            return (Array.get(value, index));
+        } else if (value instanceof List) {
+            return ((List) value).get(index);
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-indexed property for '" + name + "[" + index + "]'");
+        }
+
+    }
+
+
+    /**
+     * Return the value of a mapped property with the specified name,
+     * or <code>null</code> if there is no value for the specified key.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param key Key of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public Object get(String name, String key) {
+
+        Object value = values.get(name);
+        if (value == null) {
+            throw new NullPointerException
+                    ("No mapped value for '" + name + "(" + key + ")'");
+        } else if (value instanceof Map) {
+            return (((Map) value).get(key));
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-mapped property for '" + name + "(" + key + ")'");
+        }
+
+    }
+
+
+    /**
+     * Return the <code>DynaClass</code> instance that describes the set of
+     * properties available for this DynaBean.
+     */
+    public DynaClass getDynaClass() {
+
+        return (this.dynaClass);
+
+    }
+
+
+    /**
+     * Remove any existing value for the specified key on the
+     * specified mapped property.
+     *
+     * @param name Name of the property for which a value is to
+     *  be removed
+     * @param key Key of the value to be removed
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public void remove(String name, String key) {
+
+        Object value = values.get(name);
+        if (value == null) {
+            throw new NullPointerException
+                    ("No mapped value for '" + name + "(" + key + ")'");
+        } else if (value instanceof Map) {
+            ((Map) value).remove(key);
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-mapped property for '" + name + "(" + key + ")'");
+        }
+
+    }
+
+
+    /**
+     * Set the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception NullPointerException if an attempt is made to set a
+     *  primitive property to null
+     */
+    public void set(String name, Object value) {
+
+        DynaProperty descriptor = getDynaProperty(name);
+        if (value == null) {
+            if (descriptor.getType().isPrimitive()) {
+                throw new NullPointerException
+                        ("Primitive value for '" + name + "'");
+            }
+        } else if (!isAssignable(descriptor.getType(), value.getClass())) {
+            throw new ConversionException
+                    ("Cannot assign value of type '" +
+                    value.getClass().getName() +
+                    "' to property '" + name + "' of type '" +
+                    descriptor.getType().getName() + "'");
+        }
+        values.put(name, value);
+
+    }
+
+
+    /**
+     * Set the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param index Index of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     */
+    public void set(String name, int index, Object value) {
+
+        Object prop = values.get(name);
+        if (prop == null) {
+            throw new NullPointerException
+                    ("No indexed value for '" + name + "[" + index + "]'");
+        } else if (prop.getClass().isArray()) {
+            Array.set(prop, index, value);
+        } else if (prop instanceof List) {
+            try {
+                ((List) prop).set(index, value);
+            } catch (ClassCastException e) {
+                throw new ConversionException(e.getMessage());
+            }
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-indexed property for '" + name + "[" + index + "]'");
+        }
+
+    }
+
+
+    /**
+     * Set the value of a mapped property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param key Key of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public void set(String name, String key, Object value) {
+
+        Object prop = values.get(name);
+        if (prop == null) {
+            throw new NullPointerException
+                    ("No mapped value for '" + name + "(" + key + ")'");
+        } else if (prop instanceof Map) {
+            ((Map) prop).put(key, value);
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-mapped property for '" + name + "(" + key + ")'");
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the property descriptor for the specified property name.
+     *
+     * @param name Name of the property for which to retrieve the descriptor
+     *
+     * @exception IllegalArgumentException if this is not a valid property
+     *  name for our DynaClass
+     */
+    protected DynaProperty getDynaProperty(String name) {
+
+        DynaProperty descriptor = getDynaClass().getDynaProperty(name);
+        if (descriptor == null) {
+            throw new IllegalArgumentException
+                    ("Invalid property name '" + name + "'");
+        }
+        return (descriptor);
+
+    }
+
+
+    /**
+     * Is an object of the source class assignable to the destination class?
+     *
+     * @param dest Destination class
+     * @param source Source class
+     */
+    protected boolean isAssignable(Class dest, Class source) {
+
+        if (dest.isAssignableFrom(source) ||
+                ((dest == Boolean.TYPE) && (source == Boolean.class)) ||
+                ((dest == Byte.TYPE) && (source == Byte.class)) ||
+                ((dest == Character.TYPE) && (source == Character.class)) ||
+                ((dest == Double.TYPE) && (source == Double.class)) ||
+                ((dest == Float.TYPE) && (source == Float.class)) ||
+                ((dest == Integer.TYPE) && (source == Integer.class)) ||
+                ((dest == Long.TYPE) && (source == Long.class)) ||
+                ((dest == Short.TYPE) && (source == Short.class))) {
+            return (true);
+        } else {
+            return (false);
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BasicDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+
+
+/**
+ * <p>Minimal implementation of the <code>DynaClass</code> interface.  Can be
+ * used as a convenience base class for more sophisticated implementations.</p> *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - The <code>DynaBean</code>
+ * implementation class supplied to our constructor MUST have a one-argument
+ * constructor of its own that accepts a <code>DynaClass</code>.  This is
+ * used to associate the DynaBean instance with this DynaClass.</p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 1.11 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public class BasicDynaClass implements DynaClass, Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new BasicDynaClass with default parameters.
+     */
+    public BasicDynaClass() {
+
+        this(null, null, null);
+
+    }
+
+
+    /**
+     * Construct a new BasicDynaClass with the specified parameters.
+     *
+     * @param name Name of this DynaBean class
+     * @param dynaBeanClass The implementation class for new instances
+     */
+    public BasicDynaClass(String name, Class dynaBeanClass) {
+
+        this(name, dynaBeanClass, null);
+
+    }
+
+
+    /**
+     * Construct a new BasicDynaClass with the specified parameters.
+     *
+     * @param name Name of this DynaBean class
+     * @param dynaBeanClass The implementation class for new intances
+     * @param properties Property descriptors for the supported properties
+     */
+    public BasicDynaClass(String name, Class dynaBeanClass,
+                          DynaProperty properties[]) {
+
+        super();
+        if (name != null)
+            this.name = name;
+        if (dynaBeanClass == null)
+            dynaBeanClass = BasicDynaBean.class;
+        setDynaBeanClass(dynaBeanClass);
+        if (properties != null)
+            setProperties(properties);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The constructor of the <code>dynaBeanClass</code> that we will use
+     * for creating new instances.
+     */
+    protected transient Constructor constructor = null;
+
+
+    /**
+     * The method signature of the constructor we will use to create
+     * new DynaBean instances.
+     */
+    protected static Class constructorTypes[] = { DynaClass.class };
+
+
+    /**
+     * The argument values to be passed to the constructore we will use
+     * to create new DynaBean instances.
+     */
+    protected Object constructorValues[] = { this };
+
+
+    /**
+     * The <code>DynaBean</code> implementation class we will use for
+     * creating new instances.
+     */
+    protected Class dynaBeanClass = BasicDynaBean.class;
+
+
+    /**
+     * The "name" of this DynaBean class.
+     */
+    protected String name = this.getClass().getName();
+
+
+    /**
+     * The set of dynamic properties that are part of this DynaClass.
+     */
+    protected DynaProperty properties[] = new DynaProperty[0];
+
+
+    /**
+     * The set of dynamic properties that are part of this DynaClass,
+     * keyed by the property name.  Individual descriptor instances will
+     * be the same instances as those in the <code>properties</code> list.
+     */
+    protected HashMap propertiesMap = new HashMap();
+
+
+    // ------------------------------------------------------ DynaClass Methods
+
+
+    /**
+     * Return the name of this DynaClass (analogous to the
+     * <code>getName()</code> method of <code>java.lang.Class</code), which
+     * allows the same <code>DynaClass</code> implementation class to support
+     * different dynamic classes, with different sets of properties.
+     */
+    public String getName() {
+
+        return (this.name);
+
+    }
+
+
+    /**
+     * Return a property descriptor for the specified property, if it exists;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the dynamic property for which a descriptor
+     *  is requested
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public DynaProperty getDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException
+                    ("No property name specified");
+        }
+        return ((DynaProperty) propertiesMap.get(name));
+
+    }
+
+
+    /**
+     * <p>Return an array of <code>ProperyDescriptors</code> for the properties
+     * currently defined in this DynaClass.  If no properties are defined, a
+     * zero-length array will be returned.</p>
+     *
+     * <p><strong>FIXME</strong> - Should we really be implementing
+     * <code>getBeanInfo()</code> instead, which returns property descriptors
+     * and a bunch of other stuff?</p>
+     */
+    public DynaProperty[] getDynaProperties() {
+
+        return (properties);
+
+    }
+
+
+    /**
+     * Instantiate and return a new DynaBean instance, associated
+     * with this DynaClass.
+     *
+     * @exception IllegalAccessException if the Class or the appropriate
+     *  constructor is not accessible
+     * @exception InstantiationException if this Class represents an abstract
+     *  class, an array class, a primitive type, or void; or if instantiation
+     *  fails for some other reason
+     */
+    public DynaBean newInstance()
+            throws IllegalAccessException, InstantiationException {
+
+        try {
+            // Refind the constructor after a deserialization (if needed)
+            if (constructor == null) {
+                setDynaBeanClass(this.dynaBeanClass);
+            }
+            // Invoke the constructor to create a new bean instance
+            return ((DynaBean) constructor.newInstance(constructorValues));
+        } catch (InvocationTargetException e) {
+            throw new InstantiationException
+                    (e.getTargetException().getMessage());
+        }
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the Class object we will use to create new instances in the
+     * <code>newInstance()</code> method.  This Class <strong>MUST</strong>
+     * implement the <code>DynaBean</code> interface.
+     */
+    public Class getDynaBeanClass() {
+
+        return (this.dynaBeanClass);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Set the Class object we will use to create new instances in the
+     * <code>newInstance()</code> method.  This Class <strong>MUST</strong>
+     * implement the <code>DynaBean</code> interface.
+     *
+     * @param dynaBeanClass The new Class object
+     *
+     * @exception IllegalArgumentException if the specified Class does not
+     *  implement the <code>DynaBean</code> interface
+     */
+    protected void setDynaBeanClass(Class dynaBeanClass) {
+
+        // Validate the argument type specified
+        if (dynaBeanClass.isInterface())
+            throw new IllegalArgumentException
+                    ("Class " + dynaBeanClass.getName() +
+                    " is an interface, not a class");
+        if (!DynaBean.class.isAssignableFrom(dynaBeanClass))
+            throw new IllegalArgumentException
+                    ("Class " + dynaBeanClass.getName() +
+                    " does not implement DynaBean");
+
+        // Identify the Constructor we will use in newInstance()
+        try {
+            this.constructor = dynaBeanClass.getConstructor(constructorTypes);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException
+                    ("Class " + dynaBeanClass.getName() +
+                    " does not have an appropriate constructor");
+        }
+        this.dynaBeanClass = dynaBeanClass;
+
+    }
+
+
+    /**
+     * Set the list of dynamic properties supported by this DynaClass.
+     *
+     * @param properties List of dynamic properties to be supported
+     */
+    protected void setProperties(DynaProperty properties[]) {
+
+        this.properties = properties;
+        propertiesMap.clear();
+        for (int i = 0; i < properties.length; i++) {
+            propertiesMap.put(properties[i].getName(), properties[i]);
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanAccessLanguageException.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanAccessLanguageException.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanAccessLanguageException.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+/** 
+ * Thrown to indicate that the <em>Bean Access Language</em> cannot execute query
+ * against given bean. This is a runtime exception and access langauges are encouraged
+ * to subclass to create custom exceptions whenever appropriate.
+ *
+ * @author Robert Burrell Donkin
+ * @since 1.7
+ */
+
+public class BeanAccessLanguageException extends IllegalArgumentException {
+    
+    // --------------------------------------------------------- Constuctors
+    
+    /** 
+     * Constructs a <code>BeanAccessLanguageException</code> without a detail message.
+     */
+    public BeanAccessLanguageException() {
+        super();
+    }
+    
+    /**
+     * Constructs a <code>BeanAccessLanguageException</code> without a detail message.
+     * 
+     * @param message the detail message explaining this exception
+     */
+    public BeanAccessLanguageException(String message) {
+        super(message);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+
+import org.apache.commons.collections.FastHashMap;
+
+
+/**
+ * <p>Utility methods for populating JavaBeans properties via reflection.</p>
+ *
+ * <p>The implementations are provided by {@link BeanUtilsBean}.
+ * These static utility methods use the default instance.
+ * More sophisticated behaviour can be provided by using a <code>BeanUtilsBean</code> instance.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @version $Revision: 1.40 $ $Date: 2004/02/28 13:18:33 $
+ * @see BeanUtilsBean
+ */
+
+public class BeanUtils {
+
+
+    // ------------------------------------------------------ Private Variables
+
+
+    /**
+     * Dummy collection from the Commons Collections API, to force a
+     * ClassNotFoundException if commons-collections.jar is not present in the
+     * runtime classpath, and this class is the first one referenced.
+     * Otherwise, the ClassNotFoundException thrown by ConvertUtils or
+     * PropertyUtils can get masked.
+     */
+    private static FastHashMap dummy = new FastHashMap();
+
+    /**
+     * The debugging detail level for this component.
+     * @deprecated BeanUtils now uses commons-logging for all log messages.
+     *             Use your favorite logging tool to configure logging for
+     *             this class.
+     */
+    private static int debug = 0;
+
+    /**
+     * @deprecated BeanUtils now uses commons-logging for all log messages.
+     *             Use your favorite logging tool to configure logging for
+     *             this class.
+     */
+    public static int getDebug() {
+        return (debug);
+    }
+
+    /**
+     * @deprecated BeanUtils now uses commons-logging for all log messages.
+     *             Use your favorite logging tool to configure logging for
+     *             this class.
+     */
+    public static void setDebug(int newDebug) {
+        debug = newDebug;
+    }
+
+    // --------------------------------------------------------- Class Methods
+
+
+    /**
+     * <p>Clone a bean based on the available property getters and setters,
+     * even if the bean class itself does not implement Cloneable.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#cloneBean
+     */
+    public static Object cloneBean(Object bean)
+            throws IllegalAccessException, InstantiationException,
+            InvocationTargetException, NoSuchMethodException {
+
+        return BeanUtilsBean.getInstance().cloneBean(bean);
+
+    }
+
+
+    /**
+     * <p>Copy property values from the origin bean to the destination bean
+     * for all cases where the property names are the same.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#copyProperties
+     */
+    public static void copyProperties(Object dest, Object orig)
+        throws IllegalAccessException, InvocationTargetException {
+        
+        BeanUtilsBean.getInstance().copyProperties(dest, orig);
+    }
+
+
+    /**
+     * <p>Copy the specified property value to the specified destination bean,
+     * performing any type conversion that is required.</p>    
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#copyProperty     
+     */
+    public static void copyProperty(Object bean, String name, Object value)
+        throws IllegalAccessException, InvocationTargetException {
+
+        BeanUtilsBean.getInstance().copyProperty(bean, name, value);
+    }
+
+
+    /**
+     * <p>Return the entire set of properties for which the specified bean
+     * provides a read method.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#describe 
+     */
+    public static Map describe(Object bean)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return BeanUtilsBean.getInstance().describe(bean);
+    }
+
+
+    /**
+     * <p>Return the value of the specified array property of the specified
+     * bean, as a String array.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getArrayProperty 
+     */
+    public static String[] getArrayProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return BeanUtilsBean.getInstance().getArrayProperty(bean, name);
+    }
+
+
+    /**
+     * <p>Return the value of the specified indexed property of the specified
+     * bean, as a String.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getIndexedProperty(Object, String)
+     */
+    public static String getIndexedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+        
+        return BeanUtilsBean.getInstance().getIndexedProperty(bean, name);
+
+    }
+
+
+    /**
+     * Return the value of the specified indexed property of the specified
+     * bean, as a String.  The index is specified as a method parameter and
+     * must *not* be included in the property name expression
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getIndexedProperty(Object, String, int)
+     */
+    public static String getIndexedProperty(Object bean,
+                                            String name, int index)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+	return BeanUtilsBean.getInstance().getIndexedProperty(bean, name, index);
+
+    }
+
+
+    /**
+     * </p>Return the value of the specified indexed property of the specified
+     * bean, as a String.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getMappedProperty(Object, String)
+     */
+    public static String getMappedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return BeanUtilsBean.getInstance().getMappedProperty(bean, name);
+
+    }
+
+
+    /**
+     * </p>Return the value of the specified mapped property of the specified
+     * bean, as a String.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getMappedProperty(Object, String, String)
+     */
+    public static String getMappedProperty(Object bean,
+                                           String name, String key)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return BeanUtilsBean.getInstance().getMappedProperty(bean, name, key);
+
+    }
+
+
+    /**
+     * <p>Return the value of the (possibly nested) property of the specified
+     * name, for the specified bean, as a String.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getNestedProperty
+     */
+    public static String getNestedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+	return BeanUtilsBean.getInstance().getNestedProperty(bean, name);
+
+    }
+
+
+    /**
+     * <p>Return the value of the specified property of the specified bean,
+     * no matter which property reference format is used, as a String.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getProperty
+     */
+    public static String getProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return BeanUtilsBean.getInstance().getProperty(bean, name);
+
+    }
+
+
+    /**
+     * <p>Return the value of the specified simple property of the specified
+     * bean, converted to a String.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#getSimpleProperty
+     */
+    public static String getSimpleProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+	return BeanUtilsBean.getInstance().getSimpleProperty(bean, name);
+
+    }
+
+
+    /**
+     * <p>Populate the JavaBeans properties of the specified bean, based on
+     * the specified name/value pairs.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#populate
+     */
+    public static void populate(Object bean, Map properties)
+        throws IllegalAccessException, InvocationTargetException {
+        
+        BeanUtilsBean.getInstance().populate(bean, properties);
+    }
+
+
+    /**
+     * <p>Set the specified property value, performing type conversions as
+     * required to conform to the type of the destination property.</p>
+     *
+     * <p>For more details see <code>BeanUtilsBean</code>.</p>
+     *
+     * @see BeanUtilsBean#setProperty
+     */
+    public static void setProperty(Object bean, String name, Object value)
+        throws IllegalAccessException, InvocationTargetException {
+
+        BeanUtilsBean.getInstance().setProperty(bean, name, value);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtilsBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtilsBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/BeanUtilsBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,1075 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.apache.commons.collections.FastHashMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p>JavaBean property population methods.</p>
+ *
+ * <p>This class provides implementations for the utility methods in
+ * {@link BeanUtils}.
+ * Different instances can be used to isolate caches between classloaders
+ * and to vary the value converters registered.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @version $Revision: 1.16 $ $Date: 2004/02/28 13:18:33 $
+ * @see BeanUtils
+ * @since 1.7
+ */
+
+public class BeanUtilsBean {
+
+
+    // ------------------------------------------------------ Private Class Variables
+
+    /** 
+     * Contains <code>BeanUtilsBean</code> instances indexed by context classloader.
+     */
+    private static final ContextClassLoaderLocal 
+            beansByClassLoader = new ContextClassLoaderLocal() {
+                        // Creates the default instance used when the context classloader is unavailable
+                        protected Object initialValue() {
+                            return new BeanUtilsBean();
+                        }
+                    };
+    
+    /** 
+     * Gets the instance which provides the functionality for {@link BeanUtils}.
+     * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
+     * This mechanism provides isolation for web apps deployed in the same container. 
+     */
+    public synchronized static BeanUtilsBean getInstance() {
+        return (BeanUtilsBean) beansByClassLoader.get();
+    }
+
+    /** 
+     * Sets the instance which provides the functionality for {@link BeanUtils}.
+     * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
+     * This mechanism provides isolation for web apps deployed in the same container. 
+     */
+    public synchronized static void setInstance(BeanUtilsBean newInstance) {
+        beansByClassLoader.set(newInstance);
+    }
+
+    // --------------------------------------------------------- Attributes
+
+    /**
+     * Logging for this instance
+     */
+    private Log log = LogFactory.getLog(BeanUtils.class);
+    
+    /** Used to perform conversions between object types when setting properties */
+    private ConvertUtilsBean convertUtilsBean;
+    
+    /** Used to access properties*/
+    private PropertyUtilsBean propertyUtilsBean;
+
+    // --------------------------------------------------------- Constuctors
+
+    /** 
+     * <p>Constructs an instance using new property 
+     * and conversion instances.</p>
+     */
+    public BeanUtilsBean() {
+        this(new ConvertUtilsBean(), new PropertyUtilsBean());
+    }
+
+    /** 
+     * <p>Constructs an instance using given property and conversion instances.</p>
+     *
+     * @param convertUtilsBean use this <code>ConvertUtilsBean</code> 
+     * to perform conversions from one object to another
+     * @param propertyUtilsBean use this <code>PropertyUtilsBean</code>
+     * to access properties
+     */
+    public BeanUtilsBean(		
+                            ConvertUtilsBean convertUtilsBean, 
+                            PropertyUtilsBean propertyUtilsBean) {
+                            
+        this.convertUtilsBean = convertUtilsBean;
+        this.propertyUtilsBean = propertyUtilsBean;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Clone a bean based on the available property getters and setters,
+     * even if the bean class itself does not implement Cloneable.</p>
+     *
+     * <p>
+     * <strong>Note:</strong> this method creates a <strong>shallow</strong> clone.
+     * In other words, any objects referred to by the bean are shared with the clone
+     * rather than being cloned in turn.
+     * </p>
+     *
+     * @param bean Bean to be cloned
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InstantiationException if a new instance of the bean's
+     *  class cannot be instantiated
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public Object cloneBean(Object bean)
+            throws IllegalAccessException, InstantiationException,
+            InvocationTargetException, NoSuchMethodException {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Cloning bean: " + bean.getClass().getName());
+        }
+        Class clazz = bean.getClass();
+        Object newBean = null;
+        if (bean instanceof DynaBean) {
+            newBean = ((DynaBean) bean).getDynaClass().newInstance();
+        } else {
+            newBean = bean.getClass().newInstance();
+        }
+        getPropertyUtils().copyProperties(newBean, bean);
+        return (newBean);
+
+    }
+
+
+    /**
+     * <p>Copy property values from the origin bean to the destination bean
+     * for all cases where the property names are the same.  For each
+     * property, a conversion is attempted as necessary.  All combinations of
+     * standard JavaBeans and DynaBeans as origin and destination are
+     * supported.  Properties that exist in the origin bean, but do not exist
+     * in the destination bean (or are read-only in the destination bean) are
+     * silently ignored.</p>
+     *
+     * <p>If the origin "bean" is actually a <code>Map</code>, it is assumed
+     * to contain String-valued <strong>simple</strong> property names as the keys, pointing at
+     * the corresponding property values that will be converted (if necessary)
+     * and set in the destination bean. <strong>Note</strong> that this method
+     * is intended to perform a "shallow copy" of the properties and so complex
+     * properties (for example, nested ones) will not be copied.</p>
+     *
+     * <p>This method differs from <code>populate()</code>, which
+     * was primarily designed for populating JavaBeans from the map of request
+     * parameters retrieved on an HTTP request, is that no scalar->indexed
+     * or indexed->scalar manipulations are performed.  If the origin property
+     * is indexed, the destination property must be also.</p>
+     *
+     * <p>If you know that no type conversions are required, the
+     * <code>copyProperties()</code> method in {@link PropertyUtils} will
+     * execute faster than this method.</p>
+     *
+     * <p><strong>FIXME</strong> - Indexed and mapped properties that do not
+     * have getter and setter methods for the underlying array or Map are not
+     * copied by this method.</p>
+     *
+     * @param dest Destination bean whose properties are modified
+     * @param orig Origin bean whose properties are retrieved
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if the <code>dest</code> or
+     *  <code>orig</code> argument is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    public void copyProperties(Object dest, Object orig)
+        throws IllegalAccessException, InvocationTargetException {
+
+        // Validate existence of the specified beans
+        if (dest == null) {
+            throw new IllegalArgumentException
+                    ("No destination bean specified");
+        }
+        if (orig == null) {
+            throw new IllegalArgumentException("No origin bean specified");
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("BeanUtils.copyProperties(" + dest + ", " +
+                      orig + ")");
+        }
+
+        // Copy the properties, converting as necessary
+        if (orig instanceof DynaBean) {
+            DynaProperty origDescriptors[] =
+                ((DynaBean) orig).getDynaClass().getDynaProperties();
+            for (int i = 0; i < origDescriptors.length; i++) {
+                String name = origDescriptors[i].getName();
+                if (getPropertyUtils().isWriteable(dest, name)) {
+                    Object value = ((DynaBean) orig).get(name);
+                    copyProperty(dest, name, value);
+                }
+            }
+        } else if (orig instanceof Map) {
+            Iterator names = ((Map) orig).keySet().iterator();
+            while (names.hasNext()) {
+                String name = (String) names.next();
+                if (getPropertyUtils().isWriteable(dest, name)) {
+                    Object value = ((Map) orig).get(name);
+                    copyProperty(dest, name, value);
+                }
+            }
+        } else /* if (orig is a standard JavaBean) */ {
+            PropertyDescriptor origDescriptors[] =
+                getPropertyUtils().getPropertyDescriptors(orig);
+            for (int i = 0; i < origDescriptors.length; i++) {
+                String name = origDescriptors[i].getName();
+                if ("class".equals(name)) {
+                    continue; // No point in trying to set an object's class
+                }
+                if (getPropertyUtils().isReadable(orig, name) &&
+                    getPropertyUtils().isWriteable(dest, name)) {
+                    try {
+                        Object value =
+                            getPropertyUtils().getSimpleProperty(orig, name);
+                        copyProperty(dest, name, value);
+                    } catch (NoSuchMethodException e) {
+                        ; // Should not happen
+                    }
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * <p>Copy the specified property value to the specified destination bean,
+     * performing any type conversion that is required.  If the specified
+     * bean does not have a property of the specified name, or the property
+     * is read only on the destination bean, return without
+     * doing anything.  If you have custom destination property types, register
+     * {@link Converter}s for them by calling the <code>register()</code>
+     * method of {@link ConvertUtils}.</p>
+     *
+     * <p><strong>IMPLEMENTATION RESTRICTIONS</strong>:</p>
+     * <ul>
+     * <li>Does not support destination properties that are indexed,
+     *     but only an indexed setter (as opposed to an array setter)
+     *     is available.</li>
+     * <li>Does not support destination properties that are mapped,
+     *     but only a keyed setter (as opposed to a Map setter)
+     *     is available.</li>
+     * <li>The desired property type of a mapped setter cannot be
+     *     determined (since Maps support any data type), so no conversion
+     *     will be performed.</li>
+     * </ul>
+     *
+     * @param bean Bean on which setting is to be performed
+     * @param name Property name (can be nested/indexed/mapped/combo)
+     * @param value Value to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    public void copyProperty(Object bean, String name, Object value)
+        throws IllegalAccessException, InvocationTargetException {
+
+        // Trace logging (if enabled)
+        if (log.isTraceEnabled()) {
+            StringBuffer sb = new StringBuffer("  copyProperty(");
+            sb.append(bean);
+            sb.append(", ");
+            sb.append(name);
+            sb.append(", ");
+            if (value == null) {
+                sb.append("<NULL>");
+            } else if (value instanceof String) {
+                sb.append((String) value);
+            } else if (value instanceof String[]) {
+                String values[] = (String[]) value;
+                sb.append('[');
+                for (int i = 0; i < values.length; i++) {
+                    if (i > 0) {
+                        sb.append(',');
+                    }
+                    sb.append(values[i]);
+                }
+                sb.append(']');
+            } else {
+                sb.append(value.toString());
+            }
+            sb.append(')');
+            log.trace(sb.toString());
+        }
+
+        // Resolve any nested expression to get the actual target bean
+        Object target = bean;
+        int delim = name.lastIndexOf(PropertyUtils.NESTED_DELIM);
+        if (delim >= 0) {
+            try {
+                target =
+                    getPropertyUtils().getProperty(bean, name.substring(0, delim));
+            } catch (NoSuchMethodException e) {
+                return; // Skip this property setter
+            }
+            name = name.substring(delim + 1);
+            if (log.isTraceEnabled()) {
+                log.trace("    Target bean = " + target);
+                log.trace("    Target name = " + name);
+            }
+        }
+
+        // Declare local variables we will require
+        String propName = null;          // Simple name of target property
+        Class type = null;               // Java type of target property
+        int index = -1;                  // Indexed subscript value (if any)
+        String key = null;               // Mapped key value (if any)
+
+        // Calculate the target property name, index, and key values
+        propName = name;
+        int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
+        if (i >= 0) {
+            int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
+            try {
+                index =
+                    Integer.parseInt(propName.substring(i + 1, k));
+            } catch (NumberFormatException e) {
+                ;
+            }
+            propName = propName.substring(0, i);
+        }
+        int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
+        if (j >= 0) {
+            int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
+            try {
+                key = propName.substring(j + 1, k);
+            } catch (IndexOutOfBoundsException e) {
+                ;
+            }
+            propName = propName.substring(0, j);
+        }
+
+        // Calculate the target property type
+        if (target instanceof DynaBean) {
+            DynaClass dynaClass = ((DynaBean) target).getDynaClass();
+            DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
+            if (dynaProperty == null) {
+                return; // Skip this property setter
+            }
+            type = dynaProperty.getType();
+        } else {
+            PropertyDescriptor descriptor = null;
+            try {
+                descriptor =
+                    getPropertyUtils().getPropertyDescriptor(target, name);
+                if (descriptor == null) {
+                    return; // Skip this property setter
+                }
+            } catch (NoSuchMethodException e) {
+                return; // Skip this property setter
+            }
+            type = descriptor.getPropertyType();
+            if (type == null) {
+                // Most likely an indexed setter on a POJB only
+                if (log.isTraceEnabled()) {
+                    log.trace("    target type for property '" +
+                              propName + "' is null, so skipping ths setter");
+                }
+                return;
+            }
+        }
+        if (log.isTraceEnabled()) {
+            log.trace("    target propName=" + propName + ", type=" +
+                      type + ", index=" + index + ", key=" + key);
+        }
+
+        // Convert the specified value to the required type and store it
+        if (index >= 0) {                    // Destination must be indexed
+            Converter converter = getConvertUtils().lookup(type.getComponentType());
+            if (converter != null) {
+                log.trace("        USING CONVERTER " + converter);
+                value = converter.convert(type, value);
+            }
+            try {
+                getPropertyUtils().setIndexedProperty(target, propName,
+                                                 index, value);
+            } catch (NoSuchMethodException e) {
+                throw new InvocationTargetException
+                    (e, "Cannot set " + propName);
+            }
+        } else if (key != null) {            // Destination must be mapped
+            // Maps do not know what the preferred data type is,
+            // so perform no conversions at all
+            // FIXME - should we create or support a TypedMap?
+            try {
+                getPropertyUtils().setMappedProperty(target, propName,
+                                                key, value);
+            } catch (NoSuchMethodException e) {
+                throw new InvocationTargetException
+                    (e, "Cannot set " + propName);
+            }
+        } else {                             // Destination must be simple
+            Converter converter = getConvertUtils().lookup(type);
+            if (converter != null) {
+                log.trace("        USING CONVERTER " + converter);
+                value = converter.convert(type, value);
+            }
+            try {
+                getPropertyUtils().setSimpleProperty(target, propName, value);
+            } catch (NoSuchMethodException e) {
+                throw new InvocationTargetException
+                    (e, "Cannot set " + propName);
+            }
+        }
+
+    }
+
+
+    /**
+     * <p>Return the entire set of properties for which the specified bean
+     * provides a read method. This map contains the to <code>String</code>
+     * converted property values for all properties for which a read method
+     * is provided (i.e. where the getReadMethod() returns non-null).</p>
+     *
+     * <p>This map can be fed back to a call to
+     * <code>BeanUtils.populate()</code> to reconsitute the same set of
+     * properties, modulo differences for read-only and write-only
+     * properties, but only if there are no indexed properties.</p>
+     *
+     * @param bean Bean whose properties are to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public Map describe(Object bean)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+        //            return (Collections.EMPTY_MAP);
+            return (new java.util.HashMap());
+        }
+        
+        if (log.isDebugEnabled()) {
+            log.debug("Describing bean: " + bean.getClass().getName());
+        }
+            
+        Map description = new HashMap();
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptors[] =
+                ((DynaBean) bean).getDynaClass().getDynaProperties();
+            for (int i = 0; i < descriptors.length; i++) {
+                String name = descriptors[i].getName();
+                description.put(name, getProperty(bean, name));
+            }
+        } else {
+            PropertyDescriptor descriptors[] =
+                getPropertyUtils().getPropertyDescriptors(bean);
+            for (int i = 0; i < descriptors.length; i++) {
+                String name = descriptors[i].getName();
+                if (descriptors[i].getReadMethod() != null)
+                    description.put(name, getProperty(bean, name));
+            }
+        }
+        return (description);
+
+    }
+
+
+    /**
+     * Return the value of the specified array property of the specified
+     * bean, as a String array.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String[] getArrayProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getProperty(bean, name);
+        if (value == null) {
+            return (null);
+        } else if (value instanceof Collection) {
+            ArrayList values = new ArrayList();
+            Iterator items = ((Collection) value).iterator();
+            while (items.hasNext()) {
+                Object item = items.next();
+                if (item == null) {
+                    values.add((String) null);
+                } else {
+                    // convert to string using convert utils
+                    values.add(getConvertUtils().convert(item));
+                }
+            }
+            return ((String[]) values.toArray(new String[values.size()]));
+        } else if (value.getClass().isArray()) {
+            int n = Array.getLength(value);
+            String results[] = new String[n];
+            for (int i = 0; i < n; i++) {
+                Object item = Array.get(value, i);
+                if (item == null) {
+                    results[i] = null;
+                } else {
+                    // convert to string using convert utils
+                    results[i] = getConvertUtils().convert(item);
+                }
+            }
+            return (results);
+        } else {
+            String results[] = new String[1];
+            results[0] = value.toString();
+            return (results);
+        }
+
+    }
+
+
+    /**
+     * Return the value of the specified indexed property of the specified
+     * bean, as a String.  The zero-relative index of the
+     * required value must be included (in square brackets) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname[index]</code> of the property value
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getIndexedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getIndexedProperty(bean, name);
+        return (getConvertUtils().convert(value));
+
+    }
+
+
+    /**
+     * Return the value of the specified indexed property of the specified
+     * bean, as a String.  The index is specified as a method parameter and
+     * must *not* be included in the property name expression
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param index Index of the property value to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getIndexedProperty(Object bean,
+                                            String name, int index)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getIndexedProperty(bean, name, index);
+        return (getConvertUtils().convert(value));
+
+    }
+
+
+    /**
+     * Return the value of the specified indexed property of the specified
+     * bean, as a String.  The String-valued key of the required value
+     * must be included (in parentheses) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname(index)</code> of the property value
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getMappedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getMappedProperty(bean, name);
+        return (getConvertUtils().convert(value));
+
+    }
+
+
+    /**
+     * Return the value of the specified mapped property of the specified
+     * bean, as a String.  The key is specified as a method parameter and
+     * must *not* be included in the property name expression
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param key Lookup key of the property value to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getMappedProperty(Object bean,
+                                           String name, String key)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getMappedProperty(bean, name, key);
+        return (getConvertUtils().convert(value));
+
+    }
+
+
+    /**
+     * Return the value of the (possibly nested) property of the specified
+     * name, for the specified bean, as a String.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly nested name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getNestedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getNestedProperty(bean, name);
+        return (getConvertUtils().convert(value));
+
+    }
+
+
+    /**
+     * Return the value of the specified property of the specified bean,
+     * no matter which property reference format is used, as a String.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly indexed and/or nested name of the property
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (getNestedProperty(bean, name));
+
+    }
+
+
+    /**
+     * Return the value of the specified simple property of the specified
+     * bean, converted to a String.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  property cannot be found
+     */
+    public String getSimpleProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getSimpleProperty(bean, name);
+        return (getConvertUtils().convert(value));
+
+    }
+
+
+    /**
+     * <p>Populate the JavaBeans properties of the specified bean, based on
+     * the specified name/value pairs.  This method uses Java reflection APIs
+     * to identify corresponding "property setter" method names, and deals
+     * with setter arguments of type <code>String</code>, <code>boolean</code>,
+     * <code>int</code>, <code>long</code>, <code>float</code>, and
+     * <code>double</code>.  In addition, array setters for these types (or the
+     * corresponding primitive types) can also be identified.</p>
+     * 
+     * <p>The particular setter method to be called for each property is
+     * determined using the usual JavaBeans introspection mechanisms.  Thus,
+     * you may identify custom setter methods using a BeanInfo class that is
+     * associated with the class of the bean itself.  If no such BeanInfo
+     * class is available, the standard method name conversion ("set" plus
+     * the capitalized name of the property in question) is used.</p>
+     * 
+     * <p><strong>NOTE</strong>:  It is contrary to the JavaBeans Specification
+     * to have more than one setter method (with different argument
+     * signatures) for the same property.</p>
+     *
+     * <p><strong>WARNING</strong> - The logic of this method is customized
+     * for extracting String-based request parameters from an HTTP request.
+     * It is probably not what you want for general property copying with
+     * type conversion.  For that purpose, check out the
+     * <code>copyProperties()</code> method instead.</p>
+     *
+     * @param bean JavaBean whose properties are being populated
+     * @param properties Map keyed by property name, with the
+     *  corresponding (String or String[]) value(s) to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    public void populate(Object bean, Map properties)
+        throws IllegalAccessException, InvocationTargetException {
+
+        // Do nothing unless both arguments have been specified
+        if ((bean == null) || (properties == null)) {
+            return;
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("BeanUtils.populate(" + bean + ", " +
+                    properties + ")");
+        }
+
+        // Loop through the property name/value pairs to be set
+        Iterator names = properties.keySet().iterator();
+        while (names.hasNext()) {
+
+            // Identify the property name and value(s) to be assigned
+            String name = (String) names.next();
+            if (name == null) {
+                continue;
+            }
+            Object value = properties.get(name);
+
+            // Perform the assignment for this property
+            setProperty(bean, name, value);
+
+        }
+
+    }
+
+
+    /**
+     * <p>Set the specified property value, performing type conversions as
+     * required to conform to the type of the destination property.</p>
+     *
+     * <p>If the property is read only then the method returns 
+     * without throwing an exception.</p>
+     *
+     * <p>If <code>null</code> is passed into a property expecting a primitive value,
+     * then this will be converted as if it were a <code>null</code> string.</p>
+     *
+     * <p><strong>WARNING</strong> - The logic of this method is customized
+     * to meet the needs of <code>populate()</code>, and is probably not what
+     * you want for general property copying with type conversion.  For that
+     * purpose, check out the <code>copyProperty()</code> method instead.</p>
+     *
+     * <p><strong>WARNING</strong> - PLEASE do not modify the behavior of this
+     * method without consulting with the Struts developer community.  There
+     * are some subtleties to its functionality that are not documented in the
+     * Javadoc description above, yet are vital to the way that Struts utilizes
+     * this method.</p>
+     *
+     * @param bean Bean on which setting is to be performed
+     * @param name Property name (can be nested/indexed/mapped/combo)
+     * @param value Value to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    public void setProperty(Object bean, String name, Object value)
+        throws IllegalAccessException, InvocationTargetException {
+
+        // Trace logging (if enabled)
+        if (log.isTraceEnabled()) {
+            StringBuffer sb = new StringBuffer("  setProperty(");
+            sb.append(bean);
+            sb.append(", ");
+            sb.append(name);
+            sb.append(", ");
+            if (value == null) {
+                sb.append("<NULL>");
+            } else if (value instanceof String) {
+                sb.append((String) value);
+            } else if (value instanceof String[]) {
+                String values[] = (String[]) value;
+                sb.append('[');
+                for (int i = 0; i < values.length; i++) {
+                    if (i > 0) {
+                        sb.append(',');
+                    }
+                    sb.append(values[i]);
+                }
+                sb.append(']');
+            } else {
+                sb.append(value.toString());
+            }
+            sb.append(')');
+            log.trace(sb.toString());
+        }
+
+        // Resolve any nested expression to get the actual target bean
+        Object target = bean;
+        int delim = findLastNestedIndex(name);
+        if (delim >= 0) {
+            try {
+                target =
+                    getPropertyUtils().getProperty(bean, name.substring(0, delim));
+            } catch (NoSuchMethodException e) {
+                return; // Skip this property setter
+            }
+            name = name.substring(delim + 1);
+            if (log.isTraceEnabled()) {
+                log.trace("    Target bean = " + target);
+                log.trace("    Target name = " + name);
+            }
+        }
+
+        // Declare local variables we will require
+        String propName = null;          // Simple name of target property
+        Class type = null;               // Java type of target property
+        int index = -1;                  // Indexed subscript value (if any)
+        String key = null;               // Mapped key value (if any)
+
+        // Calculate the property name, index, and key values
+        propName = name;
+        int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
+        if (i >= 0) {
+            int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
+            try {
+                index =
+                    Integer.parseInt(propName.substring(i + 1, k));
+            } catch (NumberFormatException e) {
+                ;
+            }
+            propName = propName.substring(0, i);
+        }
+        int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
+        if (j >= 0) {
+            int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
+            try {
+                key = propName.substring(j + 1, k);
+            } catch (IndexOutOfBoundsException e) {
+                ;
+            }
+            propName = propName.substring(0, j);
+        }
+
+        // Calculate the property type
+        if (target instanceof DynaBean) {
+            DynaClass dynaClass = ((DynaBean) target).getDynaClass();
+            DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
+            if (dynaProperty == null) {
+                return; // Skip this property setter
+            }
+            type = dynaProperty.getType();
+        } else {
+            PropertyDescriptor descriptor = null;
+            try {
+                descriptor =
+                    getPropertyUtils().getPropertyDescriptor(target, name);
+                if (descriptor == null) {
+                    return; // Skip this property setter
+                }
+            } catch (NoSuchMethodException e) {
+                return; // Skip this property setter
+            }
+            if (descriptor instanceof MappedPropertyDescriptor) {
+                if (((MappedPropertyDescriptor) descriptor).getMappedWriteMethod() == null) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Skipping read-only property");
+                    }
+                    return; // Read-only, skip this property setter
+                }
+                type = ((MappedPropertyDescriptor) descriptor).
+                    getMappedPropertyType();
+            } else if (descriptor instanceof IndexedPropertyDescriptor) {
+                if (((IndexedPropertyDescriptor) descriptor).getIndexedWriteMethod() == null) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Skipping read-only property");
+                    }
+                    return; // Read-only, skip this property setter
+                }
+                type = ((IndexedPropertyDescriptor) descriptor).
+                    getIndexedPropertyType();
+            } else {
+                if (descriptor.getWriteMethod() == null) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Skipping read-only property");
+                    }
+                    return; // Read-only, skip this property setter
+                }
+                type = descriptor.getPropertyType();
+            }
+        }
+
+        // Convert the specified value to the required type
+        Object newValue = null;
+        if (type.isArray() && (index < 0)) { // Scalar value into array
+            if (value == null) {
+                String values[] = new String[1];
+                values[0] = (String) value;
+                newValue = getConvertUtils().convert((String[]) values, type);
+            } else if (value instanceof String) {
+                String values[] = new String[1];
+                values[0] = (String) value;
+                newValue = getConvertUtils().convert((String[]) values, type);
+            } else if (value instanceof String[]) {
+                newValue = getConvertUtils().convert((String[]) value, type);
+            } else {
+                newValue = value;
+            }
+        } else if (type.isArray()) {         // Indexed value into array
+            if (value instanceof String) {
+                newValue = getConvertUtils().convert((String) value,
+                                                type.getComponentType());
+            } else if (value instanceof String[]) {
+                newValue = getConvertUtils().convert(((String[]) value)[0],
+                                                type.getComponentType());
+            } else {
+                newValue = value;
+            }
+        } else {                             // Value into scalar
+            if ((value instanceof String) || (value == null)) {
+                newValue = getConvertUtils().convert((String) value, type);
+            } else if (value instanceof String[]) {
+                newValue = getConvertUtils().convert(((String[]) value)[0],
+                                                type);
+            } else if (getConvertUtils().lookup(value.getClass()) != null) {
+                newValue = getConvertUtils().convert(value.toString(), type);
+            } else {
+                newValue = value;
+            }
+        }
+
+        // Invoke the setter method
+        try {
+            if (index >= 0) {
+                getPropertyUtils().setIndexedProperty(target, propName,
+                                                 index, newValue);
+            } else if (key != null) {
+                getPropertyUtils().setMappedProperty(target, propName,
+                                                key, newValue);
+            } else {
+                getPropertyUtils().setProperty(target, propName, newValue);
+            }
+        } catch (NoSuchMethodException e) {
+            throw new InvocationTargetException
+                (e, "Cannot set " + propName);
+        }
+
+    }
+    
+    private int findLastNestedIndex(String expression)
+    {
+        // walk back from the end to the start 
+        // and find the first index that 
+        int bracketCount = 0;
+        for (int i = expression.length() - 1; i>=0 ; i--) {
+            char at = expression.charAt(i);
+            switch (at) {
+                case PropertyUtils.NESTED_DELIM:
+                    if (bracketCount < 1) {
+                        return i;
+                    }
+                    break;
+                    
+                case PropertyUtils.MAPPED_DELIM:
+                case PropertyUtils.INDEXED_DELIM:
+                    // not bothered which
+                    --bracketCount;
+                    break;
+                
+                case PropertyUtils.MAPPED_DELIM2:
+                case PropertyUtils.INDEXED_DELIM2:
+                    // not bothered which
+                    ++bracketCount;
+                    break;            
+            }
+        }
+        // can't find any
+        return -1;
+    }
+    
+    /** 
+     * Gets the <code>ConvertUtilsBean</code> instance used to perform the conversions.
+     */
+    public ConvertUtilsBean getConvertUtils() {
+        return convertUtilsBean;
+    }
+    
+    /**
+     * Gets the <code>PropertyUtilsBean</code> instance used to access properties.
+     */
+    public PropertyUtilsBean getPropertyUtils() {
+        return propertyUtilsBean;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConstructorUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConstructorUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConstructorUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+/**
+ * <p> Utility reflection methods focussed on constructors, modelled after {@link MethodUtils}. </p>
+ *
+ * <h3>Known Limitations</h3>
+ * <h4>Accessing Public Constructors In A Default Access Superclass</h4>
+ * <p>There is an issue when invoking public constructors contained in a default access superclass.
+ * Reflection locates these constructors fine and correctly assigns them as public.
+ * However, an <code>IllegalAccessException</code> is thrown if the constructors is invoked.</p>
+ *
+ * <p><code>ConstructorUtils</code> contains a workaround for this situation.
+ * It will attempt to call <code>setAccessible</code> on this constructor.
+ * If this call succeeds, then the method can be invoked as normal.
+ * This call will only succeed when the application has sufficient security privilages.
+ * If this call fails then a warning will be logged and the method may fail.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @author Jan Sorensen
+ * @author Robert Burrell Donkin
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:33 $
+ */
+public class ConstructorUtils {
+
+    // --------------------------------------------------------- Private Members
+    /** An empty class array */
+    private static final Class[] emptyClassArray = new Class[0];
+    /** An empty object array */
+    private static final Object[] emptyObjectArray = new Object[0];
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Convenience method returning new instance of <code>klazz</code> using a single argument constructor.
+     * The formal parameter type is inferred from the actual values of <code>arg</code>.
+     * See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
+     *
+     * <p>The signatures should be assignment compatible.</p>
+     *
+     * @param klass the class to be constructed.
+     * @param arg the actual argument
+     * @return new instance of <code>klazz</code>
+     *
+     * @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
+     */
+    public static Object invokeConstructor(Class klass, Object arg)
+        throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException,
+            InstantiationException {
+
+        Object[] args = { arg };
+        return invokeConstructor(klass, args);
+
+    }
+
+    /**
+     * <p>Returns new instance of <code>klazz</code> created using the actual arguments <code>args</code>.
+     * The formal parameter types are inferred from the actual values of <code>args</code>.
+     * See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
+     *
+     * <p>The signatures should be assignment compatible.</p>
+     *
+     * @param klass the class to be constructed.
+     * @param args actual argument array
+     * @return new instance of <code>klazz</code>
+     *
+     * @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
+     */
+    public static Object invokeConstructor(Class klass, Object[] args)
+        throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException,
+            InstantiationException {
+
+        if (null == args) {
+            args = emptyObjectArray;
+        }
+        int arguments = args.length;
+        Class parameterTypes[] = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeConstructor(klass, args, parameterTypes);
+
+    }
+
+    /**
+     * <p>Returns new instance of <code>klazz</code> created using constructor
+     * with signature <code>parameterTypes</code> and actual arguments <code>args</code>.</p>
+     *
+     * <p>The signatures should be assignment compatible.</p>
+     *
+     * @param klass the class to be constructed.
+     * @param args actual argument array
+     * @param parameterTypes parameter types array
+     * @return new instance of <code>klazz</code>
+     *
+     * @throws NoSuchMethodException if matching constructor cannot be found
+     * @throws IllegalAccessException thrown on the constructor's invocation
+     * @throws InvocationTargetException thrown on the constructor's invocation
+     * @throws InstantiationException thrown on the constructor's invocation
+     * @see Constructor#newInstance
+     */
+    public static Object invokeConstructor(
+        Class klass,
+        Object[] args,
+        Class[] parameterTypes)
+        throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException,
+            InstantiationException {
+
+        if (parameterTypes == null) {
+            parameterTypes = emptyClassArray;
+        }
+        if (args == null) {
+            args = emptyObjectArray;
+        }
+
+        Constructor ctor =
+            getMatchingAccessibleConstructor(klass, parameterTypes);
+        if (null == ctor) {
+            throw new NoSuchMethodException(
+                "No such accessible constructor on object: " + klass.getName());
+        }
+        return ctor.newInstance(args);
+    }
+
+
+    /**
+     * <p>Convenience method returning new instance of <code>klazz</code> using a single argument constructor.
+     * The formal parameter type is inferred from the actual values of <code>arg</code>.
+     * See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
+     *
+     * <p>The signatures should match exactly.</p>
+     *
+     * @param klass the class to be constructed.
+     * @param arg the actual argument
+     * @return new instance of <code>klazz</code>
+     *
+     * @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
+     */
+    public static Object invokeExactConstructor(Class klass, Object arg)
+        throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException,
+            InstantiationException {
+
+        Object[] args = { arg };
+        return invokeExactConstructor(klass, args);
+
+    }
+
+    /**
+     * <p>Returns new instance of <code>klazz</code> created using the actual arguments <code>args</code>.
+     * The formal parameter types are inferred from the actual values of <code>args</code>.
+     * See {@link #invokeExactConstructor(Class, Object[], Class[])} for more details.</p>
+     *
+     * <p>The signatures should match exactly.</p>
+     *
+     * @param klass the class to be constructed.
+     * @param args actual argument array
+     * @return new instance of <code>klazz</code>
+     *
+     * @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[])
+     */
+    public static Object invokeExactConstructor(Class klass, Object[] args)
+        throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException,
+            InstantiationException {
+        if (null == args) {
+            args = emptyObjectArray;
+        }
+        int arguments = args.length;
+        Class parameterTypes[] = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeExactConstructor(klass, args, parameterTypes);
+
+    }
+
+    /**
+     * <p>Returns new instance of <code>klazz</code> created using constructor
+     * with signature <code>parameterTypes</code> and actual arguments
+     * <code>args</code>.</p>
+     *
+     * <p>The signatures should match exactly.</p>
+     *
+     * @param klass the class to be constructed.
+     * @param args actual argument array
+     * @param parameterTypes parameter types array
+     * @return new instance of <code>klazz</code>
+     *
+     * @throws NoSuchMethodException if matching constructor cannot be found
+     * @throws IllegalAccessException thrown on the constructor's invocation
+     * @throws InvocationTargetException thrown on the constructor's invocation
+     * @throws InstantiationException thrown on the constructor's invocation
+     * @see Constructor#newInstance
+     */
+    public static Object invokeExactConstructor(
+        Class klass,
+        Object[] args,
+        Class[] parameterTypes)
+        throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException,
+            InstantiationException {
+
+        if (args == null) {
+            args = emptyObjectArray;
+        }
+
+        if (parameterTypes == null) {
+            parameterTypes = emptyClassArray;
+        }
+
+        Constructor ctor = getAccessibleConstructor(klass, parameterTypes);
+        if (null == ctor) {
+            throw new NoSuchMethodException(
+                "No such accessible constructor on object: " + klass.getName());
+        }
+        return ctor.newInstance(args);
+
+    }
+
+    /**
+     * Returns a constructor with single argument.
+     * @param klass the class to be constructed
+     * @return null if matching accessible constructor can not be found.
+     * @see Class#getConstructor
+     * @see #getAccessibleConstructor(java.lang.reflect.Constructor)
+     */
+    public static Constructor getAccessibleConstructor(
+        Class klass,
+        Class parameterType) {
+
+        Class[] parameterTypes = { parameterType };
+        return getAccessibleConstructor(klass, parameterTypes);
+
+    }
+
+    /**
+     * Returns a constructor given a class and signature.
+     * @param klass the class to be constructed
+     * @param parameterTypes the parameter array
+     * @return null if matching accessible constructor can not be found
+     * @see Class#getConstructor
+     * @see #getAccessibleConstructor(java.lang.reflect.Constructor)
+     */
+    public static Constructor getAccessibleConstructor(
+        Class klass,
+        Class[] parameterTypes) {
+
+        try {
+            return getAccessibleConstructor(
+                klass.getConstructor(parameterTypes));
+        } catch (NoSuchMethodException e) {
+            return (null);
+        }
+
+    }
+
+    /**
+     * Returns accessible version of the given constructor.
+     * @param ctor prototype constructor object.
+     * @return <code>null</code> if accessible constructor can not be found.
+     * @see java.lang.SecurityManager
+     */
+    public static Constructor getAccessibleConstructor(Constructor ctor) {
+
+        // Make sure we have a method to check
+        if (ctor == null) {
+            return (null);
+        }
+
+        // If the requested method is not public we cannot call it
+        if (!Modifier.isPublic(ctor.getModifiers())) {
+            return (null);
+        }
+
+        // If the declaring class is public, we are done
+        Class clazz = ctor.getDeclaringClass();
+        if (Modifier.isPublic(clazz.getModifiers())) {
+            return (ctor);
+        }
+
+        // what else can we do?
+        return null;
+
+    }
+
+    // -------------------------------------------------------- Private Methods
+    /**
+     * <p>Find an accessible constructor with compatible parameters.
+     * Compatible parameters mean that every method parameter is assignable from
+     * the given parameters. In other words, it finds constructor that will take
+     * the parameters given.</p>
+     *
+     * <p>First it checks if there is constructor matching the exact signature.
+     * If no such, all the constructors of the class are tested if their signatures
+     * are assignment compatible with the parameter types.
+     * The first matching constructor is returned.</p>
+     *
+     * @param clazz find constructor for this class
+     * @param parameterTypes find method with compatible parameters
+     * @return a valid Constructor object. If there's no matching constructor, returns <code>null</code>.
+     */
+    private static Constructor getMatchingAccessibleConstructor(
+        Class clazz,
+        Class[] parameterTypes) {
+        // see if we can find the method directly
+        // most of the time this works and it's much faster
+        try {
+            Constructor ctor = clazz.getConstructor(parameterTypes);
+            try {
+                //
+                // XXX Default access superclass workaround
+                //
+                // When a public class has a default access superclass
+                // with public methods, these methods are accessible.
+                // Calling them from compiled code works fine.
+                //
+                // Unfortunately, using reflection to invoke these methods
+                // seems to (wrongly) to prevent access even when the method
+                // modifer is public.
+                //
+                // The following workaround solves the problem but will only
+                // work from sufficiently privilages code. 
+                //
+                // Better workarounds would be greatfully accepted.
+                //
+                ctor.setAccessible(true);
+            } catch (SecurityException se) {}
+            return ctor;
+
+        } catch (NoSuchMethodException e) { /* SWALLOW */
+        }
+
+        // search through all methods 
+        int paramSize = parameterTypes.length;
+        Constructor[] ctors = clazz.getConstructors();
+        for (int i = 0, size = ctors.length; i < size; i++) {
+            // compare parameters
+            Class[] ctorParams = ctors[i].getParameterTypes();
+            int ctorParamSize = ctorParams.length;
+            if (ctorParamSize == paramSize) {
+                boolean match = true;
+                for (int n = 0; n < ctorParamSize; n++) {
+                    if (!MethodUtils
+                        .isAssignmentCompatible(
+                            ctorParams[n],
+                            parameterTypes[n])) {
+                        match = false;
+                        break;
+                    }
+                }
+
+                if (match) {
+                    // get accessible version of method
+                    Constructor ctor = getAccessibleConstructor(ctors[i]);
+                    if (ctor != null) {
+                        try {
+                            ctor.setAccessible(true);
+                        } catch (SecurityException se) {}
+                        return ctor;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ContextClassLoaderLocal.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ContextClassLoaderLocal.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ContextClassLoaderLocal.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * A value that is provided per (thread) context classloader.
+ * Patterned after ThreadLocal. 
+ * There is a separate value used when Thread.getContextClassLoader() is null.  
+ * This mechanism provides isolation for web apps deployed in the same container. 
+ * <strong>Note:</strong> A WeakHashMap bug in several 1.3 JVMs results in a memory leak
+ * for those JVMs.
+ * 
+ * @see java.lang.Thread#getContextClassLoader  
+ * @author Eric Pabst
+ */
+public class ContextClassLoaderLocal {
+    private Map valueByClassLoader = new WeakHashMap();
+    private boolean globalValueInitialized = false;
+    private Object globalValue;
+
+    public ContextClassLoaderLocal() {
+        super();
+    }
+
+    /**
+     * Returns the initial value for this ContextClassLoaderLocal
+     * variable. This method will be called once per Context ClassLoader for
+     * each ContextClassLoaderLocal, the first time it is accessed 
+     * with get or set.  If the programmer desires ContextClassLoaderLocal variables
+     * to be initialized to some value other than null, ContextClassLoaderLocal must
+     * be subclassed, and this method overridden.  Typically, an anonymous
+     * inner class will be used.  Typical implementations of initialValue
+     * will call an appropriate constructor and return the newly constructed
+     * object.
+     *
+     * @return a new Object to be used as an initial value for this ContextClassLoaderLocal
+     */
+    protected Object initialValue() {
+        return null;
+    }
+
+    /** 
+     * Gets the instance which provides the functionality for {@link BeanUtils}.
+     * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
+     * This mechanism provides isolation for web apps deployed in the same container. 
+     * @return the object currently associated with the 
+     */
+    public synchronized Object get() {
+        // synchronizing the whole method is a bit slower 
+        // but guarentees no subtle threading problems, and there's no 
+        // need to synchronize valueByClassLoader
+        
+        // make sure that the map is given a change to purge itself
+        valueByClassLoader.isEmpty();
+        try {
+            
+            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+            if (contextClassLoader != null) {
+                
+                Object value = valueByClassLoader.get(contextClassLoader);
+                if ((value == null) 
+                && !valueByClassLoader.containsKey(contextClassLoader)) {
+                    value = initialValue();
+                    valueByClassLoader.put(contextClassLoader, value);
+                }
+                return value;
+                
+            }
+            
+        } catch (SecurityException e) { /* SWALLOW - should we log this? */ }
+        
+        // if none or exception, return the globalValue 
+        if (!globalValueInitialized) {
+            globalValue = initialValue();
+            globalValueInitialized = true;
+        }//else already set
+        return globalValue;
+    }
+
+    /** 
+     * Sets the value - a value is provided per (thread) context classloader.
+     * This mechanism provides isolation for web apps deployed in the same container. 
+     * 
+     * @param value the object to be associated with the entrant thread's context classloader
+     */
+    public synchronized void set(Object value) {
+        // synchronizing the whole method is a bit slower 
+        // but guarentees no subtle threading problems
+        
+        // make sure that the map is given a change to purge itself
+        valueByClassLoader.isEmpty();
+        try {
+            
+            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+            if (contextClassLoader != null) {
+                valueByClassLoader.put(contextClassLoader, value);
+                return;
+            }
+            
+        } catch (SecurityException e) { /* SWALLOW - should we log this? */ }
+        
+        // if in doubt, set the global value
+        globalValue = value;
+        globalValueInitialized = true;
+    }
+    
+    /** 
+     * Unsets the value associated with the current thread's context classloader
+     */
+    public synchronized void unset() {    
+        try {
+        
+            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+            unset(contextClassLoader);
+            
+        } catch (SecurityException e) { /* SWALLOW - should we log this? */ }
+    }
+    
+    /** 
+     * Unsets the value associated with the given classloader
+     */
+    public synchronized void unset(ClassLoader classLoader) {    
+        valueByClassLoader.remove(classLoader);
+    }    
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConversionException.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConversionException.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConversionException.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * <p>A <strong>ConversionException</strong> indicates that a call to
+ * <code>Converter.convert()</code> has failed to complete successfully.
+ *
+ * @author Craig McClanahan
+ * @author Paulo Gaspar
+ * @since 1.3
+ */
+
+public class ConversionException extends RuntimeException {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new exception with the specified message.
+     *
+     * @param message The message describing this exception
+     */
+    public ConversionException(String message) {
+
+        super(message);
+
+    }
+
+
+    /**
+     * Construct a new exception with the specified message and root cause.
+     *
+     * @param message The message describing this exception
+     * @param cause The root cause of this exception
+     */
+    public ConversionException(String message, Throwable cause) {
+
+        super(message);
+        this.cause = cause;
+
+    }
+
+
+    /**
+     * Construct a new exception with the specified root cause.
+     *
+     * @param cause The root cause of this exception
+     */
+    public ConversionException(Throwable cause) {
+
+        super(cause.getMessage());
+        this.cause = cause;
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The root cause of this <code>ConversionException</code>, compatible with
+     * JDK 1.4's extensions to <code>java.lang.Throwable</code>.
+     */
+    protected Throwable cause = null;
+
+    public Throwable getCause() {
+        return (this.cause);
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+/**
+ * <p>Utility methods for converting String scalar values to objects of the
+ * specified Class, String arrays to arrays of the specified Class.</p>
+ *
+ * <p>For more details, see <code>ConvertUtilsBean</code> which provides the
+ * implementations for these methods.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @version $Revision: 1.17 $ $Date: 2004/02/28 13:18:33 $
+ * @see ConvertUtilsBean
+ */
+
+public class ConvertUtils {
+
+
+    // ------------------------------------------------------ Static Properties
+
+    /**
+     * Gets the default value for Boolean conversions.
+     * @deprecated Register replacement converters for Boolean.TYPE and
+     *  Boolean.class instead
+     */
+    public static boolean getDefaultBoolean() {
+        return (ConvertUtilsBean.getInstance().getDefaultBoolean());
+    }
+
+    /**
+     * Sets the default value for Boolean conversions.
+     * @deprecated Register replacement converters for Boolean.TYPE and
+     *  Boolean.class instead
+     */
+    public static void setDefaultBoolean(boolean newDefaultBoolean) {
+        ConvertUtilsBean.getInstance().setDefaultBoolean(newDefaultBoolean);
+    }
+
+
+    /**
+     * Gets the default value for Byte conversions.
+     * @deprecated Register replacement converters for Byte.TYPE and
+     *  Byte.class instead
+     */
+    public static byte getDefaultByte() {
+        return ConvertUtilsBean.getInstance().getDefaultByte();
+    }
+
+    /**
+     * Sets the default value for Byte conversions.
+     * @deprecated Register replacement converters for Byte.TYPE and
+     *  Byte.class instead
+     */
+    public static void setDefaultByte(byte newDefaultByte) {
+        ConvertUtilsBean.getInstance().setDefaultByte(newDefaultByte);
+    }
+
+
+    /**
+     * Gets the default value for Character conversions.
+     * @deprecated Register replacement converters for Character.TYPE and
+     *  Character.class instead
+     */
+    public static char getDefaultCharacter() {
+        return ConvertUtilsBean.getInstance().getDefaultCharacter();
+    }
+
+    /**
+     * Sets the default value for Character conversions.
+     * @deprecated Register replacement converters for Character.TYPE and
+     *  Character.class instead
+     */
+    public static void setDefaultCharacter(char newDefaultCharacter) {
+        ConvertUtilsBean.getInstance().setDefaultCharacter(newDefaultCharacter);
+    }
+
+
+    /**
+     * Gets the default value for Double conversions.
+     * @deprecated Register replacement converters for Double.TYPE and
+     *  Double.class instead
+     */
+    public static double getDefaultDouble() {
+        return ConvertUtilsBean.getInstance().getDefaultDouble();
+    }
+
+    /**
+     * Sets the default value for Double conversions.
+     * @deprecated Register replacement converters for Double.TYPE and
+     *  Double.class instead
+     */
+    public static void setDefaultDouble(double newDefaultDouble) {
+        ConvertUtilsBean.getInstance().setDefaultDouble(newDefaultDouble);
+    }
+
+
+    /**
+     * Get the default value for Float conversions.
+     * @deprecated Register replacement converters for Float.TYPE and
+     *  Float.class instead
+     */
+    public static float getDefaultFloat() {
+        return ConvertUtilsBean.getInstance().getDefaultFloat();
+    }
+
+    /**
+     * Sets the default value for Float conversions.
+     * @deprecated Register replacement converters for Float.TYPE and
+     *  Float.class instead
+     */
+    public static void setDefaultFloat(float newDefaultFloat) {
+        ConvertUtilsBean.getInstance().setDefaultFloat(newDefaultFloat);
+    }
+
+
+    /**
+     * Gets the default value for Integer conversions.
+     * @deprecated Register replacement converters for Integer.TYPE and
+     *  Integer.class instead
+     */
+    public static int getDefaultInteger() {
+        return ConvertUtilsBean.getInstance().getDefaultInteger();
+    }
+
+    /**
+     * Sets the default value for Integer conversions.
+     * @deprecated Register replacement converters for Integer.TYPE and
+     *  Integer.class instead
+     */
+    public static void setDefaultInteger(int newDefaultInteger) {
+        ConvertUtilsBean.getInstance().setDefaultInteger(newDefaultInteger);
+    }
+
+
+    /**
+     * Gets the default value for Long conversions.
+     * @deprecated Register replacement converters for Long.TYPE and
+     *  Long.class instead
+     */
+    public static long getDefaultLong() {
+        return (ConvertUtilsBean.getInstance().getDefaultLong());
+    }
+
+    /**
+     * Sets the default value for Long conversions.
+     * @deprecated Register replacement converters for Long.TYPE and
+     *  Long.class instead
+     */
+    public static void setDefaultLong(long newDefaultLong) {
+        ConvertUtilsBean.getInstance().setDefaultLong(newDefaultLong);
+    }
+
+
+    /**
+     * Gets the default value for Short conversions.
+     * @deprecated Register replacement converters for Short.TYPE and
+     *  Short.class instead
+     */
+    public static short getDefaultShort() {
+        return ConvertUtilsBean.getInstance().getDefaultShort();
+    }
+
+    /**
+     * Sets the default value for Short conversions.
+     * @deprecated Register replacement converters for Short.TYPE and
+     *  Short.class instead
+     */
+    public static void setDefaultShort(short newDefaultShort) {
+        ConvertUtilsBean.getInstance().setDefaultShort(newDefaultShort);
+    }
+
+    // --------------------------------------------------------- Public Classes
+
+
+    /**
+     * <p>Convert the specified value into a String.</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#convert(Object)
+     */
+    public static String convert(Object value) {
+
+        return ConvertUtilsBean.getInstance().convert(value);
+
+    }
+
+
+    /**
+     * <p>Convert the specified value to an object of the specified class (if
+     * possible).  Otherwise, return a String representation of the value.</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#convert(String, Class)
+     */
+    public static Object convert(String value, Class clazz) {
+
+        return ConvertUtilsBean.getInstance().convert(value, clazz);
+
+    }
+
+
+    /**
+     * <p>Convert an array of specified values to an array of objects of the
+     * specified class (if possible).</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#convert(String[], Class)
+     */
+    public static Object convert(String values[], Class clazz) {
+
+  return ConvertUtilsBean.getInstance().convert(values, clazz);
+
+    }
+
+
+    /**
+     * <p>Remove all registered {@link Converter}s, and re-establish the
+     * standard Converters.</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#deregister()
+     */
+    public static void deregister() {
+
+        ConvertUtilsBean.getInstance().deregister();
+
+    }
+
+
+    /**
+     * <p>Remove any registered {@link Converter} for the specified destination
+     * <code>Class</code>.</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#deregister(Class)
+     */
+    public static void deregister(Class clazz) {
+
+        ConvertUtilsBean.getInstance().deregister(clazz);
+
+    }
+
+
+    /**
+     * <p>Look up and return any registered {@link Converter} for the specified
+     * destination class; if there is no registered Converter, return
+     * <code>null</code>.</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#lookup(Class)
+     */
+    public static Converter lookup(Class clazz) {
+
+        return ConvertUtilsBean.getInstance().lookup(clazz);
+
+    }
+
+
+    /**
+     * <p>Register a custom {@link Converter} for the specified destination
+     * <code>Class</code>, replacing any previously registered Converter.</p>
+     *
+     * <p>For more details see <code>ConvertUtilsBean</code>.</p>
+     *
+     * @see ConvertUtilsBean#register(Converter, Class)
+     */
+    public static void register(Converter converter, Class clazz) {
+
+        ConvertUtilsBean.getInstance().register(converter, clazz);
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtilsBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtilsBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertUtilsBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,581 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.File;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URL;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import org.apache.commons.beanutils.converters.BigDecimalConverter;
+import org.apache.commons.beanutils.converters.BigIntegerConverter;
+import org.apache.commons.beanutils.converters.BooleanConverter;
+import org.apache.commons.beanutils.converters.BooleanArrayConverter;
+import org.apache.commons.beanutils.converters.ByteConverter;
+import org.apache.commons.beanutils.converters.ByteArrayConverter;
+import org.apache.commons.beanutils.converters.CharacterConverter;
+import org.apache.commons.beanutils.converters.CharacterArrayConverter;
+import org.apache.commons.beanutils.converters.ClassConverter;
+import org.apache.commons.beanutils.converters.DoubleConverter;
+import org.apache.commons.beanutils.converters.DoubleArrayConverter;
+import org.apache.commons.beanutils.converters.FileConverter;
+import org.apache.commons.beanutils.converters.FloatConverter;
+import org.apache.commons.beanutils.converters.FloatArrayConverter;
+import org.apache.commons.beanutils.converters.IntegerConverter;
+import org.apache.commons.beanutils.converters.IntegerArrayConverter;
+import org.apache.commons.beanutils.converters.LongConverter;
+import org.apache.commons.beanutils.converters.LongArrayConverter;
+import org.apache.commons.beanutils.converters.ShortConverter;
+import org.apache.commons.beanutils.converters.ShortArrayConverter;
+import org.apache.commons.beanutils.converters.SqlDateConverter;
+import org.apache.commons.beanutils.converters.SqlTimeConverter;
+import org.apache.commons.beanutils.converters.SqlTimestampConverter;
+import org.apache.commons.beanutils.converters.StringConverter;
+import org.apache.commons.beanutils.converters.StringArrayConverter;
+import org.apache.commons.beanutils.converters.URLConverter;
+import org.apache.commons.collections.FastHashMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p>Utility methods for converting String scalar values to objects of the
+ * specified Class, String arrays to arrays of the specified Class.  The
+ * actual {@link Converter} instance to be used can be registered for each
+ * possible destination Class.  Unless you override them, standard
+ * {@link Converter} instances are provided for all of the following
+ * destination Classes:</p>
+ * <ul>
+ * <li>java.lang.BigDecimal</li>
+ * <li>java.lang.BigInteger</li>
+ * <li>boolean and java.lang.Boolean</li>
+ * <li>byte and java.lang.Byte</li>
+ * <li>char and java.lang.Character</li>
+ * <li>java.lang.Class</li>
+ * <li>double and java.lang.Double</li>
+ * <li>float and java.lang.Float</li>
+ * <li>int and java.lang.Integer</li>
+ * <li>long and java.lang.Long</li>
+ * <li>short and java.lang.Short</li>
+ * <li>java.lang.String</li>
+ * <li>java.io.File</li>
+ * <li>java.net.URL</li>
+ * <li>java.sql.Date</li>
+ * <li>java.sql.Time</li>
+ * <li>java.sql.Timestamp</li>
+ * </ul>
+ *
+ * <p>For backwards compatibility, the standard Converters for primitive
+ * types (and the corresponding wrapper classes) return a defined
+ * default value when a conversion error occurs.  If you prefer to have a
+ * {@link ConversionException} thrown instead, replace the standard Converter
+ * instances with instances created with the zero-arguments constructor.  For
+ * example, to cause the Converters for integers to throw an exception on
+ * conversion errors, you could do this:</p>
+ * <pre>
+ *   // No-args constructor gets the version that throws exceptions
+ *   Converter myConverter =
+ *    new org.apache.commons.beanutils.converter.IntegerConverter();
+ *   ConvertUtils.register(myConverter, Integer.TYPE);    // Native type
+ *   ConvertUtils.register(myConverter, Integer.class);   // Wrapper class
+ * </pre>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author James Strachan
+ * @version $Revision: 1.12.2.1 $ $Date: 2004/07/27 21:44:26 $
+ * @since 1.7
+ */
+
+public class ConvertUtilsBean {
+    
+    // ------------------------------------------------------- Class Methods
+    /** Get singleton instance */
+    protected static ConvertUtilsBean getInstance() {
+        return BeanUtilsBean.getInstance().getConvertUtils();
+    }
+
+    // ------------------------------------------------------- Variables
+
+
+    /**
+     * The set of {@link Converter}s that can be used to convert Strings
+     * into objects of a specified Class, keyed by the destination Class.
+     */
+    private FastHashMap converters = new FastHashMap();
+
+    /**
+     * The <code>Log</code> instance for this class.
+     */
+    private Log log = LogFactory.getLog(ConvertUtils.class);
+
+    // ------------------------------------------------------- Constructors
+
+    /** Construct a bean with standard converters registered */
+    public ConvertUtilsBean() {
+        converters.setFast(false);
+        deregister();
+        converters.setFast(true);
+    }
+
+    // --------------------------------------------------------- Public Methods
+    
+    // ------------------------------------------------------ Static Properties
+
+
+    /**
+     * The default value for Boolean conversions.
+     * @deprecated Register replacement converters for Boolean.TYPE and
+     *  Boolean.class instead
+     */
+    private Boolean defaultBoolean = Boolean.FALSE;
+
+    /**
+     * Gets the default value for Boolean conversions.
+     * @deprecated Register replacement converters for Boolean.TYPE and
+     *  Boolean.class instead
+     */
+    public boolean getDefaultBoolean() {
+        return (defaultBoolean.booleanValue());
+    }
+
+    /**
+     * Sets the default value for Boolean conversions.
+     * @deprecated Register replacement converters for Boolean.TYPE and
+     *  Boolean.class instead
+     */
+    public void setDefaultBoolean(boolean newDefaultBoolean) {
+        defaultBoolean = new Boolean(newDefaultBoolean);
+        register(new BooleanConverter(defaultBoolean), Boolean.TYPE);
+        register(new BooleanConverter(defaultBoolean), Boolean.class);
+    }
+
+
+    /**
+     * The default value for Byte conversions.
+     * @deprecated Register replacement converters for Byte.TYPE and
+     *  Byte.class instead
+     */
+    private Byte defaultByte = new Byte((byte) 0);
+
+    /**
+     * Gets the default value for Byte conversions.
+     * @deprecated Register replacement converters for Byte.TYPE and
+     *  Byte.class instead
+     */
+    public byte getDefaultByte() {
+        return (defaultByte.byteValue());
+    }
+
+    /**
+     * Sets the default value for Byte conversions.
+     * @deprecated Register replacement converters for Byte.TYPE and
+     *  Byte.class instead
+     */
+    public void setDefaultByte(byte newDefaultByte) {
+        defaultByte = new Byte(newDefaultByte);
+        register(new ByteConverter(defaultByte), Byte.TYPE);
+        register(new ByteConverter(defaultByte), Byte.class);
+    }
+
+
+    /**
+     * The default value for Character conversions.
+     * @deprecated Register replacement converters for Character.TYPE and
+     *  Character.class instead
+     */
+    private Character defaultCharacter = new Character(' ');
+
+    /**
+     * Gets the default value for Character conversions.
+     * @deprecated Register replacement converters for Character.TYPE and
+     *  Character.class instead
+     */
+    public char getDefaultCharacter() {
+        return (defaultCharacter.charValue());
+    }
+
+    /**
+     * Sets the default value for Character conversions.
+     * @deprecated Register replacement converters for Character.TYPE and
+     *  Character.class instead
+     */
+    public void setDefaultCharacter(char newDefaultCharacter) {
+        defaultCharacter = new Character(newDefaultCharacter);
+        register(new CharacterConverter(defaultCharacter),
+                    Character.TYPE);
+        register(new CharacterConverter(defaultCharacter),	
+                    Character.class);
+    }
+
+
+    /**
+     * The default value for Double conversions.
+     * @deprecated Register replacement converters for Double.TYPE and
+     *  Double.class instead
+     */
+    private Double defaultDouble = new Double((double) 0.0);
+
+    /**
+     * Gets the default value for Double conversions.
+     * @deprecated Register replacement converters for Double.TYPE and
+     *  Double.class instead
+     */
+    public double getDefaultDouble() {
+        return (defaultDouble.doubleValue());
+    }
+
+    /**
+     * Sets the default value for Double conversions.
+     * @deprecated Register replacement converters for Double.TYPE and
+     *  Double.class instead
+     */
+    public void setDefaultDouble(double newDefaultDouble) {
+        defaultDouble = new Double(newDefaultDouble);
+        register(new DoubleConverter(defaultDouble), Double.TYPE);
+        register(new DoubleConverter(defaultDouble), Double.class);
+    }
+
+
+    /**
+     * The default value for Float conversions.
+     * @deprecated Register replacement converters for Float.TYPE and
+     *  Float.class instead
+     */
+    private Float defaultFloat = new Float((float) 0.0);
+
+    /**
+     * Gets the default value for Float conversions.
+     * @deprecated Register replacement converters for Float.TYPE and
+     *  Float.class instead
+     */
+    public float getDefaultFloat() {
+        return (defaultFloat.floatValue());
+    }
+
+    /**
+     * Sets the default value for Float conversions.
+     * @deprecated Register replacement converters for Float.TYPE and
+     *  Float.class instead
+     */
+    public void setDefaultFloat(float newDefaultFloat) {
+        defaultFloat = new Float(newDefaultFloat);
+        register(new FloatConverter(defaultFloat), Float.TYPE);
+        register(new FloatConverter(defaultFloat), Float.class);
+    }
+
+
+    /**
+     * The default value for Integer conversions.
+     * @deprecated Register replacement converters for Integer.TYPE and
+     *  Integer.class instead
+     */
+    private Integer defaultInteger = new Integer(0);
+
+    /**
+     * Gets the default value for Integer conversions.
+     * @deprecated Register replacement converters for Integer.TYPE and
+     *  Integer.class instead
+     */
+    public int getDefaultInteger() {
+        return (defaultInteger.intValue());
+    }
+    
+    /**
+     * Sets the default value for Integer conversions.
+     * @deprecated Register replacement converters for Integer.TYPE and
+     *  Integer.class instead
+     */
+    public void setDefaultInteger(int newDefaultInteger) {
+        defaultInteger = new Integer(newDefaultInteger);
+        register(new IntegerConverter(defaultInteger), Integer.TYPE);
+        register(new IntegerConverter(defaultInteger), Integer.class);
+    }
+
+
+    /**
+     * The default value for Long conversions.
+     * @deprecated Register replacement converters for Long.TYPE and
+     *  Long.class instead
+     */
+    private Long defaultLong = new Long((long) 0);
+
+    /**
+     * Gets the default value for Long conversions.
+     * @deprecated Register replacement converters for Long.TYPE and
+     *  Long.class instead
+     */
+    public long getDefaultLong() {
+        return (defaultLong.longValue());
+    }
+
+    /**
+     * Sets the default value for Long conversions.
+     * @deprecated Register replacement converters for Long.TYPE and
+     *  Long.class instead
+     */
+    public void setDefaultLong(long newDefaultLong) {
+        defaultLong = new Long(newDefaultLong);
+        register(new LongConverter(defaultLong), Long.TYPE);
+        register(new LongConverter(defaultLong), Long.class);
+    }
+
+
+    /**
+     * The default value for Short conversions.
+     * @deprecated Register replacement converters for Short.TYPE and
+     *  Short.class instead
+     */
+    private static Short defaultShort = new Short((short) 0);
+
+    /**
+     * Gets the default value for Short conversions.
+     * @deprecated Register replacement converters for Short.TYPE and
+     *  Short.class instead
+     */
+    public short getDefaultShort() {
+        return (defaultShort.shortValue());
+    }
+
+    /**
+     * Sets the default value for Short conversions.
+     * @deprecated Register replacement converters for Short.TYPE and
+     *  Short.class instead
+     */
+    public void setDefaultShort(short newDefaultShort) {
+        defaultShort = new Short(newDefaultShort);
+        register(new ShortConverter(defaultShort), Short.TYPE);
+        register(new ShortConverter(defaultShort), Short.class);
+    }
+
+
+
+    /**
+     * Convert the specified value into a String.  If the specified value
+     * is an array, the first element (converted to a String) will be
+     * returned.  The registered {@link Converter} for the
+     * <code>java.lang.String</code> class will be used, which allows
+     * applications to customize Object->String conversions (the default
+     * implementation simply uses toString()).
+     *
+     * @param value Value to be converted (may be null)
+     */
+    public String convert(Object value) {
+
+        if (value == null) {
+            return ((String) null);
+        } else if (value.getClass().isArray()) {
+            if (Array.getLength(value) < 1) {
+                return (null);
+            }
+            value = Array.get(value, 0);
+            if (value == null) {
+                return ((String) null);
+            } else {
+                Converter converter = lookup(String.class);
+                return ((String) converter.convert(String.class, value));
+            }
+        } else {
+            Converter converter = lookup(String.class);
+            return ((String) converter.convert(String.class, value));
+        }
+
+    }
+
+
+    /**
+     * Convert the specified value to an object of the specified class (if
+     * possible).  Otherwise, return a String representation of the value.
+     *
+     * @param value Value to be converted (may be null)
+     * @param clazz Java class to be converted to
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String value, Class clazz) {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Convert string '" + value + "' to class '" +
+                      clazz.getName() + "'");
+        }
+        Converter converter = lookup(clazz);
+        if (converter == null) {
+            converter = lookup(String.class);
+        }
+        if (log.isTraceEnabled()) {
+            log.trace("  Using converter " + converter);
+        }
+        return (converter.convert(clazz, value));
+
+    }
+
+
+    /**
+     * Convert an array of specified values to an array of objects of the
+     * specified class (if possible).  If the specified Java class is itself
+     * an array class, this class will be the type of the returned value.
+     * Otherwise, an array will be constructed whose component type is the
+     * specified class.
+     *
+     * @param values Values to be converted (may be null)
+     * @param clazz Java array or element class to be converted to
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String values[], Class clazz) {
+
+        Class type = clazz;
+        if (clazz.isArray()) {
+            type = clazz.getComponentType();
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("Convert String[" + values.length + "] to class '" +
+                      type.getName() + "[]'");
+        }
+        Converter converter = lookup(type);
+        if (converter == null) {
+            converter = lookup(String.class);
+        }
+        if (log.isTraceEnabled()) {
+            log.trace("  Using converter " + converter);
+        }
+        Object array = Array.newInstance(type, values.length);
+        for (int i = 0; i < values.length; i++) {
+            Array.set(array, i, converter.convert(type, values[i]));
+        }
+        return (array);
+
+    }
+
+
+    /**
+     * Remove all registered {@link Converter}s, and re-establish the
+     * standard Converters.
+     */
+    public void deregister() {
+
+        boolean booleanArray[] = new boolean[0];
+        byte byteArray[] = new byte[0];
+        char charArray[] = new char[0];
+        double doubleArray[] = new double[0];
+        float floatArray[] = new float[0];
+        int intArray[] = new int[0];
+        long longArray[] = new long[0];
+        short shortArray[] = new short[0];
+        String stringArray[] = new String[0];
+
+		converters.clear();
+        register(BigDecimal.class, new BigDecimalConverter());
+        register(BigInteger.class, new BigIntegerConverter());
+        register(Boolean.TYPE, new BooleanConverter(defaultBoolean));
+        register(Boolean.class,  new BooleanConverter(defaultBoolean));
+        register(booleanArray.getClass(),
+                       new BooleanArrayConverter(booleanArray));
+        register(Byte.TYPE, new ByteConverter(defaultByte));
+        register(Byte.class, new ByteConverter(defaultByte));
+        register(byteArray.getClass(),
+                       new ByteArrayConverter(byteArray));
+        register(Character.TYPE,
+                       new CharacterConverter(defaultCharacter));
+        register(Character.class,
+                       new CharacterConverter(defaultCharacter));
+        register(charArray.getClass(),
+                       new CharacterArrayConverter(charArray));
+        register(Class.class, new ClassConverter());
+        register(Double.TYPE, new DoubleConverter(defaultDouble));
+        register(Double.class, new DoubleConverter(defaultDouble));
+        register(doubleArray.getClass(),
+                       new DoubleArrayConverter(doubleArray));
+        register(Float.TYPE, new FloatConverter(defaultFloat));
+        register(Float.class, new FloatConverter(defaultFloat));
+        register(floatArray.getClass(),
+                       new FloatArrayConverter(floatArray));
+        register(Integer.TYPE, new IntegerConverter(defaultInteger));
+        register(Integer.class, new IntegerConverter(defaultInteger));
+        register(intArray.getClass(),
+                       new IntegerArrayConverter(intArray));
+        register(Long.TYPE, new LongConverter(defaultLong));
+        register(Long.class, new LongConverter(defaultLong));
+        register(longArray.getClass(),
+                       new LongArrayConverter(longArray));
+        register(Short.TYPE, new ShortConverter(defaultShort));
+        register(Short.class, new ShortConverter(defaultShort));
+        register(shortArray.getClass(),
+                       new ShortArrayConverter(shortArray));
+        register(String.class, new StringConverter());
+        register(stringArray.getClass(),
+                       new StringArrayConverter(stringArray));
+        register(Date.class, new SqlDateConverter());
+        register(Time.class, new SqlTimeConverter());
+        register(Timestamp.class, new SqlTimestampConverter());
+        register(File.class, new FileConverter());
+        register(URL.class, new URLConverter());
+
+    }
+
+    /** strictly for convenience since it has same parameter order as Map.put */
+    private void register(Class clazz, Converter converter) {
+        register(converter, clazz);
+    }
+
+    /**
+     * Remove any registered {@link Converter} for the specified destination
+     * <code>Class</code>.
+     *
+     * @param clazz Class for which to remove a registered Converter
+     */
+    public void deregister(Class clazz) {
+
+        converters.remove(clazz);
+
+    }
+
+
+    /**
+     * Look up and return any registered {@link Converter} for the specified
+     * destination class; if there is no registered Converter, return
+     * <code>null</code>.
+     *
+     * @param clazz Class for which to return a registered Converter
+     */
+    public Converter lookup(Class clazz) {
+
+        return ((Converter) converters.get(clazz));
+
+    }
+
+
+    /**
+     * Register a custom {@link Converter} for the specified destination
+     * <code>Class</code>, replacing any previously registered Converter.
+     *
+     * @param converter Converter to be registered
+     * @param clazz Destination class for conversions performed by this
+     *  Converter
+     */
+    public void register(Converter converter, Class clazz) {
+
+        converters.put(clazz, converter);
+
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/Converter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/Converter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/Converter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * <p>General purpose data type converter that can be registered and used
+ * within the BeanUtils package to manage the conversion of objects from
+ * one type to another.
+ *
+ * @author Craig McClanahan
+ * @author Paulo Gaspar
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:33 $
+ * @since 1.3
+ */
+
+public interface Converter {
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value);
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertingWrapDynaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertingWrapDynaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ConvertingWrapDynaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * <p>Implementation of <code>DynaBean</code> that wraps a standard JavaBean
+ * instance, so that DynaBean APIs can be used to access its properties,
+ * though this implementation allows type conversion to occur when properties are set.
+ * This means that (say) Strings can be passed in as values in setter methods and
+ * this DynaBean will convert them to the correct primitive data types.</p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does not
+ * support the <code>contains()</code> and <code>remove()</code> methods.</p>
+ *
+ * @author James Strachan
+ * @version $Revision: 1.3 $ $Date: 2002/01/23 22:35:58 $
+ */
+
+public class ConvertingWrapDynaBean extends WrapDynaBean {
+
+
+
+    /**
+     * Construct a new <code>DynaBean</code> associated with the specified
+     * JavaBean instance.
+     *
+     * @param instance JavaBean instance to be wrapped
+     */
+    public ConvertingWrapDynaBean(Object instance) {
+
+        super(instance);
+
+    }
+
+
+    /**
+     * Set the value of the property with the specified name
+     * performing any type conversions if necessary. So this method
+     * can accept String values for primitive numeric data types for example.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception NullPointerException if an attempt is made to set a
+     *  primitive property to null
+     */
+    public void set(String name, Object value) {
+
+        try {
+            BeanUtils.copyProperty(instance, name, value);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no write method");
+        }
+
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * <p>A <strong>DynaBean</strong> is a Java object that supports properties
+ * whose names and data types, as well as values, may be dynamically modified.
+ * To the maximum degree feasible, other components of the BeanUtils package
+ * will recognize such beans and treat them as standard JavaBeans for the
+ * purpose of retrieving and setting property values.</p>
+ *
+ * @author Craig McClanahan
+ * @author Paulo Gaspar
+ * @version $Revision: 1.9 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public interface DynaBean {
+
+
+    /**
+     * Does the specified mapped property contain a value for the specified
+     * key value?
+     *
+     * @param name Name of the property to check
+     * @param key Name of the key to check
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public boolean contains(String name, String key);
+
+
+    /**
+     * Return the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public Object get(String name);
+
+
+    /**
+     * Return the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param index Index of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     * @exception NullPointerException if no array or List has been
+     *  initialized for this property
+     */
+    public Object get(String name, int index);
+
+
+    /**
+     * Return the value of a mapped property with the specified name,
+     * or <code>null</code> if there is no value for the specified key.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param key Key of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public Object get(String name, String key);
+
+
+    /**
+     * Return the <code>DynaClass</code> instance that describes the set of
+     * properties available for this DynaBean.
+     */
+    public DynaClass getDynaClass();
+
+
+    /**
+     * Remove any existing value for the specified key on the
+     * specified mapped property.
+     *
+     * @param name Name of the property for which a value is to
+     *  be removed
+     * @param key Key of the value to be removed
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public void remove(String name, String key);
+
+
+    /**
+     * Set the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception NullPointerException if an attempt is made to set a
+     *  primitive property to null
+     */
+    public void set(String name, Object value);
+
+
+    /**
+     * Set the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param index Index of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     */
+    public void set(String name, int index, Object value);
+
+
+    /**
+     * Set the value of a mapped property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param key Key of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public void set(String name, String key, Object value);
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+
+
+
+/**
+ * <p>A <strong>DynaClass</strong> is a simulation of the functionality of
+ * <code>java.lang.Class</code> for classes implementing the
+ * <code>DynaBean</code> interface.  DynaBean instances that share the same
+ * DynaClass all have the same set of available properties, along with any
+ * associated data types, read-only states, and write-only states.</p>
+ *
+ * @author Craig McClanahan
+ * @author Michael Smith
+ * @author Paulo Gaspar
+ * @version $Revision: 1.12 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public interface DynaClass {
+
+
+    /**
+     * Return the name of this DynaClass (analogous to the
+     * <code>getName()</code> method of <code>java.lang.Class</code), which
+     * allows the same <code>DynaClass</code> implementation class to support
+     * different dynamic classes, with different sets of properties.
+     */
+    public String getName();
+
+
+    /**
+     * Return a property descriptor for the specified property, if it exists;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the dynamic property for which a descriptor
+     *  is requested
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public DynaProperty getDynaProperty(String name);
+
+
+    /**
+     * <p>Return an array of <code>ProperyDescriptors</code> for the properties
+     * currently defined in this DynaClass.  If no properties are defined, a
+     * zero-length array will be returned.</p>
+     *
+     * <p><strong>FIXME</strong> - Should we really be implementing
+     * <code>getBeanInfo()</code> instead, which returns property descriptors
+     * and a bunch of other stuff?</p>
+     */
+    public DynaProperty[] getDynaProperties();
+
+
+    /**
+     * Instantiate and return a new DynaBean instance, associated
+     * with this DynaClass.
+     *
+     * @exception IllegalAccessException if the Class or the appropriate
+     *  constructor is not accessible
+     * @exception InstantiationException if this Class represents an abstract
+     *  class, an array class, a primitive type, or void; or if instantiation
+     *  fails for some other reason
+     */
+    public DynaBean newInstance()
+            throws IllegalAccessException, InstantiationException;
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaProperty.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaProperty.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/DynaProperty.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.StreamCorruptedException;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>The metadata describing an individual property of a DynaBean.</p>
+ *
+ * <p>The meta contains an <em>optional</em> content type property ({@link #getContentType})
+ * for use by mapped and iterated properties. 
+ * A mapped or iterated property may choose to indicate the type it expects.
+ * The DynaBean implementation may choose to enforce this type on its entries.
+ * Alternatively, an implementatin may choose to ignore this property.
+ * All keys for maps must be of type String so no meta data is needed for map keys.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.13 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public class DynaProperty implements Serializable {
+
+    // ----------------------------------------------------------- Constants
+    
+    /*
+     * There are issues with serializing primitive class types on certain JVM versions
+     * (including java 1.3).
+     * This class uses a custom serialization implementation that writes an integer
+     * for these primitive class.
+     * This list of constants are the ones used in serialization.
+     * If these values are changed, then older versions will no longer be read correctly
+     */
+    private static final int BOOLEAN_TYPE = 1;
+    private static final int BYTE_TYPE = 2;
+    private static final int CHAR_TYPE = 3;
+    private static final int DOUBLE_TYPE = 4;
+    private static final int FLOAT_TYPE = 5;
+    private static final int INT_TYPE = 6;
+    private static final int LONG_TYPE = 7;
+    private static final int SHORT_TYPE = 8;
+    
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a property that accepts any data type.
+     *
+     * @param name Name of the property being described
+     */
+    public DynaProperty(String name) {
+
+        this(name, Object.class);
+
+    }
+
+
+    /**
+     * Construct a property of the specified data type.
+     *
+     * @param name Name of the property being described
+     * @param type Java class representing the property data type
+     */
+    public DynaProperty(String name, Class type) {
+
+        super();
+        this.name = name;
+        this.type = type;
+
+    }
+    
+    /**
+     * Construct an indexed or mapped <code>DynaProperty</code> that supports (pseudo)-introspection
+     * of the content type.
+     *
+     * @param name Name of the property being described
+     * @param type Java class representing the property data type
+     * @param contentType Class that all indexed or mapped elements are instances of
+     */
+    public DynaProperty(String name, Class type, Class contentType) {
+
+        super();
+        this.name = name;
+        this.type = type;
+        this.contentType = contentType;
+        
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    /** Property name */
+    protected String name = null;
+    /**
+     * Get the name of this property.
+     */
+    public String getName() {
+        return (this.name);
+    }
+    
+    /** Property type */
+    protected transient Class type = null;
+    /**
+     * <p>Gets the Java class representing the data type of the underlying property
+     * values.</p>
+     * 
+     * <p>There are issues with serializing primitive class types on certain JVM versions
+     * (including java 1.3).
+     * Therefore, this field <strong>must not be serialized using the standard methods</strong>.</p>
+     * 
+     * <p><strong>Please leave this field as <code>transient</code></strong></p>
+     */
+    public Class getType() {
+        return (this.type);
+    }
+    
+    
+    /** The <em>(optional)</em> type of content elements for indexed <code>DynaProperty</code> */
+    protected transient Class contentType;
+    /**
+     * Gets the <em>(optional)</em> type of the indexed content for <code>DynaProperty</code>'s
+     * that support this feature.
+     *
+     * <p>There are issues with serializing primitive class types on certain JVM versions
+     * (including java 1.3).
+     * Therefore, this field <strong>must not be serialized using the standard methods</strong>.</p>
+     *
+     * @return the Class for the content type if this is an indexed <code>DynaProperty</code> 
+     * and this feature is supported. Otherwise null.
+     */
+    public Class getContentType() {
+        return contentType;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Does this property represent an indexed value (ie an array or List)?
+     */
+    public boolean isIndexed() {
+
+        if (type == null) {
+            return (false);
+        } else if (type.isArray()) {
+            return (true);
+        } else if (List.class.isAssignableFrom(type)) {
+            return (true);
+        } else {
+            return (false);
+        }
+
+    }
+
+
+    /**
+     * Does this property represent a mapped value (ie a Map)?
+     */
+    public boolean isMapped() {
+
+        if (type == null) {
+            return (false);
+        } else {
+            return (Map.class.isAssignableFrom(type));
+        }
+
+    }
+
+
+    /**
+     * Return a String representation of this Object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("DynaProperty[name=");
+        sb.append(this.name);
+        sb.append(",type=");
+        sb.append(this.type);
+        if (isMapped() || isIndexed()) {
+            sb.append(" <").append(this.contentType).append(">");
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    // --------------------------------------------------------- Serialization helper methods
+    
+    /**
+     * Writes this object safely.
+     * There are issues with serializing primitive class types on certain JVM versions
+     * (including java 1.3).
+     * This method provides a workaround.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        
+        writeAnyClass(this.type,out);
+        
+        if (isMapped() || isIndexed()) {
+            writeAnyClass(this.contentType,out);
+        }
+        
+        // write out other values
+        out.defaultWriteObject();
+    }
+
+    /**
+     * Write a class using safe encoding to workaround java 1.3 serialization bug.
+     */
+    private void writeAnyClass(Class clazz, ObjectOutputStream out) throws IOException {
+        // safely write out any class
+        int primitiveType = 0;
+        if (Boolean.TYPE.equals(clazz)) {
+            primitiveType = BOOLEAN_TYPE;
+        } else if (Byte.TYPE.equals(clazz)) {
+            primitiveType = BYTE_TYPE;
+        } else if (Character.TYPE.equals(clazz)) {
+            primitiveType = CHAR_TYPE;
+        } else if (Double.TYPE.equals(clazz)) {
+            primitiveType = DOUBLE_TYPE;
+        } else if (Float.TYPE.equals(clazz)) {
+            primitiveType = FLOAT_TYPE;
+        } else if (Integer.TYPE.equals(clazz)) {
+            primitiveType = INT_TYPE;
+        } else if (Long.TYPE.equals(clazz)) {
+            primitiveType = LONG_TYPE;
+        } else if (Short.TYPE.equals(clazz)) {
+            primitiveType = SHORT_TYPE;
+        }	
+        
+        if (primitiveType == 0) {
+            // then it's not a primitive type
+            out.writeBoolean(false);
+            out.writeObject(clazz);
+        } else {
+            // we'll write out a constant instead
+            out.writeBoolean(true);
+            out.writeInt(primitiveType);
+        }
+    }
+    
+    /**
+     * Reads field values for this object safely.
+     * There are issues with serializing primitive class types on certain JVM versions
+     * (including java 1.3).
+     * This method provides a workaround.
+     *
+     * @throws StreamCorruptedException when the stream data values are outside expected range 
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        
+        this.type = readAnyClass(in);
+        
+        if (isMapped() || isIndexed()) {
+            this.contentType = readAnyClass(in);
+        }
+        
+        // read other values
+        in.defaultReadObject();
+    }
+    
+
+    /**
+     * Reads a class using safe encoding to workaround java 1.3 serialization bug.
+     */
+    private Class readAnyClass(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        // read back type class safely 
+        if (in.readBoolean()) {
+            // it's a type constant
+            switch (in.readInt()) {
+            
+                case BOOLEAN_TYPE: return   Boolean.TYPE;
+                case BYTE_TYPE:    return      Byte.TYPE;
+                case CHAR_TYPE:    return Character.TYPE;
+                case DOUBLE_TYPE:  return    Double.TYPE;
+                case FLOAT_TYPE:   return     Float.TYPE;
+                case INT_TYPE:     return   Integer.TYPE;
+                case LONG_TYPE:    return      Long.TYPE;
+                case SHORT_TYPE:   return     Short.TYPE;
+                default:
+                    // something's gone wrong
+                    throw new StreamCorruptedException(
+                        "Invalid primitive type. "
+                        + "Check version of beanutils used to serialize is compatible.");
+
+            }
+              
+        } else {
+            // it's another class
+            return ((Class) in.readObject());
+        }
+    }
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/JDBCDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/JDBCDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/JDBCDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>Provides common logic for JDBC implementations of {@link DynaClass}.</p>
+ *
+ * @author   Craig R. McClanahan
+ * @author   George Franciscus
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+abstract class JDBCDynaClass implements DynaClass, Serializable {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * <p>Flag defining whether column names should be lower cased when
+     * converted to property names.</p>
+     */
+    protected boolean lowerCase = true;
+
+    /**
+     * <p>The set of dynamic properties that are part of this
+     * {@link DynaClass}.</p>
+     */
+    protected DynaProperty properties[] = null;
+
+    /**
+     * <p>The set of dynamic properties that are part of this
+     * {@link DynaClass}, keyed by the property name.  Individual descriptor
+     * instances will be the same instances as those in the
+     * <code>properties</code> list.</p>
+     */
+    protected Map propertiesMap = new HashMap();
+
+    // ------------------------------------------------------ DynaClass Methods
+
+    /**
+     * <p>Return the name of this DynaClass (analogous to the
+     * <code>getName()</code> method of <code>java.lang.Class</code), which
+     * allows the same <code>DynaClass</code> implementation class to support
+     * different dynamic classes, with different sets of properties.</p>
+     */
+    public String getName() {
+
+        return (this.getClass().getName());
+
+    }
+
+    /**
+     * <p>Return a property descriptor for the specified property, if it
+     * exists; otherwise, return <code>null</code>.</p>
+     *
+     * @param name Name of the dynamic property for which a descriptor
+     *  is requested
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public DynaProperty getDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("No property name specified");
+        }
+        return ((DynaProperty) propertiesMap.get(name));
+
+    }
+
+    /**
+     * <p>Return an array of <code>ProperyDescriptors</code> for the properties
+     * currently defined in this DynaClass.  If no properties are defined, a
+     * zero-length array will be returned.</p>
+     */
+    public DynaProperty[] getDynaProperties() {
+
+        return (properties);
+
+    }
+
+    /**
+     * <p>Instantiate and return a new DynaBean instance, associated
+     * with this DynaClass.  <strong>NOTE</strong> - This operation is not
+     * supported, and throws an exception.</p>
+     *
+     * @exception IllegalAccessException if the Class or the appropriate
+     *  constructor is not accessible
+     * @exception InstantiationException if this Class represents an abstract
+     *  class, an array class, a primitive type, or void; or if instantiation
+     *  fails for some other reason
+     */
+    public DynaBean newInstance()
+            throws IllegalAccessException, InstantiationException {
+
+        throw new UnsupportedOperationException("newInstance() not supported");
+
+    }
+
+    /**
+     * <p>Loads and returns the <code>Class</code> of the given name.
+     * By default, a load from the thread context class loader is attempted.
+     * If there is no such class loader, the class loader used to load this
+     * class will be utilized.</p>
+     *
+     * @exception SQLException if an exception was thrown trying to load
+     *  the specified class
+     */
+    protected Class loadClass(String className) throws SQLException {
+
+        try {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            if (cl == null) {
+                    cl = this.getClass().getClassLoader();
+            }
+            return (cl.loadClass(className));
+        } catch (Exception e) {
+            throw new SQLException(
+                    "Cannot load column class '" + className + "': " + e);
+        }
+
+    }
+
+    /**
+     * <p>Factory method to create a new DynaProperty for the given index
+     * into the result set metadata.</p>
+     * 
+     * @param metadata is the result set metadata
+     * @param i is the column index in the metadata
+     * @return the newly created DynaProperty instance
+     */
+    protected DynaProperty createDynaProperty(
+                                    ResultSetMetaData metadata,
+                                    int i)
+                                    throws SQLException {
+
+        String name = null;
+        if (lowerCase) {
+            name = metadata.getColumnName(i).toLowerCase();
+        } else {
+            name = metadata.getColumnName(i);
+        }
+        String className = null;
+        try {
+            className = metadata.getColumnClassName(i);
+        } catch (SQLException e) {
+            // this is a patch for HsqlDb to ignore exceptions
+            // thrown by its metadata implementation
+        }
+
+        // Default to Object type if no class name could be retrieved
+        // from the metadata
+        Class clazz = Object.class;
+        if (className != null) {
+            clazz = loadClass(className);
+        }
+        return new DynaProperty(name, clazz);
+
+    }
+
+    /**
+     * <p>Introspect the metadata associated with our result set, and populate
+     * the <code>properties</code> and <code>propertiesMap</code> instance
+     * variables.</p>
+     *
+     * @param resultSet The <code>resultSet</code> whose metadata is to
+     *  be introspected
+     *
+     * @exception SQLException if an error is encountered processing the
+     *  result set metadata
+     */
+    protected void introspect(ResultSet resultSet) throws SQLException {
+
+        // Accumulate an ordered list of DynaProperties
+        ArrayList list = new ArrayList();
+        ResultSetMetaData metadata = resultSet.getMetaData();
+        int n = metadata.getColumnCount();
+        for (int i = 1; i <= n; i++) { // JDBC is one-relative!
+            DynaProperty dynaProperty = createDynaProperty(metadata, i);
+            if (dynaProperty != null) {
+                    list.add(dynaProperty);
+            }
+        }
+
+        // Convert this list into the internal data structures we need
+        properties =
+            (DynaProperty[]) list.toArray(new DynaProperty[list.size()]);
+        for (int i = 0; i < properties.length; i++) {
+            propertiesMap.put(properties[i].getName(), properties[i]);
+        }
+
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,836 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Date;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.io.Serializable;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>DynaBean which automatically adds properties to the <code>DynaClass</code>
+ *   and provides <i>Lazy List</i> and <i>Lazy Map</i> features.</p>
+ *
+ * <p>DynaBeans deal with three types of properties - <i>simple</i>, <i>indexed</i> and <i>mapped</i> and
+ *    have the following <code>get()</code> and <code>set()</code> methods for
+ *    each of these types:</p>
+ *    <ul>
+ *        <li><i>Simple</i> property methods - <code>get(name)</code> and <code>set(name, value)</code></li>
+ *        <li><i>Indexed</i> property methods - <code>get(name, index)</code> and <code>set(name, index, value)</code></li>
+ *        <li><i>Mapped</i> property methods - <code>get(name, key)</code> and <code>set(name, key, value)</code></li>
+ *    </ul>
+ *
+ * <p><b><u>Getting Property Values</u></b></p>
+ * <p>Calling any of the <code>get()</code> methods, for a property which
+ *    doesn't exist, returns <code>null</code> in this implementation.</p>
+ *
+ * <p><b><u>Setting Simple Properties</u></b></p>
+ *    <p>The <code>LazyDynaBean</code> will automatically add a property to the <code>DynaClass</code>
+ *       if it doesn't exist when the <code>set(name, value)</code> method is called.</p>
+ *
+ *     <code>DynaBean myBean = new LazyDynaBean();</code></br>
+ *     <code>myBean.set("myProperty", "myValue");</code></br>
+ *
+ * <p><b><u>Setting Indexed Properties</u></b></p>
+ *    <p>If the property <b>doesn't</b> exist, the <code>LazyDynaBean</code> will automatically add
+ *       a property with an <code>ArrayList</code> type to the <code>DynaClass</code> when
+ *       the <code>set(name, index, value)</code> method is called.
+ *       It will also instantiate a new <code>ArrayList</code> and automatically <i>grow</i>
+ *       the <code>List</code> so that it is big enough to accomodate the index being set.
+ *       <code>ArrayList</code> is the default indexed property that LazyDynaBean uses but
+ *       this can be easily changed by overriding the <code>newIndexedProperty(name)</code>
+ *       method.</p>
+ *
+ *     <code>DynaBean myBean = new LazyDynaBean();</code></br>
+ *     <code>myBean.set("myIndexedProperty", 0, "myValue1");</code></br>
+ *     <code>myBean.set("myIndexedProperty", 1, "myValue2");</code></br>
+ *
+ *    <p>If the indexed property <b>does</b> exist in the <code>DynaClass</code> but is set to
+ *      <code>null</code> in the <code>LazyDynaBean</code>, then it will instantiate a
+ *      new <code>List</code> or <code>Array</code> as specified by the property's type
+ *      in the <code>DynaClass</code> and automatically <i>grow</i> the <code>List</code>
+ *      or <code>Array</code> so that it is big enough to accomodate the index being set.</p>
+ *
+ *     <code>DynaBean myBean = new LazyDynaBean();</code></br>
+ *     <code>MutableDynaClass myClass = (MutableDynaClass)myBean.getDynaClass();</code></br>
+ *     <code>myClass.add("myIndexedProperty", int[].class);</code></br>
+ *     <code>myBean.set("myIndexedProperty", 0, new Integer(10));</code></br>
+ *     <code>myBean.set("myIndexedProperty", 1, new Integer(20));</code></br>
+ *
+ * <p><b><u>Setting Mapped Properties</u></b></p>
+ *    <p>If the property <b>doesn't</b> exist, the <code>LazyDynaBean</code> will automatically add
+ *       a property with a <code>HashMap</code> type to the <code>DynaClass</code> and
+ *       instantiate a new <code>HashMap</code> in the DynaBean when the
+ *       <code>set(name, key, value)</code> method is called. <code>HashMap</code> is the default
+ *       mapped property that LazyDynaBean uses but this can be easily changed by overriding
+ *       the <code>newMappedProperty(name)</code> method.</p>
+ *
+ *     <code>DynaBean myBean = new LazyDynaBean();</code></br>
+ *     <code>myBean.set("myMappedProperty", "myKey", "myValue");</code></br>
+ *
+ *    <p>If the mapped property <b>does</b> exist in the <code>DynaClass</code> but is set to
+ *      <code>null</code> in the <code>LazyDynaBean</code>, then it will instantiate a
+ *      new <code>Map</code> as specified by the property's type in the <code>DynaClass</code>.</p>
+ *
+ *     <code>DynaBean myBean = new LazyDynaBean();</code></br>
+ *     <code>MutableDynaClass myClass = (MutableDynaClass)myBean.getDynaClass();</code></br>
+ *     <code>myClass.add("myMappedProperty", TreeMap.class);</code></br>
+ *     <code>myBean.set("myMappedProperty", "myKey", "myValue");</code></br>
+ *
+ * <p><b><u><i>Restricted</i> DynaClass</u></b></p>
+ *    <p><code>MutableDynaClass</code> have a facility to <i>restrict</i> the <code>DynaClass</code>
+ *       so that its properties cannot be modified. If the <code>MutableDynaClass</code> is
+ *       restricted then calling any of the <code>set()</code> methods for a property which
+ *       doesn't exist will result in a <code>IllegalArgumentException</code> being thrown.</p>
+ *
+ * @see LazyDynaClass
+ * @author Niall Pemberton
+ */
+public class LazyDynaBean implements DynaBean, Serializable {
+
+
+   /**
+    * Commons Logging
+    */
+    private static Log logger = LogFactory.getLog(LazyDynaBean.class);
+
+    protected static final BigInteger BigInteger_ZERO = new BigInteger("0");
+    protected static final BigDecimal BigDecimal_ZERO = new BigDecimal("0");
+    protected static final Character  Character_SPACE = new Character(' ');
+    protected static final Byte       Byte_ZERO       = new Byte((byte)0);
+    protected static final Short      Short_ZERO      = new Short((short)0);
+    protected static final Integer    Integer_ZERO    = new Integer(0);
+    protected static final Long       Long_ZERO       = new Long((long)0);
+    protected static final Float      Float_ZERO      = new Float((byte)0);
+    protected static final Double     Double_ZERO     = new Double((byte)0);
+
+    /**
+     * The <code>MutableDynaClass</code> "base class" that this DynaBean
+     * is associated with.
+     */
+    protected Map values;
+
+    /**
+     * The <code>MutableDynaClass</code> "base class" that this DynaBean
+     * is associated with.
+     */
+    protected MutableDynaClass dynaClass;
+
+
+    // ------------------- Constructors ----------------------------------
+
+    /**
+     * Construct a new <code>LazyDynaBean</code> with a <code>LazyDynaClass</code> instance.
+     */
+    public LazyDynaBean() {
+        this(new LazyDynaClass());
+    }
+
+    /**
+     * Construct a new <code>LazyDynaBean</code> with a <code>LazyDynaClass</code> instance.
+     *
+     * @param name Name of this DynaBean class
+     */
+    public LazyDynaBean(String name) {
+        this(new LazyDynaClass(name));
+    }
+
+    /**
+     * Construct a new <code>DynaBean</code> associated with the specified
+     * <code>DynaClass</code> instance - if its not a <code>MutableDynaClass</code>
+     * then a new <code>LazyDynaClass</code> is created and the properties copied.
+     *
+     * @param dynaClass The DynaClass we are associated with
+     */
+    public LazyDynaBean(DynaClass dynaClass) {
+
+        values = newMap();
+
+        if (dynaClass instanceof MutableDynaClass) {
+            this.dynaClass = (MutableDynaClass)dynaClass;
+        } else {
+            this.dynaClass = new LazyDynaClass(dynaClass.getName(), dynaClass.getDynaProperties());
+        }
+
+    }
+
+
+    // ------------------- Public Methods ----------------------------------
+
+    /**
+     * Return the Map backing this <code>DynaBean</code>
+     */
+    public Map getMap() {
+        return values;
+    }
+
+    /**
+     * <p>Return the size of an indexed or mapped property.</p>
+     *
+     * @param name Name of the property
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public int size(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("No property name specified");
+        }
+
+        Object value = values.get(name);
+        if (value == null) {
+            return 0;
+        }
+
+        if (value instanceof Map) {
+            return ((Map)value).size();
+        }
+
+        if (value instanceof List) {
+            return ((List)value).size();
+        }
+
+        if ((value.getClass().isArray())) {
+            return Array.getLength(value);
+        }
+
+        return 0;
+
+    }
+
+    // ------------------- DynaBean Methods ----------------------------------
+
+    /**
+     * Does the specified mapped property contain a value for the specified
+     * key value?
+     *
+     * @param name Name of the property to check
+     * @param key Name of the key to check
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public boolean contains(String name, String key) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("No property name specified");
+        }
+
+        Object value = values.get(name);
+        if (value == null) {
+            return false;
+        }
+
+        if (value instanceof Map) {
+            return (((Map) value).containsKey(key));
+        }
+
+        return false;
+
+    }
+
+    /**
+     * <p>Return the value of a simple property with the specified name.</p>
+     *
+     * <p><strong>N.B.</strong> Returns <code>null</code> if there is no property
+     *  of the specified name.</p>
+     *
+     * @param name Name of the property whose value is to be retrieved.
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public Object get(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("No property name specified");
+        }
+
+        // Value found
+        Object value = values.get(name);
+        if (value != null) {
+            return value;
+        }
+
+        // Property doesn't exist
+        if (!isDynaProperty(name)) {
+            return null;
+        }
+
+        // Property doesn't exist
+        value = createProperty(name, dynaClass.getDynaProperty(name).getType());
+
+        if (value != null) {
+            set(name, value);
+        }
+
+        return value;
+
+    }
+
+    /**
+     * <p>Return the value of an indexed property with the specified name.</p>
+     *
+     * <p><strong>N.B.</strong> Returns <code>null</code> if there is no 'indexed'
+     * property of the specified name.</p>
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param index Index of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     */
+    public Object get(String name, int index) {
+
+        // If its not a property, then create default indexed property
+        if (!isDynaProperty(name)) {
+            set(name, defaultIndexedProperty(name));
+        }
+
+        // Get the indexed property
+        Object indexedProperty = get(name);
+
+        // Check that the property is indexed
+        if (!dynaClass.getDynaProperty(name).isIndexed()) {
+            throw new IllegalArgumentException
+                ("Non-indexed property for '" + name + "[" + index + "]' "
+                                      + dynaClass.getDynaProperty(name).getName());
+        }
+
+        // Grow indexed property to appropriate size
+        indexedProperty = growIndexedProperty(name, indexedProperty, index);
+
+        // Return the indexed value
+        if (indexedProperty.getClass().isArray()) {
+            return Array.get(indexedProperty, index);
+        } else if (indexedProperty instanceof List) {
+            return ((List)indexedProperty).get(index);
+        } else {
+            throw new IllegalArgumentException
+                ("Non-indexed property for '" + name + "[" + index + "]' "
+                                  + indexedProperty.getClass().getName());
+        }
+
+    }
+
+    /**
+     * <p>Return the value of a mapped property with the specified name.</p>
+     *
+     * <p><strong>N.B.</strong> Returns <code>null</code> if there is no 'mapped'
+     * property of the specified name.</p>
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param key Key of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public Object get(String name, String key) {
+
+        // If its not a property, then create default mapped property
+        if (!isDynaProperty(name)) {
+            set(name, defaultMappedProperty(name));
+        }
+
+        // Get the mapped property
+        Object mappedProperty = get(name);
+
+        // Check that the property is mapped
+        if (!dynaClass.getDynaProperty(name).isMapped()) {
+            throw new IllegalArgumentException
+                ("Non-mapped property for '" + name + "(" + key + ")' "
+                            + dynaClass.getDynaProperty(name).getType().getName());
+        }
+
+        // Get the value from the Map
+        if (mappedProperty instanceof Map) {
+            return (((Map) mappedProperty).get(key));
+        } else {
+            throw new IllegalArgumentException
+              ("Non-mapped property for '" + name + "(" + key + ")'"
+                                  + mappedProperty.getClass().getName());
+        }
+
+    }
+
+
+    /**
+     * Return the <code>DynaClass</code> instance that describes the set of
+     * properties available for this DynaBean.
+     */
+    public DynaClass getDynaClass() {
+        return (DynaClass)dynaClass;
+    }
+
+    /**
+     * Remove any existing value for the specified key on the
+     * specified mapped property.
+     *
+     * @param name Name of the property for which a value is to
+     *  be removed
+     * @param key Key of the value to be removed
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public void remove(String name, String key) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("No property name specified");
+        }
+
+        Object value = values.get(name);
+        if (value == null) {
+            return;
+        }
+
+        if (value instanceof Map) {
+            ((Map) value).remove(key);
+        } else {
+            throw new IllegalArgumentException
+                    ("Non-mapped property for '" + name + "(" + key + ")'"
+                            + value.getClass().getName());
+        }
+
+    }
+
+    /**
+     * Set the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception IllegalArgumentException if this is not an existing property
+     *  name for our DynaClass and the MutableDynaClass is restricted
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception NullPointerException if an attempt is made to set a
+     *  primitive property to null
+     */
+    public void set(String name, Object value) {
+
+        // If the property doesn't exist, then add it
+        if (!isDynaProperty(name)) {
+
+            if (dynaClass.isRestricted()) {
+                throw new IllegalArgumentException
+                    ("Invalid property name '" + name + "' (DynaClass is restricted)");
+            }
+            if (value == null) {
+                dynaClass.add(name);
+            } else {
+                dynaClass.add(name, value.getClass());
+            }
+
+        }
+
+        DynaProperty descriptor = dynaClass.getDynaProperty(name);
+
+        if (value == null) {
+            if (descriptor.getType().isPrimitive()) {
+                throw new NullPointerException
+                        ("Primitive value for '" + name + "'");
+            }
+        } else if (!isAssignable(descriptor.getType(), value.getClass())) {
+            throw new ConversionException
+                    ("Cannot assign value of type '" +
+                    value.getClass().getName() +
+                    "' to property '" + name + "' of type '" +
+                    descriptor.getType().getName() + "'");
+        }
+
+        // Set the property's value
+        values.put(name, value);
+
+    }
+
+    /**
+     * Set the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param index Index of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     */
+    public void set(String name, int index, Object value) {
+
+        // If its not a property, then create default indexed property
+        if (!isDynaProperty(name)) {
+            set(name, defaultIndexedProperty(name));
+        }
+
+        // Get the indexed property
+        Object indexedProperty = get(name);
+
+        // Check that the property is indexed
+        if (!dynaClass.getDynaProperty(name).isIndexed()) {
+            throw new IllegalArgumentException
+                ("Non-indexed property for '" + name + "[" + index + "]'"
+                            + dynaClass.getDynaProperty(name).getType().getName());
+        }
+
+        // Grow indexed property to appropriate size
+        indexedProperty = growIndexedProperty(name, indexedProperty, index);
+
+        // Set the value in an array
+        if (indexedProperty.getClass().isArray()) {
+            Array.set(indexedProperty, index, value);
+        } else if (indexedProperty instanceof List) {
+            ((List)indexedProperty).set(index, value);
+        } else {
+            throw new IllegalArgumentException
+                ("Non-indexed property for '" + name + "[" + index + "]' "
+                            + indexedProperty.getClass().getName());
+        }
+
+    }
+
+    /**
+     * Set the value of a mapped property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param key Key of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public void set(String name, String key, Object value) {
+
+        // If the 'mapped' property doesn't exist, then add it
+        if (!isDynaProperty(name)) {
+            set(name, defaultMappedProperty(name));
+        }
+
+        // Get the mapped property
+        Object mappedProperty = get(name);
+
+        // Check that the property is mapped
+        if (!dynaClass.getDynaProperty(name).isMapped()) {
+            throw new IllegalArgumentException
+                ("Non-mapped property for '" + name + "(" + key + ")'"
+                            + dynaClass.getDynaProperty(name).getType().getName());
+        }
+
+        // Set the value in the Map
+        ((Map)mappedProperty).put(key, value);
+
+    }
+
+    // ------------------- protected Methods ----------------------------------
+
+    protected Object growIndexedProperty(String name, Object indexedProperty, int index) {
+
+        // Grow a List to the appropriate size
+        if (indexedProperty instanceof List) {
+
+            List list = (List)indexedProperty;
+            while (index >= list.size()) {
+                list.add(null);
+            }
+
+        }
+
+        // Grow an Array to the appropriate size
+        if ((indexedProperty.getClass().isArray())) {
+
+            int length = Array.getLength(indexedProperty);
+            if (index >= length) {
+                Class componentType = indexedProperty.getClass().getComponentType();
+                Object newArray = Array.newInstance(componentType, (index + 1));
+                System.arraycopy(indexedProperty, 0, newArray, 0, length);
+                indexedProperty = newArray;
+                set(name, indexedProperty);
+                int newLength = Array.getLength(indexedProperty);
+                for (int i = length; i < newLength; i++) {
+                    Array.set(indexedProperty, i, createProperty(name+"["+i+"]", componentType));
+                }
+            }
+        }
+
+        return indexedProperty;
+
+    }
+
+    /**
+     * Create a new Instance of a Property
+     */
+    protected Object createProperty(String name, Class type) {
+
+        // Create Lists, arrays or DynaBeans
+        if (type.isArray() || List.class.isAssignableFrom(type)) {
+            return createIndexedProperty(name, type);
+        }
+
+        if (Map.class.isAssignableFrom(type)) {
+            return createMappedProperty(name, type);
+        }
+
+        if (DynaBean.class.isAssignableFrom(type)) {
+            return createDynaBeanProperty(name, type);
+        }
+
+        if (type.isPrimitive()) {
+            return createPrimitiveProperty(name, type);
+        }
+
+        if (Number.class.isAssignableFrom(type)) {
+            return createNumberProperty(name, type);
+        }
+
+        return createOtherProperty(name, type);
+
+    }
+
+    /**
+     * Create a new Instance of an 'Indexed' Property
+     */
+    protected Object createIndexedProperty(String name, Class type) {
+
+        // Create the indexed object
+        Object indexedProperty = null;
+
+        if (type == null) {
+
+            indexedProperty = defaultIndexedProperty(name);
+
+        } else if (type.isArray()) {
+
+            indexedProperty = Array.newInstance(type.getComponentType(), 0);
+
+        } else if (List.class.isAssignableFrom(type)) {
+            if (type.isInterface()) {
+                indexedProperty = defaultIndexedProperty(name);
+            } else {
+                try {
+                    indexedProperty = type.newInstance();
+                }
+                catch (Exception ex) {
+                    throw new IllegalArgumentException
+                        ("Error instantiating indexed property of type '" +
+                                   type.getName() + "' for '" + name + "' " + ex);
+                }
+            }
+        } else {
+
+            throw new IllegalArgumentException
+                    ("Non-indexed property of type '" + type.getName() + "' for '" + name + "'");
+        }
+
+        return indexedProperty;
+
+    }
+
+    /**
+     * Create a new Instance of a 'Mapped' Property
+     */
+    protected Object createMappedProperty(String name, Class type) {
+
+        // Create the mapped object
+        Object mappedProperty = null;
+
+        if (type == null) {
+
+            mappedProperty = defaultMappedProperty(name);
+
+        } else if (type.isInterface()) {
+
+            mappedProperty = defaultMappedProperty(name);
+
+        } else if (Map.class.isAssignableFrom(type)) {
+            try {
+                mappedProperty = type.newInstance();
+            }
+            catch (Exception ex) {
+                throw new IllegalArgumentException
+                    ("Error instantiating mapped property of type '" + type.getName() + "' for '" + name + "' " + ex);
+            }
+        } else {
+
+            throw new IllegalArgumentException
+                    ("Non-mapped property of type '" + type.getName() + "' for '" + name + "'");
+        }
+
+        return mappedProperty;
+
+    }
+
+    /**
+     * Create a new Instance of a 'Mapped' Property
+     */
+    protected Object createDynaBeanProperty(String name, Class type) {
+        try {
+            return type.newInstance();
+        }
+        catch (Exception ex) {
+            if (logger.isWarnEnabled()) {
+                logger.warn("Error instantiating DynaBean property of type '" + type.getName() + "' for '" + name + "' " + ex);
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Create a new Instance of a 'Primitive' Property
+     */
+    protected Object createPrimitiveProperty(String name, Class type) {
+
+        if (type == Boolean.TYPE) {
+            return Boolean.FALSE;
+        } else if (type == Integer.TYPE) {
+            return Integer_ZERO;
+        } else if (type == Long.TYPE) {
+            return Long_ZERO;
+        } else if (type == Double.TYPE) {
+            return Double_ZERO;
+        } else if (type == Float.TYPE) {
+            return Float_ZERO;
+        } else if (type == Byte.TYPE) {
+            return Byte_ZERO;
+        } else if (type == Short.TYPE) {
+            return Short_ZERO;
+        } else if (type == Character.TYPE) {
+            return Character_SPACE;
+        } else {
+            return null;
+        }
+
+    }
+
+    /**
+     * Create a new Instance of a 'Primitive' Property
+     */
+    protected Object createNumberProperty(String name, Class type) {
+
+        return null;
+
+    }
+
+    /**
+     * Create a new Instance of a 'Mapped' Property
+     */
+    protected Object createOtherProperty(String name, Class type) {
+
+        if (type == String.class || type == Boolean.class ||
+            type == Character.class || Date.class.isAssignableFrom(type)) {
+            return null;
+        }
+
+        try {
+            return type.newInstance();
+        }
+        catch (Exception ex) {
+            if (logger.isWarnEnabled()) {
+                logger.warn("Error instantiating property of type '" + type.getName() + "' for '" + name + "' " + ex);
+            }
+            return null;
+        }
+    }
+
+    /**
+     * <p>Creates a new <code>ArrayList</code> for an 'indexed' property
+     *    which doesn't exist.</p>
+     *
+     * <p>This method shouls be overriden if an alternative <code>List</code>
+     *    or <code>Array</code> implementation is required for 'indexed' properties.</p>
+     *
+     * @param name Name of the 'indexed property.
+     */
+    protected Object defaultIndexedProperty(String name) {
+        return new ArrayList();
+    }
+
+    /**
+     * <p>Creates a new <code>HashMap</code> for a 'mapped' property
+     *    which doesn't exist.</p>
+     *
+     * <p>This method can be overriden if an alternative <code>Map</code>
+     *    implementation is required for 'mapped' properties.</p>
+     *
+     * @param name Name of the 'mapped property.
+     */
+    protected Map defaultMappedProperty(String name) {
+        return new HashMap();
+    }
+
+    /**
+     * Indicates if there is a property with the specified name.
+     */
+    protected boolean isDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("No property name specified");
+        }
+
+        // Handle LazyDynaClasses
+        if (dynaClass instanceof LazyDynaClass) {
+            return ((LazyDynaClass)dynaClass).isDynaProperty(name);
+        }
+
+        // Handle other MutableDynaClass
+        return dynaClass.getDynaProperty(name) == null ? false : true;
+
+    }
+
+    /**
+     * Is an object of the source class assignable to the destination class?
+     *
+     * @param dest Destination class
+     * @param source Source class
+     */
+    protected boolean isAssignable(Class dest, Class source) {
+
+        if (dest.isAssignableFrom(source) ||
+                ((dest == Boolean.TYPE) && (source == Boolean.class)) ||
+                ((dest == Byte.TYPE) && (source == Byte.class)) ||
+                ((dest == Character.TYPE) && (source == Character.class)) ||
+                ((dest == Double.TYPE) && (source == Double.class)) ||
+                ((dest == Float.TYPE) && (source == Float.class)) ||
+                ((dest == Integer.TYPE) && (source == Integer.class)) ||
+                ((dest == Long.TYPE) && (source == Long.class)) ||
+                ((dest == Short.TYPE) && (source == Short.class))) {
+            return (true);
+        } else {
+            return (false);
+        }
+
+    }
+
+    /**
+     * <p>Creates a new instance of the <code>Map</code>.</p>
+     */
+    protected Map newMap() {
+        return new HashMap();
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+/**
+ * <p>DynaClass which implements the <code>MutableDynaClass</code> interface.</p>
+ *
+ * <p>A <code>MutableDynaClass</code> is a specialized extension to <code>DynaClass</code>
+ *    that allows properties to be added or removed dynamically.</p>
+ *
+ * <p>This implementation has one slightly unusual default behaviour - calling
+ *    the <code>getDynaProperty(name)</code> method for a property which doesn't
+ *    exist returns a <code>DynaProperty</code> rather than <code>null</code>. The
+ *    reason for this is that <code>BeanUtils</code> calls this method to check if
+ *    a property exists before trying to set the value. This would defeat the object
+ *    of the <code>LazyDynaBean</code> which automatically adds missing properties
+ *    when any of its <code>set()</code> methods are called. For this reason the
+ *    <code>isDynaProperty(name)</code> method has been added to this implementation
+ *    in order to determine if a property actually exists. If the more <i>normal</i>
+ *    behaviour of returning <code>null</code> is required, then this can be achieved
+ *    by calling the <code>setReturnNull(true)</code>.</p>
+ *
+ * <p>The <code>add(name, type, readable, writable)</code> method is not implemented
+ *    and always throws an <code>UnsupportedOperationException</code>. I believe
+ *    this attributes need to be added to the <code>DynaProperty</code> class
+ *    in order to control read/write facilities.</p>
+ *
+ * @see LazyDynaBean
+ * @author Niall Pemberton
+ */
+public class LazyDynaClass extends BasicDynaClass implements MutableDynaClass  {
+
+    /**
+     * Controls whether changes to this DynaClass's properties are allowed.
+     */
+    protected boolean restricted;
+
+    /**
+     * <p>Controls whether the <code>getDynaProperty()</code> method returns
+     * null if a property doesn't exist - or creates a new one.</p>
+     *
+     * <p>Default is <code>false</code>.
+     */
+    protected boolean returnNull = false;
+
+    /**
+     * Construct a new LazyDynaClass with default parameters.
+     */
+    public LazyDynaClass() {
+        this(null, (DynaProperty[])null);
+    }
+
+    /**
+     * Construct a new LazyDynaClass with the specified name.
+     *
+     * @param name Name of this DynaBean class
+     */
+    public LazyDynaClass(String name) {
+        this(name, (DynaProperty[])null);
+    }
+
+    /**
+     * Construct a new LazyDynaClass with the specified name and DynaBean class.
+     *
+     * @param name Name of this DynaBean class
+     * @param dynaBeanClass The implementation class for new instances
+     */
+    public LazyDynaClass(String name, Class dynaBeanClass) {
+        this(name, dynaBeanClass, null);
+    }
+
+    /**
+     * Construct a new LazyDynaClass with the specified name and properties.
+     *
+     * @param name Name of this DynaBean class
+     * @param properties Property descriptors for the supported properties
+     */
+    public LazyDynaClass(String name, DynaProperty[] properties) {
+        this(name, LazyDynaBean.class, properties);
+    }
+
+    /**
+     * Construct a new LazyDynaClass with the specified name, DynaBean class and properties.
+     *
+     * @param name Name of this DynaBean class
+     * @param dynaBeanClass The implementation class for new intances
+     * @param properties Property descriptors for the supported properties
+     */
+    public LazyDynaClass(String name, Class dynaBeanClass, DynaProperty properties[]) {
+        super(name, dynaBeanClass, properties);
+    }
+
+    /**
+     * <p>Is this DynaClass currently restricted.</p>
+     * <p>If restricted, no changes to the existing registration of
+     *  property names, data types, readability, or writeability are allowed.</p>
+     */
+    public boolean isRestricted() {
+        return restricted;
+    }
+
+    /**
+     * <p>Set whether this DynaClass is currently restricted.</p>
+     * <p>If restricted, no changes to the existing registration of
+     *  property names, data types, readability, or writeability are allowed.</p>
+     */
+    public void setRestricted(boolean restricted) {
+        this.restricted = restricted;
+    }
+
+    /**
+     * Should this DynaClass return a <code>null</code> from
+     * the <code>getDynaProperty(name)</code> method if the property
+     * doesn't exist.
+     */
+    public boolean isReturnNull() {
+        return returnNull;
+    }
+
+    /**
+     * Set whether this DynaClass should return a <code>null</code> from
+     * the <code>getDynaProperty(name)</code> method if the property
+     * doesn't exist.
+     */
+    public void setReturnNull(boolean returnNull) {
+        this.returnNull = returnNull;
+    }
+
+    /**
+     * Add a new dynamic property with no restrictions on data type,
+     * readability, or writeability.
+     *
+     * @param name Name of the new dynamic property
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    public void add(String name) {
+        add(new DynaProperty(name));
+    }
+
+    /**
+     * Add a new dynamic property with the specified data type, but with
+     * no restrictions on readability or writeability.
+     *
+     * @param name Name of the new dynamic property
+     * @param type Data type of the new dynamic property (null for no
+     *  restrictions)
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    public void add(String name, Class type) {
+        add(new DynaProperty(name, type));
+    }
+
+    /**
+     * <p>Add a new dynamic property with the specified data type, readability,
+     * and writeability.</p>
+     *
+     * <p><strong>N.B.</strong>Support for readable/writeable properties has not been implemented
+     *    and this method always throws a <code>UnsupportedOperationException</code>.</p>
+     *
+     * <p>I'm not sure the intention of the original authors for this method, but it seems to
+     *    me that readable/writable should be attributes of the <code>DynaProperty</code> class
+     *    (which they are not) and is the reason this method has not been implemented.</p>
+     *
+     * @param name Name of the new dynamic property
+     * @param type Data type of the new dynamic property (null for no
+     *  restrictions)
+     * @param readable Set to <code>true</code> if this property value
+     *  should be readable
+     * @param writeable Set to <code>true</code> if this property value
+     *  should be writeable
+     *
+     * @exception UnsupportedOperationException anytime this method is called
+     */
+    public void add(String name, Class type, boolean readable, boolean writeable) {
+        throw new java.lang.UnsupportedOperationException("readable/writable properties not supported");
+    }
+
+    /**
+     * Add a new dynamic property.
+     *
+     * @param property Property the new dynamic property to add.
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    protected void add(DynaProperty property) {
+
+        if (property.getName() == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        if (isRestricted()) {
+            throw new IllegalStateException("DynaClass is currently restricted. No new properties can be added.");
+        }
+
+        // Check if property already exists
+        if (propertiesMap.get(property.getName()) != null) {
+           return;
+        }
+
+        // Create a new property array with the specified property
+        DynaProperty[] oldProperties = getDynaProperties();
+        DynaProperty[] newProperties = new DynaProperty[oldProperties.length+1];
+        System.arraycopy(oldProperties, 0, newProperties, 0, oldProperties.length);
+        newProperties[oldProperties.length] = property;
+
+       // Update the properties
+       setProperties(newProperties);
+
+    }
+
+    /**
+     * Remove the specified dynamic property, and any associated data type,
+     * readability, and writeability, from this dynamic class.
+     * <strong>NOTE</strong> - This does <strong>NOT</strong> cause any
+     * corresponding property values to be removed from DynaBean instances
+     * associated with this DynaClass.
+     *
+     * @param name Name of the dynamic property to remove
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no properties can be removed
+     */
+    public void remove(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        if (isRestricted()) {
+            throw new IllegalStateException("DynaClass is currently restricted. No properties can be removed.");
+        }
+
+        // Ignore if property doesn't exist
+        if (propertiesMap.get(name) == null) {
+            return;
+        }
+
+
+        // Create a new property array of without the specified property
+        DynaProperty[] oldProperties = getDynaProperties();
+        DynaProperty[] newProperties = new DynaProperty[oldProperties.length-1];
+        int j = 0;
+        for (int i = 0; i < oldProperties.length; i++) {
+            if (!(name.equals(oldProperties[i].getName()))) {
+                newProperties[j] = oldProperties[i];
+                j++;
+            }
+        }
+
+        // Update the properties
+        setProperties(newProperties);
+
+    }
+
+    /**
+     * <p>Return a property descriptor for the specified property.</p>
+     *
+     * <p>If the property is not found and the <code>returnNull</code> indicator is
+     *    <code>true</code>, this method always returns <code>null</code>.</p>
+     *
+     * <p>If the property is not found and the <code>returnNull</code> indicator is
+     *    <code>false</code> a new property descriptor is created and returned (although
+     *    its not actually added to the DynaClass's properties). This is the default
+     *    beahviour.</p>
+     *
+     * <p>The reason for not returning a <code>null</code> property descriptor is that
+     *    <code>BeanUtils</code> uses this method to check if a property exists
+     *    before trying to set it - since these <i>Lazy</i> implementations automatically
+     *    add any new properties when they are set, returning <code>null</code> from
+     *    this method would defeat their purpose.</p>
+     *
+     * @param name Name of the dynamic property for which a descriptor
+     *  is requested
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public DynaProperty getDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        DynaProperty dynaProperty = (DynaProperty)propertiesMap.get(name);
+
+        // If it doesn't exist and returnNull is false
+        // create a new DynaProperty
+        if (dynaProperty == null && !isReturnNull() && !isRestricted()) {
+            dynaProperty = new DynaProperty(name);
+        }
+
+        return dynaProperty;
+
+    }
+
+    /**
+     * <p>Indicate whether a property actually exists.</p>
+     *
+     * <p><strong>N.B.</strong> Using <code>getDynaProperty(name) == null</code>
+     * doesn't work in this implementation because that method might
+     * return a DynaProperty if it doesn't exist (depending on the
+     * <code>returnNull</code> indicator).</p>
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public boolean isDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        return propertiesMap.get(name) ==  null ? false : true;
+
+    }
+
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaMap.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaMap.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/LazyDynaMap.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * <p>Provides a <i>light weight</i> <code>DynaBean</code> facade to a <code>Map</code> with <i>lazy</i> map/list processing.</p>
+ *
+ * <p>Its a <i>light weight</i> <code>DynaBean</code> implementation because there is no
+ *    actual <code>DynaClass</code> associated with this <code>DynaBean</code> - in fact
+ *    it implements the <code>DynaClass</code> interface itself providing <i>pseudo</i> DynaClass
+ *    behaviour from the actual values stored in the <code>Map</code>.</p>
+ *
+ * <p>As well providing rhe standard <code>DynaBean</code> access to the <code>Map</code>'s properties
+ *    this class also provides the usual <i>Lazy</i> behaviour:</p>
+ *    <ul>
+ *       <li>Properties don't need to be pre-defined in a <code>DynaClass</code></li>
+ *       <li>Indexed properties (<code>Lists</code> or <code>Arrays</code>) are automatically instantiated
+ *           and <i>grown</i> so that they are large enough to cater for the index being set.</li>
+ *       <li>Mapped properties are automatically instantiated.</li>
+ *    </ul>
+ *
+ * <p><b><u><i>Restricted</i> DynaClass</u></b></p>
+ *    <p>This class implements the <code>MutableDynaClass</code> interface.
+ *       <code>MutableDynaClass</code> have a facility to <i>restrict</i> the <code>DynaClass</code>
+ *       so that its properties cannot be modified. If the <code>MutableDynaClass</code> is
+ *       restricted then calling any of the <code>set()</code> methods for a property which
+ *       doesn't exist will result in a <code>IllegalArgumentException</code> being thrown.</p>
+ *
+ * @author Niall Pemberton
+ */
+public class LazyDynaMap extends LazyDynaBean implements MutableDynaClass {
+
+    /**
+     * The name of this DynaClass (analogous to the
+     * <code>getName()</code> method of <code>java.lang.Class</code>).
+     */
+    protected String name;
+
+    /**
+     * Controls whether changes to this DynaClass's properties are allowed.
+     */
+    protected boolean restricted;
+
+    /**
+     * <p>Controls whether the <code>getDynaProperty()</code> method returns
+     * null if a property doesn't exist - or creates a new one.</p>
+     *
+     * <p>Default is <code>false</code>.
+     */
+    protected boolean returnNull = false;
+
+
+    // ------------------- Constructors ----------------------------------
+
+    /**
+     * Default Constructor.
+     */
+    public LazyDynaMap() {
+        this(null, (Map)null);
+    }
+
+    /**
+     * Construct a new <code>LazyDynaMap</code> with the specified name.
+     *
+     * @param name Name of this DynaBean class
+     */
+    public LazyDynaMap(String name) {
+        this(name, (Map)null);
+    }
+
+    /**
+     * Construct a new <code>LazyDynaMap</code> with the specified <code>Map</code>.
+     *
+     * @param values The Map backing this <code>LazyDynaMap</code>
+     */
+    public LazyDynaMap(Map values) {
+        this(null, values);
+    }
+
+    /**
+     * Construct a new <code>LazyDynaMap</code> with the specified name and  <code>Map</code>.
+     *
+     * @param name Name of this DynaBean class
+     * @param values The Map backing this <code>LazyDynaMap</code>
+     */
+    public LazyDynaMap(String name, Map values) {
+        this.name      = name   == null ? "LazyDynaMap" : name;
+        this.values    = values == null ? newMap()      : values;
+        this.dynaClass = this;
+    }
+
+    /**
+     * Construct a new <code>LazyDynaMap</code> with the specified properties.
+     *
+     * @param properties Property descriptors for the supported properties
+     */
+    public LazyDynaMap(DynaProperty[] properties) {
+        this(null, properties);
+    }
+
+    /**
+     * Construct a new <code>LazyDynaMap</code> with the specified name and properties.
+     *
+     * @param name Name of this DynaBean class
+     * @param properties Property descriptors for the supported properties
+     */
+    public LazyDynaMap(String name, DynaProperty[] properties) {
+        this(name, (Map)null);
+        if (properties != null) {
+            for (int i = 0; i < properties.length; i++) {
+                add(properties[i]);
+            }
+        }
+    }
+
+    /**
+     * Construct a new <code>LazyDynaMap</code> based on an exisiting DynaClass
+     *
+     * @param dynaClass DynaClass to copy the name and properties from
+     */
+    public LazyDynaMap(DynaClass dynaClass) {
+        this(dynaClass.getName(), dynaClass.getDynaProperties());
+    }
+
+    // ------------------- Public Methods ----------------------------------
+
+    /**
+     * Set the Map backing this <code>DynaBean</code>
+     */
+    public void setMap(Map values) {
+        this.values = values;
+    }
+
+    // ------------------- DynaBean Methods ----------------------------------
+
+    /**
+     * Set the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     */
+    public void set(String name, Object value) {
+
+        if (isRestricted() && !values.containsKey(name)) {
+            throw new IllegalArgumentException
+                    ("Invalid property name '" + name + "' (DynaClass is restricted)");
+        }
+
+        values.put(name, value);
+
+    }
+
+    // ------------------- DynaClass Methods ----------------------------------
+
+    /**
+     * Return the name of this DynaClass (analogous to the
+     * <code>getName()</code> method of <code>java.lang.Class</code)
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+     * <p>Return a property descriptor for the specified property.</p>
+     *
+     * <p>If the property is not found and the <code>returnNull</code> indicator is
+     *    <code>true</code>, this method always returns <code>null</code>.</p>
+     *
+     * <p>If the property is not found and the <code>returnNull</code> indicator is
+     *    <code>false</code> a new property descriptor is created and returned (although
+     *    its not actually added to the DynaClass's properties). This is the default
+     *    beahviour.</p>
+     *
+     * <p>The reason for not returning a <code>null</code> property descriptor is that
+     *    <code>BeanUtils</code> uses this method to check if a property exists
+     *    before trying to set it - since these <i>Map</i> implementations automatically
+     *    add any new properties when they are set, returning <code>null</code> from
+     *    this method would defeat their purpose.</p>
+     *
+     * @param name Name of the dynamic property for which a descriptor
+     *  is requested
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public DynaProperty getDynaProperty(String name) {
+
+        if (name == null)
+            throw new IllegalArgumentException("Property name is missing.");
+
+        // If it doesn't exist and returnNull is false
+        // create a new DynaProperty
+        if (!values.containsKey(name) && isReturnNull()) {
+            return null;
+        }
+
+        Object value = values.get(name);
+
+        if (value == null) {
+            return new DynaProperty(name);
+        } else {
+            return new DynaProperty(name, value.getClass());
+        }
+
+    }
+
+    /**
+     * <p>Return an array of <code>ProperyDescriptors</code> for the properties
+     * currently defined in this DynaClass.  If no properties are defined, a
+     * zero-length array will be returned.</p>
+     *
+     * <p><strong>FIXME</strong> - Should we really be implementing
+     * <code>getBeanInfo()</code> instead, which returns property descriptors
+     * and a bunch of other stuff?</p>
+     */
+    public DynaProperty[] getDynaProperties() {
+
+        int i = 0;
+        DynaProperty[] properties = new DynaProperty[values.size()];
+        Iterator iterator = values.keySet().iterator();
+
+        while (iterator.hasNext()) {
+            String name = (String)iterator.next();
+            Object value = values.get(name);
+            properties[i++] = new DynaProperty(name, value == null ? null : value.getClass());
+        }
+
+        return properties;
+
+    }
+
+    /**
+     * Instantiate and return a new DynaBean instance, associated
+     * with this DynaClass.
+     */
+    public DynaBean newInstance()  {
+        return new LazyDynaMap(this);
+    }
+
+
+    // ------------------- MutableDynaClass Methods ----------------------------------
+
+    /**
+     * <p>Is this DynaClass currently restricted.</p>
+     * <p>If restricted, no changes to the existing registration of
+     *  property names, data types, readability, or writeability are allowed.</p>
+     */
+    public boolean isRestricted() {
+        return restricted;
+    }
+
+    /**
+     * <p>Set whether this DynaClass is currently restricted.</p>
+     * <p>If restricted, no changes to the existing registration of
+     *  property names, data types, readability, or writeability are allowed.</p>
+     */
+    public void setRestricted(boolean restricted) {
+        this.restricted = restricted;
+    }
+
+    /**
+     * Add a new dynamic property with no restrictions on data type,
+     * readability, or writeability.
+     *
+     * @param name Name of the new dynamic property
+     *
+     * @exception IllegalArgumentException if name is null
+     */
+    public void add(String name) {
+        add(name, null);
+    }
+
+    /**
+     * Add a new dynamic property with the specified data type, but with
+     * no restrictions on readability or writeability.
+     *
+     * @param name Name of the new dynamic property
+     * @param type Data type of the new dynamic property (null for no
+     *  restrictions)
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    public void add(String name, Class type) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        if (isRestricted())
+            throw new IllegalStateException("DynaClass is currently restricted. No new properties can be added.");
+
+        Object value = values.get(name);
+
+        // Check if the property already exists
+        if (value == null) {
+            values.put(name, type == null ? null : createProperty(name, type));
+        }
+
+    }
+
+    /**
+     * <p>Add a new dynamic property with the specified data type, readability,
+     * and writeability.</p>
+     *
+     * <p><strong>N.B.</strong>Support for readable/writeable properties has not been implemented
+     *    and this method always throws a <code>UnsupportedOperationException</code>.</p>
+     *
+     * <p>I'm not sure the intention of the original authors for this method, but it seems to
+     *    me that readable/writable should be attributes of the <code>DynaProperty</code> class
+     *    (which they are not) and is the reason this method has not been implemented.</p>
+     *
+     * @param name Name of the new dynamic property
+     * @param type Data type of the new dynamic property (null for no
+     *  restrictions)
+     * @param readable Set to <code>true</code> if this property value
+     *  should be readable
+     * @param writeable Set to <code>true</code> if this property value
+     *  should be writeable
+     *
+     * @exception UnsupportedOperationException anytime this method is called
+     */
+    public void add(String name, Class type, boolean readable, boolean writeable) {
+        throw new java.lang.UnsupportedOperationException("readable/writable properties not supported");
+    }
+
+    /**
+     * Add a new dynamic property.
+     *
+     * @param property Property the new dynamic property to add.
+     *
+     * @exception IllegalArgumentException if name is null
+     */
+    protected void add(DynaProperty property) {
+        add(property.getName(), property.getType());
+    }
+
+    /**
+     * Remove the specified dynamic property, and any associated data type,
+     * readability, and writeability, from this dynamic class.
+     * <strong>NOTE</strong> - This does <strong>NOT</strong> cause any
+     * corresponding property values to be removed from DynaBean instances
+     * associated with this DynaClass.
+     *
+     * @param name Name of the dynamic property to remove
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no properties can be removed
+     */
+    public void remove(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        if (isRestricted()) {
+            throw new IllegalStateException("DynaClass is currently restricted. No properties can be removed.");
+        }
+
+        // Remove, if property doesn't exist
+        if (values.containsKey(name)) {
+            values.remove(name);
+        }
+
+    }
+
+
+    // ------------------- Additional Public Methods ----------------------------------
+
+    /**
+     * Should this DynaClass return a <code>null</code> from
+     * the <code>getDynaProperty(name)</code> method if the property
+     * doesn't exist.
+     */
+    public boolean isReturnNull() {
+        return returnNull;
+    }
+
+    /**
+     * Set whether this DynaClass should return a <code>null</code> from
+     * the <code>getDynaProperty(name)</code> method if the property
+     * doesn't exist.
+     */
+    public void setReturnNull(boolean returnNull) {
+        this.returnNull = returnNull;
+    }
+
+
+    // ------------------- Protected Methods ----------------------------------
+
+   /**
+     * <p>Indicate whether a property actually exists.</p>
+     *
+     * <p><strong>N.B.</strong> Using <code>getDynaProperty(name) == null</code>
+     * doesn't work in this implementation because that method might
+     * return a DynaProperty if it doesn't exist (depending on the
+     * <code>returnNull</code> indicator).</p>
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    protected boolean isDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException("Property name is missing.");
+        }
+
+        return values.containsKey(name);
+
+    }
+
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MappedPropertyDescriptor.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+
+/**
+ * A MappedPropertyDescriptor describes one mapped property.
+ * Mapped properties are multivalued properties like indexed properties
+ * but that are accessed with a String key instead of an index.
+ * Such property values are typically stored in a Map collection.
+ * For this class to work properly, a mapped value must have
+ * getter and setter methods of the form
+ * <p><code>get<strong>Property</strong>(String key)<code> and
+ * <p><code>set&ltProperty&gt(String key, Object value)<code>,
+ * <p>where <code><strong>Property</strong></code> must be replaced
+ * by the name of the property.
+ * @see java.beans.PropertyDescriptor
+ *
+ * @author Rey François
+ * @author Gregor Raýman
+ * @version $Revision: 1.18.2.1 $ $Date: 2004/07/27 21:44:26 $
+ */
+
+
+public class MappedPropertyDescriptor extends PropertyDescriptor {
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The underlying data type of the property we are describing.
+     */
+    private Class mappedPropertyType;
+
+    /**
+     * The reader method for this property (if any).
+     */
+    private Method mappedReadMethod;
+
+    /**
+     * The writer method for this property (if any).
+     */
+    private Method mappedWriteMethod;
+
+    /**
+     * The parameter types array for the reader method signature.
+     */
+    private static final Class[] stringClassArray = new Class[]{String.class};
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Constructs a MappedPropertyDescriptor for a property that follows
+     * the standard Java convention by having getFoo and setFoo
+     * accessor methods, with the addition of a String parameter (the key).
+     * Thus if the argument name is "fred", it will
+     * assume that the writer method is "setFred" and the reader method
+     * is "getFred".  Note that the property name should start with a lower
+     * case character, which will be capitalized in the method names.
+     *
+     * @param propertyName The programmatic name of the property.
+     * @param beanClass The Class object for the target bean.  For
+     *		example sun.beans.OurButton.class.
+     *
+     * @exception IntrospectionException if an exception occurs during
+     *              introspection.
+     */
+    public MappedPropertyDescriptor(String propertyName, Class beanClass)
+            throws IntrospectionException {
+
+        super(propertyName, null, null);
+        
+        if (propertyName == null || propertyName.length() == 0) {
+            throw new IntrospectionException("bad property name: " +
+                    propertyName + " on class: " + beanClass.getClass().getName());
+        }
+
+        setName(propertyName);
+        String base = capitalizePropertyName(propertyName);
+        
+        // Look for mapped read method and matching write method
+        try {
+            mappedReadMethod = findMethod(beanClass, "get" + base, 1,
+                    stringClassArray);
+            Class params[] = { String.class, mappedReadMethod.getReturnType() };
+            mappedWriteMethod = findMethod(beanClass, "set" + base, 2,  params);
+        } catch (IntrospectionException e) {
+            ;
+        }
+        
+        // If there's no read method, then look for just a write method 
+        if (mappedReadMethod == null) {
+            mappedWriteMethod = findMethod(beanClass, "set" + base, 2);
+        }
+
+        if ((mappedReadMethod == null) && (mappedWriteMethod == null)) {
+            throw new IntrospectionException("Property '" + propertyName +
+                    "' not found on " +
+                    beanClass.getName());
+        }
+        
+        findMappedPropertyType();
+    }
+
+
+    /**
+     * This constructor takes the name of a mapped property, and method
+     * names for reading and writing the property.
+     *
+     * @param propertyName The programmatic name of the property.
+     * @param beanClass The Class object for the target bean.  For
+     *		example sun.beans.OurButton.class.
+     * @param mappedGetterName The name of the method used for
+     *          reading one of the property values.  May be null if the
+     *          property is write-only.
+     * @param mappedSetterName The name of the method used for writing
+     *          one of the property values.  May be null if the property is
+     *          read-only.
+     *
+     * @exception IntrospectionException if an exception occurs during
+     *              introspection.
+     */
+    public MappedPropertyDescriptor(String propertyName, Class beanClass,
+                                    String mappedGetterName, String mappedSetterName)
+            throws IntrospectionException {
+
+        super(propertyName, null, null);
+
+        if (propertyName == null || propertyName.length() == 0) {
+            throw new IntrospectionException("bad property name: " +
+                    propertyName);
+        }
+        setName(propertyName);
+
+        // search the mapped get and set methods
+        mappedReadMethod =
+            findMethod(beanClass, mappedGetterName, 1, stringClassArray);
+
+        if (mappedReadMethod != null) {
+            Class params[] = { String.class, mappedReadMethod.getReturnType() };
+            mappedWriteMethod = 
+                findMethod(beanClass, mappedSetterName, 2, params);
+        } else {
+            mappedWriteMethod =
+                findMethod(beanClass, mappedSetterName, 2);
+        }
+
+        findMappedPropertyType();
+    }
+
+    /**
+     * This constructor takes the name of a mapped property, and Method
+     * objects for reading and writing the property.
+     *
+     * @param propertyName The programmatic name of the property.
+     * @param mappedGetter The method used for reading one of
+     *          the property values.  May be be null if the property
+     *          is write-only.
+     * @param mappedSetter The method used for writing one the
+     *          property values.  May be null if the property is read-only.
+     *
+     * @exception IntrospectionException if an exception occurs during
+     *              introspection.
+     */
+    public MappedPropertyDescriptor(String propertyName,
+                                    Method mappedGetter, Method mappedSetter)
+            throws IntrospectionException {
+
+        super(propertyName, mappedGetter, mappedSetter);
+
+        if (propertyName == null || propertyName.length() == 0) {
+            throw new IntrospectionException("bad property name: " +
+                    propertyName);
+        }
+
+        setName(propertyName);
+        mappedReadMethod = mappedGetter;
+        mappedWriteMethod = mappedSetter;
+        findMappedPropertyType();
+    }
+
+    // -------------------------------------------------------- Public Methods
+
+    /**
+     * Gets the Class object for the property values.
+     *
+     * @return The Java type info for the property values.  Note that
+     * the "Class" object may describe a built-in Java type such as "int".
+     * The result may be "null" if this is a mapped property that
+     * does not support non-keyed access.
+     * <p>
+     * This is the type that will be returned by the mappedReadMethod.
+     */
+    public Class getMappedPropertyType() {
+        return mappedPropertyType;
+    }
+
+    /**
+     * Gets the method that should be used to read one of the property value.
+     *
+     * @return The method that should be used to read the property value.
+     * May return null if the property can't be read.
+     */
+    public Method getMappedReadMethod() {
+        return mappedReadMethod;
+    }
+
+    /**
+     * Sets the method that should be used to read one of the property value.
+     *
+     * @param mappedGetter The new getter method.
+     */
+    public void setMappedReadMethod(Method mappedGetter)
+            throws IntrospectionException {
+        mappedReadMethod = mappedGetter;
+        findMappedPropertyType();
+    }
+
+    /**
+     * Gets the method that should be used to write one of the property value.
+     *
+     * @return The method that should be used to write one of the property value.
+     * May return null if the property can't be written.
+     */
+    public Method getMappedWriteMethod() {
+        return mappedWriteMethod;
+    }
+
+    /**
+     * Sets the method that should be used to write the property value.
+     *
+     * @param mappedSetter The new setter method.
+     */
+    public void setMappedWriteMethod(Method mappedSetter)
+            throws IntrospectionException {
+        mappedWriteMethod = mappedSetter;
+        findMappedPropertyType();
+    }
+
+    // ------------------------------------------------------- Private Methods
+
+    /**
+     * Introspect our bean class to identify the corresponding getter
+     * and setter methods.
+     */
+    private void findMappedPropertyType() throws IntrospectionException {
+        try {
+            mappedPropertyType = null;
+            if (mappedReadMethod != null) {
+                if (mappedReadMethod.getParameterTypes().length != 1) {
+                    throw new IntrospectionException
+                            ("bad mapped read method arg count");
+                }
+                mappedPropertyType = mappedReadMethod.getReturnType();
+                if (mappedPropertyType == Void.TYPE) {
+                    throw new IntrospectionException
+                            ("mapped read method " +
+                            mappedReadMethod.getName() + " returns void");
+                }
+            }
+
+            if (mappedWriteMethod != null) {
+                Class params[] = mappedWriteMethod.getParameterTypes();
+                if (params.length != 2) {
+                    throw new IntrospectionException
+                            ("bad mapped write method arg count");
+                }
+                if (mappedPropertyType != null &&
+                        mappedPropertyType != params[1]) {
+                    throw new IntrospectionException
+                            ("type mismatch between mapped read and write methods");
+                }
+                mappedPropertyType = params[1];
+            }
+        } catch (IntrospectionException ex) {
+            throw ex;
+        }
+    }
+
+
+    /**
+     * Return a capitalized version of the specified property name.
+     *
+     * @param s The property name
+     */
+    private static String capitalizePropertyName(String s) {
+        if (s.length() == 0) {
+            return s;
+        }
+
+        char chars[] = s.toCharArray();
+        chars[0] = Character.toUpperCase(chars[0]);
+        return new String(chars);
+    }
+
+    //======================================================================
+    // Package private support methods (copied from java.beans.Introspector).
+    //======================================================================
+
+    // Cache of Class.getDeclaredMethods:
+    private static java.util.Hashtable 
+        declaredMethodCache = new java.util.Hashtable();
+
+    /*
+     * Internal method to return *public* methods within a class.
+     */
+    private static synchronized Method[] getPublicDeclaredMethods(Class clz) {
+        // Looking up Class.getDeclaredMethods is relatively expensive,
+        // so we cache the results.
+        final Class fclz = clz;
+        Method[] result = (Method[]) declaredMethodCache.get(fclz);
+        if (result != null) {
+            return result;
+        }
+
+        // We have to raise privilege for getDeclaredMethods
+        result = (Method[])
+                AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        try{
+                        
+                            return fclz.getDeclaredMethods();
+                            
+                        } catch (SecurityException ex) {
+                            // this means we're in a limited security environment
+                            // so let's try going through the public methods
+                            // and null those those that are not from the declaring 
+                            // class
+                            Method[] methods = fclz.getMethods();
+                            for (int i = 0, size = methods.length; i < size; i++) {
+                                Method method =  methods[i];
+                                if (!(fclz.equals(method.getDeclaringClass()))) {
+                                    methods[i] = null;
+                                }
+                            }
+                            return methods;
+                        }
+                    }
+                });
+
+        // Null out any non-public methods.
+        for (int i = 0; i < result.length; i++) {
+            Method method = result[i];
+            if (method != null) {
+                int mods = method.getModifiers();
+                if (!Modifier.isPublic(mods)) {
+                    result[i] = null;
+                }
+            }
+        }
+
+        // Add it to the cache.
+        declaredMethodCache.put(clz, result);
+        return result;
+    }
+
+    /**
+     * Internal support for finding a target methodName on a given class.
+     */
+    private static Method internalFindMethod(Class start, String methodName,
+                                             int argCount) {
+        // For overridden methods we need to find the most derived version.
+        // So we start with the given class and walk up the superclass chain.
+        for (Class cl = start; cl != null; cl = cl.getSuperclass()) {
+            Method methods[] = getPublicDeclaredMethods(cl);
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                if (method == null) {
+                    continue;
+                }
+                // skip static methods.
+                int mods = method.getModifiers();
+                if (Modifier.isStatic(mods)) {
+                    continue;
+                }
+                if (method.getName().equals(methodName) &&
+                        method.getParameterTypes().length == argCount) {
+                    return method;
+                }
+            }
+        }
+
+        // Now check any inherited interfaces.  This is necessary both when
+        // the argument class is itself an interface, and when the argument
+        // class is an abstract class.
+        Class ifcs[] = start.getInterfaces();
+        for (int i = 0; i < ifcs.length; i++) {
+            Method m = internalFindMethod(ifcs[i], methodName, argCount);
+            if (m != null) {
+                return m;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Internal support for finding a target methodName with a given
+     * parameter list on a given class.
+     */
+    private static Method internalFindMethod(Class start, String methodName,
+                                             int argCount, Class args[]) {
+        // For overriden methods we need to find the most derived version.
+        // So we start with the given class and walk up the superclass chain.
+        for (Class cl = start; cl != null; cl = cl.getSuperclass()) {
+            Method methods[] = getPublicDeclaredMethods(cl);
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                if (method == null) {
+                    continue;
+                }
+                // skip static methods.
+                int mods = method.getModifiers();
+                if (Modifier.isStatic(mods)) {
+                    continue;
+                }
+                // make sure method signature matches.
+                Class params[] = method.getParameterTypes();
+                if (method.getName().equals(methodName) &&
+                        params.length == argCount) {
+                    boolean different = false;
+                    if (argCount > 0) {
+                        for (int j = 0; j < argCount; j++) {
+                            if (params[j] != args[j]) {
+                                different = true;
+                                continue;
+                            }
+                        }
+                        if (different) {
+                            continue;
+                        }
+                    }
+                    return method;
+                }
+            }
+        }
+
+        // Now check any inherited interfaces.  This is necessary both when
+        // the argument class is itself an interface, and when the argument
+        // class is an abstract class.
+        Class ifcs[] = start.getInterfaces();
+        for (int i = 0; i < ifcs.length; i++) {
+            Method m = internalFindMethod(ifcs[i], methodName, argCount);
+            if (m != null) {
+                return m;
+            }
+        }
+        
+        return null;
+    }
+
+    /**
+     * Find a target methodName on a given class.
+     */
+    static Method findMethod(Class cls, String methodName, int argCount)
+            throws IntrospectionException {
+        if (methodName == null) {
+            return null;
+        }
+
+        Method m = internalFindMethod(cls, methodName, argCount);
+        if (m != null) {
+            return m;
+        }
+
+        // We failed to find a suitable method
+        throw new IntrospectionException("No method \"" + methodName +
+                "\" with " + argCount + " arg(s)");
+    }
+
+    /**
+     * Find a target methodName with specific parameter list on a given class.
+     */
+    static Method findMethod(Class cls, String methodName, int argCount,
+                             Class args[]) throws IntrospectionException {
+        if (methodName == null) {
+            return null;
+        }
+
+        Method m = internalFindMethod(cls, methodName, argCount, args);
+        if (m != null) {
+            return m;
+        }
+
+        // We failed to find a suitable method
+        throw new IntrospectionException("No method \"" + methodName +
+                "\" with " + argCount + " arg(s) of matching types.");
+    }
+
+    /**
+     * Return true if class a is either equivalent to class b, or
+     * if class a is a subclass of class b, ie if a either "extends"
+     * or "implements" b.
+     * Note tht either or both "Class" objects may represent interfaces.
+     */
+    static boolean isSubclass(Class a, Class b) {
+        // We rely on the fact that for any given java class or
+        // primtitive type there is a unqiue Class object, so
+        // we can use object equivalence in the comparisons.
+        if (a == b) {
+            return true;
+        }
+
+        if (a == null || b == null) {
+            return false;
+        }
+
+        for (Class x = a; x != null; x = x.getSuperclass()) {
+            if (x == b) {
+                return true;
+            }
+
+            if (b.isInterface()) {
+                Class interfaces[] = x.getInterfaces();
+                for (int i = 0; i < interfaces.length; i++) {
+                    if (isSubclass(interfaces[i], b)) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * Return true iff the given method throws the given exception.
+     */
+
+    private boolean throwsException(Method method, Class exception) {
+
+        Class exs[] = method.getExceptionTypes();
+        for (int i = 0; i < exs.length; i++) {
+            if (exs[i] == exception) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MethodUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MethodUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MethodUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,851 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import java.util.WeakHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+
+/**
+ * <p> Utility reflection methods focussed on methods in general rather than properties in particular. </p>
+ *
+ * <h3>Known Limitations</h3>
+ * <h4>Accessing Public Methods In A Default Access Superclass</h4>
+ * <p>There is an issue when invoking public methods contained in a default access superclass.
+ * Reflection locates these methods fine and correctly assigns them as public.
+ * However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
+ *
+ * <p><code>MethodUtils</code> contains a workaround for this situation. 
+ * It will attempt to call <code>setAccessible</code> on this method.
+ * If this call succeeds, then the method can be invoked as normal.
+ * This call will only succeed when the application has sufficient security privilages. 
+ * If this call fails then a warning will be logged and the method may fail.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @author Jan Sorensen
+ * @author Robert Burrell Donkin
+ */
+
+public class MethodUtils {
+
+    // --------------------------------------------------------- Private Methods
+    
+    /**
+     * All logging goes through this logger
+     */
+    private static Log log = LogFactory.getLog(MethodUtils.class);
+    /** Only log warning about accessibility work around once */
+    private static boolean loggedAccessibleWarning = false;
+
+    /** An empty class array */
+    private static final Class[] emptyClassArray = new Class[0];
+    /** An empty object array */
+    private static final Object[] emptyObjectArray = new Object[0];
+
+    /**
+     * Stores a cache of Methods against MethodDescriptors, in a WeakHashMap.
+     */
+    private static WeakHashMap cache = new WeakHashMap();
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * <p>Invoke a named method whose parameter type matches the object type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link #invokeExactMethod}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeMethod(Object object,String methodName,Object [] args)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param arg use this argument
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(
+            Object object,
+            String methodName,
+            Object arg)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+
+        Object[] args = {arg};
+        return invokeMethod(object, methodName, args);
+
+    }
+
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link #invokeExactMethod(Object object,String methodName,Object [] args)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(
+            Object object,
+            String methodName,
+            Object[] args)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        
+        if (args == null) {
+            args = emptyObjectArray;
+        }  
+        int arguments = args.length;
+        Class parameterTypes [] = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeMethod(object, methodName, args, parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Invoke a named method whose parameter type matches the object type.</p>
+     *
+     * <p>The behaviour of this method is less deterministic 
+     * than {@link 
+     * #invokeExactMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}. 
+     * It loops through all methods with names that match
+     * and then executes the first it finds with compatable parameters.</p>
+     *
+     * <p>This method supports calls to methods taking primitive parameters 
+     * via passing in wrapping classes. So, for example, a <code>Boolean</code> class
+     * would match a <code>boolean</code> primitive.</p>
+     *
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeMethod(
+            Object object,
+            String methodName,
+            Object[] args,
+            Class[] parameterTypes)
+                throws
+                    NoSuchMethodException,
+                    IllegalAccessException,
+                    InvocationTargetException {
+                    
+        if (parameterTypes == null) {
+            parameterTypes = emptyClassArray;
+        }        
+        if (args == null) {
+            args = emptyObjectArray;
+        }  
+
+        Method method = getMatchingAccessibleMethod(
+                object.getClass(),
+                methodName,
+                parameterTypes);
+        if (method == null)
+            throw new NoSuchMethodException("No such accessible method: " +
+                    methodName + "() on object: " + object.getClass().getName());
+        return method.invoke(object, args);
+    }
+
+
+    /**
+     * <p>Invoke a method whose parameter type matches exactly the object
+     * type.</p>
+     *
+     * <p> This is a convenient wrapper for
+     * {@link #invokeExactMethod(Object object,String methodName,Object [] args)}.
+     * </p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param arg use this argument
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object arg)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+
+        Object[] args = {arg};
+        return invokeExactMethod(object, methodName, args);
+
+    }
+
+
+    /**
+     * <p>Invoke a method whose parameter types match exactly the object
+     * types.</p>
+     *
+     * <p> This uses reflection to invoke the method obtained from a call to
+     * {@link #getAccessibleMethod}.</p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object[] args)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        if (args == null) {
+            args = emptyObjectArray;
+        }  
+        int arguments = args.length;
+        Class parameterTypes [] = new Class[arguments];
+        for (int i = 0; i < arguments; i++) {
+            parameterTypes[i] = args[i].getClass();
+        }
+        return invokeExactMethod(object, methodName, args, parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Invoke a method whose parameter types match exactly the parameter
+     * types given.</p>
+     *
+     * <p>This uses reflection to invoke the method obtained from a call to
+     * {@link #getAccessibleMethod}.</p>
+     *
+     * @param object invoke method on this object
+     * @param methodName get method with this name
+     * @param args use these arguments - treat null as empty array
+     * @param parameterTypes match these parameters - treat null as empty array
+     *
+     * @throws NoSuchMethodException if there is no such accessible method
+     * @throws InvocationTargetException wraps an exception thrown by the
+     *  method invoked
+     * @throws IllegalAccessException if the requested method is not accessible
+     *  via reflection
+     */
+    public static Object invokeExactMethod(
+            Object object,
+            String methodName,
+            Object[] args,
+            Class[] parameterTypes)
+            throws
+            NoSuchMethodException,
+            IllegalAccessException,
+            InvocationTargetException {
+        
+        if (args == null) {
+            args = emptyObjectArray;
+        }  
+                
+        if (parameterTypes == null) {
+            parameterTypes = emptyClassArray;
+        }
+
+        Method method = getAccessibleMethod(
+                object.getClass(),
+                methodName,
+                parameterTypes);
+        if (method == null)
+            throw new NoSuchMethodException("No such accessible method: " +
+                    methodName + "() on object: " + object.getClass().getName());
+        return method.invoke(object, args);
+
+    }
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) with given name and a single parameter.  If no such method
+     * can be found, return <code>null</code>.
+     * Basically, a convenience wrapper that constructs a <code>Class</code>
+     * array for you.</p>
+     *
+     * @param clazz get method from this class
+     * @param methodName get method with this name
+     * @param parameterType taking this type of parameter
+     */
+    public static Method getAccessibleMethod(
+            Class clazz,
+            String methodName,
+            Class parameterType) {
+
+        Class[] parameterTypes = {parameterType};
+        return getAccessibleMethod(clazz, methodName, parameterTypes);
+
+    }
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) with given name and parameters.  If no such method
+     * can be found, return <code>null</code>.
+     * This is just a convenient wrapper for
+     * {@link #getAccessibleMethod(Method method)}.</p>
+     *
+     * @param clazz get method from this class
+     * @param methodName get method with this name
+     * @param parameterTypes with these parameters types
+     */
+    public static Method getAccessibleMethod(
+            Class clazz,
+            String methodName,
+            Class[] parameterTypes) {
+
+        try {
+            MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, true);
+            // Check the cache first
+            Method method = (Method)cache.get(md);
+            if (method != null) {
+                return method;
+            }
+            
+            method =  getAccessibleMethod
+                    (clazz.getMethod(methodName, parameterTypes));
+            cache.put(md, method);
+            return method;
+        } catch (NoSuchMethodException e) {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified Method.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * @param method The method that we wish to call
+     */
+    public static Method getAccessibleMethod(Method method) {
+
+        // Make sure we have a method to check
+        if (method == null) {
+            return (null);
+        }
+
+        // If the requested method is not public we cannot call it
+        if (!Modifier.isPublic(method.getModifiers())) {
+            return (null);
+        }
+
+        // If the declaring class is public, we are done
+        Class clazz = method.getDeclaringClass();
+        if (Modifier.isPublic(clazz.getModifiers())) {
+            return (method);
+        }
+
+        // Check the implemented interfaces and subinterfaces
+        method =
+                getAccessibleMethodFromInterfaceNest(clazz,
+                        method.getName(),
+                        method.getParameterTypes());
+        return (method);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * <p>Return an accessible method (that is, one that can be invoked via
+     * reflection) that implements the specified method, by scanning through
+     * all implemented interfaces and subinterfaces.  If no such method
+     * can be found, return <code>null</code>.</p>
+     *
+     * <p> There isn't any good reason why this method must be private.
+     * It is because there doesn't seem any reason why other classes should
+     * call this rather than the higher level methods.</p>
+     *
+     * @param clazz Parent class for the interfaces to be checked
+     * @param methodName Method name of the method we wish to call
+     * @param parameterTypes The parameter type signatures
+     */
+    private static Method getAccessibleMethodFromInterfaceNest
+            (Class clazz, String methodName, Class parameterTypes[]) {
+
+        Method method = null;
+
+        // Search up the superclass chain
+        for (; clazz != null; clazz = clazz.getSuperclass()) {
+
+            // Check the implemented interfaces of the parent class
+            Class interfaces[] = clazz.getInterfaces();
+            for (int i = 0; i < interfaces.length; i++) {
+
+                // Is this interface public?
+                if (!Modifier.isPublic(interfaces[i].getModifiers()))
+                    continue;
+
+                // Does the method exist on this interface?
+                try {
+                    method = interfaces[i].getDeclaredMethod(methodName,
+                            parameterTypes);
+                } catch (NoSuchMethodException e) {
+                    ;
+                }
+                if (method != null)
+                    break;
+
+                // Recursively check our parent interfaces
+                method =
+                        getAccessibleMethodFromInterfaceNest(interfaces[i],
+                                methodName,
+                                parameterTypes);
+                if (method != null)
+                    break;
+
+            }
+
+        }
+
+        // If we found a method return it
+        if (method != null)
+            return (method);
+
+        // We did not find anything
+        return (null);
+
+    }
+
+    /**
+     * <p>Find an accessible method that matches the given name and has compatible parameters.
+     * Compatible parameters mean that every method parameter is assignable from 
+     * the given parameters.
+     * In other words, it finds a method with the given name 
+     * that will take the parameters given.<p>
+     *
+     * <p>This method is slightly undeterminstic since it loops 
+     * through methods names and return the first matching method.</p>
+     * 
+     * <p>This method is used by 
+     * {@link 
+     * #invokeMethod(Object object,String methodName,Object [] args,Class[] parameterTypes)}.
+     *
+     * <p>This method can match primitive parameter by passing in wrapper classes.
+     * For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
+     * parameter.
+     *
+     * @param clazz find method in this class
+     * @param methodName find method with this name
+     * @param parameterTypes find method with compatible parameters 
+     */
+    public static Method getMatchingAccessibleMethod(
+                                                Class clazz,
+                                                String methodName,
+                                                Class[] parameterTypes) {
+        // trace logging
+        if (log.isTraceEnabled()) {
+            log.trace("Matching name=" + methodName + " on " + clazz);
+        }
+        MethodDescriptor md = new MethodDescriptor(clazz, methodName, parameterTypes, false);
+        
+        // see if we can find the method directly
+        // most of the time this works and it's much faster
+        try {
+            // Check the cache first
+            Method method = (Method)cache.get(md);
+            if (method != null) {
+                return method;
+            }
+
+            method = clazz.getMethod(methodName, parameterTypes);
+            if (log.isTraceEnabled()) {
+                log.trace("Found straight match: " + method);
+                log.trace("isPublic:" + Modifier.isPublic(method.getModifiers()));
+            }
+            
+            try {
+                //
+                // XXX Default access superclass workaround
+                //
+                // When a public class has a default access superclass
+                // with public methods, these methods are accessible.
+                // Calling them from compiled code works fine.
+                //
+                // Unfortunately, using reflection to invoke these methods
+                // seems to (wrongly) to prevent access even when the method
+                // modifer is public.
+                //
+                // The following workaround solves the problem but will only
+                // work from sufficiently privilages code. 
+                //
+                // Better workarounds would be greatfully accepted.
+                //
+                method.setAccessible(true);
+                
+            } catch (SecurityException se) {
+                // log but continue just in case the method.invoke works anyway
+                if (!loggedAccessibleWarning) {
+                    boolean vunerableJVM = false;
+                    try {
+                        String specVersion = System.getProperty("java.specification.version");
+                        if (specVersion.charAt(0) == '1' && 
+                                (specVersion.charAt(0) == '0' ||
+                                 specVersion.charAt(0) == '1' ||
+                                 specVersion.charAt(0) == '2' ||
+                                 specVersion.charAt(0) == '3')) {
+                                 
+                            vunerableJVM = true;
+                        }
+                    } catch (SecurityException e) {
+                        // don't know - so display warning
+                        vunerableJVM = true;
+                    }
+                    if (vunerableJVM) {
+                        log.warn(
+                            "Current Security Manager restricts use of workarounds for reflection bugs "
+                            + " in pre-1.4 JVMs.");
+                    }
+                    loggedAccessibleWarning = true;
+                }
+                log.debug(
+                        "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", 
+                        se);
+            }
+            cache.put(md, method);
+            return method;
+            
+        } catch (NoSuchMethodException e) { /* SWALLOW */ }
+        
+        // search through all methods 
+        int paramSize = parameterTypes.length;
+        Method[] methods = clazz.getMethods();
+        for (int i = 0, size = methods.length; i < size ; i++) {
+            if (methods[i].getName().equals(methodName)) {	
+                // log some trace information
+                if (log.isTraceEnabled()) {
+                    log.trace("Found matching name:");
+                    log.trace(methods[i]);
+                }                
+                
+                // compare parameters
+                Class[] methodsParams = methods[i].getParameterTypes();
+                int methodParamSize = methodsParams.length;
+                if (methodParamSize == paramSize) {          
+                    boolean match = true;
+                    for (int n = 0 ; n < methodParamSize; n++) {
+                        if (log.isTraceEnabled()) {
+                            log.trace("Param=" + parameterTypes[n].getName());
+                            log.trace("Method=" + methodsParams[n].getName());
+                        }
+                        if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
+                            if (log.isTraceEnabled()) {
+                                log.trace(methodsParams[n] + " is not assignable from " 
+                                            + parameterTypes[n]);
+                            }    
+                            match = false;
+                            break;
+                        }
+                    }
+                    
+                    if (match) {
+                        // get accessible version of method
+                        Method method = getAccessibleMethod(methods[i]);
+                        if (method != null) {
+                            if (log.isTraceEnabled()) {
+                                log.trace(method + " accessible version of " 
+                                            + methods[i]);
+                            }
+                            try {
+                                //
+                                // XXX Default access superclass workaround
+                                // (See above for more details.)
+                                //
+                                method.setAccessible(true);
+                                
+                            } catch (SecurityException se) {
+                                // log but continue just in case the method.invoke works anyway
+                                if (!loggedAccessibleWarning) {
+                                    log.warn(
+            "Cannot use JVM pre-1.4 access bug workaround due to restrictive security manager.");
+                                    loggedAccessibleWarning = true;
+                                }
+                                log.debug(
+            "Cannot setAccessible on method. Therefore cannot use jvm access bug workaround.", 
+                                        se);
+                            }
+                            cache.put(md, method);
+                            return method;
+                        }
+                        
+                        log.trace("Couldn't find accessible method.");
+                    }
+                }
+            }
+        }
+        
+        // didn't find a match
+        log.trace("No match found.");
+        return null;                                        
+    }
+
+    /**
+     * <p>Determine whether a type can be used as a parameter in a method invocation.
+     * This method handles primitive conversions correctly.</p>
+     *
+     * <p>In order words, it will match a <code>Boolean</code> to a <code>boolean</code>,
+     * a <code>Long</code> to a <code>long</code>,
+     * a <code>Float</code> to a <code>float</code>,
+     * a <code>Integer</code> to a <code>int</code>,
+     * and a <code>Double</code> to a <code>double</code>.
+     * Now logic widening matches are allowed.
+     * For example, a <code>Long</code> will not match a <code>int</code>.
+     *
+     * @param parameterType the type of parameter accepted by the method
+     * @param parameterization the type of parameter being tested 
+     *
+     * @return true if the assignement is compatible.
+     */
+    public static final boolean isAssignmentCompatible(Class parameterType, Class parameterization) {
+        // try plain assignment
+        if (parameterType.isAssignableFrom(parameterization)) {
+            return true;
+        }
+        
+        if (parameterType.isPrimitive()) {
+            // this method does *not* do widening - you must specify exactly
+            // is this the right behaviour?
+            Class parameterWrapperClazz = getPrimitiveWrapper(parameterType);
+            if (parameterWrapperClazz != null) {
+                return parameterWrapperClazz.equals(parameterization);
+            }
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Gets the wrapper object class for the given primitive type class.
+     * For example, passing <code>boolean.class</code> returns <code>Boolean.class</code>
+     * @param primitiveType the primitive type class for which a match is to be found
+     * @return the wrapper type associated with the given primitive 
+     * or null if no match is found
+     */
+    public static Class getPrimitiveWrapper(Class primitiveType) {
+        // does anyone know a better strategy than comparing names?
+        if (boolean.class.equals(primitiveType)) {
+            return Boolean.class;
+        } else if (float.class.equals(primitiveType)) {
+            return Float.class;
+        } else if (long.class.equals(primitiveType)) {
+            return Long.class;
+        } else if (int.class.equals(primitiveType)) {
+            return Integer.class;
+        } else if (short.class.equals(primitiveType)) {
+            return Short.class;
+        } else if (byte.class.equals(primitiveType)) {
+            return Byte.class;
+        } else if (double.class.equals(primitiveType)) {
+            return Double.class;
+        } else if (char.class.equals(primitiveType)) {
+            return Character.class;
+        } else {
+            
+            return null;
+        }
+    }
+
+    /**
+     * Gets the class for the primitive type corresponding to the primitive wrapper class given.
+     * For example, an instance of <code>Boolean.class</code> returns a <code>boolean.class</code>. 
+     * @param wrapperType the 
+     * @return the primitive type class corresponding to the given wrapper class,
+     * null if no match is found
+     */
+    public static Class getPrimitiveType(Class wrapperType) {
+        // does anyone know a better strategy than comparing names?
+        if (Boolean.class.equals(wrapperType)) {
+            return boolean.class;
+        } else if (Float.class.equals(wrapperType)) {
+            return float.class;
+        } else if (Long.class.equals(wrapperType)) {
+            return long.class;
+        } else if (Integer.class.equals(wrapperType)) {
+            return int.class;
+        } else if (Short.class.equals(wrapperType)) {
+            return short.class;
+        } else if (Byte.class.equals(wrapperType)) {
+            return byte.class;
+        } else if (Double.class.equals(wrapperType)) {
+            return double.class;
+        } else if (Character.class.equals(wrapperType)) {
+            return char.class;
+        } else {
+            if (log.isDebugEnabled()) {
+                log.debug("Not a known primitive wrapper class: " + wrapperType);
+            }
+            return null;
+        }
+    }
+    
+    /**
+     * Find a non primitive representation for given primitive class.
+     *
+     * @param clazz the class to find a representation for, not null
+     * @return the original class if it not a primitive. Otherwise the wrapper class. Not null
+     */
+    public static Class toNonPrimitiveClass(Class clazz) {
+        if (clazz.isPrimitive()) {
+            Class primitiveClazz = MethodUtils.getPrimitiveWrapper(clazz);
+            // the above method returns 
+            if (primitiveClazz != null) {
+                return primitiveClazz;
+            } else {
+                return clazz;
+            }
+        } else {
+            return clazz;
+        }
+    }
+    
+
+    /**
+     * Represents the key to looking up a Method by reflection.
+     */
+    private static class MethodDescriptor {
+        private Class cls;
+        private String methodName;
+        private Class[] paramTypes;
+        private boolean exact;
+        private int hashCode;
+
+        /**
+         * The sole constructor.
+         *
+         * @param cls  the class to reflect, must not be null
+         * @param methodName  the method name to obtain
+         * @param paramTypes the array of classes representing the paramater types
+         * @param exact whether the match has to be exact.
+         */
+        public MethodDescriptor(Class cls, String methodName, Class[] paramTypes, boolean exact) {
+            if (cls == null) {
+                throw new IllegalArgumentException("Class cannot be null");
+            }
+            if (methodName == null) {
+                throw new IllegalArgumentException("Method Name cannot be null");
+            }
+            if (paramTypes == null) {
+                paramTypes = emptyClassArray;
+            }
+
+            this.cls = cls;
+            this.methodName = methodName;
+            this.paramTypes = paramTypes;
+            this.exact= exact;
+
+            this.hashCode = methodName.length();
+        }
+        /**
+         * Checks for equality.
+         * @param obj object to be tested for equality
+         * @return true, if the object describes the same Method.
+         */
+        public boolean equals(Object obj) {
+            if (!(obj instanceof MethodDescriptor)) {
+                return false;
+            }
+            MethodDescriptor md = (MethodDescriptor)obj;
+
+            return (
+                exact == md.exact &&
+                methodName.equals(md.methodName) &&
+                cls.equals(md.cls) &&
+                java.util.Arrays.equals(paramTypes, md.paramTypes)
+            );
+        }
+        /**
+         * Returns the string length of method name. I.e. if the
+         * hashcodes are different, the objects are different. If the
+         * hashcodes are the same, need to use the equals method to
+         * determine equality.
+         * @return the string length of method name.
+         */
+        public int hashCode() {
+            return hashCode;
+        }
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MutableDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MutableDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/MutableDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+
+
+
+/**
+ * <p>A specialized extension to <code>DynaClass</code> that allows properties
+ * to be added or removed dynamically.</p>
+ *
+ * <p><strong>WARNING</strong> - No guarantees that this will be in the final
+ * APIs ... it's here primarily to preserve some concepts that were in the
+ * original proposal for further discussion.</p>
+ *
+ * @author Craig McClanahan
+ * @author Michael Smith
+ * @author Paulo Gaspar
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public interface MutableDynaClass extends DynaClass {
+
+
+    /**
+     * Add a new dynamic property with no restrictions on data type,
+     * readability, or writeability.
+     *
+     * @param name Name of the new dynamic property
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    public void add(String name);
+
+
+    /**
+     * Add a new dynamic property with the specified data type, but with
+     * no restrictions on readability or writeability.
+     *
+     * @param name Name of the new dynamic property
+     * @param type Data type of the new dynamic property (null for no
+     *  restrictions)
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    public void add(String name, Class type);
+
+
+    /**
+     * Add a new dynamic property with the specified data type, readability,
+     * and writeability.
+     *
+     * @param name Name of the new dynamic property
+     * @param type Data type of the new dynamic property (null for no
+     *  restrictions)
+     * @param readable Set to <code>true</code> if this property value
+     *  should be readable
+     * @param writeable Set to <code>true</code> if this property value
+     *  should be writeable
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no new properties can be added
+     */
+    public void add(String name, Class type, boolean readable,
+                    boolean writeable);
+
+
+    /**
+     * Is this DynaClass currently restricted, if so, no changes to the
+     * existing registration of property names, data types, readability, or
+     * writeability are allowed.
+     */
+    public boolean isRestricted();
+
+
+    /**
+     * Remove the specified dynamic property, and any associated data type,
+     * readability, and writeability, from this dynamic class.
+     * <strong>NOTE</strong> - This does <strong>NOT</strong> cause any
+     * corresponding property values to be removed from DynaBean instances
+     * associated with this DynaClass.
+     *
+     * @param name Name of the dynamic property to remove
+     *
+     * @exception IllegalArgumentException if name is null
+     * @exception IllegalStateException if this DynaClass is currently
+     *  restricted, so no properties can be removed
+     */
+    public void remove(String name);
+
+
+    /**
+     * Set the restricted state of this DynaClass to the specified value.
+     *
+     * @param restricted The new restricted state
+     */
+    public void setRestricted(boolean restricted);
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/NestedNullException.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/NestedNullException.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/NestedNullException.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+/** 
+ * Thrown to indicate that the <em>Bean Access Language</em> cannot execute query
+ * against given bean since a nested bean referenced is null.
+ *
+ * @author Robert Burrell Donkin
+ * @since 1.7
+ */
+
+public class NestedNullException extends BeanAccessLanguageException {
+    
+    // --------------------------------------------------------- Constuctors
+    
+    /** 
+     * Constructs a <code>NestedNullException</code> without a detail message.
+     */
+    public NestedNullException() {
+        super();
+    }
+    
+    /**
+     * Constructs a <code>NestedNullException</code> without a detail message.
+     * 
+     * @param message the detail message explaining this exception
+     */
+    public NestedNullException(String message) {
+        super(message);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,581 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.apache.commons.collections.FastHashMap;
+
+
+/**
+ * <p>Utility methods for using Java Reflection APIs to facilitate generic
+ * property getter and setter operations on Java objects.</p>
+ *
+ * <p>The implementations for these methods are provided by <code>PropertyUtilsBean</code>.
+ * For more details see {@link PropertyUtilsBean}.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @author Jan Sorensen
+ * @author Scott Sanders
+ * @version $Revision: 1.42.2.1 $ $Date: 2004/07/27 21:31:00 $
+ * @see PropertyUtilsBean
+ */
+
+public class PropertyUtils {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The delimiter that preceeds the zero-relative subscript for an
+     * indexed reference.
+     */
+    public static final char INDEXED_DELIM = '[';
+
+
+    /**
+     * The delimiter that follows the zero-relative subscript for an
+     * indexed reference.
+     */
+    public static final char INDEXED_DELIM2 = ']';
+
+
+    /**
+     * The delimiter that preceeds the key of a mapped property.
+     */
+    public static final char MAPPED_DELIM = '(';
+
+
+    /**
+     * The delimiter that follows the key of a mapped property.
+     */
+    public static final char MAPPED_DELIM2 = ')';
+
+
+    /**
+     * The delimiter that separates the components of a nested reference.
+     */
+    public static final char NESTED_DELIM = '.';
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The debugging detail level for this component.
+     * @deprecated The <code>debug</code> static property is no longer used
+     */
+    private static int debug = 0;
+
+    /**
+     * @deprecated The <code>debug</code> static property is no longer used
+     */
+    public static int getDebug() {
+        return (debug);
+    }
+
+    /**
+     * @deprecated The <code>debug</code> static property is no longer used
+     */
+    public static void setDebug(int newDebug) {
+        debug = newDebug;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear any cached property descriptors information for all classes
+     * loaded by any class loaders.  This is useful in cases where class
+     * loaders are thrown away to implement class reloading.
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#clearDescriptors  
+     */
+    public static void clearDescriptors() {
+	
+        PropertyUtilsBean.getInstance().clearDescriptors();
+
+    }
+
+
+    /**
+     * <p>Copy property values from the "origin" bean to the "destination" bean
+     * for all cases where the property names are the same (even though the
+     * actual getter and setter methods might have been customized via
+     * <code>BeanInfo</code> classes).</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#copyProperties  
+     */
+    public static void copyProperties(Object dest, Object orig)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().copyProperties(dest, orig);
+    }
+
+
+    /**
+     * <p>Return the entire set of properties for which the specified bean
+     * provides a read method.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#describe  
+     */
+    public static Map describe(Object bean)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (PropertyUtilsBean.getInstance().describe(bean));
+
+    }
+
+
+    /**
+     * <p>Return the value of the specified indexed property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getIndexedProperty(Object,String)  
+     */
+    public static Object getIndexedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (PropertyUtilsBean.getInstance().getIndexedProperty(bean, name));
+
+    }
+
+
+    /**
+     * <p>Return the value of the specified indexed property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getIndexedProperty(Object,String, int)  
+     */
+    public static Object getIndexedProperty(Object bean,
+                                            String name, int index)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (PropertyUtilsBean.getInstance().getIndexedProperty(bean, name, index));
+    }
+
+
+    /**
+     * <p>Return the value of the specified mapped property of the
+     * specified bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getMappedProperty(Object,String)  
+     */
+    public static Object getMappedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (PropertyUtilsBean.getInstance().getMappedProperty(bean, name));
+
+    }
+
+
+    /**
+     * <p>Return the value of the specified mapped property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getMappedProperty(Object,String, String)  
+     */
+    public static Object getMappedProperty(Object bean,
+                                           String name, String key)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return PropertyUtilsBean.getInstance().getMappedProperty(bean, name, key);
+
+    }
+
+
+    /**
+     * <p>Return the mapped property descriptors for this bean class.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getMappedPropertyDescriptors(Class)
+     * @deprecated This method should not be exposed
+     */
+    public static FastHashMap getMappedPropertyDescriptors(Class beanClass) {
+	
+        return PropertyUtilsBean.getInstance().getMappedPropertyDescriptors(beanClass);
+
+    }
+
+
+    /**
+     * <p>Return the mapped property descriptors for this bean.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getMappedPropertyDescriptors(Object)
+     * @deprecated This method should not be exposed
+     */
+    public static FastHashMap getMappedPropertyDescriptors(Object bean) {
+
+	return PropertyUtilsBean.getInstance().getMappedPropertyDescriptors(bean);
+
+    }
+
+
+    /**
+     * <p>Return the value of the (possibly nested) property of the specified
+     * name, for the specified bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getNestedProperty
+     */
+    public static Object getNestedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return PropertyUtilsBean.getInstance().getNestedProperty(bean, name);
+        
+    }
+
+
+    /**
+     * <p>Return the value of the specified property of the specified bean,
+     * no matter which property reference format is used, with no
+     * type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getProperty
+     */
+    public static Object getProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (PropertyUtilsBean.getInstance().getProperty(bean, name));
+
+    }
+
+
+    /**
+     * <p>Retrieve the property descriptor for the specified property of the
+     * specified bean, or return <code>null</code> if there is no such
+     * descriptor.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getPropertyDescriptor
+     */
+    public static PropertyDescriptor getPropertyDescriptor(Object bean,
+                                                           String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return PropertyUtilsBean.getInstance().getPropertyDescriptor(bean, name);
+
+    }
+
+
+    /**
+     * <p>Retrieve the property descriptors for the specified class,
+     * introspecting and caching them the first time a particular bean class
+     * is encountered.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getPropertyDescriptors(Class)
+     */
+    public static PropertyDescriptor[]
+            getPropertyDescriptors(Class beanClass) {
+
+        return PropertyUtilsBean.getInstance().getPropertyDescriptors(beanClass);
+
+    }
+
+
+    /**
+     * <p>Retrieve the property descriptors for the specified bean,
+     * introspecting and caching them the first time a particular bean class
+     * is encountered.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getPropertyDescriptors(Object)
+     */
+    public static PropertyDescriptor[] getPropertyDescriptors(Object bean) {
+
+        return PropertyUtilsBean.getInstance().getPropertyDescriptors(bean);
+
+    }
+
+
+    /**
+     * <p>Return the Java Class repesenting the property editor class that has
+     * been registered for this property (if any).</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getPropertyEditorClass(Object,String)
+     */
+    public static Class getPropertyEditorClass(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+	return PropertyUtilsBean.getInstance().getPropertyEditorClass(bean, name);
+
+    }
+
+
+    /**
+     * <p>Return the Java Class representing the property type of the specified
+     * property, or <code>null</code> if there is no such property for the
+     * specified bean.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getPropertyType
+     */
+    public static Class getPropertyType(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return PropertyUtilsBean.getInstance().getPropertyType(bean, name);
+    }
+
+
+    /**
+     * <p>Return an accessible property getter method for this property,
+     * if there is one; otherwise return <code>null</code>.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getReadMethod
+     */
+    public static Method getReadMethod(PropertyDescriptor descriptor) {
+
+        return (PropertyUtilsBean.getInstance().getReadMethod(descriptor));
+
+    }
+
+
+    /**
+     * <p>Return the value of the specified simple property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getSimpleProperty
+     */
+    public static Object getSimpleProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return PropertyUtilsBean.getInstance().getSimpleProperty(bean, name);
+        
+    }
+
+
+    /**
+     * <p>Return an accessible property setter method for this property,
+     * if there is one; otherwise return <code>null</code>.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#getWriteMethod
+     */
+    public static Method getWriteMethod(PropertyDescriptor descriptor) {
+
+        return PropertyUtilsBean.getInstance().getWriteMethod(descriptor);
+
+    }
+
+
+    /**
+     * <p>Return <code>true</code> if the specified property name identifies
+     * a readable property on the specified bean; otherwise, return
+     * <code>false</code>.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#isReadable
+     * @since BeanUtils 1.6
+     */
+    public static boolean isReadable(Object bean, String name) {
+
+        return PropertyUtilsBean.getInstance().isReadable(bean, name);
+    }
+
+
+    /**
+     * <p>Return <code>true</code> if the specified property name identifies
+     * a writeable property on the specified bean; otherwise, return
+     * <code>false</code>.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#isWriteable
+     * @since BeanUtils 1.6
+     */
+    public static boolean isWriteable(Object bean, String name) {
+
+	return PropertyUtilsBean.getInstance().isWriteable(bean, name);
+    }
+
+
+    /**
+     * <p>Sets the value of the specified indexed property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setIndexedProperty(Object, String, Object)
+     */
+    public static void setIndexedProperty(Object bean, String name,
+                                          Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setIndexedProperty(bean, name, value);
+
+    }
+
+
+    /**
+     * <p>Sets the value of the specified indexed property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setIndexedProperty(Object, String, Object)
+     */
+    public static void setIndexedProperty(Object bean, String name,
+                                          int index, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setIndexedProperty(bean, name, index, value);
+    }
+
+
+    /**
+     * <p>Sets the value of the specified mapped property of the
+     * specified bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setMappedProperty(Object, String, Object)
+     */
+    public static void setMappedProperty(Object bean, String name,
+                                         Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setMappedProperty(bean, name, value);
+    }
+
+
+    /**
+     * <p>Sets the value of the specified mapped property of the specified
+     * bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setMappedProperty(Object, String, String, Object)
+     */
+    public static void setMappedProperty(Object bean, String name,
+                                         String key, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setMappedProperty(bean, name, key, value);
+    }
+
+
+    /**
+     * <p>Sets the value of the (possibly nested) property of the specified
+     * name, for the specified bean, with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setNestedProperty
+     */
+    public static void setNestedProperty(Object bean,
+                                         String name, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setNestedProperty(bean, name, value);
+    }
+
+
+    /**
+     * <p>Set the value of the specified property of the specified bean,
+     * no matter which property reference format is used, with no
+     * type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setProperty
+     */
+    public static void setProperty(Object bean, String name, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setProperty(bean, name, value);
+
+    }
+
+
+    /**
+     * <p>Set the value of the specified simple property of the specified bean,
+     * with no type conversions.</p>
+     *
+     * <p>For more details see <code>PropertyUtilsBean</code>.</p>
+     *
+     * @see PropertyUtilsBean#setSimpleProperty
+     */
+    public static void setSimpleProperty(Object bean,
+                                         String name, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        PropertyUtilsBean.getInstance().setSimpleProperty(bean, name, value);
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/PropertyUtilsBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,1784 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.beans.BeanInfo;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.FastHashMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Utility methods for using Java Reflection APIs to facilitate generic
+ * property getter and setter operations on Java objects.  Much of this
+ * code was originally included in <code>BeanUtils</code>, but has been
+ * separated because of the volume of code involved.
+ * <p>
+ * In general, the objects that are examined and modified using these
+ * methods are expected to conform to the property getter and setter method
+ * naming conventions described in the JavaBeans Specification (Version 1.0.1).
+ * No data type conversions are performed, and there are no usage of any
+ * <code>PropertyEditor</code> classes that have been registered, although
+ * a convenient way to access the registered classes themselves is included.
+ * <p>
+ * For the purposes of this class, five formats for referencing a particular
+ * property value of a bean are defined, with the layout of an identifying
+ * String in parentheses:
+ * <ul>
+ * <li><strong>Simple (<code>name</code>)</strong> - The specified
+ *     <code>name</code> identifies an individual property of a particular
+ *     JavaBean.  The name of the actual getter or setter method to be used
+ *     is determined using standard JavaBeans instrospection, so that (unless
+ *     overridden by a <code>BeanInfo</code> class, a property named "xyz"
+ *     will have a getter method named <code>getXyz()</code> or (for boolean
+ *     properties only) <code>isXyz()</code>, and a setter method named
+ *     <code>setXyz()</code>.</li>
+ * <li><strong>Nested (<code>name1.name2.name3</code>)</strong> The first
+ *     name element is used to select a property getter, as for simple
+ *     references above.  The object returned for this property is then
+ *     consulted, using the same approach, for a property getter for a
+ *     property named <code>name2</code>, and so on.  The property value that
+ *     is ultimately retrieved or modified is the one identified by the
+ *     last name element.</li>
+ * <li><strong>Indexed (<code>name[index]</code>)</strong> - The underlying
+ *     property value is assumed to be an array, or this JavaBean is assumed
+ *     to have indexed property getter and setter methods.  The appropriate
+ *     (zero-relative) entry in the array is selected.  <code>List</code>
+ *     objects are now also supported for read/write.  You simply need to define
+ *     a getter that returns the <code>List</code></li>
+ * <li><strong>Mapped (<code>name(key)</code>)</strong> - The JavaBean
+ *     is assumed to have an property getter and setter methods with an
+ *     additional attribute of type <code>java.lang.String</code>.</li>
+ * <li><strong>Combined (<code>name1.name2[index].name3(key)</code>)</strong> -
+ *     Combining mapped, nested, and indexed references is also
+ *     supported.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @author Jan Sorensen
+ * @author Scott Sanders
+ * @version $Revision: 1.14.2.1 $ $Date: 2004/07/27 21:31:00 $
+ * @see PropertyUtils
+ * @since 1.7
+ */
+
+public class PropertyUtilsBean {
+
+    // --------------------------------------------------------- Class Methods
+    
+    protected static PropertyUtilsBean getInstance() {
+        return BeanUtilsBean.getInstance().getPropertyUtils();
+    }	
+
+    // --------------------------------------------------------- Variables
+
+    /**
+     * The cache of PropertyDescriptor arrays for beans we have already
+     * introspected, keyed by the java.lang.Class of this object.
+     */
+    private FastHashMap descriptorsCache = null;
+    private FastHashMap mappedDescriptorsCache = null;
+    
+    /** Log instance */
+    private Log log = LogFactory.getLog(PropertyUtils.class);
+    
+    // ---------------------------------------------------------- Constructors
+    
+    /** Base constructor */
+    public PropertyUtilsBean() {
+        descriptorsCache = new FastHashMap();
+        descriptorsCache.setFast(true);
+        mappedDescriptorsCache = new FastHashMap();
+        mappedDescriptorsCache.setFast(true);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear any cached property descriptors information for all classes
+     * loaded by any class loaders.  This is useful in cases where class
+     * loaders are thrown away to implement class reloading.
+     */
+    public void clearDescriptors() {
+
+        descriptorsCache.clear();
+        mappedDescriptorsCache.clear();
+        Introspector.flushCaches();
+
+    }
+
+
+    /**
+     * <p>Copy property values from the "origin" bean to the "destination" bean
+     * for all cases where the property names are the same (even though the
+     * actual getter and setter methods might have been customized via
+     * <code>BeanInfo</code> classes).  No conversions are performed on the
+     * actual property values -- it is assumed that the values retrieved from
+     * the origin bean are assignment-compatible with the types expected by
+     * the destination bean.</p>
+     *
+     * <p>If the origin "bean" is actually a <code>Map</code>, it is assumed
+     * to contain String-valued <strong>simple</strong> property names as the keys, pointing
+     * at the corresponding property values that will be set in the destination
+     * bean.<strong>Note</strong> that this method is intended to perform 
+     * a "shallow copy" of the properties and so complex properties 
+     * (for example, nested ones) will not be copied.</p>
+     *
+     * @param dest Destination bean whose properties are modified
+     * @param orig Origin bean whose properties are retrieved
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if the <code>dest</code> or
+     *  <code>orig</code> argument is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void copyProperties(Object dest, Object orig)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (dest == null) {
+            throw new IllegalArgumentException
+                    ("No destination bean specified");
+        }
+        if (orig == null) {
+            throw new IllegalArgumentException("No origin bean specified");
+        }
+
+        if (orig instanceof DynaBean) {
+            DynaProperty origDescriptors[] =
+                ((DynaBean) orig).getDynaClass().getDynaProperties();
+            for (int i = 0; i < origDescriptors.length; i++) {
+                String name = origDescriptors[i].getName();
+                if (dest instanceof DynaBean) {
+                    if (isWriteable(dest, name)) {
+                        Object value = ((DynaBean) orig).get(name);
+                        ((DynaBean) dest).set(name, value);
+                    }
+                } else /* if (dest is a standard JavaBean) */ {
+                    if (isWriteable(dest, name)) {
+                        Object value = ((DynaBean) orig).get(name);
+                        setSimpleProperty(dest, name, value);
+                    }
+                }
+            }
+        } else if (orig instanceof Map) {
+            Iterator names = ((Map) orig).keySet().iterator();
+            while (names.hasNext()) {
+                String name = (String) names.next();
+                if (dest instanceof DynaBean) {
+                    if (isWriteable(dest, name)) {
+                        Object value = ((Map) orig).get(name);
+                        ((DynaBean) dest).set(name, value);
+                    }
+                } else /* if (dest is a standard JavaBean) */ {
+                    if (isWriteable(dest, name)) {
+                        Object value = ((Map) orig).get(name);
+                        setSimpleProperty(dest, name, value);
+                    }
+                }
+            }
+        } else /* if (orig is a standard JavaBean) */ {
+            PropertyDescriptor origDescriptors[] =
+                getPropertyDescriptors(orig);
+            for (int i = 0; i < origDescriptors.length; i++) {
+                String name = origDescriptors[i].getName();
+                if (isReadable(orig, name)) {
+                    if (dest instanceof DynaBean) {
+                        if (isWriteable(dest, name)) {
+                            Object value = getSimpleProperty(orig, name);
+                            ((DynaBean) dest).set(name, value);
+                        }
+                    } else /* if (dest is a standard JavaBean) */ {
+                        if (isWriteable(dest, name)) {
+                            Object value = getSimpleProperty(orig, name);
+                            setSimpleProperty(dest, name, value);
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * <p>Return the entire set of properties for which the specified bean
+     * provides a read method.  This map contains the unconverted property
+     * values for all properties for which a read method is provided
+     * (i.e. where the <code>getReadMethod()</code> returns non-null).</p>
+     *
+     * <p><strong>FIXME</strong> - Does not account for mapped properties.</p>
+     *
+     * @param bean Bean whose properties are to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Map describe(Object bean)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        Map description = new HashMap();
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptors[] =
+                ((DynaBean) bean).getDynaClass().getDynaProperties();
+            for (int i = 0; i < descriptors.length; i++) {
+                String name = descriptors[i].getName();
+                description.put(name, getProperty(bean, name));
+            }
+        } else {
+            PropertyDescriptor descriptors[] =
+                getPropertyDescriptors(bean);
+            for (int i = 0; i < descriptors.length; i++) {
+                String name = descriptors[i].getName();
+                if (descriptors[i].getReadMethod() != null)
+                    description.put(name, getProperty(bean, name));
+            }
+        }
+        return (description);
+
+    }
+
+
+    /**
+     * Return the value of the specified indexed property of the specified
+     * bean, with no type conversions.  The zero-relative index of the
+     * required value must be included (in square brackets) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.  In addition to supporting the JavaBeans specification, this
+     * method has been extended to support <code>List</code> objects as well.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname[index]</code> of the property value
+     *  to be extracted
+     *
+     * @exception ArrayIndexOutOfBoundsException if the specified index
+     *  is outside the valid range for the underlying array
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getIndexedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Identify the index of the requested individual property
+        int delim = name.indexOf(PropertyUtils.INDEXED_DELIM);
+        int delim2 = name.indexOf(PropertyUtils.INDEXED_DELIM2);
+        if ((delim < 0) || (delim2 <= delim)) {
+            throw new IllegalArgumentException("Invalid indexed property '" +
+                    name + "'");
+        }
+        int index = -1;
+        try {
+            String subscript = name.substring(delim + 1, delim2);
+            index = Integer.parseInt(subscript);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("Invalid indexed property '" +
+                    name + "'");
+        }
+        name = name.substring(0, delim);
+
+        // Request the specified indexed property value
+        return (getIndexedProperty(bean, name, index));
+
+    }
+
+
+    /**
+     * Return the value of the specified indexed property of the specified
+     * bean, with no type conversions.  In addition to supporting the JavaBeans
+     * specification, this method has been extended to support
+     * <code>List</code> objects as well.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param index Index of the property value to be extracted
+     *
+     * @exception ArrayIndexOutOfBoundsException if the specified index
+     *  is outside the valid range for the underlying array
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getIndexedProperty(Object bean,
+                                            String name, int index)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Handle DynaBean instances specially
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                throw new NoSuchMethodException("Unknown property '" +
+                        name + "'");
+            }
+            return (((DynaBean) bean).get(name, index));
+        }
+
+        // Retrieve the property descriptor for the specified property
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                    name + "'");
+        }
+
+        // Call the indexed getter method if there is one
+        if (descriptor instanceof IndexedPropertyDescriptor) {
+            Method readMethod = ((IndexedPropertyDescriptor) descriptor).
+                    getIndexedReadMethod();
+            if (readMethod != null) {
+                Object subscript[] = new Object[1];
+                subscript[0] = new Integer(index);
+                try {
+                    return (invokeMethod(readMethod,bean, subscript));
+                } catch (InvocationTargetException e) {
+                    if (e.getTargetException() instanceof
+                            ArrayIndexOutOfBoundsException) {
+                        throw (ArrayIndexOutOfBoundsException)
+                                e.getTargetException();
+                    } else {
+                        throw e;
+                    }
+                }
+            }
+        }
+
+        // Otherwise, the underlying property must be an array
+        Method readMethod = getReadMethod(descriptor);
+        if (readMethod == null) {
+            throw new NoSuchMethodException("Property '" + name +
+                    "' has no getter method");
+        }
+
+        // Call the property getter and return the value
+        Object value = invokeMethod(readMethod, bean, new Object[0]);
+        if (!value.getClass().isArray()) {
+            if (!(value instanceof java.util.List)) {
+                throw new IllegalArgumentException("Property '" + name
+                        + "' is not indexed");
+            } else {
+                //get the List's value
+                return ((java.util.List) value).get(index);
+            }
+        } else {
+            //get the array's value
+            return (Array.get(value, index));
+        }
+
+    }
+
+
+    /**
+     * Return the value of the specified mapped property of the
+     * specified bean, with no type conversions.  The key of the
+     * required value must be included (in brackets) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname(key)</code> of the property value
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getMappedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Identify the index of the requested individual property
+        int delim = name.indexOf(PropertyUtils.MAPPED_DELIM);
+        int delim2 = name.indexOf(PropertyUtils.MAPPED_DELIM2);
+        if ((delim < 0) || (delim2 <= delim)) {
+            throw new IllegalArgumentException
+                    ("Invalid mapped property '" + name + "'");
+        }
+
+        // Isolate the name and the key
+        String key = name.substring(delim + 1, delim2);
+        name = name.substring(0, delim);
+
+        // Request the specified indexed property value
+        return (getMappedProperty(bean, name, key));
+
+    }
+
+
+    /**
+     * Return the value of the specified mapped property of the specified
+     * bean, with no type conversions.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Mapped property name of the property value to be extracted
+     * @param key Key of the property value to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getMappedProperty(Object bean,
+                                           String name, String key)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+        if (key == null) {
+            throw new IllegalArgumentException("No key specified");
+        }
+
+        // Handle DynaBean instances specially
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                throw new NoSuchMethodException("Unknown property '" +
+                        name + "'");
+            }
+            return (((DynaBean) bean).get(name, key));
+        }
+
+        Object result = null;
+
+        // Retrieve the property descriptor for the specified property
+        PropertyDescriptor descriptor = getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                    name + "'");
+        }
+
+        if (descriptor instanceof MappedPropertyDescriptor) {
+            // Call the keyed getter method if there is one
+            Method readMethod = ((MappedPropertyDescriptor) descriptor).
+                    getMappedReadMethod();
+            if (readMethod != null) {
+                Object keyArray[] = new Object[1];
+                keyArray[0] = key;
+                result = invokeMethod(readMethod, bean, keyArray);
+            } else {
+                throw new NoSuchMethodException("Property '" + name +
+                        "' has no mapped getter method");
+            }
+        } else {
+          /* means that the result has to be retrieved from a map */
+          Method readMethod = descriptor.getReadMethod();
+          if (readMethod != null) {
+            Object invokeResult = invokeMethod(readMethod, bean, new Object[0]);
+            /* test and fetch from the map */
+            if (invokeResult instanceof java.util.Map) {
+              result = ((java.util.Map)invokeResult).get(key);
+            }
+          } else {
+            throw new NoSuchMethodException("Property '" + name +
+                    "' has no mapped getter method");
+          }
+        }
+        return result;
+
+    }
+
+
+    /**
+     * <p>Return the mapped property descriptors for this bean class.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param beanClass Bean class to be introspected
+     * @deprecated This method should not be exposed
+     */
+    public FastHashMap getMappedPropertyDescriptors(Class beanClass) {
+
+        if (beanClass == null) {
+            return null;
+        }
+
+        // Look up any cached descriptors for this bean class
+        return (FastHashMap) mappedDescriptorsCache.get(beanClass);
+
+    }
+
+
+    /**
+     * <p>Return the mapped property descriptors for this bean.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param bean Bean to be introspected
+     * @deprecated This method should not be exposed
+     */
+    public FastHashMap getMappedPropertyDescriptors(Object bean) {
+
+        if (bean == null) {
+            return null;
+        }
+        return (getMappedPropertyDescriptors(bean.getClass()));
+
+    }
+
+
+    /**
+     * Return the value of the (possibly nested) property of the specified
+     * name, for the specified bean, with no type conversions.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly nested name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception NestedNullException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException 
+     * if the property accessor method throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getNestedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        int indexOfINDEXED_DELIM = -1;
+        int indexOfMAPPED_DELIM = -1;
+        int indexOfMAPPED_DELIM2 = -1;
+        int indexOfNESTED_DELIM = -1;
+        while (true) {
+            indexOfNESTED_DELIM  = name.indexOf(PropertyUtils.NESTED_DELIM);
+            indexOfMAPPED_DELIM  = name.indexOf(PropertyUtils.MAPPED_DELIM);
+            indexOfMAPPED_DELIM2 = name.indexOf(PropertyUtils.MAPPED_DELIM2);
+            if (indexOfMAPPED_DELIM2 >= 0 && indexOfMAPPED_DELIM >=0 &&
+                (indexOfNESTED_DELIM < 0 || indexOfNESTED_DELIM > indexOfMAPPED_DELIM)) {
+                indexOfNESTED_DELIM =
+                    name.indexOf(PropertyUtils.NESTED_DELIM, indexOfMAPPED_DELIM2);
+            } else {
+                indexOfNESTED_DELIM = name.indexOf(PropertyUtils.NESTED_DELIM);
+            }
+            if (indexOfNESTED_DELIM < 0) {
+                break;
+            }
+            String next = name.substring(0, indexOfNESTED_DELIM);
+            indexOfINDEXED_DELIM = next.indexOf(PropertyUtils.INDEXED_DELIM);
+            indexOfMAPPED_DELIM = next.indexOf(PropertyUtils.MAPPED_DELIM);
+            if (bean instanceof Map) {
+                bean = ((Map) bean).get(next);
+            } else if (indexOfMAPPED_DELIM >= 0) {
+                bean = getMappedProperty(bean, next);
+            } else if (indexOfINDEXED_DELIM >= 0) {
+                bean = getIndexedProperty(bean, next);
+            } else {
+                bean = getSimpleProperty(bean, next);
+            }
+            if (bean == null) {
+                throw new NestedNullException
+                        ("Null property value for '" +
+                        name.substring(0, indexOfNESTED_DELIM) + "'");
+            }
+            name = name.substring(indexOfNESTED_DELIM + 1);
+        }
+
+        indexOfINDEXED_DELIM = name.indexOf(PropertyUtils.INDEXED_DELIM);
+        indexOfMAPPED_DELIM = name.indexOf(PropertyUtils.MAPPED_DELIM);
+
+        if (bean instanceof Map) {
+            bean = ((Map) bean).get(name);
+        } else if (indexOfMAPPED_DELIM >= 0) {
+            bean = getMappedProperty(bean, name);
+        } else if (indexOfINDEXED_DELIM >= 0) {
+            bean = getIndexedProperty(bean, name);
+        } else {
+            bean = getSimpleProperty(bean, name);
+        }
+        return bean;
+
+    }
+
+
+    /**
+     * Return the value of the specified property of the specified bean,
+     * no matter which property reference format is used, with no
+     * type conversions.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly indexed and/or nested name of the property
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return (getNestedProperty(bean, name));
+
+    }
+
+
+    /**
+     * <p>Retrieve the property descriptor for the specified property of the
+     * specified bean, or return <code>null</code> if there is no such
+     * descriptor.  This method resolves indexed and nested property
+     * references in the same manner as other methods in this class, except
+     * that if the last (or only) name element is indexed, the descriptor
+     * for the last resolved property itself is returned.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param bean Bean for which a property descriptor is requested
+     * @param name Possibly indexed and/or nested name of the property for
+     *  which a property descriptor is requested
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public PropertyDescriptor getPropertyDescriptor(Object bean,
+                                                           String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Resolve nested references
+        while (true) {            
+            int period = findNextNestedIndex(name);
+            if (period < 0) {
+                break;
+            }
+            String next = name.substring(0, period);
+            int indexOfINDEXED_DELIM = next.indexOf(PropertyUtils.INDEXED_DELIM);
+            int indexOfMAPPED_DELIM = next.indexOf(PropertyUtils.MAPPED_DELIM);
+            if (indexOfMAPPED_DELIM >= 0 &&
+                    (indexOfINDEXED_DELIM < 0 ||
+                    indexOfMAPPED_DELIM < indexOfINDEXED_DELIM)) {
+                bean = getMappedProperty(bean, next);
+            } else {
+                if (indexOfINDEXED_DELIM >= 0) {
+                    bean = getIndexedProperty(bean, next);
+                } else {
+                    bean = getSimpleProperty(bean, next);
+                }
+            }
+            if (bean == null) {
+                throw new IllegalArgumentException
+                        ("Null property value for '" +
+                        name.substring(0, period) + "'");
+            }
+            name = name.substring(period + 1);
+        }
+
+        // Remove any subscript from the final name value
+        int left = name.indexOf(PropertyUtils.INDEXED_DELIM);
+        if (left >= 0) {
+            name = name.substring(0, left);
+        }
+        left = name.indexOf(PropertyUtils.MAPPED_DELIM);
+        if (left >= 0) {
+            name = name.substring(0, left);
+        }
+
+        // Look up and return this property from our cache
+        // creating and adding it to the cache if not found.
+        if ((bean == null) || (name == null)) {
+            return (null);
+        }
+        
+        PropertyDescriptor descriptors[] = getPropertyDescriptors(bean);
+        if (descriptors != null) {
+            
+            for (int i = 0; i < descriptors.length; i++) {
+                if (name.equals(descriptors[i].getName()))
+                    return (descriptors[i]);
+            }
+        }
+
+        PropertyDescriptor result = null;
+        FastHashMap mappedDescriptors =
+                getMappedPropertyDescriptors(bean);
+        if (mappedDescriptors == null) {
+            mappedDescriptors = new FastHashMap();
+            mappedDescriptors.setFast(true);
+            mappedDescriptorsCache.put(bean.getClass(), mappedDescriptors);
+        }
+        result = (PropertyDescriptor) mappedDescriptors.get(name);
+        if (result == null) {
+            // not found, try to create it
+            try {
+                result =
+                        new MappedPropertyDescriptor(name, bean.getClass());
+            } catch (IntrospectionException ie) {
+            }
+            if (result != null) {
+                mappedDescriptors.put(name, result);
+            }
+        }
+        
+        return result;
+
+    }
+    
+    private int findNextNestedIndex(String expression)
+    {
+        // walk back from the end to the start 
+        // and find the first index that 
+        int bracketCount = 0;
+        for (int i=0, size=expression.length(); i<size ; i++) {
+            char at = expression.charAt(i);
+            switch (at) {
+                case PropertyUtils.NESTED_DELIM:
+                    if (bracketCount < 1) {
+                        return i;
+                    }
+                    break;
+                    
+                case PropertyUtils.MAPPED_DELIM:
+                case PropertyUtils.INDEXED_DELIM:
+                    // not bothered which
+                    ++bracketCount;
+                    break;
+                
+                case PropertyUtils.MAPPED_DELIM2:
+                case PropertyUtils.INDEXED_DELIM2:
+                    // not bothered which
+                    --bracketCount;
+                    break;            
+            }
+        }
+        // can't find any
+        return -1;
+    }
+
+
+    /**
+     * <p>Retrieve the property descriptors for the specified class,
+     * introspecting and caching them the first time a particular bean class
+     * is encountered.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param beanClass Bean class for which property descriptors are requested
+     *
+     * @exception IllegalArgumentException if <code>beanClass</code> is null
+     */
+    public PropertyDescriptor[]
+            getPropertyDescriptors(Class beanClass) {
+
+        if (beanClass == null) {
+            throw new IllegalArgumentException("No bean class specified");
+        }
+
+        // Look up any cached descriptors for this bean class
+        PropertyDescriptor descriptors[] = null;
+        descriptors =
+                (PropertyDescriptor[]) descriptorsCache.get(beanClass);
+        if (descriptors != null) {
+            return (descriptors);
+        }
+
+        // Introspect the bean and cache the generated descriptors
+        BeanInfo beanInfo = null;
+        try {
+            beanInfo = Introspector.getBeanInfo(beanClass);
+        } catch (IntrospectionException e) {
+            return (new PropertyDescriptor[0]);
+        }
+        descriptors = beanInfo.getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+        descriptorsCache.put(beanClass, descriptors);
+        return (descriptors);
+
+    }
+
+
+    /**
+     * <p>Retrieve the property descriptors for the specified bean,
+     * introspecting and caching them the first time a particular bean class
+     * is encountered.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param bean Bean for which property descriptors are requested
+     *
+     * @exception IllegalArgumentException if <code>bean</code> is null
+     */
+    public PropertyDescriptor[] getPropertyDescriptors(Object bean) {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        return (getPropertyDescriptors(bean.getClass()));
+
+    }
+
+
+    /**
+     * <p>Return the Java Class repesenting the property editor class that has
+     * been registered for this property (if any).  This method follows the
+     * same name resolution rules used by <code>getPropertyDescriptor()</code>,
+     * so if the last element of a name reference is indexed, the property
+     * editor for the underlying property's class is returned.</p>
+     *
+     * <p>Note that <code>null</code> will be returned if there is no property,
+     * or if there is no registered property editor class.  Because this
+     * return value is ambiguous, you should determine the existence of the
+     * property itself by other means.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param bean Bean for which a property descriptor is requested
+     * @param name Possibly indexed and/or nested name of the property for
+     *  which a property descriptor is requested
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Class getPropertyEditorClass(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor != null) {
+            return (descriptor.getPropertyEditorClass());
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the Java Class representing the property type of the specified
+     * property, or <code>null</code> if there is no such property for the
+     * specified bean.  This method follows the same name resolution rules
+     * used by <code>getPropertyDescriptor()</code>, so if the last element
+     * of a name reference is indexed, the type of the property itself will
+     * be returned.  If the last (or only) element has no property with the
+     * specified name, <code>null</code> is returned.
+     *
+     * @param bean Bean for which a property descriptor is requested
+     * @param name Possibly indexed and/or nested name of the property for
+     *  which a property descriptor is requested
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Class getPropertyType(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Special handling for DynaBeans
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                return (null);
+            }
+            Class type = descriptor.getType();
+            if (type == null) {
+                return (null);
+            } else if (type.isArray()) {
+                return (type.getComponentType());
+            } else {
+                return (type);
+            }
+        }
+
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            return (null);
+        } else if (descriptor instanceof IndexedPropertyDescriptor) {
+            return (((IndexedPropertyDescriptor) descriptor).
+                    getIndexedPropertyType());
+        } else if (descriptor instanceof MappedPropertyDescriptor) {
+            return (((MappedPropertyDescriptor) descriptor).
+                    getMappedPropertyType());
+        } else {
+            return (descriptor.getPropertyType());
+        }
+
+    }
+
+
+    /**
+     * <p>Return an accessible property getter method for this property,
+     * if there is one; otherwise return <code>null</code>.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param descriptor Property descriptor to return a getter for
+     */
+    public Method getReadMethod(PropertyDescriptor descriptor) {
+
+        return (MethodUtils.getAccessibleMethod(descriptor.getReadMethod()));
+
+    }
+
+
+    /**
+     * Return the value of the specified simple property of the specified
+     * bean, with no type conversions.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception IllegalArgumentException if the property name
+     *  is nested or indexed
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public Object getSimpleProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Validate the syntax of the property name
+        if (name.indexOf(PropertyUtils.NESTED_DELIM) >= 0) {
+            throw new IllegalArgumentException
+                    ("Nested property names are not allowed");
+        } else if (name.indexOf(PropertyUtils.INDEXED_DELIM) >= 0) {
+            throw new IllegalArgumentException
+                    ("Indexed property names are not allowed");
+        } else if (name.indexOf(PropertyUtils.MAPPED_DELIM) >= 0) {
+            throw new IllegalArgumentException
+                    ("Mapped property names are not allowed");
+        }
+
+        // Handle DynaBean instances specially
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                throw new NoSuchMethodException("Unknown property '" +
+                        name + "'");
+            }
+            return (((DynaBean) bean).get(name));
+        }
+
+        // Retrieve the property getter method for the specified property
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                    name + "'");
+        }
+        Method readMethod = getReadMethod(descriptor);
+        if (readMethod == null) {
+            throw new NoSuchMethodException("Property '" + name +
+                    "' has no getter method");
+        }
+
+        // Call the property getter and return the value
+        Object value = invokeMethod(readMethod, bean, new Object[0]);
+        return (value);
+
+    }
+
+
+    /**
+     * <p>Return an accessible property setter method for this property,
+     * if there is one; otherwise return <code>null</code>.</p>
+     *
+     * <p><strong>FIXME</strong> - Does not work with DynaBeans.</p>
+     *
+     * @param descriptor Property descriptor to return a setter for
+     */
+    public Method getWriteMethod(PropertyDescriptor descriptor) {
+
+        return (MethodUtils.getAccessibleMethod(descriptor.getWriteMethod()));
+
+    }
+
+
+    /**
+     * <p>Return <code>true</code> if the specified property name identifies
+     * a readable property on the specified bean; otherwise, return
+     * <code>false</code>.
+     *
+     * @param bean Bean to be examined (may be a {@link DynaBean}
+     * @param name Property name to be evaluated
+     *
+     * @exception IllegalArgumentException if <code>bean</code>
+     *  or <code>name</code> is <code>null</code>
+     *
+     * @since BeanUtils 1.6
+     */
+    public boolean isReadable(Object bean, String name) {
+
+        // Validate method parameters
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Return the requested result
+        if (bean instanceof DynaBean) {
+            // All DynaBean properties are readable
+            return (((DynaBean) bean).getDynaClass().getDynaProperty(name) != null);
+        } else {
+            try {
+                PropertyDescriptor desc =
+                    getPropertyDescriptor(bean, name);
+                if (desc != null) {
+                    Method readMethod = desc.getReadMethod();
+                    if ((readMethod == null) &&
+                        (desc instanceof IndexedPropertyDescriptor)) {
+                        readMethod = ((IndexedPropertyDescriptor) desc).getIndexedReadMethod();
+                    }
+                    return (readMethod != null);
+                } else {
+                    return (false);
+                }
+            } catch (IllegalAccessException e) {
+                return (false);
+            } catch (InvocationTargetException e) {
+                return (false);
+            } catch (NoSuchMethodException e) {
+                return (false);
+            }
+        }
+
+    }
+
+
+    /**
+     * <p>Return <code>true</code> if the specified property name identifies
+     * a writeable property on the specified bean; otherwise, return
+     * <code>false</code>.
+     *
+     * @param bean Bean to be examined (may be a {@link DynaBean}
+     * @param name Property name to be evaluated
+     *
+     * @exception IllegalPointerException if <code>bean</code>
+     *  or <code>name</code> is <code>null</code>
+     *
+     * @since BeanUtils 1.6
+     */
+    public boolean isWriteable(Object bean, String name) {
+
+        // Validate method parameters
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Return the requested result
+        if (bean instanceof DynaBean) {
+            // All DynaBean properties are writeable
+            return (((DynaBean) bean).getDynaClass().getDynaProperty(name) != null);
+        } else {
+            try {
+                PropertyDescriptor desc =
+                    getPropertyDescriptor(bean, name);
+                if (desc != null) {
+                    Method writeMethod = desc.getWriteMethod();
+                    if ((writeMethod == null) &&
+                        (desc instanceof IndexedPropertyDescriptor)) {
+                        writeMethod = ((IndexedPropertyDescriptor) desc).getIndexedWriteMethod();
+                    }
+                    return (writeMethod != null);
+                } else {
+                    return (false);
+                }
+            } catch (IllegalAccessException e) {
+                return (false);
+            } catch (InvocationTargetException e) {
+                return (false);
+            } catch (NoSuchMethodException e) {
+                return (false);
+            }
+        }
+
+    }
+
+
+    /**
+     * Set the value of the specified indexed property of the specified
+     * bean, with no type conversions.  The zero-relative index of the
+     * required value must be included (in square brackets) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.  In addition to supporting the JavaBeans specification, this
+     * method has been extended to support <code>List</code> objects as well.
+     *
+     * @param bean Bean whose property is to be modified
+     * @param name <code>propertyname[index]</code> of the property value
+     *  to be modified
+     * @param value Value to which the specified property element
+     *  should be set
+     *
+     * @exception ArrayIndexOutOfBoundsException if the specified index
+     *  is outside the valid range for the underlying array
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setIndexedProperty(Object bean, String name,
+                                          Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Identify the index of the requested individual property
+        int delim = name.indexOf(PropertyUtils.INDEXED_DELIM);
+        int delim2 = name.indexOf(PropertyUtils.INDEXED_DELIM2);
+        if ((delim < 0) || (delim2 <= delim)) {
+            throw new IllegalArgumentException("Invalid indexed property '" +
+                    name + "'");
+        }
+        int index = -1;
+        try {
+            String subscript = name.substring(delim + 1, delim2);
+            index = Integer.parseInt(subscript);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("Invalid indexed property '" +
+                    name + "'");
+        }
+        name = name.substring(0, delim);
+
+        // Set the specified indexed property value
+        setIndexedProperty(bean, name, index, value);
+
+    }
+
+
+    /**
+     * Set the value of the specified indexed property of the specified
+     * bean, with no type conversions.  In addition to supporting the JavaBeans
+     * specification, this method has been extended to support
+     * <code>List</code> objects as well.
+     *
+     * @param bean Bean whose property is to be set
+     * @param name Simple property name of the property value to be set
+     * @param index Index of the property value to be set
+     * @param value Value to which the indexed property element is to be set
+     *
+     * @exception ArrayIndexOutOfBoundsException if the specified index
+     *  is outside the valid range for the underlying array
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setIndexedProperty(Object bean, String name,
+                                          int index, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Handle DynaBean instances specially
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                throw new NoSuchMethodException("Unknown property '" +
+                        name + "'");
+            }
+            ((DynaBean) bean).set(name, index, value);
+            return;
+        }
+
+        // Retrieve the property descriptor for the specified property
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                    name + "'");
+        }
+
+        // Call the indexed setter method if there is one
+        if (descriptor instanceof IndexedPropertyDescriptor) {
+            Method writeMethod = ((IndexedPropertyDescriptor) descriptor).
+                    getIndexedWriteMethod();
+            if (writeMethod != null) {
+                Object subscript[] = new Object[2];
+                subscript[0] = new Integer(index);
+                subscript[1] = value;
+                try {
+                    if (log.isTraceEnabled()) {
+                        String valueClassName =
+                            value == null ? "<null>" 
+                                          : value.getClass().getName();
+                        log.trace("setSimpleProperty: Invoking method "
+                                  + writeMethod +" with index=" + index
+                                  + ", value=" + value
+                                  + " (class " + valueClassName+ ")");
+                    }
+                    invokeMethod(writeMethod, bean, subscript);
+                } catch (InvocationTargetException e) {
+                    if (e.getTargetException() instanceof
+                            ArrayIndexOutOfBoundsException) {
+                        throw (ArrayIndexOutOfBoundsException)
+                                e.getTargetException();
+                    } else {
+                        throw e;
+                    }
+                }
+                return;
+            }
+        }
+
+        // Otherwise, the underlying property must be an array or a list
+        Method readMethod = descriptor.getReadMethod();
+        if (readMethod == null) {
+            throw new NoSuchMethodException("Property '" + name +
+                    "' has no getter method");
+        }
+
+        // Call the property getter to get the array or list
+        Object array = invokeMethod(readMethod, bean, new Object[0]);
+        if (!array.getClass().isArray()) {
+            if (array instanceof List) {
+                // Modify the specified value in the List
+                ((List) array).set(index, value);
+            } else {
+                throw new IllegalArgumentException("Property '" + name +
+                        "' is not indexed");
+            }
+        } else {
+            // Modify the specified value in the array
+            Array.set(array, index, value);
+        }
+
+    }
+
+
+    /**
+     * Set the value of the specified mapped property of the
+     * specified bean, with no type conversions.  The key of the
+     * value to set must be included (in brackets) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be set
+     * @param name <code>propertyname(key)</code> of the property value
+     *  to be set
+     * @param value The property value to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setMappedProperty(Object bean, String name,
+                                         Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Identify the index of the requested individual property
+        int delim = name.indexOf(PropertyUtils.MAPPED_DELIM);
+        int delim2 = name.indexOf(PropertyUtils.MAPPED_DELIM2);
+        if ((delim < 0) || (delim2 <= delim)) {
+            throw new IllegalArgumentException
+                    ("Invalid mapped property '" + name + "'");
+        }
+
+        // Isolate the name and the key
+        String key = name.substring(delim + 1, delim2);
+        name = name.substring(0, delim);
+
+        // Request the specified indexed property value
+        setMappedProperty(bean, name, key, value);
+
+    }
+
+
+    /**
+     * Set the value of the specified mapped property of the specified
+     * bean, with no type conversions.
+     *
+     * @param bean Bean whose property is to be set
+     * @param name Mapped property name of the property value to be set
+     * @param key Key of the property value to be set
+     * @param value The property value to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setMappedProperty(Object bean, String name,
+                                         String key, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+        if (key == null) {
+            throw new IllegalArgumentException("No key specified");
+        }
+
+        // Handle DynaBean instances specially
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                throw new NoSuchMethodException("Unknown property '" +
+                        name + "'");
+            }
+            ((DynaBean) bean).set(name, key, value);
+            return;
+        }
+
+        // Retrieve the property descriptor for the specified property
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                    name + "'");
+        }
+
+        if (descriptor instanceof MappedPropertyDescriptor) {
+            // Call the keyed setter method if there is one
+            Method mappedWriteMethod =
+                    ((MappedPropertyDescriptor) descriptor).
+                    getMappedWriteMethod();
+            if (mappedWriteMethod != null) {
+                Object params[] = new Object[2];
+                params[0] = key;
+                params[1] = value;
+                if (log.isTraceEnabled()) {
+                    String valueClassName =
+                        value == null ? "<null>" : value.getClass().getName();
+                    log.trace("setSimpleProperty: Invoking method "
+                              + mappedWriteMethod + " with key=" + key
+                              + ", value=" + value
+                              + " (class " + valueClassName +")");
+                }
+                invokeMethod(mappedWriteMethod, bean, params);
+            } else {
+                throw new NoSuchMethodException
+                        ("Property '" + name +
+                        "' has no mapped setter method");
+            }
+        } else {
+          /* means that the result has to be retrieved from a map */
+          Method readMethod = descriptor.getReadMethod();
+          if (readMethod != null) {
+            Object invokeResult = invokeMethod(readMethod, bean, new Object[0]);
+            /* test and fetch from the map */
+            if (invokeResult instanceof java.util.Map) {
+              ((java.util.Map)invokeResult).put(key, value);
+            }
+          } else {
+            throw new NoSuchMethodException("Property '" + name +
+                    "' has no mapped getter method");
+          }
+        }
+
+    }
+
+
+    /**
+     * Set the value of the (possibly nested) property of the specified
+     * name, for the specified bean, with no type conversions.
+     *
+     * @param bean Bean whose property is to be modified
+     * @param name Possibly nested name of the property to be modified
+     * @param value Value to which the property is to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setNestedProperty(Object bean,
+                                         String name, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        int indexOfINDEXED_DELIM = -1;
+        int indexOfMAPPED_DELIM = -1;
+        while (true) {
+            int delim = name.indexOf(PropertyUtils.NESTED_DELIM);
+            if (delim < 0) {
+                break;
+            }
+            String next = name.substring(0, delim);
+            indexOfINDEXED_DELIM = next.indexOf(PropertyUtils.INDEXED_DELIM);
+            indexOfMAPPED_DELIM = next.indexOf(PropertyUtils.MAPPED_DELIM);
+            if (bean instanceof Map) {
+                bean = ((Map) bean).get(next);
+            } else if (indexOfMAPPED_DELIM >= 0) {
+                bean = getMappedProperty(bean, next);
+            } else if (indexOfINDEXED_DELIM >= 0) {
+                bean = getIndexedProperty(bean, next);
+            } else {
+                bean = getSimpleProperty(bean, next);
+            }
+            if (bean == null) {
+                throw new IllegalArgumentException
+                        ("Null property value for '" +
+                        name.substring(0, delim) + "'");
+            }
+            name = name.substring(delim + 1);
+        }
+
+        indexOfINDEXED_DELIM = name.indexOf(PropertyUtils.INDEXED_DELIM);
+        indexOfMAPPED_DELIM = name.indexOf(PropertyUtils.MAPPED_DELIM);
+
+        if (bean instanceof Map) {
+            // check to see if the class has a standard property 
+            PropertyDescriptor descriptor = 
+                getPropertyDescriptor(bean, name);
+            if (descriptor == null) {
+                // no - then put the value into the map
+                ((Map) bean).put(name, value);
+            } else {
+                // yes - use that instead
+                setSimpleProperty(bean, name, value);
+            }
+        } else if (indexOfMAPPED_DELIM >= 0) {
+            setMappedProperty(bean, name, value);
+        } else if (indexOfINDEXED_DELIM >= 0) {
+            setIndexedProperty(bean, name, value);
+        } else {
+            setSimpleProperty(bean, name, value);
+        }
+
+    }
+
+
+    /**
+     * Set the value of the specified property of the specified bean,
+     * no matter which property reference format is used, with no
+     * type conversions.
+     *
+     * @param bean Bean whose property is to be modified
+     * @param name Possibly indexed and/or nested name of the property
+     *  to be modified
+     * @param value Value to which this property is to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setProperty(Object bean, String name, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        setNestedProperty(bean, name, value);
+
+    }
+
+
+    /**
+     * Set the value of the specified simple property of the specified bean,
+     * with no type conversions.
+     *
+     * @param bean Bean whose property is to be modified
+     * @param name Name of the property to be modified
+     * @param value Value to which the property should be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if <code>bean</code> or
+     *  <code>name</code> is null
+     * @exception IllegalArgumentException if the property name is
+     *  nested or indexed
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public void setSimpleProperty(Object bean,
+                                         String name, Object value)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        if (bean == null) {
+            throw new IllegalArgumentException("No bean specified");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("No name specified");
+        }
+
+        // Validate the syntax of the property name
+        if (name.indexOf(PropertyUtils.NESTED_DELIM) >= 0) {
+            throw new IllegalArgumentException
+                    ("Nested property names are not allowed");
+        } else if (name.indexOf(PropertyUtils.INDEXED_DELIM) >= 0) {
+            throw new IllegalArgumentException
+                    ("Indexed property names are not allowed");
+        } else if (name.indexOf(PropertyUtils.MAPPED_DELIM) >= 0) {
+            throw new IllegalArgumentException
+                    ("Mapped property names are not allowed");
+        }
+
+        // Handle DynaBean instances specially
+        if (bean instanceof DynaBean) {
+            DynaProperty descriptor =
+                    ((DynaBean) bean).getDynaClass().getDynaProperty(name);
+            if (descriptor == null) {
+                throw new NoSuchMethodException("Unknown property '" +
+                        name + "'");
+            }
+            ((DynaBean) bean).set(name, value);
+            return;
+        }
+
+        // Retrieve the property setter method for the specified property
+        PropertyDescriptor descriptor =
+                getPropertyDescriptor(bean, name);
+        if (descriptor == null) {
+            throw new NoSuchMethodException("Unknown property '" +
+                    name + "'");
+        }
+        Method writeMethod = getWriteMethod(descriptor);
+        if (writeMethod == null) {
+            throw new NoSuchMethodException("Property '" + name +
+                    "' has no setter method");
+        }
+
+        // Call the property setter method
+        Object values[] = new Object[1];
+        values[0] = value;
+        if (log.isTraceEnabled()) {
+            String valueClassName =
+                value == null ? "<null>" : value.getClass().getName();
+            log.trace("setSimpleProperty: Invoking method " + writeMethod
+                      + " with value " + value + " (class " + valueClassName + ")");
+        }
+        invokeMethod(writeMethod, bean, values);
+
+    }
+    
+    /** This just catches and wraps IllegalArgumentException. */
+    private Object invokeMethod(
+                        Method method, 
+                        Object bean, 
+                        Object[] values) 
+                            throws
+                                IllegalAccessException,
+                                InvocationTargetException {
+        try {
+            
+            return method.invoke(bean, values);
+        
+        } catch (IllegalArgumentException e) {
+            
+            log.error("Method invocation failed.", e);
+            throw new IllegalArgumentException(
+                "Cannot invoke " + method.getDeclaringClass().getName() + "." 
+                + method.getName() + " - " + e.getMessage());
+            
+        }
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.beanutils;
+
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+
+
+/**
+ * <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap the
+ * <code>java.sql.Row</code> objects of a <code>java.sql.ResultSet</code>.
+ * The normal usage pattern is something like:</p>
+ * <pre>
+ *   ResultSet rs = ...;
+ *   ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);
+ *   Iterator rows = rsdc.iterator();
+ *   while (rows.hasNext())  {
+ *     DynaBean row = (DynaBean) rows.next();
+ *     ... process this row ...
+ *   }
+ *   rs.close();
+ * </pre>
+ *
+ * <p>Each column in the result set will be represented as a DynaBean
+ * property of the corresponding name (optionally forced to lower case
+ * for portability).</p>
+ *
+ * <p><strong>WARNING</strong> - Any {@link DynaBean} instance returned by
+ * this class, or from the <code>Iterator</code> returned by the
+ * <code>iterator()</code> method, is directly linked to the row that the
+ * underlying result set is currently positioned at.  This has the following
+ * implications:</p>
+ * <ul>
+ * <li>Once you retrieve a different {@link DynaBean} instance, you should
+ *     no longer use any previous instance.</li>
+ * <li>Changing the position of the underlying result set will change the
+ *     data that the {@link DynaBean} references.</li>
+ * <li>Once the underlying result set is closed, the {@link DynaBean}
+ *     instance may no longer be used.</li>
+ * </ul>
+ *
+ * <p>Any database data that you wish to utilize outside the context of the
+ * current row of an open result set must be copied.  For example, you could
+ * use the following code to create standalone copies of the information in
+ * a result set:</p>
+ * <pre>
+ *   ArrayList results = new ArrayList(); // To hold copied list
+ *   ResultSetDynaClass rsdc = ...;
+ *   DynaProperty properties[] = rsdc.getDynaProperties();
+ *   BasicDynaClass bdc =
+ *     new BasicDynaClass("foo", BasicDynaBean.class,
+ *                        rsdc.getDynaProperties());
+ *   Iterator rows = rsdc.iterator();
+ *   while (rows.hasNext()) {
+ *     DynaBean oldRow = (DynaBean) rows.next();
+ *     DynaBean newRow = bdc.newInstance();
+ *     PropertyUtils.copyProperties(newRow, oldRow);
+ *     results.add(newRow);
+ *   }
+ * </pre>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.15 $ $Date: 2004/02/28 13:18:33 $
+ */
+
+public class ResultSetDynaClass extends JDBCDynaClass implements DynaClass {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * <p>Construct a new ResultSetDynaClass for the specified
+     * <code>ResultSet</code>.  The property names corresponding
+     * to column names in the result set will be lower cased.</p>
+     *
+     * @param resultSet The result set to be wrapped
+     *
+     * @exception NullPointerException if <code>resultSet</code>
+     *  is <code>null</code>
+     * @exception SQLException if the metadata for this result set
+     *  cannot be introspected
+     */
+    public ResultSetDynaClass(ResultSet resultSet) throws SQLException {
+
+        this(resultSet, true);
+
+    }
+
+
+    /**
+     * <p>Construct a new ResultSetDynaClass for the specified
+     * <code>ResultSet</code>.  The property names corresponding
+     * to the column names in the result set will be lower cased or not,
+     * depending on the specified <code>lowerCase</code> value.</p>
+     *
+     * <p><strong>WARNING</strong> - If you specify <code>false</code>
+     * for <code>lowerCase</code>, the returned property names will
+     * exactly match the column names returned by your JDBC driver.
+     * Because different drivers might return column names in different
+     * cases, the property names seen by your application will vary
+     * depending on which JDBC driver you are using.</p>
+     *
+     * @param resultSet The result set to be wrapped
+     * @param lowerCase Should property names be lower cased?
+     *
+     * @exception NullPointerException if <code>resultSet</code>
+     *  is <code>null</code>
+     * @exception SQLException if the metadata for this result set
+     *  cannot be introspected
+     */
+    public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase)
+        throws SQLException {
+
+        if (resultSet == null) {
+            throw new NullPointerException();
+        }
+        this.resultSet = resultSet;
+        this.lowerCase = lowerCase;
+        introspect(resultSet);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * <p>The <code>ResultSet</code> we are wrapping.</p>
+     */
+    protected ResultSet resultSet = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Return an <code>Iterator</code> of {@link DynaBean} instances for
+     * each row of the wrapped <code>ResultSet</code>, in "forward" order.
+     * Unless the underlying result set supports scrolling, this method
+     * should be called only once.</p>
+     */
+    public Iterator iterator() {
+
+        return (new ResultSetIterator(this));
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * <p>Return the result set we are wrapping.</p>
+     */
+    ResultSet getResultSet() {
+
+        return (this.resultSet);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+    
+    /**
+     * <p>Loads the class of the given name which by default uses the class loader used 
+     * to load this library.
+     * Dervations of this class could implement alternative class loading policies such as
+     * using custom ClassLoader or using the Threads's context class loader etc.
+     * </p>
+     */        
+    protected Class loadClass(String className) throws SQLException {
+
+        try {
+            return getClass().getClassLoader().loadClass(className);
+        } 
+        catch (Exception e) {
+            throw new SQLException("Cannot load column class '" +
+                                   className + "': " + e);
+        }
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetIterator.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetIterator.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/ResultSetIterator.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+
+/**
+ * <p>Implementation of <code>java.util.Iterator</code> returned by the
+ * <code>iterator()</code> method of {@link ResultSetDynaClass}.  Each
+ * object returned by this iterator will be a {@link DynaBean} that
+ * represents a single row from the result set being wrapped.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:34 $
+ */
+
+public class ResultSetIterator implements DynaBean, Iterator {
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * <p>Construct an <code>Iterator</code> for the result set being wrapped
+     * by the specified {@link ResultSetDynaClass}.</p>
+     *
+     * @param dynaClass The {@link ResultSetDynaClass} wrapping the
+     *  result set we will iterate over
+     */
+    ResultSetIterator(ResultSetDynaClass dynaClass) {
+
+        this.dynaClass = dynaClass;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+
+    /**
+     * <p>Flag indicating whether the result set is currently positioned at a
+     * row for which we have not yet returned an element in the iteration.</p>
+     */
+    protected boolean current = false;
+
+
+    /**
+     * <p>The {@link ResultSetDynaClass} we are associated with.</p>
+     */
+    protected ResultSetDynaClass dynaClass = null;
+
+
+    /**
+     * <p>Flag indicating whether the result set has indicated that there are
+     * no further rows.</p>
+     */
+    protected boolean eof = false;
+
+
+    // ------------------------------------------------------- DynaBean Methods
+
+
+    /**
+     * Does the specified mapped property contain a value for the specified
+     * key value?
+     *
+     * @param name Name of the property to check
+     * @param key Name of the key to check
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public boolean contains(String name, String key) {
+
+        throw new UnsupportedOperationException
+            ("FIXME - mapped properties not currently supported");
+
+    }
+
+
+    /**
+     * Return the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public Object get(String name) {
+
+        if (dynaClass.getDynaProperty(name) == null) {
+            throw new IllegalArgumentException(name);
+        }
+        try {
+            return (dynaClass.getResultSet().getObject(name));
+        } catch (SQLException e) {
+            throw new RuntimeException
+                ("get(" + name + "): SQLException: " + e);
+        }
+
+    }
+
+
+    /**
+     * Return the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param index Index of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     * @exception NullPointerException if no array or List has been
+     *  initialized for this property
+     */
+    public Object get(String name, int index) {
+
+        throw new UnsupportedOperationException
+            ("FIXME - indexed properties not currently supported");
+
+    }
+
+
+    /**
+     * Return the value of a mapped property with the specified name,
+     * or <code>null</code> if there is no value for the specified key.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param key Key of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public Object get(String name, String key) {
+
+        throw new UnsupportedOperationException
+            ("FIXME - mapped properties not currently supported");
+
+    }
+
+
+    /**
+     * Return the <code>DynaClass</code> instance that describes the set of
+     * properties available for this DynaBean.
+     */
+    public DynaClass getDynaClass() {
+
+        return (this.dynaClass);
+
+    }
+
+
+    /**
+     * Remove any existing value for the specified key on the
+     * specified mapped property.
+     *
+     * @param name Name of the property for which a value is to
+     *  be removed
+     * @param key Key of the value to be removed
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public void remove(String name, String key) {
+
+        throw new UnsupportedOperationException
+            ("FIXME - mapped operations not currently supported");
+
+    }
+
+
+    /**
+     * Set the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception NullPointerException if an attempt is made to set a
+     *  primitive property to null
+     */
+    public void set(String name, Object value) {
+
+        if (dynaClass.getDynaProperty(name) == null) {
+            throw new IllegalArgumentException(name);
+        }
+        try {
+            dynaClass.getResultSet().updateObject(name, value);
+        } catch (SQLException e) {
+            throw new RuntimeException
+                ("set(" + name + "): SQLException: " + e);
+        }
+
+    }
+
+
+    /**
+     * Set the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param index Index of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     */
+    public void set(String name, int index, Object value) {
+
+        throw new UnsupportedOperationException
+            ("FIXME - indexed properties not currently supported");
+
+    }
+
+
+    /**
+     * Set the value of a mapped property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param key Key of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public void set(String name, String key, Object value) {
+
+        throw new UnsupportedOperationException
+            ("FIXME - mapped properties not currently supported");
+
+    }
+
+
+    // ------------------------------------------------------- Iterator Methods
+
+
+    /**
+     * <p>Return <code>true</code> if the iteration has more elements.</p>
+     */
+    public boolean hasNext() {
+
+        try {
+            advance();
+            return (!eof);
+        } catch (SQLException e) {
+            throw new RuntimeException("hasNext():  SQLException:  " + e);
+        }
+
+    }
+
+
+    /**
+     * <p>Return the next element in the iteration.</p>
+     */
+    public Object next() {
+
+        try {
+            advance();
+            if (eof) {
+                throw new NoSuchElementException();
+            }
+            current = false;
+            return (this);
+        } catch (SQLException e) {
+            throw new RuntimeException("next():  SQLException:  " + e);
+        }
+
+    }
+
+
+    /**
+     * <p>Remove the current element from the iteration.  This method is
+     * not supported.</p>
+     */
+    public void remove() {
+
+        throw new UnsupportedOperationException("remove()");
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * <p>Advance the result set to the next row, if there is not a current
+     * row (and if we are not already at eof).</p>
+     *
+     * @exception SQLException if the result set throws an exception
+     */
+    protected void advance() throws SQLException {
+
+        if (!current && !eof) {
+            if (dynaClass.getResultSet().next()) {
+                current = true;
+                eof = false;
+            } else {
+                current = false;
+                eof = true;
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/RowSetDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/RowSetDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/RowSetDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Implementation of {@link DynaClass} that creates an in-memory collection
+ * of {@link DynaBean}s representing the results of an SQL query.  Once the
+ * {@link DynaClass} instance has been created, the JDBC <code>ResultSet</code>
+ * and <code>Statement</code> on which it is based can be closed, and the
+ * underlying <code>Connection</code> can be returned to its connection pool
+ * (if you are using one).</p>
+ *
+ * <p>The normal usage pattern is something like:</p>
+ * <pre>
+ *   Connection conn = ...;  // Acquire connection from pool
+ *   Statement stmt = conn.createStatement();
+ *   ResultSet rs = stmt.executeQuery("SELECT ...");
+ *   RowSetDynaClass rsdc = new RowSetDynaClass(rs);
+ *   rs.close();
+ *   stmt.close();
+ *   ...;                    // Return connection to pool
+ *   List rows = rsdc.getRows();
+ *   ...;                   // Process the rows as desired
+ * </pre>
+ *
+ * <p>Each column in the result set will be represented as a {@link DynaBean}
+ * property of the corresponding name (optionally forced to lower case
+ * for portability).  There will be one {@link DynaBean} in the
+ * <code>List</code> returned by <code>getRows()</code> for each
+ * row in the original <code>ResultSet</code>.</p>
+ *
+ * <p>In general, instances of {@link RowSetDynaClass} can be serialized
+ * and deserialized, which will automatically include the list of
+ * {@link DynaBean}s representing the data content.  The only exception
+ * to this rule would be when the underlying property values that were
+ * copied from the <code>ResultSet</code> originally cannot themselves
+ * be serialized.  Therefore, a {@link RowSetDynaClass} makes a very
+ * convenient mechanism for transporting data sets to remote Java-based
+ * application components.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.9 $ $Date: 2004/02/28 13:18:34 $
+ */
+
+public class RowSetDynaClass extends JDBCDynaClass implements DynaClass, Serializable {
+
+
+    // ----------------------------------------------------- Instance variables
+    
+    /**
+     * <p>Limits the size of the returned list.  The call to 
+     * <code>getRows()</code> will return at most limit number of rows.
+     * If less than or equal to 0, does not limit the size of the result.
+     */
+    protected int limit = -1;
+
+    /**
+     * <p>The list of {@link DynaBean}s representing the contents of
+     * the original <code>ResultSet</code> on which this
+     * {@link RowSetDynaClass} was based.</p>
+     */
+    protected List rows = new ArrayList();
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * <p>Construct a new {@link RowSetDynaClass} for the specified
+     * <code>ResultSet</code>.  The property names corresponding
+     * to column names in the result set will be lower cased.</p>
+     *
+     * @param resultSet The result set to be wrapped
+     *
+     * @exception NullPointerException if <code>resultSet</code>
+     *  is <code>null</code>
+     * @exception SQLException if the metadata for this result set
+     *  cannot be introspected
+     */
+    public RowSetDynaClass(ResultSet resultSet) throws SQLException {
+
+        this(resultSet, true, -1);
+
+    }
+
+    /**
+     * <p>Construct a new {@link RowSetDynaClass} for the specified
+     * <code>ResultSet</code>.  The property names corresponding
+     * to column names in the result set will be lower cased.</p>
+     * 
+     * If <code>limit</code> is not less than 0, max <code>limit</code>
+     * number of rows will be copied into the list. 
+     *
+     * @param resultSet The result set to be wrapped
+     * @param limit The maximum for the size of the result. 
+     *
+     * @exception NullPointerException if <code>resultSet</code>
+     *  is <code>null</code>
+     * @exception SQLException if the metadata for this result set
+     *  cannot be introspected
+     */
+    public RowSetDynaClass(ResultSet resultSet, int limit) throws SQLException {
+
+        this(resultSet, true, limit);
+
+    }
+
+
+    /**
+     * <p>Construct a new {@link RowSetDynaClass} for the specified
+     * <code>ResultSet</code>.  The property names corresponding
+     * to the column names in the result set will be lower cased or not,
+     * depending on the specified <code>lowerCase</code> value.</p>
+     *
+     * If <code>limit</code> is not less than 0, max <code>limit</code>
+     * number of rows will be copied into the resultset. 
+     *
+     *
+     * @param resultSet The result set to be wrapped
+     * @param lowerCase Should property names be lower cased?
+     *
+     * @exception NullPointerException if <code>resultSet</code>
+     *  is <code>null</code>
+     * @exception SQLException if the metadata for this result set
+     *  cannot be introspected
+     */
+    public RowSetDynaClass(ResultSet resultSet, boolean lowerCase)
+                                                    throws SQLException {
+        this(resultSet, lowerCase, -1);
+
+    }
+	
+    /**
+     * <p>Construct a new {@link RowSetDynaClass} for the specified
+     * <code>ResultSet</code>.  The property names corresponding
+     * to the column names in the result set will be lower cased or not,
+     * depending on the specified <code>lowerCase</code> value.</p>
+     *
+     * <p><strong>WARNING</strong> - If you specify <code>false</code>
+     * for <code>lowerCase</code>, the returned property names will
+     * exactly match the column names returned by your JDBC driver.
+     * Because different drivers might return column names in different
+     * cases, the property names seen by your application will vary
+     * depending on which JDBC driver you are using.</p>
+     *
+     * @param resultSet The result set to be wrapped
+     * @param lowerCase Should property names be lower cased?
+     *
+     * @exception NullPointerException if <code>resultSet</code>
+     *  is <code>null</code>
+     * @exception SQLException if the metadata for this result set
+     *  cannot be introspected
+     */
+    public RowSetDynaClass(ResultSet resultSet, boolean lowerCase, int limit)
+                                                            throws SQLException {
+
+        if (resultSet == null) {
+            throw new NullPointerException();
+        }
+        this.lowerCase = lowerCase;
+        this.limit = limit;
+        introspect(resultSet);
+        copy(resultSet);
+
+    }
+
+    /**
+     * <p>Return a <code>List</code> containing the {@link DynaBean}s that
+     * represent the contents of each <code>Row</code> from the
+     * <code>ResultSet</code> that was the basis of this
+     * {@link RowSetDynaClass} instance.  These {@link DynaBean}s are
+     * disconnected from the database itself, so there is no problem with
+     * modifying the contents of the list, or the values of the properties
+     * of these {@link DynaBean}s.  However, it is the application's
+     * responsibility to persist any such changes back to the database,
+     * if it so desires.</p>
+     */
+    public List getRows() {
+
+        return (this.rows);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * <p>Copy the column values for each row in the specified
+     * <code>ResultSet</code> into a newly created {@link DynaBean}, and add
+     * this bean to the list of {@link DynaBean}s that will later by
+     * returned by a call to <code>getRows()</code>.</p>
+     *
+     * @param resultSet The <code>ResultSet</code> whose data is to be
+     *  copied
+     *
+     * @exception SQLException if an error is encountered copying the data
+     */
+    protected void copy(ResultSet resultSet) throws SQLException {
+
+        int cnt = 0;
+        while (resultSet.next() && (limit < 0  || cnt++ < limit) ) {	
+            DynaBean bean = createDynaBean();
+            for (int i = 0; i < properties.length; i++) {
+                String name = properties[i].getName();
+                bean.set(name, resultSet.getObject(name));
+            }
+            rows.add(bean);
+        }
+
+    }
+
+
+    /**
+     * <p>Create and return a new {@link DynaBean} instance to be used for
+     * representing a row in the underlying result set.</p>
+     */
+    protected DynaBean createDynaBean() {
+
+        return (new BasicDynaBean(this));
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+
+
+
+/**
+ * <p>Implementation of <code>DynaBean</code> that wraps a standard JavaBean
+ * instance, so that DynaBean APIs can be used to access its properties.</p>
+ *
+ * <p>
+ * The most common use cases for this class involve wrapping an existing java bean.
+ * (This makes it different from the typical use cases for other <code>DynaBean</code>'s.) 
+ * For example:
+ * </p>
+ * <code><pre>
+ *  Object aJavaBean = ...;
+ *  ...
+ *  DynaBean db = new WrapDynaBean(aJavaBean);
+ *  ...
+ * </pre></code>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does not
+ * support the <code>contains()</code> and <code>remove()</code> methods.</p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 1.9 $ $Date: 2004/02/28 13:18:34 $
+ */
+
+public class WrapDynaBean implements DynaBean {
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new <code>DynaBean</code> associated with the specified
+     * JavaBean instance.
+     *
+     * @param instance JavaBean instance to be wrapped
+     */
+    public WrapDynaBean(Object instance) {
+
+        super();
+        this.instance = instance;
+        this.dynaClass = WrapDynaClass.createDynaClass(instance.getClass());
+
+    }
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    /**
+     * The <code>DynaClass</code> "base class" that this DynaBean
+     * is associated with.
+     */
+    protected WrapDynaClass dynaClass = null;
+
+
+    /**
+     * The JavaBean instance wrapped by this WrapDynaBean.
+     */
+    protected Object instance = null;
+
+
+    // ------------------------------------------------------ DynaBean Methods
+
+
+    /**
+     * Does the specified mapped property contain a value for the specified
+     * key value?
+     *
+     * @param name Name of the property to check
+     * @param key Name of the key to check
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public boolean contains(String name, String key) {
+
+        throw new UnsupportedOperationException
+                ("WrapDynaBean does not support contains()");
+
+    }
+
+
+    /**
+     * Return the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public Object get(String name) {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getSimpleProperty(instance, name);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no read method");
+        }
+        return (value);
+
+    }
+
+
+    /**
+     * Return the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param index Index of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     * @exception NullPointerException if no array or List has been
+     *  initialized for this property
+     */
+    public Object get(String name, int index) {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getIndexedProperty(instance, name, index);
+        } catch (IndexOutOfBoundsException e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no indexed read method");
+        }
+        return (value);
+
+    }
+
+
+    /**
+     * Return the value of a mapped property with the specified name,
+     * or <code>null</code> if there is no value for the specified key.
+     *
+     * @param name Name of the property whose value is to be retrieved
+     * @param key Key of the value to be retrieved
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public Object get(String name, String key) {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getMappedProperty(instance, name, key);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no mapped read method");
+        }
+        return (value);
+
+    }
+
+
+    /**
+     * Return the <code>DynaClass</code> instance that describes the set of
+     * properties available for this DynaBean.
+     */
+    public DynaClass getDynaClass() {
+
+        return (this.dynaClass);
+
+    }
+
+
+    /**
+     * Remove any existing value for the specified key on the
+     * specified mapped property.
+     *
+     * @param name Name of the property for which a value is to
+     *  be removed
+     * @param key Key of the value to be removed
+     *
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     */
+    public void remove(String name, String key) {
+
+
+        throw new UnsupportedOperationException
+                ("WrapDynaBean does not support remove()");
+
+    }
+
+
+    /**
+     * Set the value of a simple property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception NullPointerException if an attempt is made to set a
+     *  primitive property to null
+     */
+    public void set(String name, Object value) {
+
+        try {
+            PropertyUtils.setSimpleProperty(instance, name, value);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no write method");
+        }
+
+    }
+
+
+    /**
+     * Set the value of an indexed property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param index Index of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not indexed
+     * @exception IndexOutOfBoundsException if the specified index
+     *  is outside the range of the underlying property
+     */
+    public void set(String name, int index, Object value) {
+
+        try {
+            PropertyUtils.setIndexedProperty(instance, name, index, value);
+        } catch (IndexOutOfBoundsException e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no indexed write method");
+        }
+
+    }
+
+
+    /**
+     * Set the value of a mapped property with the specified name.
+     *
+     * @param name Name of the property whose value is to be set
+     * @param key Key of the property to be set
+     * @param value Value to which this property is to be set
+     *
+     * @exception ConversionException if the specified value cannot be
+     *  converted to the type required for this property
+     * @exception IllegalArgumentException if there is no property
+     *  of the specified name
+     * @exception IllegalArgumentException if the specified property
+     *  exists, but is not mapped
+     */
+    public void set(String name, String key, Object value) {
+
+        try {
+            PropertyUtils.setMappedProperty(instance, name, key, value);
+        } catch (Throwable t) {
+            throw new IllegalArgumentException
+                    ("Property '" + name + "' has no mapped write method");
+        }
+
+    }
+
+    /** 
+     * Gets the bean instance wrapped by this DynaBean.
+     * For most common use cases, 
+     * this object should already be known 
+     * and this method safely be ignored.
+     * But some creators of frameworks using <code>DynaBean</code>'s may 
+     * find this useful.
+     *
+     * @return the java bean Object wrapped by this <code>DynaBean</code>
+     */
+    public Object getInstance() {
+        return instance;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the property descriptor for the specified property name.
+     *
+     * @param name Name of the property for which to retrieve the descriptor
+     *
+     * @exception IllegalArgumentException if this is not a valid property
+     *  name for our DynaClass
+     */
+    protected DynaProperty getDynaProperty(String name) {
+
+        DynaProperty descriptor = getDynaClass().getDynaProperty(name);
+        if (descriptor == null) {
+            throw new IllegalArgumentException
+                    ("Invalid property name '" + name + "'");
+        }
+        return (descriptor);
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaClass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaClass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/WrapDynaClass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.beans.PropertyDescriptor;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap
+ * standard JavaBean instances.</p>
+ *
+ * <p>
+ * It is suggested that this class should not usually need to be used directly
+ * to create new <code>WrapDynaBean</code> instances. 
+ * It's usually better to call the <code>WrapDynaBean</code> constructor directly.
+ * For example:</p>
+ * <code><pre>
+ *   Object javaBean = ...;
+ *   DynaBean wrapper = new WrapDynaBean(javaBean);
+ * </pre></code>
+ * <p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:34 $
+ */
+
+public class WrapDynaClass implements DynaClass {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new WrapDynaClass for the specified JavaBean class.  This
+     * constructor is private; WrapDynaClass instances will be created as
+     * needed via calls to the <code>createDynaClass(Class)</code> method.
+     *
+     * @param beanClass JavaBean class to be introspected around
+     */
+    private WrapDynaClass(Class beanClass) {
+
+        this.beanClass = beanClass;
+        introspect();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The JavaBean <code>Class</code> which is represented by this
+     * <code>WrapDynaClass</code>.
+     */
+    protected Class beanClass = null;
+
+
+    /**
+     * The set of PropertyDescriptors for this bean class.
+     */
+    protected PropertyDescriptor descriptors[] = null;
+
+
+    /**
+     * The set of PropertyDescriptors for this bean class, keyed by the
+     * property name.  Individual descriptor instances will be the same
+     * instances as those in the <code>descriptors</code> list.
+     */
+    protected HashMap descriptorsMap = new HashMap();
+
+
+    /**
+     * The set of dynamic properties that are part of this DynaClass.
+     */
+    protected DynaProperty properties[] = null;
+
+
+    /**
+     * The set of dynamic properties that are part of this DynaClass,
+     * keyed by the property name.  Individual descriptor instances will
+     * be the same instances as those in the <code>properties</code> list.
+     */
+    protected HashMap propertiesMap = new HashMap();
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of <code>WrapDynaClass</code> instances that have ever been
+     * created, keyed by the underlying bean Class.
+     */
+    protected static HashMap dynaClasses = new HashMap();
+
+
+    // ------------------------------------------------------ DynaClass Methods
+
+
+    /**
+     * Return the name of this DynaClass (analogous to the
+     * <code>getName()</code> method of <code>java.lang.Class</code), which
+     * allows the same <code>DynaClass</code> implementation class to support
+     * different dynamic classes, with different sets of properties.
+     */
+    public String getName() {
+
+        return (this.beanClass.getName());
+
+    }
+
+
+    /**
+     * Return a property descriptor for the specified property, if it exists;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the dynamic property for which a descriptor
+     *  is requested
+     *
+     * @exception IllegalArgumentException if no property name is specified
+     */
+    public DynaProperty getDynaProperty(String name) {
+
+        if (name == null) {
+            throw new IllegalArgumentException
+                    ("No property name specified");
+        }
+        return ((DynaProperty) propertiesMap.get(name));
+
+    }
+
+
+    /**
+     * <p>Return an array of <code>ProperyDescriptors</code> for the properties
+     * currently defined in this DynaClass.  If no properties are defined, a
+     * zero-length array will be returned.</p>
+     *
+     * <p><strong>FIXME</strong> - Should we really be implementing
+     * <code>getBeanInfo()</code> instead, which returns property descriptors
+     * and a bunch of other stuff?</p>
+     */
+    public DynaProperty[] getDynaProperties() {
+
+        return (properties);
+
+    }
+
+
+    /**
+     * <p>Instantiates a new standard JavaBean instance associated with
+     * this DynaClass and return it wrapped in a new WrapDynaBean   
+     * instance. <strong>NOTE</strong> the JavaBean should have a 
+     * no argument constructor.</p>
+     *
+     * <strong>NOTE</strong> - Most common use cases should not need to use
+     * this method. It is usually better to create new
+     * <code>WrapDynaBean</code> instances by calling its constructor.
+     * For example:</p>
+     * <code><pre>
+     *   Object javaBean = ...;
+     *   DynaBean wrapper = new WrapDynaBean(javaBean);
+     * </pre></code>
+     * <p>
+     * (This method is needed for some kinds of <code>DynaBean</code> framework.)
+     * </p>
+     *
+     * @exception IllegalAccessException if the Class or the appropriate
+     *  constructor is not accessible
+     * @exception InstantiationException if this Class represents an abstract
+     *  class, an array class, a primitive type, or void; or if instantiation
+     *  fails for some other reason
+     */
+    public DynaBean newInstance()
+            throws IllegalAccessException, InstantiationException {
+
+        return new WrapDynaBean(beanClass.newInstance());
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the PropertyDescriptor for the specified property name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param name Name of the property to be retrieved
+     */
+    public PropertyDescriptor getPropertyDescriptor(String name) {
+
+        return ((PropertyDescriptor) descriptorsMap.get(name));
+
+    }
+
+
+    // --------------------------------------------------------- Static Methods
+
+
+    /**
+     * Clear our cache of WrapDynaClass instances.
+     */
+    public static void clear() {
+
+        synchronized (dynaClasses) {
+            dynaClasses.clear();
+        }
+
+    }
+
+
+    /**
+     * Create (if necessary) and return a new <code>WrapDynaClass</code>
+     * instance for the specified bean class.
+     *
+     * @param beanClass Bean class for which a WrapDynaClass is requested
+     */
+    public static WrapDynaClass createDynaClass(Class beanClass) {
+
+        synchronized (dynaClasses) {
+            WrapDynaClass dynaClass =
+                    (WrapDynaClass) dynaClasses.get(beanClass);
+            if (dynaClass == null) {
+                dynaClass = new WrapDynaClass(beanClass);
+                dynaClasses.put(beanClass, dynaClass);
+            }
+            return (dynaClass);
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Introspect our bean class to identify the supported properties.
+     */
+    protected void introspect() {
+
+        // Look up the property descriptors for this bean class
+        PropertyDescriptor regulars[] =
+                PropertyUtils.getPropertyDescriptors(beanClass);
+        if (regulars == null) {
+            regulars = new PropertyDescriptor[0];
+        }
+        HashMap mappeds =
+                PropertyUtils.getMappedPropertyDescriptors(beanClass);
+        if (mappeds == null) {
+            mappeds = new HashMap();
+        }
+
+        // Construct corresponding DynaProperty information
+        properties = new DynaProperty[regulars.length + mappeds.size()];
+        for (int i = 0; i < regulars.length; i++) {
+            descriptorsMap.put(regulars[i].getName(),
+                    regulars[i]);
+            properties[i] =
+                    new DynaProperty(regulars[i].getName(),
+                            regulars[i].getPropertyType());
+            propertiesMap.put(properties[i].getName(),
+                    properties[i]);
+        }
+        int j = regulars.length;
+        Iterator names = mappeds.keySet().iterator();
+        while (names.hasNext()) {
+            String name = (String) names.next();
+            PropertyDescriptor descriptor =
+                    (PropertyDescriptor) mappeds.get(name);
+            properties[j] =
+                    new DynaProperty(descriptor.getName(),
+                            Map.class);
+            propertiesMap.put(properties[j].getName(),
+                    properties[j]);
+            j++;
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/AbstractArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/AbstractArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/AbstractArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+
+/**
+ * <p>Convenience base class for converters that translate the String
+ * representation of an array into a corresponding array of primitives
+ * object.  This class encapsulates the functionality required to parse
+ * the String into a list of String elements that can later be
+ * individually converted to the appropriate primitive type.</p>
+ *
+ * <p>The input syntax accepted by the <code>parseElements()</code> method
+ * is designed to be compatible with the syntax used to initialize arrays
+ * in a Java source program, except that only String literal values are
+ * supported.  For maximum flexibility, the surrounding '{' and '}'
+ * characters are optional, and individual elements may be separated by
+ * any combination of whitespace and comma characters.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public abstract class AbstractArrayConverter implements Converter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    protected Object defaultValue = null;
+
+
+    /**
+     * <p>Model object for string arrays.</p>
+     */
+    protected static String strings[] = new String[0];
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    protected boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.  This method must be implemented by a concrete
+     * subclass.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public abstract Object convert(Class type, Object value);
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * <p>Parse an incoming String of the form similar to an array initializer
+     * in the Java language into a <code>List</code> individual Strings
+     * for each element, according to the following rules.</p>
+     * <ul>
+     * <li>The string must have matching '{' and '}' delimiters around
+     *     a comma-delimited list of values.</li>
+     * <li>Whitespace before and after each element is stripped.
+     * <li>If an element is itself delimited by matching single or double
+     *     quotes, the usual rules for interpreting a quoted String apply.</li>
+     * </ul>
+     *
+     * @param svalue String value to be parsed
+     *
+     * @exception ConversionException if the syntax of <code>svalue</code>
+     *  is not syntactically valid
+     * @exception NullPointerException if <code>svalue</code>
+     *  is <code>null</code>
+     */
+    protected List parseElements(String svalue) {
+
+        // Validate the passed argument
+        if (svalue == null) {
+            throw new NullPointerException();
+        }
+
+        // Trim any matching '{' and '}' delimiters
+        svalue = svalue.trim();
+        if (svalue.startsWith("{") && svalue.endsWith("}")) {
+            svalue = svalue.substring(1, svalue.length() - 1);
+        }
+
+        try {
+
+            // Set up a StreamTokenizer on the characters in this String
+            StreamTokenizer st =
+                new StreamTokenizer(new StringReader(svalue));
+            st.whitespaceChars(',',','); // Commas are delimiters
+            st.ordinaryChars('0', '9');  // Needed to turn off numeric flag
+            st.ordinaryChars('.', '.');
+            st.ordinaryChars('-', '-');
+            st.wordChars('0', '9');      // Needed to make part of tokens
+            st.wordChars('.', '.');
+            st.wordChars('-', '-');
+
+            // Split comma-delimited tokens into a List
+            ArrayList list = new ArrayList();
+            while (true) {
+                int ttype = st.nextToken();
+                if ((ttype == StreamTokenizer.TT_WORD) ||
+                    (ttype > 0)) {
+                    list.add(st.sval);
+                } else if (ttype == StreamTokenizer.TT_EOF) {
+                    break;
+                } else {
+                    throw new ConversionException
+                        ("Encountered token of type " + ttype);
+                }
+            }
+
+            // Return the completed list
+            return (list);
+
+        } catch (IOException e) {
+
+            throw new ConversionException(e);
+
+        }
+
+
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigDecimalConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigDecimalConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigDecimalConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.math.BigDecimal;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.math.BigDecimal</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class BigDecimalConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public BigDecimalConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public BigDecimalConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof BigDecimal) {
+            return (value);
+        }
+
+        try {
+            return (new BigDecimal(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigIntegerConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigIntegerConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BigIntegerConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.math.BigInteger;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.math.BigInteger</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class BigIntegerConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public BigIntegerConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public BigIntegerConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof BigInteger) {
+            return (value);
+        }
+
+        try {
+            return (new BigInteger(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of boolean.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class BooleanArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public BooleanArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public BooleanArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static boolean model[] = new boolean[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                boolean results[] = new boolean[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    String stringValue = values[i];
+                    if (stringValue.equalsIgnoreCase("yes") ||
+                        stringValue.equalsIgnoreCase("y") ||
+                        stringValue.equalsIgnoreCase("true") ||
+                        stringValue.equalsIgnoreCase("on") ||
+                        stringValue.equalsIgnoreCase("1")) {
+                        results[i] = true;
+                    } else if (stringValue.equalsIgnoreCase("no") ||
+                               stringValue.equalsIgnoreCase("n") ||
+                               stringValue.equalsIgnoreCase("false") ||
+                               stringValue.equalsIgnoreCase("off") ||
+                               stringValue.equalsIgnoreCase("0")) {
+                        results[i] = false;
+                    } else {
+                        if (useDefault) {
+                            return (defaultValue);
+                        } else {
+                            throw new ConversionException(value.toString());
+                        }
+                    }
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            boolean results[] = new boolean[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                String stringValue = (String) list.get(i);
+                if (stringValue.equalsIgnoreCase("yes") ||
+                    stringValue.equalsIgnoreCase("y") ||
+                    stringValue.equalsIgnoreCase("true") ||
+                    stringValue.equalsIgnoreCase("on") ||
+                    stringValue.equalsIgnoreCase("1")) {
+                    results[i] = true;
+                } else if (stringValue.equalsIgnoreCase("no") ||
+                           stringValue.equalsIgnoreCase("n") ||
+                           stringValue.equalsIgnoreCase("false") ||
+                           stringValue.equalsIgnoreCase("off") ||
+                           stringValue.equalsIgnoreCase("0")) {
+                    results[i] = false;
+                } else {
+                    if (useDefault) {
+                        return (defaultValue);
+                    } else {
+                        throw new ConversionException(value.toString());
+                    }
+                }
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/BooleanConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Boolean</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.9 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class BooleanConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public BooleanConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public BooleanConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Boolean) {
+            return (value);
+        }
+
+        try {
+            String stringValue = value.toString();
+            if (stringValue.equalsIgnoreCase("yes") ||
+                stringValue.equalsIgnoreCase("y") ||
+                stringValue.equalsIgnoreCase("true") ||
+                stringValue.equalsIgnoreCase("on") ||
+                stringValue.equalsIgnoreCase("1")) {
+                return (Boolean.TRUE);
+            } else if (stringValue.equalsIgnoreCase("no") ||
+                       stringValue.equalsIgnoreCase("n") ||
+                       stringValue.equalsIgnoreCase("false") ||
+                       stringValue.equalsIgnoreCase("off") ||
+                       stringValue.equalsIgnoreCase("0")) {
+                return (Boolean.FALSE);
+            } else if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(stringValue);
+            }
+        } catch (ClassCastException e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of byte.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class ByteArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public ByteArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public ByteArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static byte model[] = new byte[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                byte results[] = new byte[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = Byte.parseByte(values[i]);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            byte results[] = new byte[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = Byte.parseByte((String) list.get(i));
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ByteConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Byte</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.9 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class ByteConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public ByteConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public ByteConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // System.err.println("VALUE=" + value + ", TYPE=" + value.getClass().getName());
+
+        if (value instanceof Byte) {
+            return (value);
+        } else if (value instanceof Number) {
+            return new Byte(((Number)value).byteValue());
+        }
+
+        try {
+            return (new Byte(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of char.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class CharacterArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public CharacterArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public CharacterArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static char model[] = new char[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                char results[] = new char[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = values[i].charAt(0);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            char results[] = new char[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = ((String) list.get(i)).charAt(0);
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/CharacterConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Character</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class CharacterConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public CharacterConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public CharacterConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Character) {
+            return (value);
+        }
+
+        try {
+            return (new Character(value.toString().charAt(0)));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ClassConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ClassConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ClassConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Class</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.  The class will be loaded from the thread context class
+ * loader (if it exists); otherwise the class loader that loaded this class
+ * will be used.</p>
+ *
+ * @author Tomas Viberg
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class ClassConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public ClassConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public ClassConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Class) {
+            return (value);
+        }
+
+        try {
+            ClassLoader classLoader =
+                Thread.currentThread().getContextClassLoader();
+            if (classLoader == null) {
+                classLoader = ClassConverter.class.getClassLoader();
+            }
+            return (classLoader.loadClass(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of double.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class DoubleArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public DoubleArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public DoubleArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static double model[] = new double[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                double results[] = new double[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = Double.parseDouble(values[i]);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            double results[] = new double[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = Double.parseDouble((String) list.get(i));
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/DoubleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Double</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class DoubleConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public DoubleConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public DoubleConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Double) {
+            return (value);
+        } else if(value instanceof Number) {
+            return new Double(((Number)value).doubleValue());
+        }
+            
+
+        try {
+            return (new Double(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FileConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FileConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FileConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import java.io.File;
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.io.FileL</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author James Strachan
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.6
+ */
+public final class FileConverter implements Converter {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public FileConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public FileConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof File) {
+            return (value);
+        }
+
+        return new File(value.toString());
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of float.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class FloatArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public FloatArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public FloatArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static float model[] = new float[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                float results[] = new float[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = Float.parseFloat(values[i]);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            float results[] = new float[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = Float.parseFloat((String) list.get(i));
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/FloatConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Float</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class FloatConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public FloatConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public FloatConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Float) {
+            return (value);
+        } else if(value instanceof Number) {
+            return new Float(((Number)value).floatValue());
+        }
+
+        try {
+            return (new Float(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of int.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class IntegerArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public IntegerArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public IntegerArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static int model[] = new int[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                int results[] = new int[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = Integer.parseInt(values[i]);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            int results[] = new int[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = Integer.parseInt((String) list.get(i));
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/IntegerConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Integer</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class IntegerConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public IntegerConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public IntegerConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Integer) {
+            return (value);
+        } else if(value instanceof Number) {
+            return new Integer(((Number)value).intValue());
+        }
+
+        try {
+            return (new Integer(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of long.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class LongArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public LongArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public LongArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static long model[] = new long[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                long results[] = new long[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = Long.parseLong(values[i]);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            long results[] = new long[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = Long.parseLong((String) list.get(i));
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/LongConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Long</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class LongConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public LongConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public LongConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Long) {
+            return (value);
+        } else if(value instanceof Number) {
+            return new Long(((Number)value).longValue());
+        }
+
+        try {
+            return (new Long(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a primitive array of short.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class ShortArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public ShortArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public ShortArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static short model[] = new short[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with input value as a String array
+        if (strings.getClass() == value.getClass()) {
+            try {
+                String values[] = (String[]) value;
+                short results[] = new short[values.length];
+                for (int i = 0; i < values.length; i++) {
+                    results[i] = Short.parseShort(values[i]);
+                }
+                return (results);
+            } catch (Exception e) {
+                if (useDefault) {
+                    return (defaultValue);
+                } else {
+                    throw new ConversionException(value.toString(), e);
+                }
+            }
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            short results[] = new short[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = Short.parseShort((String) list.get(i));
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/ShortConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.Short</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.8 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class ShortConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public ShortConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public ShortConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Short) {
+            return (value);
+        } else if (value instanceof Number) {
+            return new Short(((Number)value).shortValue());
+        }
+
+        try {
+            return (new Short(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlDateConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlDateConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlDateConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.sql.Date;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.sql.Date</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class SqlDateConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public SqlDateConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public SqlDateConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Date) {
+            return (value);
+        }
+
+        try {
+            return (Date.valueOf(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimeConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimeConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimeConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.sql.Time;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.sql.Time</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class SqlTimeConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public SqlTimeConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public SqlTimeConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Time) {
+            return (value);
+        }
+
+        try {
+            return (Time.valueOf(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimestampConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimestampConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/SqlTimestampConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.sql.Timestamp;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.sql.Timestamp</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class SqlTimestampConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public SqlTimestampConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public SqlTimestampConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof Timestamp) {
+            return (value);
+        }
+
+        try {
+            return (Timestamp.valueOf(value.toString()));
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringArrayConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringArrayConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringArrayConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import java.util.List;
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into an array of String.  On a conversion failure, returns
+ * a specified default value or throws a {@link ConversionException} depending
+ * on how this instance is constructed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.4
+ */
+
+public final class StringArrayConverter extends AbstractArrayConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public StringArrayConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public StringArrayConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * <p>Model object for type comparisons.</p>
+     */
+    private static String model[] = new String[0];
+    
+    /**
+     * <p> Model object for int arrays.</p>
+     */
+    private static int ints[] = new int[0];
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        // Deal with a null value
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        // Deal with the no-conversion-needed case
+        if (model.getClass() == value.getClass()) {
+            return (value);
+        }
+
+        // Deal with the input value as an int array
+        if (ints.getClass() == value.getClass())
+        {
+            int[] values = (int[]) value;
+            String[] results = new String[values.length];
+            for (int i = 0; i < values.length; i++)
+            {
+                results[i] = Integer.toString(values[i]);
+            }
+
+            return (results);
+        }
+
+        // Parse the input value as a String into elements
+        // and convert to the appropriate type
+        try {
+            List list = parseElements(value.toString());
+            String results[] = new String[list.size()];
+            for (int i = 0; i < results.length; i++) {
+                results[i] = (String) list.get(i);
+            }
+            return (results);
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(value.toString(), e);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/StringConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.lang.String</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class StringConverter implements Converter {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            return ((String) null);
+        } else {
+            return (value.toString());
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/URLConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/URLConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/URLConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.converters;
+
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+import java.net.URL;
+import java.net.MalformedURLException;
+
+
+
+/**
+ * <p>Standard {@link Converter} implementation that converts an incoming
+ * String into a <code>java.net.URL</code> object, optionally using a
+ * default value or throwing a {@link ConversionException} if a conversion
+ * error occurs.</p>
+ *
+ * @author Henri Yandell
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:34 $
+ * @since 1.3
+ */
+
+public final class URLConverter implements Converter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a {@link Converter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     */
+    public URLConverter() {
+
+        this.defaultValue = null;
+        this.useDefault = false;
+
+    }
+
+
+    /**
+     * Create a {@link Converter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue The default value to be returned
+     */
+    public URLConverter(Object defaultValue) {
+
+        this.defaultValue = defaultValue;
+        this.useDefault = true;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default value specified to our Constructor, if any.
+     */
+    private Object defaultValue = null;
+
+
+    /**
+     * Should we return the default value on conversion errors?
+     */
+    private boolean useDefault = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert the specified input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException("No value specified");
+            }
+        }
+
+        if (value instanceof URL) {
+            return (value);
+        }
+
+        try {
+            return new URL(value.toString());
+        } catch(MalformedURLException murle) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(murle);
+            }
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/package.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/package.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/converters/package.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>Package Documentation for org.apache.commons.beanutils.converters</title>
+</head>
+<body bgcolor="white">
+<p>Standard implementations of the
+<code>Converter</code>
+interface that are pre-registered with
+<code>ConvertUtils</code>
+at startup time.</p>
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/BaseLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/BaseLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/BaseLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale;
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.text.ParseException;
+import java.util.Locale;
+
+
+/**
+ * <p>The base class for all standart type locale-sensitive converters.
+ * It has {@link LocaleConverter} and {@link org.apache.commons.beanutils.Converter} implementations,
+ * that convert an incoming locale-sensitive Object into an object of correspond type,
+ * optionally using a default value or throwing a {@link ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public abstract class BaseLocaleConverter implements LocaleConverter {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /** All logging goes through this logger */
+    private static Log log = LogFactory.getLog(BaseLocaleConverter.class);
+
+    /** The default value specified to our Constructor, if any. */
+    private Object defaultValue = null;
+
+    /** Should we return the default value on conversion errors? */
+    protected boolean useDefault = false;
+
+    /** The locale specified to our Constructor, by default - system locale. */
+    protected Locale locale = Locale.getDefault();
+
+    /** The default pattern specified to our Constructor, if any. */
+    protected String pattern = null;
+
+    /** The flag indicating whether the given pattern string is localized or not. */
+    protected boolean locPattern = false;
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link LocaleConverter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     * An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    protected BaseLocaleConverter(Locale locale, String pattern) {
+
+        this(null, locale, pattern, false, false);
+    }
+
+    /**
+     * Create a {@link LocaleConverter} that will throw a {@link ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    protected BaseLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        this(null, locale, pattern, false, locPattern);
+    }
+
+    /**
+     * Create a {@link LocaleConverter} that will return the specified default value
+     * if a conversion error occurs.
+     * An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    protected BaseLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link LocaleConverter} that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    protected BaseLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        this(defaultValue, locale, pattern, true, locPattern);
+    }
+
+    /**
+     * Create a {@link LocaleConverter} that will return the specified default value
+     * or throw a {@link ConversionException} if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param useDefault    Indicate whether the default value is used or not
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    private BaseLocaleConverter(Object defaultValue, Locale locale,
+                                String pattern, boolean useDefault, boolean locPattern) {
+
+        if (useDefault) {
+            this.defaultValue = defaultValue;
+            this.useDefault = true;
+        }
+
+        if (locale != null) {
+            this.locale = locale;
+        }
+
+        this.pattern = pattern;
+        this.locPattern = locPattern;
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+
+    abstract protected Object parse(Object value, String pattern) throws ParseException;
+
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object.
+     * The default pattern is used for the convertion.
+     *
+     * @param value The input object to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Object value) {
+        return convert(value, null);
+    }
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Object value, String pattern) {
+        return convert(null, value, pattern);
+    }
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type. The default pattern is used for the convertion.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input object to be converted
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value) {
+        return convert(type, value, null);
+    }
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value, String pattern) {
+        if (value == null) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                // symmetric beanutils function allows null
+                // so do not: throw new ConversionException("No value specified");
+                log.debug("Null value specified for conversion, returing null");
+                return null;
+            }
+        }
+
+        try {
+            if (pattern != null) {
+                return parse(value, pattern);
+            } else {
+                return parse(value, this.pattern);
+            }
+        } catch (Exception e) {
+            if (useDefault) {
+                return (defaultValue);
+            } else {
+                throw new ConversionException(e);
+            }
+        }
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/BaseLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale;
+
+
+import org.apache.commons.beanutils.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Locale;
+
+
+/**
+ * <p>Utility methods for populating JavaBeans properties
+ * via reflection in a locale-dependent manner.</p>
+ *
+ * <p>The implementations for these methods are provided by <code>LocaleBeanUtilsBean</code>.
+ * For more details see {@link LocaleBeanUtilsBean}.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @author Yauheny Mikulski
+ */
+
+public class LocaleBeanUtils extends BeanUtils {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /** All logging goes through this logger */
+    private static Log log = LogFactory.getLog(LocaleBeanUtils.class);
+
+    /**
+     * <p>Gets the locale used when no locale is passed.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getDefaultLocale()
+     */
+    public static Locale getDefaultLocale() {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getDefaultLocale();
+    }
+
+
+    /**
+     * <p>Sets the locale used when no locale is passed.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#setDefaultLocale(Locale)
+     */
+    public static void setDefaultLocale(Locale locale) {
+
+        LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().setDefaultLocale(locale);
+    }
+
+    /**
+     * <p>Gets whether the pattern is localized or not.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getApplyLocalized()
+     */
+    public static boolean getApplyLocalized() {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getApplyLocalized();
+    }
+
+    /**
+     * <p>Sets whether the pattern is localized or not.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#setApplyLocalized(boolean)
+     */
+    public static void setApplyLocalized(boolean newApplyLocalized) {
+
+        LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().setApplyLocalized(newApplyLocalized);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Return the value of the specified locale-sensitive indexed property
+     * of the specified bean, as a String.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getIndexedProperty(Object, String, String)
+     */
+    public static String getIndexedProperty(Object bean, String name, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getIndexedProperty(bean, name, pattern);
+    }
+
+    /**
+     * Return the value of the specified locale-sensitive indexed property
+     * of the specified bean, as a String using the default convertion pattern of
+     * the corresponding {@link LocaleConverter}.
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getIndexedProperty(Object, String)
+     */
+    public static String getIndexedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getIndexedProperty(bean, name);
+    }
+
+    /**
+     * <p>Return the value of the specified locale-sensetive indexed property
+     * of the specified bean, as a String using the specified convertion pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getIndexedProperty(Object, String, int, String)
+     */
+    public static String getIndexedProperty(Object bean,
+                                            String name, int index, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getIndexedProperty(bean, name, index, pattern);
+    }
+
+    /**
+     * <p>Return the value of the specified locale-sensetive indexed property
+     * of the specified bean, as a String using the default convertion pattern of
+     * the corresponding {@link LocaleConverter}.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getIndexedProperty(Object, String, int)
+     */
+    public static String getIndexedProperty(Object bean,
+                                            String name, int index)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getIndexedProperty(bean, name, index);
+    }
+
+    /**
+     * <p>Return the value of the specified simple locale-sensitive property
+     * of the specified bean, converted to a String using the specified
+     * convertion pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getSimpleProperty(Object, String, String)
+     */
+    public static String getSimpleProperty(Object bean, String name, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getSimpleProperty(bean, name, pattern);
+    }
+
+    /**
+     * <p>Return the value of the specified simple locale-sensitive property
+     * of the specified bean, converted to a String using the default
+     * convertion pattern of the corresponding {@link LocaleConverter}.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getSimpleProperty(Object, String)
+     */
+    public static String getSimpleProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getSimpleProperty(bean, name);
+    }
+
+    /**
+     * <p>Return the value of the specified mapped locale-sensitive property
+     * of the specified bean, as a String using the specified convertion pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getMappedProperty(Object, String, String, String)
+     */
+    public static String getMappedProperty(Object bean,
+                                           String name, String key, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getMappedProperty(bean, name, key, pattern);
+    }
+
+    /**
+     * <p>Return the value of the specified mapped locale-sensitive property
+     * of the specified bean, as a String
+     * The key is specified as a method parameter and must *not* be included
+     * in the property name expression.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getMappedProperty(Object, String, String)
+     */
+    public static String getMappedProperty(Object bean,
+                                           String name, String key)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getMappedProperty(bean, name, key);
+    }
+
+
+    /**
+     * <p>Return the value of the specified locale-sensitive mapped property
+     * of the specified bean, as a String using the specified pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getMappedPropertyLocale(Object, String, String)
+     */
+    public static String getMappedPropertyLocale(Object bean, String name, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getMappedPropertyLocale(bean, name, pattern);
+    }
+
+
+    /**
+     * <p>Return the value of the specified locale-sensitive mapped property
+     * of the specified bean, as a String using the default
+     * convertion pattern of the corresponding {@link LocaleConverter}.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getMappedProperty(Object, String)
+     */
+    public static String getMappedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getMappedProperty(bean, name);
+    }
+
+    /**
+     * <p>Return the value of the (possibly nested) locale-sensitive property
+     * of the specified name, for the specified bean,
+     * as a String using the specified pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getNestedProperty(Object, String, String)
+     */
+    public static String getNestedProperty(Object bean, String name, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getNestedProperty(bean, name, pattern);
+    }
+
+    /**
+     * <p>Return the value of the (possibly nested) locale-sensitive property
+     * of the specified name.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getNestedProperty(Object, String)
+     */
+    public static String getNestedProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getNestedProperty(bean, name);
+    }
+
+    /**
+     * <p>Return the value of the specified locale-sensitive property
+     * of the specified bean.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getProperty(Object, String, String)
+     */
+    public static String getProperty(Object bean, String name, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getProperty(bean, name, pattern);
+    }
+
+    /**
+     * <p>Return the value of the specified locale-sensitive property
+     * of the specified bean.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#getProperty(Object, String)
+     */
+    public static String getProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getProperty(bean, name);
+    }
+
+    /**
+     * <p>Set the specified locale-sensitive property value, performing type
+     * conversions as required to conform to the type of the destination property
+     * using the default convertion pattern of the corresponding {@link LocaleConverter}.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#setProperty(Object, String, Object)
+     */
+    public static void setProperty(Object bean, String name, Object value)
+            throws IllegalAccessException, InvocationTargetException {
+
+        LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().setProperty(bean, name, value);
+    }
+
+    /**
+     * <p>Set the specified locale-sensitive property value, performing type
+     * conversions as required to conform to the type of the destination
+     * property using the specified convertion pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#setProperty(Object, String, Object, String)
+     */
+    public static void setProperty(Object bean, String name, Object value, String pattern)
+            throws IllegalAccessException, InvocationTargetException {
+
+        LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().setProperty(bean, name, value, pattern);
+     }
+
+    /**
+     * <p>Calculate the property type.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#definePropertyType(Object, String, String)
+     */
+    protected static Class definePropertyType(Object target, String name, String propName)
+            throws IllegalAccessException, InvocationTargetException {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().definePropertyType(target, name, propName);
+    }
+
+    /**
+     * <p>Convert the specified value to the required type using the
+     * specified convertion pattern.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#convert(Class, int, Object, String)
+     */
+    protected static Object convert(Class type, int index, Object value, String pattern) {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().convert(type, index, value, pattern);
+    }
+
+    /**
+     * <p>Convert the specified value to the required type.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#convert(Class, int, Object)
+     */
+    protected static Object convert(Class type, int index, Object value) {
+
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().convert(type, index, value);
+    }
+
+    /**
+     * <p>Invoke the setter method.</p>
+     *
+     * <p>For more details see <code>LocaleBeanUtilsBean</code></p>
+     *
+     * @see LocaleBeanUtilsBean#invokeSetter(Object, String, String, int, Object)
+     */
+    protected static void invokeSetter(Object target, String propName, String key, int index, Object newValue)
+            throws IllegalAccessException, InvocationTargetException {
+
+       LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().invokeSetter(target, propName, key, index, newValue);
+    }
+
+    /**
+     * Resolve any nested expression to get the actual target bean.
+     *
+     * @deprecated moved into <code>LocaleBeanUtilsBean</code>
+     * @param bean The bean
+     * @param name The property name
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    protected static Descriptor calculate(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException {
+
+        String propName = null;          // Simple name of target property
+        int index = -1;                  // Indexed subscript value (if any)
+        String key = null;               // Mapped key value (if any)
+
+        Object target = bean;
+        int delim = name.lastIndexOf(PropertyUtils.NESTED_DELIM);
+        if (delim >= 0) {
+            try {
+                target =
+                        PropertyUtils.getProperty(bean, name.substring(0, delim));
+            }
+            catch (NoSuchMethodException e) {
+                return null; // Skip this property setter
+            }
+            name = name.substring(delim + 1);
+            if (log.isTraceEnabled()) {
+                log.trace("    Target bean = " + target);
+                log.trace("    Target name = " + name);
+            }
+        }
+
+        // Calculate the property name, index, and key values
+        propName = name;
+        int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
+        if (i >= 0) {
+            int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
+            try {
+                index =
+                        Integer.parseInt(propName.substring(i + 1, k));
+            }
+            catch (NumberFormatException e) {
+                ;
+            }
+            propName = propName.substring(0, i);
+        }
+        int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
+        if (j >= 0) {
+            int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
+            try {
+                key = propName.substring(j + 1, k);
+            }
+            catch (IndexOutOfBoundsException e) {
+                ;
+            }
+            propName = propName.substring(0, j);
+        }
+        return new Descriptor(target, name, propName, key, index);
+    }
+
+    /** @deprecated moved into <code>LocaleBeanUtils</code> */
+    protected static class Descriptor {
+
+        private int index = -1;    // Indexed subscript value (if any)
+        private String name;
+        private String propName;   // Simple name of target property
+        private String key;        // Mapped key value (if any)
+        private Object target;
+
+        public Descriptor(Object target, String name, String propName, String key, int index) {
+
+            setTarget(target);
+            setName(name);
+            setPropName(propName);
+            setKey(key);
+            setIndex(index);
+        }
+
+        public Object getTarget() {
+            return target;
+        }
+
+        public void setTarget(Object target) {
+            this.target = target;
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public void setKey(String key) {
+            this.key = key;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public void setIndex(int index) {
+            this.index = index;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getPropName() {
+            return propName;
+        }
+
+        public void setPropName(String propName) {
+            this.propName = propName;
+        }
+    }
+}
+
+


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtils.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtilsBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtilsBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtilsBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,957 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale;
+
+
+import org.apache.commons.beanutils.*;
+import org.apache.commons.beanutils.ContextClassLoaderLocal;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Locale;
+
+
+/**
+ * <p>Utility methods for populating JavaBeans properties
+ * via reflection in a locale-dependent manner.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Ralph Schaer
+ * @author Chris Audley
+ * @author Rey François
+ * @author Gregor Raýman
+ * @author Yauheny Mikulski
+ * @since 1.7
+ */
+
+public class LocaleBeanUtilsBean extends BeanUtilsBean {
+
+	/** 
+	 * Contains <code>LocaleBeanUtilsBean</code> instances indexed by context classloader.
+	 */
+    private static final ContextClassLoaderLocal 
+            localeBeansByClassLoader = new ContextClassLoaderLocal() {
+                        // Creates the default instance used when the context classloader is unavailable
+                        protected Object initialValue() {
+                            return new LocaleBeanUtilsBean();
+                        }
+                    };
+     
+     /** Gets singleton instance */
+     public synchronized static LocaleBeanUtilsBean getLocaleBeanUtilsInstance() {
+        return (LocaleBeanUtilsBean)localeBeansByClassLoader.get();
+     }
+ 
+	/** 
+	 * Sets the instance which provides the functionality for {@link LocaleBeanUtils}.
+	 * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
+	 * This mechanism provides isolation for web apps deployed in the same container. 
+	 */
+	public synchronized static void setInstance(LocaleBeanUtilsBean newInstance) {
+        localeBeansByClassLoader.set(newInstance);
+	}
+
+    /** All logging goes through this logger */
+    private static Log log = LogFactory.getLog(LocaleBeanUtilsBean.class);
+
+    // ----------------------------------------------------- Instance Variables
+        
+    /** Convertor used by this class */
+    private LocaleConvertUtilsBean localeConvertUtils;
+    
+    // --------------------------------------------------------- Constructors
+    
+    /** Construct instance with standard conversion bean */
+    public LocaleBeanUtilsBean() {
+        this.localeConvertUtils = new LocaleConvertUtilsBean();
+    }
+    
+    /** 
+     * Construct instance that uses given locale conversion
+     *
+     * @param localeConvertUtils use this <code>localeConvertUtils</code> to perform
+     * conversions
+     * @param convertUtilsBean use this for standard conversions
+     * @param propertyUtilsBean use this for property conversions
+     */
+    public LocaleBeanUtilsBean(
+                            LocaleConvertUtilsBean localeConvertUtils,
+                            ConvertUtilsBean convertUtilsBean,
+                            PropertyUtilsBean propertyUtilsBean) {
+        super(convertUtilsBean, propertyUtilsBean);
+        this.localeConvertUtils = localeConvertUtils;
+    }
+    
+    /** 
+     * Construct instance that uses given locale conversion
+     *
+     * @param localeConvertUtils use this <code>localeConvertUtils</code> to perform
+     * conversions
+     */
+    public LocaleBeanUtilsBean(LocaleConvertUtilsBean localeConvertUtils) {
+        this.localeConvertUtils = localeConvertUtils;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /** Gets the bean instance used for conversions */
+    public LocaleConvertUtilsBean getLocaleConvertUtils() {
+        return localeConvertUtils;
+    }
+    
+    /**
+     * Gets the default Locale
+     */
+    public Locale getDefaultLocale() {
+
+        return getLocaleConvertUtils().getDefaultLocale();
+    }
+
+
+    /**
+     * Sets the default Locale
+     */
+    public void setDefaultLocale(Locale locale) {
+
+        getLocaleConvertUtils().setDefaultLocale(locale);
+    }
+
+    /**
+     * Is the pattern to be applied localized
+     * (Indicate whether the pattern is localized or not)
+     */
+    public boolean getApplyLocalized() {
+
+        return getLocaleConvertUtils().getApplyLocalized();
+    }
+
+    /**
+     * Sets whether the pattern is applied localized
+     * (Indicate whether the pattern is localized or not)
+     */
+    public void setApplyLocalized(boolean newApplyLocalized) {
+
+        getLocaleConvertUtils().setApplyLocalized(newApplyLocalized);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Return the value of the specified locale-sensitive indexed property
+     * of the specified bean, as a String. The zero-relative index of the
+     * required value must be included (in square brackets) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname[index]</code> of the property value
+     *  to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getIndexedProperty(
+                                    Object bean, 
+                                    String name, 
+                                    String pattern)
+                                        throws 
+                                            IllegalAccessException, 
+                                            InvocationTargetException,
+                                            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getIndexedProperty(bean, name);
+        return getLocaleConvertUtils().convert(value, pattern);
+    }
+
+    /**
+     * Return the value of the specified locale-sensitive indexed property
+     * of the specified bean, as a String using the default convertion pattern of
+     * the corresponding {@link LocaleConverter}. The zero-relative index
+     * of the required value must be included (in square brackets) as a suffix
+     * to the property name, or <code>IllegalArgumentException</code> will be thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname[index]</code> of the property value
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getIndexedProperty(
+                                    Object bean, 
+                                    String name)
+                                        throws 
+                                            IllegalAccessException, 
+                                            InvocationTargetException,
+                                            NoSuchMethodException {
+
+        return getIndexedProperty(bean, name, null);
+    }
+
+    /**
+     * Return the value of the specified locale-sensetive indexed property
+     * of the specified bean, as a String using the specified convertion pattern.
+     * The index is specified as a method parameter and
+     * must *not* be included in the property name expression
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param index Index of the property value to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getIndexedProperty(Object bean,
+                                            String name, int index, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getIndexedProperty(bean, name, index);
+        return getLocaleConvertUtils().convert(value, pattern);
+    }
+
+    /**
+     * Return the value of the specified locale-sensetive indexed property
+     * of the specified bean, as a String using the default convertion pattern of
+     * the corresponding {@link LocaleConverter}.
+     * The index is specified as a method parameter and
+     * must *not* be included in the property name expression
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param index Index of the property value to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getIndexedProperty(Object bean,
+                                            String name, int index)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+        return getIndexedProperty(bean, name, index, null);
+    }
+
+    /**
+     * Return the value of the specified simple locale-sensitive property
+     * of the specified bean, converted to a String using the specified
+     * convertion pattern.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Name of the property to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getSimpleProperty(Object bean, String name, String pattern)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getSimpleProperty(bean, name);
+        return getLocaleConvertUtils().convert(value, pattern);
+    }
+
+    /**
+     * Return the value of the specified simple locale-sensitive property
+     * of the specified bean, converted to a String using the default
+     * convertion pattern of the corresponding {@link LocaleConverter}.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getSimpleProperty(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return getSimpleProperty(bean, name, null);
+    }
+
+    /**
+     * Return the value of the specified mapped locale-sensitive property
+     * of the specified bean, as a String using the specified convertion pattern.
+     * The key is specified as a method parameter and must *not* be included in
+     * the property name expression.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param key Lookup key of the property value to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getMappedProperty(
+                                    Object bean,
+                                    String name, 
+                                    String key, 
+                                    String pattern)
+                                        throws 
+                                            IllegalAccessException, 
+                                            InvocationTargetException,
+                                            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getMappedProperty(bean, name, key);
+        return getLocaleConvertUtils().convert(value, pattern);
+    }
+
+    /**
+     * Return the value of the specified mapped locale-sensitive property
+     * of the specified bean, as a String
+     * The key is specified as a method parameter and must *not* be included
+     * in the property name expression
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Simple property name of the property value to be extracted
+     * @param key Lookup key of the property value to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getMappedProperty(Object bean,
+                                           String name, String key)
+            throws IllegalAccessException, InvocationTargetException,
+            NoSuchMethodException {
+
+        return getMappedProperty(bean, name, key, null);
+    }
+
+
+    /**
+     * Return the value of the specified locale-sensitive mapped property
+     * of the specified bean, as a String using the specified pattern.
+     * The String-valued key of the required value
+     * must be included (in parentheses) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname(index)</code> of the property value
+     *  to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getMappedPropertyLocale(
+                                        Object bean, 
+                                        String name, 
+                                        String pattern)
+                                            throws 
+                                                IllegalAccessException, 
+                                                InvocationTargetException,
+                                                NoSuchMethodException {
+
+        Object value = getPropertyUtils().getMappedProperty(bean, name);
+        return getLocaleConvertUtils().convert(value, pattern);
+    }
+
+
+    /**
+     * Return the value of the specified locale-sensitive mapped property
+     * of the specified bean, as a String using the default
+     * convertion pattern of the corresponding {@link LocaleConverter}.
+     * The String-valued key of the required value
+     * must be included (in parentheses) as a suffix to
+     * the property name, or <code>IllegalArgumentException</code> will be
+     * thrown.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name <code>propertyname(index)</code> of the property value
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getMappedProperty(Object bean, String name)
+                                    throws 
+                                        IllegalAccessException, 
+                                        InvocationTargetException,
+                                        NoSuchMethodException {
+
+        return getMappedPropertyLocale(bean, name, null);
+    }
+
+    /**
+     * Return the value of the (possibly nested) locale-sensitive property
+     * of the specified name, for the specified bean,
+     * as a String using the specified pattern.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly nested name of the property to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getNestedProperty(    
+                                    Object bean, 
+                                    String name, 
+                                    String pattern)
+                                        throws 
+                                            IllegalAccessException, 
+                                            InvocationTargetException,
+                                            NoSuchMethodException {
+
+        Object value = getPropertyUtils().getNestedProperty(bean, name);
+        return getLocaleConvertUtils().convert(value, pattern);
+    }
+
+    /**
+     * Return the value of the (possibly nested) locale-sensitive property
+     * of the specified name, for the specified bean, as a String using the default
+     * convertion pattern of the corresponding {@link LocaleConverter}.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly nested name of the property to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception IllegalArgumentException if a nested reference to a
+     *  property returns null
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getNestedProperty(Object bean, String name)
+                                    throws 
+                                        IllegalAccessException, 
+                                        InvocationTargetException,
+                                        NoSuchMethodException {
+
+        return getNestedProperty(bean, name, null);
+    }
+
+    /**
+     * Return the value of the specified locale-sensitive property
+     * of the specified bean, no matter which property reference
+     * format is used, as a String using the specified convertion pattern.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly indexed and/or nested name of the property
+     *  to be extracted
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getProperty(Object bean, String name, String pattern)
+                                throws 
+                                    IllegalAccessException, 
+                                    InvocationTargetException,
+                                    NoSuchMethodException {
+
+        return getNestedProperty(bean, name, pattern);
+    }
+
+    /**
+     * Return the value of the specified locale-sensitive property
+     * of the specified bean, no matter which property reference
+     * format is used, as a String using the default
+     * convertion pattern of the corresponding {@link LocaleConverter}.
+     *
+     * @param bean Bean whose property is to be extracted
+     * @param name Possibly indexed and/or nested name of the property
+     *  to be extracted
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     * @exception NoSuchMethodException if an accessor method for this
+     *  propety cannot be found
+     */
+    public String getProperty(Object bean, String name)
+                                throws 
+                                    IllegalAccessException, 
+                                    InvocationTargetException,
+                                    NoSuchMethodException {
+
+        return getNestedProperty(bean, name);
+    }
+
+    /**
+     * Set the specified locale-sensitive property value, performing type
+     * conversions as required to conform to the type of the destination property
+     * using the default convertion pattern of the corresponding {@link LocaleConverter}.
+     *
+     * @param bean Bean on which setting is to be performed
+     * @param name Property name (can be nested/indexed/mapped/combo)
+     * @param value Value to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    public void setProperty(Object bean, String name, Object value)
+                                throws 
+                                    IllegalAccessException, 
+                                    InvocationTargetException {
+
+        setProperty(bean, name, value, null);
+    }
+
+    /**
+     * Set the specified locale-sensitive property value, performing type
+     * conversions as required to conform to the type of the destination
+     * property using the specified convertion pattern.
+     *
+     * @param bean Bean on which setting is to be performed
+     * @param name Property name (can be nested/indexed/mapped/combo)
+     * @param value Value to be set
+     * @param pattern The convertion pattern
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    public void setProperty(
+                            Object bean, 
+                            String name, 
+                            Object value, 
+                            String pattern)
+                                throws 
+                                    IllegalAccessException, 
+                                    InvocationTargetException {
+
+        // Trace logging (if enabled)
+        if (log.isTraceEnabled()) {
+            StringBuffer sb = new StringBuffer("  setProperty(");
+            sb.append(bean);
+            sb.append(", ");
+            sb.append(name);
+            sb.append(", ");
+            if (value == null) {
+                sb.append("<NULL>");
+            }
+            else if (value instanceof String) {
+                sb.append((String) value);
+            }
+            else if (value instanceof String[]) {
+                String values[] = (String[]) value;
+                sb.append('[');
+                for (int i = 0; i < values.length; i++) {
+                    if (i > 0) {
+                        sb.append(',');
+                    }
+                    sb.append(values[i]);
+                }
+                sb.append(']');
+            }
+            else {
+                sb.append(value.toString());
+            }
+            sb.append(')');
+            log.trace(sb.toString());
+        }
+
+        Descriptor propInfo = calculate(bean, name);
+
+        if (propInfo != null) {
+            Class type = definePropertyType(propInfo.getTarget(), name, propInfo.getPropName());
+
+            if (type != null) {
+
+                Object newValue = convert(type, propInfo.getIndex(), value, pattern);
+                invokeSetter(propInfo.getTarget(), propInfo.getPropName(),
+                        propInfo.getKey(), propInfo.getIndex(), newValue);
+            }
+        }
+    }
+
+    /**
+     * Calculate the property type.
+     *
+     * @param target The bean
+     * @param name The property name
+     * @param propName The Simple name of target property
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    protected Class definePropertyType(Object target, String name, String propName)
+            throws IllegalAccessException, InvocationTargetException {
+
+        Class type = null;               // Java type of target property
+
+        if (target instanceof DynaBean) {
+            DynaClass dynaClass = ((DynaBean) target).getDynaClass();
+            DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
+            if (dynaProperty == null) {
+                return null; // Skip this property setter
+            }
+            type = dynaProperty.getType();
+        }
+        else {
+            PropertyDescriptor descriptor = null;
+            try {
+                descriptor =
+                        getPropertyUtils().getPropertyDescriptor(target, name);
+                if (descriptor == null) {
+                    return null; // Skip this property setter
+                }
+            }
+            catch (NoSuchMethodException e) {
+                return null; // Skip this property setter
+            }
+            if (descriptor instanceof MappedPropertyDescriptor) {
+                type = ((MappedPropertyDescriptor) descriptor).
+                        getMappedPropertyType();
+            }
+            else if (descriptor instanceof IndexedPropertyDescriptor) {
+                type = ((IndexedPropertyDescriptor) descriptor).
+                        getIndexedPropertyType();
+            }
+            else {
+                type = descriptor.getPropertyType();
+            }
+        }
+        return type;
+    }
+
+    /**
+     * Convert the specified value to the required type using the
+     * specified convertion pattern.
+     *
+     * @param type The Java type of target property
+     * @param index The indexed subscript value (if any)
+     * @param value The value to be converted
+     * @param pattern The convertion pattern
+     */
+    protected Object convert(Class type, int index, Object value, String pattern) {
+		
+		if (log.isTraceEnabled()) {
+			log.trace("Converting value '" + value + "' to type:" + type);
+		}
+		
+        Object newValue = null;
+
+        if (type.isArray() && (index < 0)) { // Scalar value into array
+            if (value instanceof String) {
+                String values[] = new String[1];
+                values[0] = (String) value;
+                newValue = getLocaleConvertUtils().convert((String[]) values, type, pattern);
+            }
+            else if (value instanceof String[]) {
+                newValue = getLocaleConvertUtils().convert((String[]) value, type, pattern);
+            }
+            else {
+                newValue = value;
+            }
+        }
+        else if (type.isArray()) {         // Indexed value into array
+            if (value instanceof String) {
+                newValue = getLocaleConvertUtils().convert((String) value,
+                        type.getComponentType(), pattern);
+            }
+            else if (value instanceof String[]) {
+                newValue = getLocaleConvertUtils().convert(((String[]) value)[0],
+                        type.getComponentType(), pattern);
+            }
+            else {
+                newValue = value;
+            }
+        }
+        else {                             // Value into scalar
+            if (value instanceof String) {
+                newValue = getLocaleConvertUtils().convert((String) value, type, pattern);
+            }
+            else if (value instanceof String[]) {
+                newValue = getLocaleConvertUtils().convert(((String[]) value)[0],
+                        type, pattern);
+            }
+            else {
+                newValue = value;
+            }
+        }
+        return newValue;
+    }
+
+    /**
+     *  Convert the specified value to the required type.
+     *
+     * @param type The Java type of target property
+     * @param index The indexed subscript value (if any)
+     * @param value The value to be converted
+     */
+    protected Object convert(Class type, int index, Object value) {
+
+        Object newValue = null;
+
+        if (type.isArray() && (index < 0)) { // Scalar value into array
+            if (value instanceof String) {
+                String values[] = new String[1];
+                values[0] = (String) value;
+                newValue = ConvertUtils.convert((String[]) values, type);
+            }
+            else if (value instanceof String[]) {
+                newValue = ConvertUtils.convert((String[]) value, type);
+            }
+            else {
+                newValue = value;
+            }
+        }
+        else if (type.isArray()) {         // Indexed value into array
+            if (value instanceof String) {
+                newValue = ConvertUtils.convert((String) value,
+                        type.getComponentType());
+            }
+            else if (value instanceof String[]) {
+                newValue = ConvertUtils.convert(((String[]) value)[0],
+                        type.getComponentType());
+            }
+            else {
+                newValue = value;
+            }
+        }
+        else {                             // Value into scalar
+            if (value instanceof String) {
+                newValue = ConvertUtils.convert((String) value, type);
+            }
+            else if (value instanceof String[]) {
+                newValue = ConvertUtils.convert(((String[]) value)[0],
+                        type);
+            }
+            else {
+                newValue = value;
+            }
+        }
+        return newValue;
+    }
+
+    /**
+     * Invoke the setter method.
+     *
+     * @param target The bean
+     * @param propName The Simple name of target property
+     * @param key The Mapped key value (if any)
+     * @param index The indexed subscript value (if any)
+     * @param newValue The value to be set
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    protected void invokeSetter(Object target, String propName, String key, int index, Object newValue)
+            throws IllegalAccessException, InvocationTargetException {
+
+        try {
+            if (index >= 0) {
+                getPropertyUtils().setIndexedProperty(target, propName,
+                        index, newValue);
+            }
+            else if (key != null) {
+                getPropertyUtils().setMappedProperty(target, propName,
+                        key, newValue);
+            }
+            else {
+                getPropertyUtils().setProperty(target, propName, newValue);
+            }
+        }
+        catch (NoSuchMethodException e) {
+            throw new InvocationTargetException
+                    (e, "Cannot set " + propName);
+        }
+    }
+
+    /**
+     * Resolve any nested expression to get the actual target bean.
+     *
+     * @param bean The bean
+     * @param name The property name
+     *
+     * @exception IllegalAccessException if the caller does not have
+     *  access to the property accessor method
+     * @exception InvocationTargetException if the property accessor method
+     *  throws an exception
+     */
+    protected Descriptor calculate(Object bean, String name)
+            throws IllegalAccessException, InvocationTargetException {
+
+        String propName = null;          // Simple name of target property
+        int index = -1;                  // Indexed subscript value (if any)
+        String key = null;               // Mapped key value (if any)
+
+        Object target = bean;
+        int delim = name.lastIndexOf(PropertyUtils.NESTED_DELIM);
+        if (delim >= 0) {
+            try {
+                target =
+                        getPropertyUtils().getProperty(bean, name.substring(0, delim));
+            }
+            catch (NoSuchMethodException e) {
+                return null; // Skip this property setter
+            }
+            name = name.substring(delim + 1);
+            if (log.isTraceEnabled()) {
+                log.trace("    Target bean = " + target);
+                log.trace("    Target name = " + name);
+            }
+        }
+
+        // Calculate the property name, index, and key values
+        propName = name;
+        int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
+        if (i >= 0) {
+            int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
+            try {
+                index =
+                        Integer.parseInt(propName.substring(i + 1, k));
+            }
+            catch (NumberFormatException e) {
+                ;
+            }
+            propName = propName.substring(0, i);
+        }
+        int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
+        if (j >= 0) {
+            int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
+            try {
+                key = propName.substring(j + 1, k);
+            }
+            catch (IndexOutOfBoundsException e) {
+                ;
+            }
+            propName = propName.substring(0, j);
+        }
+        return new Descriptor(target, name, propName, key, index);
+    }
+
+    protected class Descriptor {
+
+        private int index = -1;    // Indexed subscript value (if any)
+        private String name;
+        private String propName;   // Simple name of target property
+        private String key;        // Mapped key value (if any)
+        private Object target;
+
+        public Descriptor(Object target, String name, String propName, String key, int index) {
+
+            setTarget(target);
+            setName(name);
+            setPropName(propName);
+            setKey(key);
+            setIndex(index);
+        }
+
+        public Object getTarget() {
+            return target;
+        }
+
+        public void setTarget(Object target) {
+            this.target = target;
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public void setKey(String key) {
+            this.key = key;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public void setIndex(int index) {
+            this.index = index;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getPropName() {
+            return propName;
+        }
+
+        public void setPropName(String propName) {
+            this.propName = propName;
+        }
+    }
+}
+
+

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtils.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtils.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtils.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale;
+
+import org.apache.commons.collections.FastHashMap;
+
+import java.util.Locale;
+
+/**
+ * <p>Utility methods for converting locale-sensitive String scalar values to objects of the
+ * specified Class, String arrays to arrays of the specified Class and
+ * object to locale-sensitive String scalar value.</p>
+ *
+ * <p>The implementations for these method are provided by {@link LocaleConvertUtilsBean}.
+ * These static utility method use the default instance. More sophisticated can be provided
+ * by using a <code>LocaleConvertUtilsBean</code> instance.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+public class LocaleConvertUtils {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * <p>Gets the <code>Locale</code> which will be used when 
+     * no <code>Locale</code> is passed to a method.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#getDefaultLocale()
+     */
+    public static Locale getDefaultLocale() {
+
+        return LocaleConvertUtilsBean.getInstance().getDefaultLocale();
+    }
+
+    /**
+     * <p>Sets the <code>Locale</code> which will be used when 
+     * no <code>Locale</code> is passed to a method.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#setDefaultLocale(Locale)
+     */
+    public static void setDefaultLocale(Locale locale) {
+
+        LocaleConvertUtilsBean.getInstance().setDefaultLocale(locale);
+    }
+
+    /**
+     * <p>Gets applyLocalized.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#getApplyLocalized()
+     */
+    public static boolean getApplyLocalized() {
+        return LocaleConvertUtilsBean.getInstance().getApplyLocalized();
+    }
+
+    /**
+     * <p>Sets applyLocalized.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#setApplyLocalized(boolean)
+     */
+    public static void setApplyLocalized(boolean newApplyLocalized) {
+        LocaleConvertUtilsBean.getInstance().setApplyLocalized(newApplyLocalized);
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * <p>Convert the specified locale-sensitive value into a String.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(Object)
+     */
+    public static String convert(Object value) {
+        return LocaleConvertUtilsBean.getInstance().convert(value);
+    }
+
+    /**
+     * <p>Convert the specified locale-sensitive value into a String
+     * using the convertion pattern.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(Object, String)
+     */
+    public static String convert(Object value, String pattern) {
+        return LocaleConvertUtilsBean.getInstance().convert(value, pattern);
+    }
+
+    /**
+     * <p>Convert the specified locale-sensitive value into a String
+     * using the paticular convertion pattern.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(Object, Locale, String)
+     */
+    public static String convert(Object value, Locale locale, String pattern) {
+
+        return LocaleConvertUtilsBean.getInstance().convert(value, locale, pattern);
+    }
+
+    /**
+     * <p>Convert the specified value to an object of the specified class (if
+     * possible).  Otherwise, return a String representation of the value.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(String, Class)
+     */
+    public static Object convert(String value, Class clazz) {
+
+        return LocaleConvertUtilsBean.getInstance().convert(value, clazz);
+    }
+
+    /**
+     * <p>Convert the specified value to an object of the specified class (if
+     * possible) using the convertion pattern. Otherwise, return a String
+     * representation of the value.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(String, Class, String)
+     */
+    public static Object convert(String value, Class clazz, String pattern) {
+
+        return LocaleConvertUtilsBean.getInstance().convert(value, clazz, pattern);
+    }
+
+    /**
+     * <p>Convert the specified value to an object of the specified class (if
+     * possible) using the convertion pattern. Otherwise, return a String
+     * representation of the value.</p>
+     *
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(String, Class, Locale, String)
+     */
+    public static Object convert(String value, Class clazz, Locale locale, String pattern) {
+
+        return LocaleConvertUtilsBean.getInstance().convert(value, clazz, locale, pattern);
+    }
+
+    /**
+     * <p>Convert an array of specified values to an array of objects of the
+     * specified class (if possible) using the convertion pattern.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(String[], Class, String)
+     */
+    public static Object convert(String values[], Class clazz, String pattern) {
+
+        return LocaleConvertUtilsBean.getInstance().convert(values, clazz, pattern);
+    }
+
+   /**
+    * <p>Convert an array of specified values to an array of objects of the
+    * specified class (if possible).</p>
+    * 
+    * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+    *
+    * @see LocaleConvertUtilsBean#convert(String[], Class)
+    */
+   public static Object convert(String values[], Class clazz) {
+
+       return LocaleConvertUtilsBean.getInstance().convert(values, clazz);
+   }
+
+    /**
+     * <p>Convert an array of specified values to an array of objects of the
+     * specified class (if possible) using the convertion pattern.</p>
+     *
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#convert(String[], Class, Locale, String)
+     */
+    public static Object convert(String values[], Class clazz, Locale locale, String pattern) {
+
+        return LocaleConvertUtilsBean.getInstance().convert(values, clazz, locale, pattern);
+    }
+
+    /**
+     * <p>Register a custom {@link LocaleConverter} for the specified destination
+     * <code>Class</code>, replacing any previously registered converter.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#register(LocaleConverter, Class, Locale)
+     */
+    public static void register(LocaleConverter converter, Class clazz, Locale locale) {
+
+        LocaleConvertUtilsBean.getInstance().register(converter, clazz, locale);
+    }
+
+    /**
+     * <p>Remove any registered {@link LocaleConverter}.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#deregister()
+     */
+    public static void deregister() {
+
+       LocaleConvertUtilsBean.getInstance().deregister();
+    }
+
+
+    /**
+     * <p>Remove any registered {@link LocaleConverter} for the specified locale.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#deregister(Locale)
+     */
+    public static void deregister(Locale locale) {
+
+        LocaleConvertUtilsBean.getInstance().deregister(locale);
+    }
+
+
+    /**
+     * <p>Remove any registered {@link LocaleConverter} for the specified locale and Class.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#deregister(Class, Locale)
+     */
+    public static void deregister(Class clazz, Locale locale) {
+
+        LocaleConvertUtilsBean.getInstance().deregister(clazz, locale);
+    }
+
+    /**
+     * <p>Look up and return any registered {@link LocaleConverter} for the specified
+     * destination class and locale; if there is no registered Converter, return
+     * <code>null</code>.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#lookup(Class, Locale)
+     */
+    public static LocaleConverter lookup(Class clazz, Locale locale) {
+
+        return LocaleConvertUtilsBean.getInstance().lookup(clazz, locale);
+    }
+
+    /**
+     * <p>Look up and return any registered FastHashMap instance for the specified locale.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#lookup(Locale)
+     */
+    protected static FastHashMap lookup(Locale locale) {
+        return LocaleConvertUtilsBean.getInstance().lookup(locale);
+    }
+
+    /**
+     * <p>Create all {@link LocaleConverter} types for specified locale.</p>
+     * 
+     * <p>For more details see <code>LocaleConvertUtilsBean</code></p>
+     *
+     * @see LocaleConvertUtilsBean#create(Locale)
+     */
+    protected static FastHashMap create(Locale locale) {
+
+        return LocaleConvertUtilsBean.getInstance().create(locale);
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtils.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtilsBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtilsBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtilsBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,456 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale;
+
+import org.apache.commons.beanutils.locale.converters.*;
+import org.apache.commons.beanutils.Converter;
+import org.apache.commons.collections.FastHashMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Locale;
+
+/**
+ * <p>Utility methods for converting locale-sensitive String scalar values to objects of the
+ * specified Class, String arrays to arrays of the specified Class and
+ * object to locale-sensitive String scalar value.</p>
+ *
+ * <p>This class provides the implementations used by the static utility methods in 
+ * {@link LocaleConvertUtils}.</p>
+ * 
+ * <p>The actual {@link LocaleConverter} instance to be used
+ * can be registered for each possible destination Class. Unless you override them, standard
+ * {@link LocaleConverter} instances are provided for all of the following
+ * destination Classes:</p>
+ * <ul>
+ * <li>java.lang.BigDecimal</li>
+ * <li>java.lang.BigInteger</li>
+ * <li>byte and java.lang.Byte</li>
+ * <li>double and java.lang.Double</li>
+ * <li>float and java.lang.Float</li>
+ * <li>int and java.lang.Integer</li>
+ * <li>long and java.lang.Long</li>
+ * <li>short and java.lang.Short</li>
+ * <li>java.lang.String</li>
+ * <li>java.sql.Date</li>
+ * <li>java.sql.Time</li>
+ * <li>java.sql.Timestamp</li>
+ * </ul>
+ *
+ * <p>For backwards compatibility, the standard locale converters
+ * for primitive types (and the corresponding wrapper classes).
+ *
+ * If you prefer to have another {@link LocaleConverter}
+ * thrown instead, replace the standard {@link LocaleConverter} instances
+ * with ones created with the one of the appropriate constructors.
+ *
+ * It's important that {@link LocaleConverter} should be registered for
+ * the specified locale and Class (or primitive type).
+ *
+ * @author Yauheny Mikulski
+ * @since 1.7
+ */
+public class LocaleConvertUtilsBean {
+    
+    /** 
+     * Gets singleton instance.
+     * This is the same as the instance used by the default {@link LocaleBeanUtilsBean} singleton.
+     */
+    public static LocaleConvertUtilsBean getInstance() {
+        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getLocaleConvertUtils();
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+    /** The locale - default for convertion. */
+    private Locale defaultLocale = Locale.getDefault();
+
+    /** Indicate whether the pattern is localized or not */
+    private boolean applyLocalized = false;
+
+    /** The <code>Log</code> instance for this class. */
+    private Log log = LogFactory.getLog(LocaleConvertUtils.class);
+
+    /** Every entry of the mapConverters is:
+     *  key = locale
+     *  value = FastHashMap of converters for the certain locale.
+     */
+    private FastHashMap mapConverters = new FastHashMap();
+
+    // --------------------------------------------------------- Constructors
+
+    /**
+     *  Makes the state by default (deregisters all converters for all locales)
+     *  and then registers default locale converters.
+     */
+    public LocaleConvertUtilsBean() {
+        deregister();
+    }
+    
+    // --------------------------------------------------------- Properties
+     
+    /**
+     * getter for defaultLocale
+     */
+    public Locale getDefaultLocale() {
+
+        return defaultLocale;
+    }
+
+    /**
+     * setter for defaultLocale
+     */
+    public void setDefaultLocale(Locale locale) {
+
+        if (locale == null) {
+            defaultLocale = Locale.getDefault();
+        }
+        else {
+            defaultLocale = locale;
+        }
+    }
+    
+    /**
+     * getter for applyLocalized
+     */
+    public boolean getApplyLocalized() {
+        return applyLocalized;
+    }
+
+    /**
+     * setter for applyLocalized
+     */
+    public void setApplyLocalized(boolean newApplyLocalized) {
+        applyLocalized = newApplyLocalized;
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive value into a String.
+     *
+     * @param value The Value to be converted
+     *
+     * @exception org.apache.commons.beanutils.ConversionException if thrown by an underlying Converter
+     */
+    public String convert(Object value) {
+        return convert(value, defaultLocale, null);
+    }
+
+    /**
+     * Convert the specified locale-sensitive value into a String
+     * using the convertion pattern.
+     *
+     * @param value The Value to be converted
+     * @param pattern       The convertion pattern
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public String convert(Object value, String pattern) {
+        return convert(value, defaultLocale, pattern);
+    }
+
+    /**
+     * Convert the specified locale-sensitive value into a String
+     * using the paticular convertion pattern.
+     *
+     * @param value The Value to be converted
+     * @param locale The locale
+     * @param pattern The convertion pattern
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public String convert(Object value, Locale locale, String pattern) {
+
+        LocaleConverter converter = lookup(String.class, locale);
+		
+        return (String) converter.convert(String.class, value, pattern);
+    }
+
+    /**
+     * Convert the specified value to an object of the specified class (if
+     * possible).  Otherwise, return a String representation of the value.
+     *
+     * @param value The String scalar value to be converted
+     * @param clazz The Data type to which this value should be converted.
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String value, Class clazz) {
+
+        return convert(value, clazz, defaultLocale, null);
+    }
+
+    /**
+     * Convert the specified value to an object of the specified class (if
+     * possible) using the convertion pattern. Otherwise, return a String
+     * representation of the value.
+     *
+     * @param value The String scalar value to be converted
+     * @param clazz The Data type to which this value should be converted.
+     * @param pattern The convertion pattern
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String value, Class clazz, String pattern) {
+
+        return convert(value, clazz, defaultLocale, pattern);
+    }
+
+    /**
+     * Convert the specified value to an object of the specified class (if
+     * possible) using the convertion pattern. Otherwise, return a String
+     * representation of the value.
+     *
+     * @param value The String scalar value to be converted
+     * @param clazz The Data type to which this value should be converted.
+     * @param locale The locale
+     * @param pattern The convertion pattern
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String value, Class clazz, Locale locale, String pattern) {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Convert string " + value + " to class " +
+                    clazz.getName() + " using " + locale.toString() +
+                    " locale and " + pattern + " pattern");
+        }
+
+        LocaleConverter converter = lookup(clazz, locale);
+
+        if (converter == null) {
+            converter = (LocaleConverter) lookup(String.class, locale);
+        }
+        if (log.isTraceEnabled()) {
+            log.trace("  Using converter " + converter);
+        }
+
+        return (converter.convert(clazz, value, pattern));
+    }
+
+    /**
+     * Convert an array of specified values to an array of objects of the
+     * specified class (if possible) using the convertion pattern.
+     *
+     * @param values Value to be converted (may be null)
+     * @param clazz Java array or element class to be converted to
+     * @param pattern The convertion pattern
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String values[], Class clazz, String pattern) {
+
+        return convert(values, clazz, getDefaultLocale(), pattern);
+    }
+
+   /**
+    * Convert an array of specified values to an array of objects of the
+    * specified class (if possible) .
+    *
+    * @param values Value to be converted (may be null)
+    * @param clazz Java array or element class to be converted to
+    *
+    * @exception ConversionException if thrown by an underlying Converter
+    */
+   public Object convert(String values[], Class clazz) {
+
+       return convert(values, clazz, getDefaultLocale(), null);
+   }
+
+    /**
+     * Convert an array of specified values to an array of objects of the
+     * specified class (if possible) using the convertion pattern.
+     *
+     * @param values Value to be converted (may be null)
+     * @param clazz Java array or element class to be converted to
+     * @param locale The locale
+     * @param pattern The convertion pattern
+     *
+     * @exception ConversionException if thrown by an underlying Converter
+     */
+    public Object convert(String values[], Class clazz, Locale locale, String pattern) {
+
+        Class type = clazz;
+        if (clazz.isArray()) {
+            type = clazz.getComponentType();
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("Convert String[" + values.length + "] to class " +
+                    type.getName() + "[] using " + locale.toString() +
+                    " locale and " + pattern + " pattern");
+        }
+
+        Object array = Array.newInstance(type, values.length);
+        for (int i = 0; i < values.length; i++) {
+            Array.set(array, i, convert(values[i], type, locale, pattern));
+        }
+
+        return (array);
+    }
+
+    /**
+     * Register a custom {@link LocaleConverter} for the specified destination
+     * <code>Class</code>, replacing any previously registered converter.
+     *
+     * @param converter The LocaleConverter to be registered
+     * @param clazz The Destination class for conversions performed by this
+     *  Converter
+     * @param locale The locale
+     */
+    public void register(LocaleConverter converter, Class clazz, Locale locale) {
+
+        lookup(locale).put(clazz, converter);
+    }
+
+    /**
+     * Remove any registered {@link LocaleConverter}.
+     */
+    public void deregister() {
+
+        FastHashMap defaultConverter = lookup(defaultLocale);
+
+        mapConverters.setFast(false);
+
+        mapConverters.clear();
+        mapConverters.put(defaultLocale, defaultConverter);
+
+        mapConverters.setFast(true);
+    }
+
+
+    /**
+     * Remove any registered {@link LocaleConverter} for the specified locale
+     *
+     * @param locale The locale
+     */
+    public void deregister(Locale locale) {
+
+        mapConverters.remove(locale);
+    }
+
+
+    /**
+     * Remove any registered {@link LocaleConverter} for the specified locale and Class.
+     *
+     * @param clazz Class for which to remove a registered Converter
+     * @param locale The locale
+     */
+    public void deregister(Class clazz, Locale locale) {
+
+        lookup(locale).remove(clazz);
+    }
+
+    /**
+     * Look up and return any registered {@link LocaleConverter} for the specified
+     * destination class and locale; if there is no registered Converter, return
+     * <code>null</code>.
+     *
+     * @param clazz Class for which to return a registered Converter
+     * @param locale The Locale
+     */
+    public LocaleConverter lookup(Class clazz, Locale locale) {
+
+        LocaleConverter converter = (LocaleConverter) lookup(locale).get(clazz);
+        
+        if (log.isTraceEnabled()) {
+            log.trace("LocaleConverter:" + converter);
+        }
+        
+        return converter;
+    }
+
+    /**
+     * Look up and return any registered FastHashMap instance for the specified locale;
+     * if there is no registered one, return <code>null</code>.
+     *
+     * @param locale The Locale
+     * @return The FastHashMap instance contains the all {@link LocaleConverter} types for
+     *  the specified locale.
+     */
+    protected FastHashMap lookup(Locale locale) {
+        FastHashMap localeConverters;
+
+        if (locale == null) {
+            localeConverters = (FastHashMap) mapConverters.get(defaultLocale);
+        }
+        else {
+            localeConverters = (FastHashMap) mapConverters.get(locale);
+
+            if (localeConverters == null) {
+                localeConverters = create(locale);
+                mapConverters.put(locale, localeConverters);
+            }
+        }
+
+        return localeConverters;
+    }
+
+    /**
+     *  Create all {@link LocaleConverter} types for specified locale.
+     *
+     * @param locale The Locale
+     * @return The FastHashMap instance contains the all {@link LocaleConverter} types
+     *  for the specified locale.
+     */
+    protected FastHashMap create(Locale locale) {
+
+        FastHashMap converter = new FastHashMap();
+        converter.setFast(false);
+
+        converter.put(BigDecimal.class, new BigDecimalLocaleConverter(locale, applyLocalized));
+        converter.put(BigInteger.class, new BigIntegerLocaleConverter(locale, applyLocalized));
+
+        converter.put(Byte.class, new ByteLocaleConverter(locale, applyLocalized));
+        converter.put(Byte.TYPE, new ByteLocaleConverter(locale, applyLocalized));
+
+        converter.put(Double.class, new DoubleLocaleConverter(locale, applyLocalized));
+        converter.put(Double.TYPE, new DoubleLocaleConverter(locale, applyLocalized));
+
+        converter.put(Float.class, new FloatLocaleConverter(locale, applyLocalized));
+        converter.put(Float.TYPE, new FloatLocaleConverter(locale, applyLocalized));
+
+        converter.put(Integer.class, new IntegerLocaleConverter(locale, applyLocalized));
+        converter.put(Integer.TYPE, new IntegerLocaleConverter(locale, applyLocalized));
+
+        converter.put(Long.class, new LongLocaleConverter(locale, applyLocalized));
+        converter.put(Long.TYPE, new LongLocaleConverter(locale, applyLocalized));
+
+        converter.put(Short.class, new ShortLocaleConverter(locale, applyLocalized));
+        converter.put(Short.TYPE, new ShortLocaleConverter(locale, applyLocalized));
+
+        converter.put(String.class, new StringLocaleConverter(locale, applyLocalized));
+
+        // conversion format patterns of java.sql.* types should correspond to default
+        // behaviour of toString and valueOf methods of these classes
+        converter.put(java.sql.Date.class, new SqlDateLocaleConverter(locale, "yyyy-MM-dd"));
+        converter.put(java.sql.Time.class, new SqlTimeLocaleConverter(locale, "HH:mm:ss"));
+        converter.put( java.sql.Timestamp.class,
+                       new SqlTimestampLocaleConverter(locale, "yyyy-MM-dd HH:mm:ss.S")
+                     );
+
+        converter.setFast(true);
+
+        return converter;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * <p>General purpose locale-sensitive data type converter that can be registered and used
+ * within the BeanUtils package to manage the conversion of objects from
+ * one type to another.
+ *
+ * @author Yauheny Mikulski
+ */
+
+public interface LocaleConverter extends Converter {
+
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param type Data type to which this value should be converted
+     * @param value The input value to be converted
+     * @param pattern The user-defined pattern is used for the input object formatting.
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    public Object convert(Class type, Object value, String pattern);
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/LocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.math.BigDecimal</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class BigDecimalLocaleConverter extends DecimalLocaleConverter {
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public BigDecimalLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigDecimalLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public BigDecimalLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigDecimalLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public BigDecimalLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigDecimalLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public BigDecimalLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigDecimalLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public BigDecimalLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigDecimalLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public BigDecimalLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigDecimalLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern);
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import java.util.Locale;
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.math.BigInteger</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class BigIntegerLocaleConverter extends DecimalLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public BigIntegerLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigIntegerLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public BigIntegerLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigIntegerLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public BigIntegerLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigIntegerLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public BigIntegerLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigIntegerLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public BigIntegerLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigIntegerLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public BigIntegerLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public BigIntegerLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern);
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ByteLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ByteLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ByteLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import org.apache.commons.beanutils.ConversionException;
+
+import java.util.Locale;
+import java.text.ParseException;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter}
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.lang.Byte</code> object,
+ * optionally using a default value or throwing a
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class ByteLocaleConverter extends DecimalLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public ByteLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ByteLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public ByteLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ByteLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public ByteLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ByteLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public ByteLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ByteLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public ByteLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ByteLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public ByteLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+   /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ByteLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern);
+    }
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type. This method will return values of type Byte.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception org.apache.commons.beanutils.ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+        final Number parsed = (Number) super.parse(value, pattern);
+        if (parsed.longValue() != parsed.byteValue()) {
+            throw new ConversionException("Supplied number is not of type Byte: " + parsed.longValue());
+        }
+        // now returns property Byte
+        return new Byte(parsed.byteValue());
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ByteLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import org.apache.commons.beanutils.locale.BaseLocaleConverter;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.util.Date</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ * @author Michael Szlapa
+ */
+
+public class DateLocaleConverter extends BaseLocaleConverter {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /** All logging goes through this logger */
+    private static Log log = LogFactory.getLog(DateLocaleConverter.class);
+
+    /** Should the date conversion be lenient? */
+    boolean isLenient = false;
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public DateLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DateLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public DateLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DateLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public DateLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DateLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public DateLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DateLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public DateLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DateLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public DateLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DateLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+
+    // --------------------------------------------------------- Methods
+    
+    /**
+     * Returns whether date formatting is lenient.
+     *
+     * @return true if the <code>DateFormat</code> used for formatting is lenient
+     * @see java.text.DateFormat#isLenient
+     */
+    public boolean isLenient() {
+        return isLenient;
+    }
+    
+    /**
+     * Specify whether or not date-time parsing should be lenient.
+     * 
+     * @param lenient true if the <code>DateFormat</code> used for formatting should be lenient
+     * @see java.text.DateFormat#setLenient
+     */
+    public void setLenient(boolean lenient) {
+        isLenient = lenient;
+    }	
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception org.apache.commons.beanutils.ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+        SimpleDateFormat formatter = getFormatter(pattern, locale);
+        if (locPattern) {
+            formatter.applyLocalizedPattern(pattern);
+        }
+        else {
+            formatter.applyPattern(pattern);
+        }
+        return formatter.parse((String) value);
+    }
+
+    /**
+     * Gets an appropriate <code>SimpleDateFormat</code> for given locale, 
+     * default Date format pattern is not provided.
+     */
+    private SimpleDateFormat getFormatter(String pattern, Locale locale) {
+        // This method is a fix for null pattern, which would cause 
+        // Null pointer exception when applied
+        // Note: that many constructors default the pattern to null, 
+        // so it only makes sense to handle nulls gracefully
+        if(pattern == null) {
+            pattern = locPattern ? 
+                new SimpleDateFormat().toLocalizedPattern() : new SimpleDateFormat().toPattern();
+            log.warn("Null pattern was provided, defaulting to: " + pattern);
+        }
+        SimpleDateFormat format = new SimpleDateFormat(pattern, locale);
+        format.setLenient(isLenient);
+        return format;
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import org.apache.commons.beanutils.locale.BaseLocaleConverter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.lang.Decimal</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ * @author Yoav Shapira
+ * @since 1.7
+ */
+
+public class DecimalLocaleConverter extends BaseLocaleConverter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /** All logging goes through this logger */
+    private static Log log = LogFactory.getLog(DecimalLocaleConverter.class);     
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public DecimalLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DecimalLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public DecimalLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DecimalLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public DecimalLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DecimalLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        this(null, locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public DecimalLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DecimalLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public DecimalLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DecimalLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public DecimalLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DecimalLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+	
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+        // DecimalFormat is not thread safe so best to construct one each time
+        DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(locale);
+        // if some constructors default pattern to null, it makes only sense to handle null pattern gracefully
+        if (pattern != null) {
+            if (locPattern) {
+                formatter.applyLocalizedPattern(pattern);
+            } else {
+                formatter.applyPattern(pattern);
+            }
+        } else {
+            log.warn("No pattern provided, using default.");
+        }
+
+        return formatter.parse((String) value);
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+
+import java.text.ParseException;
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.lang.Double</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class DoubleLocaleConverter extends DecimalLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public DoubleLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DoubleLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public DoubleLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DoubleLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public DoubleLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DoubleLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public DoubleLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DoubleLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public DoubleLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DoubleLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public DoubleLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public DoubleLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern);
+    }
+
+    protected Object parse(Object value, String pattern) throws ParseException {
+        Number result = (Number) super.parse(value, pattern);
+        if (result instanceof Long) {
+            return new Double(result.doubleValue());
+        } else {
+            return (result);
+        }
+    }
+
+
+}
+
+


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import org.apache.commons.beanutils.ConversionException;
+
+import java.util.Locale;
+import java.text.ParseException;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter}
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.math.BigDecimal</code> object,
+ * optionally using a default value or throwing a
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class FloatLocaleConverter extends DecimalLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public FloatLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public FloatLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public FloatLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public FloatLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public FloatLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public FloatLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public FloatLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public FloatLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public FloatLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public FloatLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public FloatLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public FloatLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern);
+    }
+
+   /**
+    * Convert the specified locale-sensitive input object into an output object of the
+    * specified type.  This method will return Float value or throw exception if value
+    * can not be stored in the Float.
+    *
+    * @param value The input object to be converted
+    * @param pattern The pattern is used for the convertion
+    *
+    * @exception ConversionException if conversion cannot be performed
+    *  successfully
+    */
+   protected Object parse(Object value, String pattern) throws ParseException {
+      final Number parsed = (Number) super.parse(value, pattern);
+      if( Math.abs(parsed.doubleValue() - parsed.floatValue()) > parsed.floatValue() * 0.00001 ) {
+         throw new ConversionException("Suplied number is not of type Float: "+parsed.longValue());
+      }
+      return new Float(parsed.floatValue()); // unlike superclass it returns Float type
+   }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import org.apache.commons.beanutils.ConversionException;
+
+import java.util.Locale;
+import java.text.ParseException;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter}
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.lang.Integer</code> object,
+ * optionally using a default value or throwing a
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class IntegerLocaleConverter extends DecimalLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+
+    public IntegerLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public IntegerLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public IntegerLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public IntegerLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public IntegerLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public IntegerLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public IntegerLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public IntegerLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public IntegerLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public IntegerLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public IntegerLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public IntegerLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type. This method will return Integer type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+        final Number parsed = (Number) super.parse(value, pattern);
+        if (parsed.longValue() != parsed.intValue()) {
+            throw new ConversionException("Suplied number is not of type Integer: " + parsed.longValue());
+        }
+        return new Integer(parsed.intValue()); // unlike superclass it will return proper Integer
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.lang.Long</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class LongLocaleConverter extends DecimalLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public LongLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public LongLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public LongLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public LongLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public LongLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public LongLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public LongLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public LongLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public LongLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public LongLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public LongLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public LongLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale.converters;
+
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.lang.Short</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class ShortLocaleConverter extends DecimalLocaleConverter {
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public ShortLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ShortLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public ShortLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ShortLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public ShortLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ShortLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public ShortLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ShortLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public ShortLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ShortLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public ShortLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public ShortLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern);
+    }
+}
+


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlDateLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlDateLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlDateLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale.converters;
+
+import java.sql.Date;
+import java.text.ParseException;
+import java.util.Locale;
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.sql.Date</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class SqlDateLocaleConverter extends DateLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public SqlDateLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlDateLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public SqlDateLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlDateLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public SqlDateLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlDateLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public SqlDateLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlDateLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public SqlDateLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlDateLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public SqlDateLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlDateLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+
+        return new Date(((java.util.Date) super.parse((String) value, pattern)).getTime());
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlDateLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale.converters;
+
+import java.sql.Time;
+import java.text.ParseException;
+import java.util.Locale;
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.sql.Time</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class SqlTimeLocaleConverter extends DateLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public SqlTimeLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimeLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public SqlTimeLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimeLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public SqlTimeLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimeLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public SqlTimeLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimeLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public SqlTimeLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimeLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public SqlTimeLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimeLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+
+        return new Time(((java.util.Date) super.parse((String) value, pattern)).getTime());
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale.converters;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.util.Locale;
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+ * implementation that converts an incoming
+ * locale-sensitive String into a <code>java.sql.Timestamp</code> object,
+ * optionally using a default value or throwing a 
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class SqlTimestampLocaleConverter extends DateLocaleConverter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public SqlTimestampLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimestampLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public SqlTimestampLocaleConverter(Locale locale) {
+
+        this(locale, (String) null);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimestampLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public SqlTimestampLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimestampLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public SqlTimestampLocaleConverter(Object defaultValue) {
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimestampLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public SqlTimestampLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimestampLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public SqlTimestampLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter} 
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public SqlTimestampLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+
+        return new Timestamp(((java.util.Date) super.parse(value, pattern)).getTime());
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/StringLocaleConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/StringLocaleConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/StringLocaleConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils.locale.converters;
+
+import org.apache.commons.beanutils.locale.BaseLocaleConverter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+
+/**
+ * <p>Standard {@link org.apache.commons.beanutils.locale.LocaleConverter}
+ * implementation that converts an incoming
+ * locale-sensitive object into a <code>java.lang.String</code> object,
+ * optionally using a default value or throwing a
+ * {@link org.apache.commons.beanutils.ConversionException}
+ * if a conversion error occurs.</p>
+ *
+ * @author Yauheny Mikulski
+ */
+
+public class StringLocaleConverter extends BaseLocaleConverter {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /** All logging goes through this logger */
+    private static Log log = LogFactory.getLog(StringLocaleConverter.class);     //msz fix
+
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     */
+    public StringLocaleConverter() {
+
+        this(false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public StringLocaleConverter(boolean locPattern) {
+
+        this(Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     */
+    public StringLocaleConverter(Locale locale) {
+
+        this(locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public StringLocaleConverter(Locale locale, boolean locPattern) {
+
+        this(locale, (String) null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public StringLocaleConverter(Locale locale, String pattern) {
+
+        this(locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will throw a {@link org.apache.commons.beanutils.ConversionException}
+     * if a conversion error occurs.
+     *
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public StringLocaleConverter(Locale locale, String pattern, boolean locPattern) {
+
+        super(locale, pattern, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine and an unlocalized pattern is used
+     * for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     */
+    public StringLocaleConverter(Object defaultValue) {
+
+        this(defaultValue, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. The locale is the default locale for
+     * this instance of the Java Virtual Machine.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public StringLocaleConverter(Object defaultValue, boolean locPattern) {
+
+        this(defaultValue, Locale.getDefault(), locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     */
+    public StringLocaleConverter(Object defaultValue, Locale locale) {
+
+        this(defaultValue, locale, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public StringLocaleConverter(Object defaultValue, Locale locale, boolean locPattern) {
+
+        this(defaultValue, locale, null, locPattern);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs. An unlocalized pattern is used for the convertion.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     */
+    public StringLocaleConverter(Object defaultValue, Locale locale, String pattern) {
+
+        this(defaultValue, locale, pattern, false);
+    }
+
+    /**
+     * Create a {@link org.apache.commons.beanutils.locale.LocaleConverter}
+     * that will return the specified default value
+     * if a conversion error occurs.
+     *
+     * @param defaultValue  The default value to be returned
+     * @param locale        The locale
+     * @param pattern       The convertion pattern
+     * @param locPattern    Indicate whether the pattern is localized or not
+     */
+    public StringLocaleConverter(Object defaultValue, Locale locale, String pattern, boolean locPattern) {
+
+        super(defaultValue, locale, pattern, locPattern);
+    }
+
+    // --------------------------------------------------------- Methods
+
+    /**
+     * Convert the specified locale-sensitive input object into an output object of the
+     * specified type.
+     *
+     * @param value The input object to be converted
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    protected Object parse(Object value, String pattern) throws ParseException {
+
+        String result = null;
+
+        if ((value instanceof Integer) ||
+                (value instanceof Long) ||
+                (value instanceof BigInteger) ||
+                (value instanceof Byte) ||
+                (value instanceof Short)) {
+
+            result = getDecimalFormat(locale, pattern).format(((Number) value).longValue());
+        }
+        else if ((value instanceof Double) ||
+                (value instanceof BigDecimal) ||
+                (value instanceof Float)) {
+
+            result = getDecimalFormat(locale, pattern).format(((Number) value).doubleValue());
+        }
+        else if (value instanceof Date) { // java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp
+
+            SimpleDateFormat dateFormat =
+                    new SimpleDateFormat(pattern, locale);
+
+            result = dateFormat.format(value);
+        }
+        else {
+            result = value.toString();
+        }
+
+        return result;
+    }
+
+    /**
+     * Make an instance of DecimalFormat.
+     *
+     * @param locale The locale
+     * @param pattern The pattern is used for the convertion
+     *
+     * @exception ConversionException if conversion cannot be performed
+     *  successfully
+     */
+    private DecimalFormat getDecimalFormat(Locale locale, String pattern) {
+
+        DecimalFormat numberFormat = (DecimalFormat) NumberFormat.getInstance(locale);
+
+        // if some constructors default pattern to null, it makes only sense to handle null pattern gracefully
+        if (pattern != null) {
+            if (locPattern) {
+                numberFormat.applyLocalizedPattern(pattern);
+            } else {
+                numberFormat.applyPattern(pattern);
+            }
+        } else {
+            log.warn("No pattern provided, using default.");
+        }
+
+        return numberFormat;
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/StringLocaleConverter.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/package.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/package.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/converters/package.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>Package Documentation for org.apache.commons.beanutils.locale.converters</title>
+</head>
+<body bgcolor="white">
+<p>Standard implementations of the locale-aware
+<code>LocaleConverter</code>
+interface that are pre-registered with locale-aware
+<code>LocaleConvertUtils</code>
+at startup time.</p>
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/package.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/package.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/locale/package.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Package Documentation for org.apache.commons.beanutils.locale Package</title>
+</head>
+<body bgcolor="white">
+<p>Locale-aware extensions of the standard beanutils classes. 
+This package allows locale-dependent population of JavaBeans.</p>
+
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/package.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/package.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/beanutils/package.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,990 @@
+<html>
+<head>
+<title>Package Documentation for org.apache.commons.beanutils Package</title>
+</head>
+<body bgcolor="white">
+<p>The <em>Bean Introspection Utilities</em> component of the Jakarta Commons
+subproject offers low-level utility classes that assist in getting and setting
+property values on Java classes that follow the naming design patterns outlined
+in the JavaBeans Specification, as well as mechanisms for dynamically defining
+and accessing bean properties.</p>
+
+<h1>Table of Contents</h1>
+
+<ol>
+<li><a href="#overview">Overview</a>
+    <ul>
+    <li><a href="#overview.background">Background</a></li>
+    <li><a href="#overview.dependencies">External Dependencies</a></li>
+    </ul></li>
+<li><a href="#standard">Standard JavaBeans</a>
+    <ul>
+    <li><a href="#standard.background">Background</a></li>
+    <li><a href="#standard.basic">Basic Property Access</a></li>
+    <li><a href="#standard.nested">Nested Property Access</a></li>
+    </ul></li>
+<li><a href="#dynamic">Dynamic Beans (DynaBeans)</a>
+    <ul>
+    <li><a href="#dynamic.background">Background</a></li>
+    <li><a href="#dynamic.basic">BasicDynaBean and BasicDynaClass</a></li>
+    <li><a href="#dynamic.resultSet">ResultSetDynaClass (Wraps ResultSet in DynaBeans)</a></li>
+    <li><a href="#dynamic.rowSet">RowSetDynaClass (Disconnected ResultSet as DynaBeans)</a></li>
+    <li><a href="#dynamic.wrap">WrapDynaBean and WrapDynaClass</a></li>
+    <li><a href="#dynamic.lazy"><i>Lazy</i> DynaBeans</a></li>
+    </ul></li>
+<li><a href="#conversion">Data Type Conversions</a>
+    <ul>
+    <li><a href="#conversion.background">Background</a></li>
+    <li><a href="#conversion.beanutils">BeanUtils and ConvertUtils
+        Conversions</a></li>
+    <li><a href="#conversion.defining">Defining Your Own Converters</a></li>
+    <li><a href="#conversion.i18n">Locale Aware Conversions</a></li>
+    </ul></li>
+<li><a href="#instances">Utility Objects And Static Utility Classes</a>
+    <ul>
+    <li><a href="#instances.background">Background</a></li>
+    </ul></li>
+<li><a href="#collections">Collections</a>
+    <ul>
+    <li><a href="#bean-comparator">Comparing Beans</a></li>
+    <li><a href="#bean-property-closure">Operating On Collections Of Beans</a></li>
+    <li><a href="#bean-property-predicate">Querying Or Filtering Collections Of Beans</a></li>
+    <li><a href="#bean-property-transformer">Transforming Collections Of Beans</a></li>
+    </ul></li>
+<li><a href="#FAQ">Frequently Asked Questions</a>
+    <ul>
+    <li><a href="#FAQ.property">Why Can't BeanUtils Find My Method?</a></li>
+    <li><a href="#FAQ.bc.order">How Do I Set The BeanComparator Order To Be Ascending/Descending?</a></li>
+    </ul></li>
+<li><a href='#Packaging'>Packaging</a></li>
+</ol>
+
+<a name="overview"></a>
+<h1>Overview</h1>
+
+<a name="overview.background"></a>
+<h3>Background</h3>
+
+<p>The <em>JavaBeans</em> name comes from a
+<a href="http://java.sun.com/products/javabeans/">Java API specification</a>
+for a component architecture for the Java language.  Writing Java classes that
+conform to the JavaBeans design patterns makes it easier for Java developers
+to understand the functionality provided by your class, as well as allowing
+JavaBeans-aware tools to use Java's <em>introspection</em> capabilities to
+learn about the properties and operations provided by your class, and present
+them in a visually appealing manner in development tools.</p>
+
+<p>The <a href="http://java.sun.com/products/javabeans/docs/spec.html">JavaBeans
+Specification</a> describes the complete set of characteristics that makes
+an arbitrary Java class a JavaBean or not -- and you should consider reading
+this document to be an important part of developing your Java programming
+skills.  However, the required characteristics of JavaBeans that are
+important for most development scenarios are listed here:</p>
+<ul>
+<li>The class must be <strong>public</strong>, and provide a
+    <strong>public</strong> constructor that accepts no arguments.  This allows
+    tools and applications to dynamically create new instances of your bean,
+    without necessarily knowing what Java class name will be used ahead of
+    time, like this:
+<pre>
+        String className = ...;
+        Class beanClass = Class.forName(className);
+        Object beanInstance = beanClass.newInstance();
+</pre></li>
+<li>As a necessary consequence of having a no-arguments constructor,
+    configuration of your bean's behavior must be accomplished separately
+    from its instantiation.  This is typically done by defining a set of
+    <em>properties</em> of your bean, which can be used to modify its behavior
+    or the data that the bean represents.  The normal convention for
+    property names is that they start with a lower case letter, and be
+    comprised only of characters that are legal in a Java identifier.</li>
+<li>Typically, each bean property will have a public <em>getter</em> and
+    <em>setter</em> method that are used to retrieve or define the property's
+    value, respectively.  The JavaBeans Specification defines a design
+    pattern for these names, using <code>get</code> or <code>set</code> as the
+    prefix for the property name with it's first character capitalized.  Thus,
+    you a JavaBean representing an employee might have
+    (among others) properties named <code>firstName</code>,
+    <code>lastName</code>, and <code>hireDate</code>, with method signatures
+    like this:
+<pre>
+        public class Employee {
+            public Employee();   // Zero-arguments constructor
+            public String getFirstName();
+            public void setFirstName(String firstName);
+            public String getLastName();
+            public void setLastName(String lastName);
+            public Date getHireDate();
+            public void setHireDate(Date hireDate);
+            public boolean isManager();
+            public void setManager(boolean manager);
+            public String getFullName();
+        }
+</pre></li>
+<li>As you can see from the above example, there is a special variant allowed
+    for boolean properties -- you can name the <em>getter</em> method with a
+    <code>is</code> prefix instead of a <code>get</code> prefix if that makes
+    for a more understandable method name.</li>
+<li>If you have both a <em>getter</em> and a <em>setter</em> method for a
+    property, the data type returned by the <em>getter</em> must match the
+    data type accepted by the <em>setter</em>.  In addition, it is contrary
+    to the JavaBeans specification to have more than one <em>setter</em>
+    with the same name, but different property types.</li>
+<li>It is not required that you provide a <em>getter</em> and a
+    <em>setter</em> for every property.  In the example above, the
+    <code>fullName</code> property is read-only, because there is no
+    <em>setter</em> method.  It is also possible, but less common, to provide
+    write-only properties.</li>
+<li>It is also possible to create a JavaBean where the <em>getter</em> and
+    <em>setter</em> methods do not match the naming pattern described above.
+    The standard JavaBeans support classes in the Java language, as well as
+    all classes in the BeanUtils package, allow you to describe the actual
+    property method names in a <code>BeanInfo</code> class associated with
+    your bean class.  See the JavaBeans Specification for full details.</li>
+<li>The JavaBeans Specification also describes many additional design patterns
+    for event listeners, wiring JavaBeans together into component hierarchies,
+    and other useful features that are beyond the scope of the BeanUtils
+    package.</li>
+</ul>
+
+<p>Using standard Java coding techniques, it is very easy to deal with
+JavaBeans if you know ahead of time which bean classes you will be using, and
+which properties you are interested in:</p>
+<pre>
+        Employee employee = ...;
+        System.out.println("Hello " + employee.getFirstName() + "!");
+</pre>
+
+<a name="overview.dependencies"></a>
+<h3>External Dependencies</h3>
+
+<p>The <em>commons-beanutils</em> package requires that the following
+additional packages be available in the application's class path at runtime:
+</p>
+<ul>
+<li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-collections">
+Collections Package (Jakarta Commons)</a>, version 1.0 or later</li>
+<li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-logging">
+Logging Package (Jakarta Commons)</a>, version 1.0 or later</li>
+</ul>
+
+
+<a name="standard"></a>
+<h1>Standard JavaBeans</h1>
+
+<a name="standard.background"></a>
+<h3>Background</h3>
+
+<p>As described above, the standard facilities of the Java programming language
+make it easy and natural to access the property values of your beans using
+calls to the appropriate getter methods.
+But what happens in more sophisticated environments where you do not
+necessarily know ahead of time which bean class you are going to be using,
+or which property you want to retrieve or modify?  The Java language provides
+classes like <code>java.beans.Introspector</code>, which can examine a Java
+class at runtime and identify for you the names of the property getter and
+setter methods, plus the <em>Reflection</em> capabilities to dynamically call
+such a method.  However, these APIs can be difficult to use, and expose the
+application developer to many unnecessary details of the underlying structure
+of Java classes.  The APIs in the BeanUtils package are intended to simplify
+getting and setting bean properties dynamically, where the objects you are
+accessing -- and the names of the properties you care about -- are determined
+at runtime in your application, rather than as you are writing and compiling
+your application's classes.</p>
+
+<p>This is the set of needs that are satisfied by the static methods of the
+<a href="PropertyUtils.html">PropertyUtils</a>
+class, which are described further in this section.  First, however, some
+further definitions will prove to be useful:</p>
+
+<p>The general set of possible property types supported by a JavaBean can be
+broken into three categories -- some of which are supported by the standard
+JavaBeans specification, and some of which are uniquely supported by the
+<em>BeanUtils</em> package:</p>
+<ul>
+<li><strong>Simple</strong> - Simple, or scalar, properties have a single
+    value that may be retrieved or modified.  The underlying property type
+    might be a Java language primitive (such as <code>int</code>, a simple
+    object (such as a <code>java.lang.String</code>), or a more complex
+    object whose class is defined either by the Java language, by the
+    application, or by a class library included with the application.</li>
+<li><strong>Indexed</strong> - An indexed property stores an ordered collection
+    of objects (all of the same type) that can be individually accessed by an
+    integer-valued, non-negative index (or subscript).  Alternatively, the
+    entire set of values may be set or retrieved using an array.
+    As an extension to the JavaBeans specification, the
+    <em>BeanUtils</em> package considers any property whose underlying data
+    type is <code>java.util.List</code> (or an implementation of List) to be
+    indexed as well.</li>
+<li><strong>Mapped</strong> - As an extension to standard JavaBeans APIs,
+    the <em>BeanUtils</em> package considers any property whose underlying
+    value is a <code>java.util.Map</code> to be "mapped".  You can set and
+    retrieve individual values via a String-valued key.</li>
+</ul>
+
+<p>A variety of API methods are provided in the <a href="PropertyUtils.html">
+PropertyUtils</a> class to get and set property values of all of these types.
+In the code fragments below, assume that there are two bean classes defined
+with the following method signatures:</p>
+<pre>
+    public class Employee {
+        public Address getAddress(String type);
+        public void setAddress(String type, Address address);
+        public Employee getSubordinate(int index);
+        public void setSubordinate(int index, Employee subordinate);
+        public String getFirstName();
+        public void setFirstName(String firstName);
+        public String getLastName();
+        public void setLastName(String lastName);
+    }
+</pre>
+
+<a name="standard.basic"></a>
+<h3>Basic Property Access</h3>
+
+<p>Getting and setting <strong>simple</strong> property values is, well,
+simple :-).  Check out the following API signatures in the Javadocs:</p>
+
+<ul>
+<li><a href="PropertyUtils.html#getSimpleProperty(java.lang.Object,java.lang.String)">
+    PropertyUtils.getSimpleProperty(Object bean, String name)</a></li>
+<li><a href="PropertyUtils.html#setSimpleProperty(java.lang.Object,java.lang.String,java.lang.Object)">
+    PropertyUtils.setSimpleProperty(Object bean, String name, Object value)</a></li>
+</ul>
+
+<p>Using these methods, you might dynamically manipulate the employee's name
+in an application:</p>
+<pre>
+    Employee employee = ...;
+    String firstName = (String)
+      PropertyUtils.getSimpleProperty(employee, "firstName");
+    String lastName = (String)
+      PropertyUtils.getSimpleProperty(employee, "lastName");
+    ... manipulate the values ...
+    PropertyUtils.setSimpleProperty(employee, "firstName", firstName);
+    PropertyUtils.setSimpleProperty(employee, "lastName", lastName);
+</pre>
+
+<p>For <strong>indexed</strong> properties, you have two choices - you can
+either build a subscript into the "property name" string, using square
+brackets, or you can specify the subscript in a separate argument to the
+method call:</p>
+
+<ul>
+<li><a href="PropertyUtils.html#getIndexedProperty(java.lang.Object,java.lang.String)">
+    PropertyUtils.getIndexedProperty(Object bean, String name)</a></li>
+<li><a href="PropertyUtils.html#getIndexedProperty(java.lang.Object,java.lang.String,int)">
+    PropertyUtils.getIndexedProperty(Object bean, String name, int index)</a></li>
+<li><a href="PropertyUtils.html#setIndexedProperty(java.lang.Object,java.lang.String,java.lang.Object)">
+    PropertyUtils.setIndexedProperty(Object bean, String name, Object value)</a></li>
+<li><a href="PropertyUtils.html#setIndexedProperty(java.lang.Object,java.lang.String,int,java.lang.Object)">
+    PropertyUtils.setIndexedProperty(Object bean, String name, int index, Object value)</a></li>
+</ul>
+
+<p>Only integer constants are allowed when you add a subscript to the property
+name.  If you need to calculate the index of the entry you wish to retrieve,
+you can use String concatenation to assemble the property name expression.
+For example, you might do either of the following:</p>
+<pre>
+    Employee employee = ...;
+    int index = ...;
+    String name = "subordinate[" + index + "]";
+    Employee subordinate = (Employee)
+      PropertyUtils.getIndexedProperty(employee, name);
+
+    Employee employee = ...;
+    int index = ...;
+    Employee subordinate = (Employee)
+      PropertyUtils.getIndexedProperty(employee, "subordinate", index);
+</pre>
+
+<p>In a similar manner, there are two possible method signatures for getting
+and setting <strong>mapped</strong> properties.  The difference is that the
+extra argument is surrounded by parentheses ("(" and ")") instead of square
+brackets, and it is considered to be a String-value key used to get or set
+the appropriate value from an underlying map.</p>
+
+<ul>
+<li><a href="PropertyUtils.html#getMappedProperty(java.lang.Object,java.lang.String)">
+    PropertyUtils.getMappedProperty(Object bean, String name)</a></li>
+<li><a href="PropertyUtils.html#getMappedProperty(java.lang.Object,java.lang.String,java.lang.String)">
+    PropertyUtils.getMappedProperty(Object bean, String name, String key)</a></li>
+<li><a href="PropertyUtils.html#setMappedProperty(java.lang.Object,java.lang.String,java.lang.Object)">
+    PropertyUtils.setMappedProperty(Object bean, String name, Object value)</a></li>
+<li><a href="PropertyUtils.html#setMappedProperty(java.lang.Object,java.lang.String,java.lang.String,java.lang.Object)">
+    PropertyUtils.setMappedProperty(Object bean, String name, String key, Object value)</a></li>
+</ul>
+
+<p>You can, for example, set the employee's home address in either of these
+two manners:</p>
+
+<pre>
+    Employee employee = ...;
+    Address address = ...;
+    PropertyUtils.setMappedProperty(employee, "address(home)", address);
+
+    Employee employee = ...;
+    Address address = ...;
+    PropertyUtils.setMappedProperty(employee, "address", "home", address);
+</pre>
+
+<a name="standard.nested"></a>
+<h3>Nested Property Access</h3>
+
+<p>In all of the examples above, we have assumed that you wished to retrieve
+the value of a property of the bean being passed as the first argument to a
+PropertyUtils method.  However, what if the property value you retrieve is
+really a Java object, and you wish to retrieve a property of <em>that</em>
+object instead?</p>
+
+<p>For example, assume we really wanted the <code>city</code> property of the
+employee's home address.  Using standard Java programming techniques for direct
+access to the bean properties, we might write:</p>
+
+<pre>
+    String city = employee.getAddress("home").getCity();
+</pre>
+
+<p>The equivalent mechanism using the PropertyUtils class is called
+<strong>nested</strong> property access.  To use this approach, you concatenate
+together the property names of the access path, using "." separators -- very
+similar to the way you can perform nested property access in JavaScript.</p>
+
+<ul>
+<li><a href="PropertyUtils.html#getNestedProperty(java.lang.Object,java.lang.String)">
+    PropertyUtils.getNestedProperty(Object bean, String name)</a></li>
+<li><a href="PropertyUtils.html#setNestedProperty(java.lang.Object,java.lang.String,java.lang.Object)">
+    PropertyUtils.setNestedProperty(Object bean, String name, Object value)</a></li>
+</ul>
+
+<p>The PropertyUtils equivalent to the above Java expression would be:</p>
+
+<pre>
+    String city = (String)
+      PropertyUtils.getNestedProperty(employee, "address(home).city");
+</pre>
+
+<p>Finally, for convenience, PropertyUtils provides method signatures that
+accept any arbitrary combination of simple, indexed, and mapped property
+access, using any arbitrary level of nesting:</p>
+
+<ul>
+<li><a href="PropertyUtils.html#getProperty(java.lang.Object,java.lang.String)">
+    PropertyUtils.getProperty(Object bean, String name)</a></li>
+<li><a href="PropertyUtils.html#setProperty(java.lang.Object,java.lang.String,java.lang.Object)">
+    PropertyUtils.setProperty(Object bean, String name, Object value)</a></li>
+</ul>
+
+<p>which you might use like this:</p>
+
+<pre>
+    Employee employee = ...;
+    String city = (String) PropertyUtils.getProperty(employee,
+      "subordinate[3].address(home).city");
+</pre>
+
+<a name="dynamic"></a>
+<h1>Dynamic Beans (DynaBeans)</h1>
+
+<a name="dynamic.background"></a>
+<h3>Background</h3>
+
+<p>The <a href="PropertyUtils.html">PropertyUtils</a> class described in the
+preceding section is designed to provide dynamic property access on existing
+JavaBean classes, without modifying them in any way.  A different use case for
+dynamic property access is when you wish to represent a dynamically calculated
+set of property values as a JavaBean, but <em>without</em> having to actually
+write a Java class to represent these properties.  Besides the effort savings
+in not having to create and maintain a separate Java class, this ability also
+means you can deal with situations where the set of properties you care about
+is determined dynamically (think of representing the result set of an SQL
+select as a set of JavaBeans ...).</p>
+
+<p>To support this use case, the <em>BeanUtils</em> package provides the
+<a href="DynaBean.html">DynaBean</a> interface, which must be implemented by a
+bean class actually implementing the interface's methods, and the associated
+<a href="DynaClass.html">DynaClass</a> interface that defines the set of
+properties supported by a particular group of DynaBeans, in much the same way
+that <code>java.lang.Class</code> defines the set of properties supported by
+all instances of a particular JavaBean class.</p>
+
+<p>For example, the <code>Employee</code> class used in the examples above
+might be implemented as a DynaBean, rather than as a standard JavaBean.  You
+can access its properties like this:</p>
+
+<pre>
+    DynaBean employee = ...; // Details depend on which
+                             // DynaBean implementation you use
+    String firstName = (String) employee.get("firstName");
+    Address homeAddress = (Address) employee.get("address", "home");
+    Object subordinate = employee.get("subordinate", 2);
+</pre>
+
+<p>One very important convenience feature should be noted:  <em>the
+PropertyUtils property getter and setter methods understand how to access
+properties in DynaBeans</em>.  Therefore, if the bean you pass as the first
+argument to, say, <code>PropertyUtils.getSimpleProperty()</code> is really a
+DynaBean implementation, the call will get converted to the appropriate
+DynaBean getter method transparently.  Thus, you can base your application's
+dynamic property access totally on the PropertyUtils APIs, if you wish, and
+use them to access either standard JavaBeans or DynaBeans without having to
+care ahead of time how a particular bean is implemented.</p>
+
+<p>Because DynaBean and DynaClass are interfaces, they may be implemented
+multiple times, in different ways, to address different usage scenarios.  The
+following subsections describe the implementations that are provided as a part
+of the standard <em>BeanUtils</em> package, although you are encouraged to
+provide your own custom implementations for cases where the standard
+implementations are not sufficient.</p>
+
+<a name="dynamic.basic"></a>
+<h3><code>BasicDynaBean</code> and <code>BasicDynaClass</code></h3>
+
+<p>The <a href="BasicDynaBean.html">BasicDynaBean</a> and
+<a href="BasicDynaClass.html">BasicDynaClass</a> implementation provides a
+basic set of
+dynamic property capabilities where you want to dynamically define the
+set of properties (described by instances of <a href="DynaProperty.html">
+DynaProperty</a>).  You start by defining the DynaClass that establishes
+the set of properties you care about:</p>
+
+<pre>
+    DynaProperty[] props = new DynaProperty[]{
+        new DynaProperty("address", java.util.Map.class),
+        new DynaProperty("subordinate", mypackage.Employee[].class),
+        new DynaProperty("firstName", String.class),
+        new DynaProperty("lastName",  String.class)
+      };
+    BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
+</pre>
+
+<p>Note that the 'dynaBeanClass' argument (in the constructor of
+<code>BasicDynaClass</code>) can have the value of <code>null</code>.  In this
+case, the value of <code>dynaClass.getDynaBeanClass</code> will just be the
+<code>Class</code> for BasicDynaBean.</p>
+
+<p>Next, you use the <code>newInstance()</code> method of this DynaClass to
+create new DynaBean instances that conform to this DynaClass, and populate
+its initial property values (much as you would instantiate a new standard
+JavaBean and then call its property setters):</p>
+
+<pre>
+    DynaBean employee = dynaClass.newInstance();
+    employee.set("address", new HashMap());
+    employee.set("subordinate", new mypackage.Employee[0]);
+    employee.set("firstName", "Fred");
+    employee.set("lastName", "Flintstone");
+</pre>
+
+<p>Note that the DynaBean class was declared to be
+<code>DynaBean</code> instead of <code>BasicDynaBean</code>.  In
+general, if you are using DynaBeans, you will not want to care about the
+actual implementation class that is being used -- you only care about
+declaring that it is a <code>DynaBean</code> so that you can use the
+DynaBean APIs.</p>
+
+<p>As stated above, you can pass a DynaBean instance as the first argument
+to a <code>PropertyUtils</code> method that gets and sets properties, and it
+will be interpreted as you expect -- the dynamic properties of the DynaBean
+will be retrieved or modified, instead of underlying properties on the
+actual BasicDynaBean implementation class.</p>
+
+<a name="dynamic.resultSet"></a>
+<h3><code>ResultSetDynaClass</code> (Wraps ResultSet in DynaBeans)</h3>
+
+<p>A very common use case for DynaBean APIs is to wrap other collections of
+"stuff" that do not normally present themselves as JavaBeans.  One of the most
+common collections that would be nice to wrap is the
+<code>java.sql.ResultSet</code> that is returned when you ask a JDBC driver
+to perform a SQL SELECT statement.  Commons BeanUtils offers a standard
+mechanism for making each row of the result set visible as a DynaBean,
+which you can utilize as shown in this example:</p>
+<pre>
+  Connection conn = ...;
+  Statement stmt = conn.createStatement();
+  ResultSet rs = stmt.executeQuery
+    ("select account_id, name from customers");
+  Iterator rows = (new ResultSetDynaClass(rs)).iterator();
+  while (rows.hasNext()) {
+    DynaBean row = (DynaBean) rows.next();
+    System.out.println("Account number is " +
+                       row.get("account_id") +
+                       " and name is " + row.get("name"));
+  }
+  rs.close();
+  stmt.close();
+</pre>
+
+
+<a name="dynamic.rowSet"></a>
+<h3><code>RowSetDynaClass</code> (Disconnected ResultSet as DynaBeans)</h3>
+<p>Although <a href="#dynamic.resultSet"><code>ResultSetDynaClass</code></a> is
+a very useful technique for representing the results of an SQL query as a
+series of DynaBeans, an important problem is that the underlying
+<code>ResultSet</code> must remain open throughout the period of time that the
+rows are being processed by your application.  This hinders the ability to use
+<code>ResultSetDynaClass</code> as a means of communicating information from
+the model layer to the view layer in a model-view-controller architecture
+such as that provided by the <a href="http://jakarta.apache.org/struts/">Struts
+Framework</a>, because there is no easy mechanism to assure that the result set
+is finally closed (and the underlying <code>Connection</code> returned to its
+connection pool, if you are using one).</p>
+
+<p>The <code>RowSetDynaClass</code> class represents a different approach to
+this problem.  When you construct such an instance, the underlying data is
+<em>copied</em> into a set of in-memory DynaBeans that represent the result.
+The advantage of this technique, of course, is that you can immediately close
+the ResultSet (and the corresponding Statement), normally before you even
+process the actual data that was returned.  The disadvantage, of course, is
+that you must pay the performance and memory costs of copying the result data,
+and the result data must fit entirely into available heap memory.  For many
+environments (particularly in web applications), this tradeoff is usually
+quite beneficial.</p>
+
+<p>As an additional benefit, the <code>RowSetDynaClass</code> class is defined
+to implement <code>java.io.Serializable</code>, so that it (and the
+DynaBeans that correspond to each row of the result) can be conveniently
+serialized and deserialized (as long as the underlying column values are
+also Serializable).  Thus, <code>RowSetDynaClass</code> represents a very
+convenient way to transmit the results of an SQL query to a remote Java-based
+client application (such as an applet).</p>
+
+<p>The normal usage pattern for a <code>RowSetDynaClass</code> will look
+something like this:</p>
+<pre>
+    Connection conn = ...;  // Acquire connection from pool
+    Statement stmt = conn.createStatement();
+    ResultSet rs = stmt.executeQuery("SELECT ...");
+    RowSetDynaClass rsdc = new RowSetDynaClass(rs);
+    rs.close();
+    stmt.close();
+    ...;                    // Return connection to pool
+    List rows = rsdc.getRows();
+    ...;                   // Process the rows as desired
+</pre>
+
+
+<a name="dynamic.wrap"></a>
+<h3><code>WrapDynaBean</code> and <code>WrapDynaClass</code></h3>
+
+<p>OK, you've tried the DynaBeans APIs and they are cool -- very simple
+<code>get()</code> and <code>set()</code> methods provide easy access to all
+of the dynamically defined simple, indexed, and mapped properties of your
+DynaBeans.  You'd like to use the DynaBean APIs to access <strong>all</strong>
+of your beans, but you've got a bunch of existing standard JavaBeans classes
+to deal with as well.  This is where the
+<a href="WrapDynaBean.html">WrapDynaBean</a> (and its associated
+<a href="WrapDynaClass.html">WrapDynaClass</a>) come into play.  As the name
+implies, a WrapDynaBean is used to "wrap" the DynaBean APIs around an
+existing standard JavaBean class.  To use it, simply create the wrapper
+like this:</p>
+
+<pre>
+    MyBean bean = ...;
+    DynaBean wrapper = new WrapDynaBean(bean);
+    String firstName = wrapper.get("firstName");
+</pre>
+
+<p>Note that, although appropriate <code>WrapDynaClass</code> instances are
+created internally, you never need to deal with them.</p>
+
+<a name="dynamic.lazy"></a>
+<h3><i>Lazy</i> DynaBeans (<a href="LazyDynaBean.html">LazyDynaBean</a>, 
+<a href="LazyDynaMap.html">LazyDynaMap</a> and <a href="LazyDynaClass.html">LazyDynaClass</a>)</h3>
+
+<p>You bought into the DynaBeans because it saves coding all those POJO JavaBeans but
+   you're here because <i>lazy</i> caught your eye and wondered whats that about?
+   What makes these flavors of DynaBean <i>lazy</i> are the following features:</p> 
+    <ul>
+        <li><strong><i>Lazy</i> property addition</strong> - lazy beans use a
+             <code><a href="DynaClass.html">DynaClass</a></code> which implements
+             the <code><a href="MutableDynaClass.html">MutableDynaClass</a></code> 
+             interface. This provides the ability to add and remove a DynaClass's 
+             properties. <i>Lazy</i> beans use this feature to automatically add
+             a property which doesn't exist to the DynaClass when
+             the <code>set(name, value)</code> method is called.</li>
+         <li><strong><i>Lazy</i> List/Array growth</strong> - If an <i>indexed</i> property is not large
+             enough to accomodate the <code>index</code> being set then the <code>List</code> or
+             <code>Array</code> is automatically <i>grown</i> so that it is.</li>
+         <li><strong><i>Lazy</i> List/Array instantiation</strong> - if an <i>indexed</i>
+             property doesn't exist then calling the <a href="DynaBean.html">DynaBean</a>'s 
+            <i>indexed</i> property getter/setter methods (i.e. <code>get(name, index)</code> or
+             <code>set(name, index, value)</code>) results in either a new <code>List</code>
+             or <code>Array</code> being instantiated. If the indexed property has not been
+             defined in the DynaClass then it is automatically added and a default <code>List</code>
+             implementation instantiated.</li>
+        <li><strong><i>Lazy</i> Map instantiation</strong> - if a <i>mapped</i>
+             property doesn't exist then calling the <a href="DynaBean.html">DynaBean</a>'s 
+             <i>mapped</i> property getter/setter methods (i.e. <code>get(name, key)</code> or
+             <code>set(name, key, value)</code>) results in a new <code>Map</code>
+             being instantiated. If the mapped property has not been defined in the DynaClass
+             then it is automatically added and a default <code>Map</code> implementation
+             instantiated.</li>
+        <li><strong><i>Lazy</i> Bean instantiation</strong> - if a property is defined in
+             the <code>DynaClass</code> as a <code>DynaBean</code> or regular bean and
+             doesn't exist in the <code>DynaBean</code> then <code>LazyDynaBean</code> wiill
+             try to instantiate the bean using a default empty constructor.</li> 
+    </ul>
+
+<p><strong><a href="LazyDynaBean.html">LazyDynaBean</a></strong> is the standard <i>lazy</i> bean 
+   implementation. By default it is associated with a <a href="LazyDynaClass.html">LazyDynaClass</a> 
+   which implements the <a href="MutableDynaClass.html">MutableDynaClass</a> interface - however
+   it can be used with any <code>MutableDynaClass</code> implementation. The question is <i>how do
+   I use it?</i> - well it can be as simple as creating a new bean and then calling the getters/setters...</p>
+
+<pre>
+    DynaBean dynaBean = new LazyDynaBean();
+
+    dynaBean.set("foo", "bar");                   // simple
+
+    dynaBean.set("customer", "title", "Mr");      // mapped
+    dynaBean.set("customer", "surname", "Smith"); // mapped
+
+    dynaBean.set("address", 0, addressLine1);     // indexed
+    dynaBean.set("address", 1, addressLine2);     // indexed
+    dynaBean.set("address", 2, addressLine3);     // indexed
+</pre>
+
+<p><strong><a href="LazyDynaMap.html">LazyDynaMap</a></strong> is a <i>light wieght</i> <code>DynaBean</code>
+   facade to a <code>Map</code> with all the usual <i>lazy</i> features. Its <i>light weight</i> because it doesn't
+   have an associated <code>DynaClass</code> containing all the properties. In fact it actually implements
+   the <code>DynaClass</code> interface itself (and <code>MutableDynaClass</code>) and derives all the <i>DynaClass</i>
+   information from the actual contents of the <code>Map</code>. A <code>LazyDynaMap</code> can be created around an
+   existing <code>Map</code> or can instantiate its own <code>Map</code>. After any <code>DynaBean</code>
+   processing has finished the <code>Map</code> can be retrieved and the DynaBean <i>facade</i> discarded.</p>
+
+<p>If you need a new <code>Map</code> then to use....</p>
+
+<pre>
+    DynaBean dynaBean = new LazyDynaMap();        // create DynaBean
+
+    dynaBean.set("foo", "bar");                   // simple
+    dynaBean.set("customer", "title", "Mr");      // mapped
+    dynaBean.set("address", 0, addressLine1);     // indexed
+
+    Map myMap = dynaBean.getMap()                 // retrieve the Map
+</pre>
+<p><i>or</i> to use with an existing <code>Map</code> ....</p>
+
+<pre>
+    Map myMap = ....                             // exisitng Map
+    DynaBean dynaBean = new LazyDynaMap(myMap);  // wrap Map in DynaBean
+    dynaBean.set("foo", "bar");                  // set properties
+</pre>
+
+<p><strong><a href="LazyDynaClass.html">LazyDynaClass</a></strong> extends <a href="BasicDynaClass.html">BasicDynaClass</a>
+   and implements the <a href="MutableDynaClass.html">MutableDynaClass</a> interface. It can be used with other
+   <code>DynaBean</code> implementations, but it is the default <code>DynaClass</code> used by <code>LazyDynaBean</code>.
+   When using the <code>LazyDynaBean</code> there may be no need to have anything to do with the <code>DynaClass</code>
+   However sometimes there is a requirement to set up the <code>DynaClass</code> first - perhaps to
+   define the type of array for an indexed property, or if using the DynaBean in <i>restricted</i> mode (see note below)
+   is required. Doing so is straight forward...</p>
+
+<p><i>Either</i> create a <code>LazyDynaClass</code> first...
+
+<pre>
+    MutableDynaClass dynaClass = new LazyDynaClass();    // create DynaClass
+
+    dynaClass.add("amount", java.lang.Integer.class);    // add property
+    dynaClass.add("orders", OrderBean[].class);          // add indexed property
+    dynaClass.add("orders", java.util.TreeMapp.class);   // add mapped property
+
+    DynaBean dynaBean = new LazyDynaBean(dynaClass);     // Create DynaBean with associated DynaClass
+</pre>
+
+<p><i>or</i> create a <code>LazyDynaBean</code> and get the <code>DynaClass</code>...
+
+<pre>
+    DynaBean dynaBean = new LazyDynaBean();              // Create LazyDynaBean
+    MutableDynaClass dynaClass = 
+             (MutableDynaClass)dynaBean.getDynaClass();  // get DynaClass
+
+    dynaClass.add("amount", java.lang.Integer.class);    // add property
+    dynaClass.add("myBeans", myPackage.MyBean[].class);  // add 'array' indexed property
+    dynaClass.add("myMap", java.util.TreeMapp.class);    // add mapped property
+</pre>
+
+<p><strong>NOTE:</strong> One feature of <a href="MutableDynaClass.html">MutableDynaClass</a> is that it
+   has a <i>Restricted</i> property. When the DynaClass is <i>restricted</i> no properties can be added
+   or removed from the <code>DynaClass</code>. Neither the <code>LazyDynaBean</code> or <code>LazyDynaMap</code>
+   will add properties automatically if the <code>DynaClass</code> is <i>restricted</i>.</p>
+
+
+
+<a name="conversion"></a>
+<h1>Data Type Conversions</h1>
+
+<a name="conversion.background"></a>
+<h3>Background</h3>
+
+<p>So far, we've only considered the cases where the data types of the
+dynamically accessed properties are known, and where we can use Java casts
+to perform type conversions.  What happens if you want to automatically
+perform type conversions when casting is not possible?  The
+<em>BeanUtils</em> package provides a variety of APIs and design patterns
+for performing this task as well.</p>
+
+<a name="conversion.beanutils"></a>
+<h3><code>BeanUtils</code> and <code>ConvertUtils</code> Conversions</h3>
+
+<p>A very common use case (and the situation that caused the initial creation
+of the <em>BeanUtils</em> package) was the desire to convert the set of request
+parameters that were included in a
+<code>javax.servlet.HttpServletRequest</code> received by a web application
+into a set of corresponding property setter calls on an arbitrary JavaBean.
+(This is one of the fundamental services provided by the
+<a href="http://jakarta.apache.org/struts">Struts Framework</a>, which uses
+<em>BeanUtils</em> internally to implement this functionality.)</p>
+
+<p>In an HTTP request, the set of included parameters is made available as a
+series of String (or String array, if there is more than one value for the
+same parameter name) instances, which need to be converted to the underlying
+data type.  The <a href="BeanUtils.html">BeanUtils</a> class provides
+property setter methods that accept String values, and automatically convert
+them to appropriate property types for Java primitives (such as
+<code>int</code> or <code>boolean</code>), and property getter methods that
+perform the reverse conversion.  Finally, a <code>populate()</code> method
+is provided that accepts a <code>java.util.Map</code> containing a set of
+property values (keyed by property name), and calls all of the appropriate
+setters whenever the underlying bean has a property with the same name as
+one of the request parameters.  So, you can perform the all-in-one property
+setting operation like this:</p>
+
+<pre>
+    HttpServletRequest request = ...;
+    MyBean bean = ...;
+    HashMap map = new HashMap();
+    Enumeration names = request.getParameterNames();
+    while (names.hasMoreElements()) {
+      String name = (String) names.nextElement();
+      map.put(name, request.getParameterValues(name));
+    }
+    BeanUtils.populate(bean, map);
+</pre>
+
+<p>The <code>BeanUtils</code> class relies on conversion methods defined in
+the <a href="ConvertUtils.html">ConvertUtils</a> class to perform the actual
+conversions, and these methods are availablve for direct use as well.
+<strong>WARNING</strong> - It is likely that the hard coded use of
+<code>ConvertUtils</code> methods will be deprecated in the future, and
+replaced with a mechanism that allows you to plug in your own implementations
+of the <a href="Converter.html">Converter</a> interface instead.  Therefore,
+new code should not be written with reliance on ConvertUtils.</p>
+
+<a name="conversion.defining"></a>
+<h3>Defining Your Own Converters</h3>
+
+<p>The <code>ConvertUtils</code> class supports the ability to define and
+register your own String --> Object conversions for any given Java class.
+Once registered, such converters will be used transparently by all of the
+<code>BeanUtils</code> methods (including <code>populate()</code>).  To
+create and register your own converter, follow these steps:</p>
+<ul>
+<li>Write a class that implements the <a href="Converter.html">Converter</a>
+    interface.  The <code>convert()</code> method should accept the
+    <code>java.lang.Class</code> object of your application class (i.e.
+    the class that you want to convert to, and a String representing the
+    incoming value to be converted.</li>
+<li>At application startup time, register an instance of your converter class
+    by calling the <code>ConvertUtils.register()</code> method.</li>
+</ul>
+
+<a name="conversion.i18n"></a>
+<h3>Locale Aware Conversions</h3>
+<p>The standard classes in <code>org.apache.commons.beanutils</code> are not
+locale aware. This gives them a cleaner interface and makes then easier to use
+in situations where the locale is not important.</p>
+<p>Extended, locale-aware analogues can be found in 
+<code><a href='locale/package-summary.html'>org.apache.commons.beanutils.locale
+</a></code>. These are built along the same
+lines as the basic classes but support localization.</p>
+
+
+<a name="instances"></a>
+<h1>Utility Objects And Static Utility Classes</h1>
+<a name="instances.background"></a>
+<h3>Background</h3>
+<p>
+So far, the examples have covered the static utility classes (<code>BeanUtils</code>,
+<code>ConvertUtils</code> and <code>PropertyUtils</code>). These are easy to use but are
+somewhat inflexible. These all share the same registered converters and the same caches.
+</p>
+<p>
+This functionality can also be accessed through utility objects (in fact, the static utility
+class use worker instances of these classes). For each static utility class, there is a corresponding
+class with the same functionality that can be instantiated:
+</p>
+<p>
+<table cols='2' width='60%'>
+<tr><th>Static Utility Class</th><th>Utility Object</th></tr>
+<tr><td>BeanUtils</td><td>BeanUtilsBean</td></tr>
+<tr><td>ConvertUtils</td><td>ConvertUtilsBean</td></tr>
+<tr><td>PropertyUtils</td><td>PropertyUtilsBean</td></tr>
+</table>
+</p>
+<p>
+Creating an instances allow gives guarenteed control of the caching and registration 
+to the code that creates it. 
+</p>
+
+<a name="collections"></a>
+<h1>Collections</h1>
+<strong>Note:</strong> these classes depend on 
+<a href='http://jakarta.apache.org/commons/collections'>Commons Collection</a> 3.0 or higher
+and are optional. To use them, please ensure that this library is available 
+and that either the all-in-one jar is used or the modular
+<code>commons-beanutils-bean-collections.jar</code> is available 
+(in addition to <code>commons-beanutils-core.jar</code>, of course :-).
+<a name="bean-comparator"></a>
+<h3>Comparing Beans</h3>
+<p>
+<code>org.apache.commons.beanutils.BeanComparator</code> is a <code>Comparator</code> implementation
+that compares beans based on a shared property value.
+</p>
+<a name="bean-property-closure"></a>
+<h3>Operating On Collections Of Beans</h3>
+<p>
+The <code>Closure</code> interface in <code>commons-collections</code> encapsulates a block of code that 
+executes on an arbitrary input Object. <code>Commons-collections</code> contains code that allows 
+<code>Closures</code> to be applied to the contents of a Collection. For more details, see the 
+<a href='http://jakarta.apache.org/commons/collections.html'>commons-collections</a>
+documentation.
+</p>
+<p>
+<code>BeanPropertyValueChangeClosure</code> is a <code>Closure</code> that sets a specified property
+to a particular value. A typical usage is to combine this with <code>commons-collections</code>
+so that all the beans in a collection can have a particular property set to a particular value.
+</p>
+<p>
+For example, set the activeEmployee property to TRUE for an entire collection:
+ <code><pre>
+    // create the closure
+    BeanPropertyValueChangeClosure closure =
+        new BeanPropertyValueChangeClosure( "activeEmployee", Boolean.TRUE );
+ 
+    // update the Collection
+    CollectionUtils.forAllDo( peopleCollection, closure );
+  </pre></code>
+</p>
+
+<a name="bean-property-predicate"></a>
+<h3>Querying Or Filtering Collections Of Beans</h3>
+<p>
+The <code>Predicate</code> interface in <code>commons-collections</code> encapsulates an evaluation
+of an input Object that returns either true or false. <code>Commons-collections</code> contains code 
+that allows 
+<code>Predicates</code> to be applied to be used to filter collections. For more details, see the 
+<a href='http://jakarta.apache.org/commons/collections.html'>commons-collections</a>
+documentation.
+</p>
+<p>
+<code>BeanPropertyValueEqualsPredicate</code> is a <code>Predicate</code> that evaluates a 
+set property value against a given value. A typical usage is 
+(in combination with <code>commons-collections</code>)
+to filter collections on the basis of a property value.
+</p>
+<p>
+For example, to filter a collection to find all beans where active employee is false use:
+<code><pre>
+    BeanPropertyValueEqualsPredicate predicate =
+        new BeanPropertyValueEqualsPredicate( "activeEmployee", Boolean.FALSE );
+ 
+    // filter the Collection
+    CollectionUtils.filter( peopleCollection, predicate );
+</pre></code>
+</p>
+
+<a href="bean-property-transformer"></a>
+<h3>Transforming Collections Of Beans</h3>
+<p>
+The <code>Transformer</code> interface in <code>commons-collections</code> encapsulates the transformation
+of an input Object into an output object. <code>Commons-collections</code> contains code 
+that allows 
+<code>Transformers</code> to be applied produce a collection of outputs from a collection of inputs. 
+For more details, see the 
+<a href='http://jakarta.apache.org/commons/collections.html'>commons-collections</a>
+documentation.
+</p>
+<p>
+<code>BeanToPropertyTransformer</code> is a <code>Transformer</code> implementation
+that transforms a bean into it's property value.
+</p>
+<p>
+For example, to find all cities that are contained in the address of each person property of each bean in 
+a collection:
+    <code><pre>
+    // create the transformer
+    BeanToPropertyValueTransformer transformer = new BeanToPropertyValueTransformer( "person.address.city" );
+ 
+    // transform the Collection
+    Collection peoplesCities = CollectionUtils.collect( peopleCollection, transformer );
+    </pre></code>
+</p>
+
+<a name="FAQ"></a>
+<h1>Frequently Asked Questions</h1>
+
+<a name="FAQ.property"></a>
+<h3>Why Can't BeanUtils Find My Method?</h3>
+<p>The <em>BeanUtils</em> package relies on <em>introspection</em> rather than 
+<em>reflection</em>. This means that it will find only 
+<a href='http://java.sun.com/products/javabeans'><em>JavaBean</em> 
+compliant</a> properties.</p>
+<p>There are some subtleties  of this specification that can catch out the unwary:
+<ul>
+<li>A property can have only one set and one get method. Overloading is not allowed.</li>
+<li>The <code>java.beans.Introspector</code> searches widely for a custom <em>BeanInfo</em> 
+class. If your class has the same name as another with a custom <em>BeanUtils</em> 
+(typically a java API class) then the <code>Introspector</code> may use that instead of
+creating via reflection based on your class. If this happens, the only solution is to 
+create your own <em>BeanInfo</em>.</li>
+</ul>
+</p>
+<a name="FAQ.bc.order"></a>
+<h3>How Do I Set The BeanComparator Order To Be Ascending/Descending?</h3>
+<p>
+BeanComparator relies on an internal Comparator to perform the actual 
+comparisions. By default, 
+<code>org.apache.commons.collections.comparators.ComparableComparator</code> 
+is used which imposes a natural order. If you want to change the order, 
+then a custom Comparator should be created and passed into the 
+appropriate constructor.
+</p>
+<p>
+For example:
+</p>
+<code><pre>
+    import org.apache.commons.collections.comparators.ComparableComparator;
+    import org.apache.commons.collections.comparators.ReverseComparator;
+    import org.apache.commons.beanutils.BeanComparator;
+    ...
+    BeanComparator reversedNaturalOrderBeanComparator
+        = new BeanComparator("propertyName", new ReverseComparator(new ComparableComparator()));
+    Collections.sort(myList, reversedNaturalOrderBeanComparator);
+    ...
+</pre></code>
+
+<a name="Packaging"></a>
+<h1>Packaging</h1>
+<p>
+BeanUtils now comes packaged (into jars) in two different ways: 
+</p>
+<ol>
+    <li>an all-in-one jar (<code>commons-beanutils.jar</code>)</li>
+    <li>and as modular component jars:
+        <ul>
+	<li><code>commons-beanutils-core.jar</code> (core classes)</li>
+	<li><code>commons-beanutils-bean-collections.jar</code> 
+    (additional dependency on commons-collections 3.0)</li>
+</ol>
+<p>
+Those who want it all should grab the all-in-one <code>commons-beanutils.jar</code> 
+(and remember to add any optional dependencies needed) 
+whereas those who need minimal dependencies should use <code>commons-beanutils-core.jar</code>
+plus any optional jars they plan to use. 
+</p>
+<p>
+The binary distribution contains all these jars.
+</p>
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/ArrayStack.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/ArrayStack.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/ArrayStack.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,199 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+
+/**
+ * An implementation of the {@link java.util.Stack} API that is based on an
+ * <code>ArrayList</code> instead of a <code>Vector</code>, so it is not
+ * synchronized to protect against multi-threaded access.  The implementation
+ * is therefore operates faster in environments where you do not need to
+ * worry about multiple thread contention.
+ * <p>
+ * The removal order of an <code>ArrayStack</code> is based on insertion 
+ * order: The most recently added element is removed first.  The iteration
+ * order is <i>not</i> the same as the removal order.  The iterator returns
+ * elements from the bottom up, whereas the {@link #remove()} method removes
+ * them from the top down.
+ * <p>
+ * Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries.
+ * <p>
+ * <strong>Note:</strong> this class should be bytecode-identical to the 
+ * version in commons collections. This is required to allow backwards 
+ * compability with both previous versions of BeanUtils and also allow 
+ * coexistance with both collections 2.1 and 3.0.
+ *
+ * @see java.util.Stack
+ * @since Commons Collections 1.0
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:50:13 $
+ * 
+ * @author Craig R. McClanahan
+ * @author Paul Jack
+ * @author Stephen Colebourne
+ */
+public class ArrayStack extends ArrayList implements Buffer {
+
+    /** Ensure serialization compatibility */    
+    private static final long serialVersionUID = 2130079159931574599L;
+
+    /**
+     * Constructs a new empty <code>ArrayStack</code>. The initial size
+     * is controlled by <code>ArrayList</code> and is currently 10.
+     */
+    public ArrayStack() {
+        super();
+    }
+
+    /**
+     * Constructs a new empty <code>ArrayStack</code> with an initial size.
+     * 
+     * @param initialSize  the initial size to use
+     * @throws IllegalArgumentException  if the specified initial size
+     *  is negative
+     */
+    public ArrayStack(int initialSize) {
+        super(initialSize);
+    }
+
+    /**
+     * Return <code>true</code> if this stack is currently empty.
+     * <p>
+     * This method exists for compatibility with <code>java.util.Stack</code>.
+     * New users of this class should use <code>isEmpty</code> instead.
+     * 
+     * @return true if the stack is currently empty
+     */
+    public boolean empty() {
+        return isEmpty();
+    }
+
+    /**
+     * Returns the top item off of this stack without removing it.
+     *
+     * @return the top item on the stack
+     * @throws EmptyStackException  if the stack is empty
+     */
+    public Object peek() throws EmptyStackException {
+        int n = size();
+        if (n <= 0) {
+            throw new EmptyStackException();
+        } else {
+            return get(n - 1);
+        }
+    }
+
+    /**
+     * Returns the n'th item down (zero-relative) from the top of this
+     * stack without removing it.
+     *
+     * @param n  the number of items down to go
+     * @return the n'th item on the stack, zero relative
+     * @throws EmptyStackException  if there are not enough items on the
+     *  stack to satisfy this request
+     */
+    public Object peek(int n) throws EmptyStackException {
+        int m = (size() - n) - 1;
+        if (m < 0) {
+            throw new EmptyStackException();
+        } else {
+            return get(m);
+        }
+    }
+
+    /**
+     * Pops the top item off of this stack and return it.
+     *
+     * @return the top item on the stack
+     * @throws EmptyStackException  if the stack is empty
+     */
+    public Object pop() throws EmptyStackException {
+        int n = size();
+        if (n <= 0) {
+            throw new EmptyStackException();
+        } else {
+            return remove(n - 1);
+        }
+    }
+
+    /**
+     * Pushes a new item onto the top of this stack. The pushed item is also
+     * returned. This is equivalent to calling <code>add</code>.
+     *
+     * @param item  the item to be added
+     * @return the item just pushed
+     */
+    public Object push(Object item) {
+        add(item);
+        return item;
+    }
+
+    /**
+     * Returns the one-based position of the distance from the top that the
+     * specified object exists on this stack, where the top-most element is
+     * considered to be at distance <code>1</code>.  If the object is not
+     * present on the stack, return <code>-1</code> instead.  The
+     * <code>equals()</code> method is used to compare to the items
+     * in this stack.
+     *
+     * @param object  the object to be searched for
+     * @return the 1-based depth into the stack of the object, or -1 if not found
+     */
+    public int search(Object object) {
+        int i = size() - 1;        // Current index
+        int n = 1;                 // Current distance
+        while (i >= 0) {
+            Object current = get(i);
+            if ((object == null && current == null) ||
+                (object != null && object.equals(current))) {
+                return n;
+            }
+            i--;
+            n++;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the element on the top of the stack.
+     *
+     * @return the element on the top of the stack
+     * @throws BufferUnderflowException  if the stack is empty
+     */
+    public Object get() {
+        int size = size();
+        if (size == 0) {
+            throw new BufferUnderflowException();
+        }
+        return get(size - 1);
+    }
+
+    /**
+     * Removes the element on the top of the stack.
+     *
+     * @return the removed element 
+     * @throws BufferUnderflowException  if the stack is empty
+     */
+    public Object remove() {
+        int size = size();
+        if (size == 0) {
+            throw new BufferUnderflowException();
+        }
+        return remove(size - 1);
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/Buffer.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/Buffer.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/Buffer.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,68 @@
+/*
+ *  Copyright 2002-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections;
+
+import java.util.Collection;
+
+/**
+ * Defines a collection that allows objects to be removed in some well-defined order.
+ * <p>
+ * The removal order can be based on insertion order (eg, a FIFO queue or a
+ * LIFO stack), on access order (eg, an LRU cache), on some arbitrary comparator
+ * (eg, a priority queue) or on any other well-defined ordering.
+ * <p>
+ * Note that the removal order is not necessarily the same as the iteration
+ * order.  A <code>Buffer</code> implementation may have equivalent removal
+ * and iteration orders, but this is not required.
+ * <p>
+ * This interface does not specify any behavior for 
+ * {@link Object#equals(Object)} and {@link Object#hashCode} methods.  It
+ * is therefore possible for a <code>Buffer</code> implementation to also
+ * also implement {@link java.util.List}, {@link java.util.Set} or 
+ * {@link Bag}.
+ * <p>
+ * <strong>Note:</strong> this class should be bytecode-identical to the 
+ * version in commons collections. This is required to allow backwards 
+ * compability with both previous versions of BeanUtils and also allow 
+ * coexistance with both collections 2.1 and 3.0.
+ *
+ * @since Commons Collections 2.1
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:50:28 $
+ * 
+ * @author Avalon
+ * @author Berin Loritsch
+ * @author Paul Jack
+ * @author Stephen Colebourne
+ */
+public interface Buffer extends Collection {
+
+    /**
+     * Gets and removes the next object from the buffer.
+     *
+     * @return the next object in the buffer, which is also removed
+     * @throws BufferUnderflowException if the buffer is already empty
+     */
+    Object remove();
+
+    /**
+     * Gets the next object from the buffer without removing it.
+     *
+     * @return the next object in the buffer, which is not removed
+     * @throws BufferUnderflowException if the buffer is empty
+     */
+    Object get();
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/BufferUnderflowException.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/BufferUnderflowException.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/BufferUnderflowException.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,76 @@
+/*
+ *  Copyright 2002-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections;
+
+import java.util.NoSuchElementException;
+
+/**
+ * The BufferUnderflowException is used when the buffer is already empty.
+ * <p>
+ * NOTE: From version 3.0, this exception extends NoSuchElementException.
+ * 
+ * @since Commons Collections 2.1
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:50:52 $
+ *
+ * @author Avalon
+ * @author Berin Loritsch
+ * @author Jeff Turner
+ * @author Paul Jack
+ * @author Stephen Colebourne
+ */
+public class BufferUnderflowException extends NoSuchElementException {
+    
+    /** The root cause throwable */
+    private final Throwable throwable;
+
+    /**
+     * Constructs a new <code>BufferUnderflowException</code>.
+     */
+    public BufferUnderflowException() {
+        super();
+        throwable = null;
+    }
+
+    /** 
+     * Construct a new <code>BufferUnderflowException</code>.
+     * 
+     * @param message  the detail message for this exception
+     */
+    public BufferUnderflowException(String message) {
+        this(message, null);
+    }
+
+    /** 
+     * Construct a new <code>BufferUnderflowException</code>.
+     * 
+     * @param message  the detail message for this exception
+     * @param exception  the root cause of the exception
+     */
+    public BufferUnderflowException(String message, Throwable exception) {
+        super(message);
+        throwable = exception;
+    }
+
+    /**
+     * Gets the root cause of the exception.
+     *
+     * @return the root cause
+     */
+    public final Throwable getCause() {
+        return throwable;
+    }
+    
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/FastHashMap.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/FastHashMap.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/FastHashMap.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,714 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections;
+
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>A customized implementation of <code>java.util.HashMap</code> designed
+ * to operate in a multithreaded environment where the large majority of
+ * method calls are read-only, instead of structural changes.  When operating
+ * in "fast" mode, read calls are non-synchronized and write calls perform the
+ * following steps:</p>
+ * <ul>
+ * <li>Clone the existing collection
+ * <li>Perform the modification on the clone
+ * <li>Replace the existing collection with the (modified) clone
+ * </ul>
+ * <p>When first created, objects of this class default to "slow" mode, where
+ * all accesses of any type are synchronized but no cloning takes place.  This
+ * is appropriate for initially populating the collection, followed by a switch
+ * to "fast" mode (by calling <code>setFast(true)</code>) after initialization
+ * is complete.</p>
+ *
+ * <p><strong>NOTE</strong>: If you are creating and accessing a
+ * <code>HashMap</code> only within a single thread, you should use
+ * <code>java.util.HashMap</code> directly (with no synchronization), for
+ * maximum performance.</p>
+ *
+ * <p><strong>NOTE</strong>: <i>This class is not cross-platform.  
+ * Using it may cause unexpected failures on some architectures.</i>
+ * It suffers from the same problems as the double-checked locking idiom.  
+ * In particular, the instruction that clones the internal collection and the 
+ * instruction that sets the internal reference to the clone can be executed 
+ * or perceived out-of-order.  This means that any read operation might fail 
+ * unexpectedly, as it may be reading the state of the internal collection
+ * before the internal collection is fully formed.
+ * For more information on the double-checked locking idiom, see the
+ * <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
+ * Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
+ *
+ * @since Commons Collections 1.0
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:51:13 $
+ * 
+ * @author Craig R. McClanahan
+ * @author Stephen Colebourne
+ */
+public class FastHashMap extends HashMap {
+
+    /**
+     * The underlying map we are managing.
+     */
+    protected HashMap map = null;
+
+    /**
+     * Are we currently operating in "fast" mode?
+     */
+    protected boolean fast = false;
+
+    // Constructors
+    // ----------------------------------------------------------------------
+
+    /**
+     * Construct an empty map.
+     */
+    public FastHashMap() {
+        super();
+        this.map = new HashMap();
+    }
+
+    /**
+     * Construct an empty map with the specified capacity.
+     *
+     * @param capacity  the initial capacity of the empty map
+     */
+    public FastHashMap(int capacity) {
+        super();
+        this.map = new HashMap(capacity);
+    }
+
+    /**
+     * Construct an empty map with the specified capacity and load factor.
+     *
+     * @param capacity  the initial capacity of the empty map
+     * @param factor  the load factor of the new map
+     */
+    public FastHashMap(int capacity, float factor) {
+        super();
+        this.map = new HashMap(capacity, factor);
+    }
+
+    /**
+     * Construct a new map with the same mappings as the specified map.
+     *
+     * @param map  the map whose mappings are to be copied
+     */
+    public FastHashMap(Map map) {
+        super();
+        this.map = new HashMap(map);
+    }
+
+
+    // Property access
+    // ----------------------------------------------------------------------
+
+    /**
+     *  Returns true if this map is operating in fast mode.
+     *
+     *  @return true if this map is operating in fast mode
+     */
+    public boolean getFast() {
+        return (this.fast);
+    }
+
+    /**
+     *  Sets whether this map is operating in fast mode.
+     *
+     *  @param fast true if this map should operate in fast mode
+     */
+    public void setFast(boolean fast) {
+        this.fast = fast;
+    }
+
+
+    // Map access
+    // ----------------------------------------------------------------------
+    // These methods can forward straight to the wrapped Map in 'fast' mode.
+    // (because they are query methods)
+
+    /**
+     * Return the value to which this map maps the specified key.  Returns
+     * <code>null</code> if the map contains no mapping for this key, or if
+     * there is a mapping with a value of <code>null</code>.  Use the
+     * <code>containsKey()</code> method to disambiguate these cases.
+     *
+     * @param key  the key whose value is to be returned
+     * @return the value mapped to that key, or null
+     */
+    public Object get(Object key) {
+        if (fast) {
+            return (map.get(key));
+        } else {
+            synchronized (map) {
+                return (map.get(key));
+            }
+        }
+    }
+
+    /**
+     * Return the number of key-value mappings in this map.
+     * 
+     * @return the current size of the map
+     */
+    public int size() {
+        if (fast) {
+            return (map.size());
+        } else {
+            synchronized (map) {
+                return (map.size());
+            }
+        }
+    }
+
+    /**
+     * Return <code>true</code> if this map contains no mappings.
+     * 
+     * @return is the map currently empty
+     */
+    public boolean isEmpty() {
+        if (fast) {
+            return (map.isEmpty());
+        } else {
+            synchronized (map) {
+                return (map.isEmpty());
+            }
+        }
+    }
+
+    /**
+     * Return <code>true</code> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param key  the key to be searched for
+     * @return true if the map contains the key
+     */
+    public boolean containsKey(Object key) {
+        if (fast) {
+            return (map.containsKey(key));
+        } else {
+            synchronized (map) {
+                return (map.containsKey(key));
+            }
+        }
+    }
+
+    /**
+     * Return <code>true</code> if this map contains one or more keys mapping
+     * to the specified value.
+     *
+     * @param value  the value to be searched for
+     * @return true if the map contains the value
+     */
+    public boolean containsValue(Object value) {
+        if (fast) {
+            return (map.containsValue(value));
+        } else {
+            synchronized (map) {
+                return (map.containsValue(value));
+            }
+        }
+    }
+
+    // Map modification
+    // ----------------------------------------------------------------------
+    // These methods perform special behaviour in 'fast' mode.
+    // The map is cloned, updated and then assigned back.
+    // See the comments at the top as to why this won't always work.
+
+    /**
+     * Associate the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced and returned.
+     *
+     * @param key  the key with which the value is to be associated
+     * @param value  the value to be associated with this key
+     * @return the value previously mapped to the key, or null
+     */
+    public Object put(Object key, Object value) {
+        if (fast) {
+            synchronized (this) {
+                HashMap temp = (HashMap) map.clone();
+                Object result = temp.put(key, value);
+                map = temp;
+                return (result);
+            }
+        } else {
+            synchronized (map) {
+                return (map.put(key, value));
+            }
+        }
+    }
+
+    /**
+     * Copy all of the mappings from the specified map to this one, replacing
+     * any mappings with the same keys.
+     *
+     * @param in  the map whose mappings are to be copied
+     */
+    public void putAll(Map in) {
+        if (fast) {
+            synchronized (this) {
+                HashMap temp = (HashMap) map.clone();
+                temp.putAll(in);
+                map = temp;
+            }
+        } else {
+            synchronized (map) {
+                map.putAll(in);
+            }
+        }
+    }
+
+    /**
+     * Remove any mapping for this key, and return any previously
+     * mapped value.
+     *
+     * @param key  the key whose mapping is to be removed
+     * @return the value removed, or null
+     */
+    public Object remove(Object key) {
+        if (fast) {
+            synchronized (this) {
+                HashMap temp = (HashMap) map.clone();
+                Object result = temp.remove(key);
+                map = temp;
+                return (result);
+            }
+        } else {
+            synchronized (map) {
+                return (map.remove(key));
+            }
+        }
+    }
+
+    /**
+     * Remove all mappings from this map.
+     */
+    public void clear() {
+        if (fast) {
+            synchronized (this) {
+                map = new HashMap();
+            }
+        } else {
+            synchronized (map) {
+                map.clear();
+            }
+        }
+    }
+
+    // Basic object methods
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Compare the specified object with this list for equality.  This
+     * implementation uses exactly the code that is used to define the
+     * list equals function in the documentation for the
+     * <code>Map.equals</code> method.
+     *
+     * @param o  the object to be compared to this list
+     * @return true if the two maps are equal
+     */
+    public boolean equals(Object o) {
+        // Simple tests that require no synchronization
+        if (o == this) {
+            return (true);
+        } else if (!(o instanceof Map)) {
+            return (false);
+        }
+        Map mo = (Map) o;
+
+        // Compare the two maps for equality
+        if (fast) {
+            if (mo.size() != map.size()) {
+                return (false);
+            }
+            Iterator i = map.entrySet().iterator();
+            while (i.hasNext()) {
+                Map.Entry e = (Map.Entry) i.next();
+                Object key = e.getKey();
+                Object value = e.getValue();
+                if (value == null) {
+                    if (!(mo.get(key) == null && mo.containsKey(key))) {
+                        return (false);
+                    }
+                } else {
+                    if (!value.equals(mo.get(key))) {
+                        return (false);
+                    }
+                }
+            }
+            return (true);
+            
+        } else {
+            synchronized (map) {
+                if (mo.size() != map.size()) {
+                    return (false);
+                }
+                Iterator i = map.entrySet().iterator();
+                while (i.hasNext()) {
+                    Map.Entry e = (Map.Entry) i.next();
+                    Object key = e.getKey();
+                    Object value = e.getValue();
+                    if (value == null) {
+                        if (!(mo.get(key) == null && mo.containsKey(key))) {
+                            return (false);
+                        }
+                    } else {
+                        if (!value.equals(mo.get(key))) {
+                            return (false);
+                        }
+                    }
+                }
+                return (true);
+            }
+        }
+    }
+
+    /**
+     * Return the hash code value for this map.  This implementation uses
+     * exactly the code that is used to define the list hash function in the
+     * documentation for the <code>Map.hashCode</code> method.
+     * 
+     * @return suitable integer hash code
+     */
+    public int hashCode() {
+        if (fast) {
+            int h = 0;
+            Iterator i = map.entrySet().iterator();
+            while (i.hasNext()) {
+                h += i.next().hashCode();
+            }
+            return (h);
+        } else {
+            synchronized (map) {
+                int h = 0;
+                Iterator i = map.entrySet().iterator();
+                while (i.hasNext()) {
+                    h += i.next().hashCode();
+                }
+                return (h);
+            }
+        }
+    }
+
+    /**
+     * Return a shallow copy of this <code>FastHashMap</code> instance.
+     * The keys and values themselves are not copied.
+     * 
+     * @return a clone of this map
+     */
+    public Object clone() {
+        FastHashMap results = null;
+        if (fast) {
+            results = new FastHashMap(map);
+        } else {
+            synchronized (map) {
+                results = new FastHashMap(map);
+            }
+        }
+        results.setFast(getFast());
+        return (results);
+    }
+
+    // Map views
+    // ----------------------------------------------------------------------
+    
+    /**
+     * Return a collection view of the mappings contained in this map.  Each
+     * element in the returned collection is a <code>Map.Entry</code>.
+     */
+    public Set entrySet() {
+        return new EntrySet();
+    }
+
+    /**
+     * Return a set view of the keys contained in this map.
+     */
+    public Set keySet() {
+        return new KeySet();
+    }
+
+    /**
+     * Return a collection view of the values contained in this map.
+     */
+    public Collection values() {
+        return new Values();
+    }
+
+    // Map view inner classes
+    // ----------------------------------------------------------------------
+
+    /**
+     * Abstract collection implementation shared by keySet(), values() and entrySet().
+     */
+    private abstract class CollectionView implements Collection {
+
+        public CollectionView() {
+        }
+
+        protected abstract Collection get(Map map);
+        protected abstract Object iteratorNext(Map.Entry entry);
+
+
+        public void clear() {
+            if (fast) {
+                synchronized (FastHashMap.this) {
+                    map = new HashMap();
+                }
+            } else {
+                synchronized (map) {
+                    get(map).clear();
+                }
+            }
+        }
+
+        public boolean remove(Object o) {
+            if (fast) {
+                synchronized (FastHashMap.this) {
+                    HashMap temp = (HashMap) map.clone();
+                    boolean r = get(temp).remove(o);
+                    map = temp;
+                    return r;
+                }
+            } else {
+                synchronized (map) {
+                    return get(map).remove(o);
+                }
+            }
+        }
+
+        public boolean removeAll(Collection o) {
+            if (fast) {
+                synchronized (FastHashMap.this) {
+                    HashMap temp = (HashMap) map.clone();
+                    boolean r = get(temp).removeAll(o);
+                    map = temp;
+                    return r;
+                }
+            } else {
+                synchronized (map) {
+                    return get(map).removeAll(o);
+                }
+            }
+        }
+
+        public boolean retainAll(Collection o) {
+            if (fast) {
+                synchronized (FastHashMap.this) {
+                    HashMap temp = (HashMap) map.clone();
+                    boolean r = get(temp).retainAll(o);
+                    map = temp;
+                    return r;
+                }
+            } else {
+                synchronized (map) {
+                    return get(map).retainAll(o);
+                }
+            }
+        }
+
+        public int size() {
+            if (fast) {
+                return get(map).size();
+            } else {
+                synchronized (map) {
+                    return get(map).size();
+                }
+            }
+        }
+
+
+        public boolean isEmpty() {
+            if (fast) {
+                return get(map).isEmpty();
+            } else {
+                synchronized (map) {
+                    return get(map).isEmpty();
+                }
+            }
+        }
+
+        public boolean contains(Object o) {
+            if (fast) {
+                return get(map).contains(o);
+            } else {
+                synchronized (map) {
+                    return get(map).contains(o);
+                }
+            }
+        }
+
+        public boolean containsAll(Collection o) {
+            if (fast) {
+                return get(map).containsAll(o);
+            } else {
+                synchronized (map) {
+                    return get(map).containsAll(o);
+                }
+            }
+        }
+
+        public Object[] toArray(Object[] o) {
+            if (fast) {
+                return get(map).toArray(o);
+            } else {
+                synchronized (map) {
+                    return get(map).toArray(o);
+                }
+            }
+        }
+
+        public Object[] toArray() {
+            if (fast) {
+                return get(map).toArray();
+            } else {
+                synchronized (map) {
+                    return get(map).toArray();
+                }
+            }
+        }
+
+
+        public boolean equals(Object o) {
+            if (o == this) return true;
+            if (fast) {
+                return get(map).equals(o);
+            } else {
+                synchronized (map) {
+                    return get(map).equals(o);
+                }
+            }
+        }
+
+        public int hashCode() {
+            if (fast) {
+                return get(map).hashCode();
+            } else {
+                synchronized (map) {
+                    return get(map).hashCode();
+                }
+            }
+        }
+
+        public boolean add(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean addAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Iterator iterator() {
+            return new CollectionViewIterator();
+        }
+
+        private class CollectionViewIterator implements Iterator {
+
+            private Map expected;
+            private Map.Entry lastReturned = null;
+            private Iterator iterator;
+
+            public CollectionViewIterator() {
+                this.expected = map;
+                this.iterator = expected.entrySet().iterator();
+            }
+ 
+            public boolean hasNext() {
+                if (expected != map) {
+                    throw new ConcurrentModificationException();
+                }
+                return iterator.hasNext();
+            }
+
+            public Object next() {
+                if (expected != map) {
+                    throw new ConcurrentModificationException();
+                }
+                lastReturned = (Map.Entry)iterator.next();
+                return iteratorNext(lastReturned);
+            }
+
+            public void remove() {
+                if (lastReturned == null) {
+                    throw new IllegalStateException();
+                }
+                if (fast) {
+                    synchronized (FastHashMap.this) {
+                        if (expected != map) {
+                            throw new ConcurrentModificationException();
+                        }
+                        FastHashMap.this.remove(lastReturned.getKey());
+                        lastReturned = null;
+                        expected = map;
+                    }
+                } else {
+                    iterator.remove();
+                    lastReturned = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Set implementation over the keys of the FastHashMap
+     */
+    private class KeySet extends CollectionView implements Set {
+    
+        protected Collection get(Map map) {
+            return map.keySet();
+        }
+    
+        protected Object iteratorNext(Map.Entry entry) {
+            return entry.getKey();
+        }
+    
+    }
+    
+    /**
+     * Collection implementation over the values of the FastHashMap
+     */
+    private class Values extends CollectionView {
+    
+        protected Collection get(Map map) {
+            return map.values();
+        }
+    
+        protected Object iteratorNext(Map.Entry entry) {
+            return entry.getValue();
+        }
+    }
+    
+    /**
+     * Set implementation over the entries of the FastHashMap
+     */
+    private class EntrySet extends CollectionView implements Set {
+    
+        protected Collection get(Map map) {
+            return map.entrySet();
+        }
+    
+        protected Object iteratorNext(Map.Entry entry) {
+            return entry;
+        }
+    
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/package.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/package.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/org/apache/commons/collections/package.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>Package Documentation for org.apache.commons.collections Package</title>
+</head>
+<body bgcolor="white">
+<p>
+This package contains a small number of collections classes that are needed for beanutils 
+to function. The dependencies will be deprecated in the 1.7.0 release and the need for these
+classes will be removed in the future. These classes are identical to those in both 2.x and 3.x 
+series of commons-collections releases.
+</p>
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/src/java/overview.html
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/java/overview.html	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/java/overview.html	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<title>Overview Documentation for COMMONS-BEANUTILS</title>
+</head>
+<body bgcolor="white">
+<p>The <em>Bean Introspection Utilities</em> component of the Jakarta Commons
+subproject offers low-level utility classes that assist in getting and setting
+property values on Java classes that follow the naming design patterns outlined
+in the JavaBeans Specification, as well as mechanisms for dynamically defining
+and accessing bean properties.</p>
+
+<p>See the
+<a href="org/apache/commons/beanutils/package-summary.html#package_description">
+Package Description</a> for the <code>org.apache.commons.beanutils</code>
+package for more information.</p>
+</body>
+</html>

Added: trunk/commons-beanutils/branches/upstream/current/src/media/logo.xcf
===================================================================
(Binary files differ)


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/media/logo.xcf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/A.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/A.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/A.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+import java.io.OutputStream;
+
+/**
+ * <p>Class used in MethodUtils test</p>
+ *
+ */
+public class A {
+    
+    boolean called = false;
+    
+    public void foo(OutputStream os)
+    {
+        called = true;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractChild.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractChild.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractChild.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.beanutils;
+
+public class AbstractChild implements Child {
+    
+    private String name;
+    
+    protected void setName(String name)
+    {
+        this.name = name;
+    }
+    
+    public String getName()
+    {
+        return name;
+    }
+    
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractParent.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractParent.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AbstractParent.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+public abstract class AbstractParent {
+    
+    private Child child;
+    
+    public Child getChild()
+    {
+        return child;
+    }
+
+    /**
+     * Method which matches signature but which has wrong parameters 
+     */
+    public String testAddChild(String badParameter) {
+        return null;
+    }
+
+    /**
+     * Method which matches signature but which has wrong parameters 
+     */
+    public String testAddChild2(String ignore, String badParameter) {
+        return null;
+    }
+    
+    public String testAddChild(Child child) {
+        this.child = child;
+        return child.getName();
+    }
+    
+
+    public String testAddChild2(String ignore, Child child) {
+        this.child = child;
+        return child.getName();
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AlphaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AlphaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/AlphaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+public class AlphaBean extends AbstractParent implements Child {
+    
+    private String name;
+    
+    public AlphaBean() {}
+    
+    public AlphaBean(String name) {
+        setName(name);
+    }
+    
+    public String getName() {
+        return name;
+    }    
+    
+    public void setName(String name) {
+        this.name = name;
+    }	
+    
+    /**
+     * Used for testing that correct exception is thrown.
+     */
+    public void bogus(String badParameter){}
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BasicDynaBeanTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BasicDynaBeanTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BasicDynaBeanTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,1030 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>Test Case for the <code>BasicDynaBean</code> implementation class.
+ * These tests were based on the ones in <code>PropertyUtilsTestCase</code>
+ * because the two classes provide similar levels of functionality.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.10 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class BasicDynaBeanTestCase extends TestCase {
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    /**
+     * The basic test bean for each test.
+     */
+    protected DynaBean bean = null;
+
+
+    /**
+     * The set of property names we expect to have returned when calling
+     * <code>getDynaProperties()</code>.  You should update this list
+     * when new properties are added to TestBean.
+     */
+    protected final static String[] properties = {
+        "booleanProperty",
+        "booleanSecond",
+        "doubleProperty",
+        "floatProperty",
+        "intArray",
+        "intIndexed",
+        "intProperty",
+        "listIndexed",
+        "longProperty",
+        "mappedProperty",
+        "mappedIntProperty",
+        "nullProperty",
+        "shortProperty",
+        "stringArray",
+        "stringIndexed",
+        "stringProperty",
+    };
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public BasicDynaBeanTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        // Instantiate a new DynaBean instance
+        DynaClass dynaClass = createDynaClass();
+        bean = dynaClass.newInstance();
+
+        // Initialize the DynaBean's property values (like TestBean)
+        bean.set("booleanProperty", new Boolean(true));
+        bean.set("booleanSecond", new Boolean(true));
+        bean.set("doubleProperty", new Double(321.0));
+        bean.set("floatProperty", new Float((float) 123.0));
+        int intArray[] = { 0, 10, 20, 30, 40 };
+        bean.set("intArray", intArray);
+        int intIndexed[] = { 0, 10, 20, 30, 40 };
+        bean.set("intIndexed", intIndexed);
+        bean.set("intProperty", new Integer(123));
+        List listIndexed = new ArrayList();
+        listIndexed.add("String 0");
+        listIndexed.add("String 1");
+        listIndexed.add("String 2");
+        listIndexed.add("String 3");
+        listIndexed.add("String 4");
+        bean.set("listIndexed", listIndexed);
+        bean.set("longProperty", new Long((long) 321));
+        HashMap mappedProperty = new HashMap();
+        mappedProperty.put("First Key", "First Value");
+        mappedProperty.put("Second Key", "Second Value");
+        bean.set("mappedProperty", mappedProperty);
+        HashMap mappedIntProperty = new HashMap();
+        mappedIntProperty.put("One", new Integer(1));
+        mappedIntProperty.put("Two", new Integer(2));
+        bean.set("mappedIntProperty", mappedIntProperty);
+        // Property "nullProperty" is not initialized, so it should return null
+        bean.set("shortProperty", new Short((short) 987));
+        String stringArray[] =
+                { "String 0", "String 1", "String 2", "String 3", "String 4" };
+        bean.set("stringArray", stringArray);
+        String stringIndexed[] =
+                { "String 0", "String 1", "String 2", "String 3", "String 4" };
+        bean.set("stringIndexed", stringIndexed);
+        bean.set("stringProperty", "This is a string");
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(BasicDynaBeanTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        bean = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Corner cases on getDynaProperty invalid arguments.
+     */
+    public void testGetDescriptorArguments() {
+
+        try {
+            DynaProperty descriptor =
+                    bean.getDynaClass().getDynaProperty("unknown");
+            assertNull("Unknown property descriptor should be null",
+                    descriptor);
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of returning null");
+        }
+
+        try {
+            bean.getDynaClass().getDynaProperty(null);
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException");
+        }
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>booleanProperty</code>.
+     */
+    public void testGetDescriptorBoolean() {
+
+        testGetDescriptorBase("booleanProperty", Boolean.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>doubleProperty</code>.
+     */
+    public void testGetDescriptorDouble() {
+
+        testGetDescriptorBase("doubleProperty", Double.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>floatProperty</code>.
+     */
+    public void testGetDescriptorFloat() {
+
+        testGetDescriptorBase("floatProperty", Float.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>intProperty</code>.
+     */
+    public void testGetDescriptorInt() {
+
+        testGetDescriptorBase("intProperty", Integer.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>longProperty</code>.
+     */
+    public void testGetDescriptorLong() {
+
+        testGetDescriptorBase("longProperty", Long.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>booleanSecond</code>
+     * that uses an "is" method as the getter.
+     */
+    public void testGetDescriptorSecond() {
+
+        testGetDescriptorBase("booleanSecond", Boolean.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>shortProperty</code>.
+     */
+    public void testGetDescriptorShort() {
+
+        testGetDescriptorBase("shortProperty", Short.TYPE);
+
+    }
+
+
+    /**
+     * Positive getDynaProperty on property <code>stringProperty</code>.
+     */
+    public void testGetDescriptorString() {
+
+        testGetDescriptorBase("stringProperty", String.class);
+
+    }
+
+
+    /**
+     * Positive test for getDynaPropertys().  Each property name
+     * listed in <code>properties</code> should be returned exactly once.
+     */
+    public void testGetDescriptors() {
+
+        DynaProperty pd[] = bean.getDynaClass().getDynaProperties();
+        assertNotNull("Got descriptors", pd);
+        int count[] = new int[properties.length];
+        for (int i = 0; i < pd.length; i++) {
+            String name = pd[i].getName();
+            for (int j = 0; j < properties.length; j++) {
+                if (name.equals(properties[j]))
+                    count[j]++;
+            }
+        }
+        for (int j = 0; j < properties.length; j++) {
+            if (count[j] < 0)
+                fail("Missing property " + properties[j]);
+            else if (count[j] > 1)
+                fail("Duplicate property " + properties[j]);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getIndexedProperty invalid arguments.
+     */
+    public void testGetIndexedArguments() {
+
+        try {
+            bean.get("intArray", -1);
+            fail("Should throw IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+
+    }
+
+
+    /**
+     * Positive and negative tests on getIndexedProperty valid arguments.
+     */
+    public void testGetIndexedValues() {
+
+        Object value = null;
+
+        for (int i = 0; i < 5; i++) {
+
+            try {
+                value = bean.get("intArray", i);
+                assertNotNull("intArray returned value " + i, value);
+                assertTrue("intArray returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intArray returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intArray " + i + " threw " + t);
+            }
+
+            try {
+                value = bean.get("intIndexed", i);
+                assertNotNull("intIndexed returned value " + i, value);
+                assertTrue("intIndexed returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intIndexed returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value = bean.get("listIndexed", i);
+                assertNotNull("listIndexed returned value " + i, value);
+                assertTrue("list returned String " + i,
+                        value instanceof String);
+                assertEquals("listIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("listIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value = bean.get("stringArray", i);
+                assertNotNull("stringArray returned value " + i, value);
+                assertTrue("stringArray returned String " + i,
+                        value instanceof String);
+                assertEquals("stringArray returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringArray " + i + " threw " + t);
+            }
+
+            try {
+                value = bean.get("stringIndexed", i);
+                assertNotNull("stringIndexed returned value " + i, value);
+                assertTrue("stringIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("stringIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringIndexed " + i + " threw " + t);
+            }
+
+        }
+
+
+    }
+
+
+    /**
+     * Corner cases on getMappedProperty invalid arguments.
+     */
+    public void testGetMappedArguments() {
+
+
+        try {
+            Object value = bean.get("mappedProperty", "unknown");
+            assertNull("Should not return a value", value);
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of returning null");
+        }
+
+
+    }
+
+
+    /**
+     * Positive and negative tests on getMappedProperty valid arguments.
+     */
+    public void testGetMappedValues() {
+
+        Object value = null;
+
+        try {
+            value = bean.get("mappedProperty", "First Key");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value = bean.get("mappedProperty", "Second Key");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value = bean.get("mappedProperty", "Third Key");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getSimpleProperty invalid arguments.
+     */
+    public void testGetSimpleArguments() {
+
+        try {
+            bean.get(null);
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a boolean property.
+     */
+    public void testGetSimpleBoolean() {
+
+        try {
+            Object value = bean.get("booleanProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Boolean));
+            assertTrue("Got correct value",
+                    ((Boolean) value).booleanValue() == true);
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a double property.
+     */
+    public void testGetSimpleDouble() {
+
+        try {
+            Object value = bean.get("doubleProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Double));
+            assertEquals("Got correct value",
+                    ((Double) value).doubleValue(),
+                    (double) 321.0,
+                    (double) 0.005);
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a float property.
+     */
+    public void testGetSimpleFloat() {
+
+        try {
+            Object value = bean.get("floatProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Float));
+            assertEquals("Got correct value",
+                    ((Float) value).floatValue(),
+                    (float) 123.0,
+                    (float) 0.005);
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a int property.
+     */
+    public void testGetSimpleInt() {
+
+        try {
+            Object value = bean.get("intProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Integer));
+            assertEquals("Got correct value",
+                    ((Integer) value).intValue(),
+                    (int) 123);
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a long property.
+     */
+    public void testGetSimpleLong() {
+
+        try {
+            Object value = bean.get("longProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Long));
+            assertEquals("Got correct value",
+                    ((Long) value).longValue(),
+                    (long) 321);
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a short property.
+     */
+    public void testGetSimpleShort() {
+
+        try {
+            Object value = bean.get("shortProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Short));
+            assertEquals("Got correct value",
+                    ((Short) value).shortValue(),
+                    (short) 987);
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a String property.
+     */
+    public void testGetSimpleString() {
+
+        try {
+            Object value = bean.get("stringProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            assertEquals("Got correct value",
+                    (String) value,
+                    "This is a string");
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test <code>contains()</code> method for mapped properties.
+     */
+    public void testMappedContains() {
+
+        try {
+            assertTrue("Can see first key",
+                    bean.contains("mappedProperty", "First Key"));
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+
+        try {
+            assertTrue("Can not see unknown key",
+                    !bean.contains("mappedProperty", "Unknown Key"));
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test <code>remove()</code> method for mapped properties.
+     */
+    public void testMappedRemove() {
+
+        try {
+            assertTrue("Can see first key",
+                    bean.contains("mappedProperty", "First Key"));
+            bean.remove("mappedProperty", "First Key");
+            assertTrue("Can not see first key",
+                    !bean.contains("mappedProperty", "First Key"));
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+        try {
+            assertTrue("Can not see unknown key",
+                    !bean.contains("mappedProperty", "Unknown Key"));
+            bean.remove("mappedProperty", "Unknown Key");
+            assertTrue("Can not see unknown key",
+                    !bean.contains("mappedProperty", "Unknown Key"));
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test serialization and deserialization.
+     */
+    public void testSerialization() {
+
+        // Serialize the test bean
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(bean);
+            oos.flush();
+            oos.close();
+        } catch (Exception e) {
+            fail("Exception during serialization: " + e);
+        }
+
+        // Deserialize the test bean
+        try {
+            bean = null;
+            ByteArrayInputStream bais =
+                new ByteArrayInputStream(baos.toByteArray());
+            ObjectInputStream ois = new ObjectInputStream(bais);
+            bean = (DynaBean) ois.readObject();
+            bais.close();
+        } catch (Exception e) {
+            fail("Exception during deserialization: " + e);
+        }
+
+        // Confirm property values
+        testGetDescriptorArguments();
+        testGetDescriptorBoolean();
+        testGetDescriptorDouble();
+        testGetDescriptorFloat();
+        testGetDescriptorInt();
+        testGetDescriptorLong();
+        testGetDescriptorSecond();
+        testGetDescriptorShort();
+        testGetDescriptorString();
+        testGetDescriptors();
+        testGetIndexedArguments();
+        testGetIndexedValues();
+        testGetMappedArguments();
+        testGetMappedValues();
+        testGetSimpleArguments();
+        testGetSimpleBoolean();
+        testGetSimpleDouble();
+        testGetSimpleFloat();
+        testGetSimpleInt();
+        testGetSimpleLong();
+        testGetSimpleShort();
+        testGetSimpleString();
+        testMappedContains();
+        testMappedRemove();
+
+        // Ensure that we can create a new instance of the same DynaClass
+        try {
+            bean = bean.getDynaClass().newInstance();
+        } catch (Exception e) {
+            fail("Exception creating new instance: " + e);
+        }
+        testGetDescriptorArguments();
+        testGetDescriptorBoolean();
+        testGetDescriptorDouble();
+        testGetDescriptorFloat();
+        testGetDescriptorInt();
+        testGetDescriptorLong();
+        testGetDescriptorSecond();
+        testGetDescriptorShort();
+        testGetDescriptorString();
+        testGetDescriptors();
+
+    }
+
+
+    /**
+     * Corner cases on setIndexedProperty invalid arguments.
+     */
+    public void testSetIndexedArguments() {
+
+        try {
+            bean.set("intArray", -1, new Integer(0));
+            fail("Should throw IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on setIndexedProperty valid arguments.
+     */
+    public void testSetIndexedValues() {
+
+        Object value = null;
+
+        try {
+            bean.set("intArray", 0, new Integer(1));
+            value = (Integer) bean.get("intArray", 0);
+            assertNotNull("Returned new value 0", value);
+            assertTrue("Returned Integer new value 0",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 0", 1,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            bean.set("intIndexed", 1, new Integer(11));
+            value = (Integer) bean.get("intIndexed", 1);
+            assertNotNull("Returned new value 1", value);
+            assertTrue("Returned Integer new value 1",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 1", 11,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            bean.set("listIndexed", 2, "New Value 2");
+            value = (String) bean.get("listIndexed", 2);
+            assertNotNull("Returned new value 2", value);
+            assertTrue("Returned String new value 2",
+                    value instanceof String);
+            assertEquals("Returned correct new value 2", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            bean.set("stringArray", 3, "New Value 3");
+            value = (String) bean.get("stringArray", 3);
+            assertNotNull("Returned new value 3", value);
+            assertTrue("Returned String new value 3",
+                    value instanceof String);
+            assertEquals("Returned correct new value 3", "New Value 3",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            bean.set("stringIndexed", 4, "New Value 4");
+            value = (String) bean.get("stringIndexed", 4);
+            assertNotNull("Returned new value 4", value);
+            assertTrue("Returned String new value 4",
+                    value instanceof String);
+            assertEquals("Returned correct new value 4", "New Value 4",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+
+    }
+
+
+    /**
+     * Positive and negative tests on setMappedProperty valid arguments.
+     */
+    public void testSetMappedValues() {
+
+        try {
+            bean.set("mappedProperty", "First Key", "New First Value");
+            assertEquals("Can replace old value",
+                    "New First Value",
+                    (String) bean.get("mappedProperty", "First Key"));
+        } catch (Throwable t) {
+            fail("Finding fourth value threw " + t);
+        }
+
+        try {
+            bean.set("mappedProperty", "Fourth Key", "Fourth Value");
+            assertEquals("Can set new value",
+                    "Fourth Value",
+                    (String) bean.get("mappedProperty", "Fourth Key"));
+        } catch (Throwable t) {
+            fail("Finding fourth value threw " + t);
+        }
+
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a boolean property.
+     */
+    public void testSetSimpleBoolean() {
+
+        try {
+            boolean oldValue =
+                    ((Boolean) bean.get("booleanProperty")).booleanValue();
+            boolean newValue = !oldValue;
+            bean.set("booleanProperty", new Boolean(newValue));
+            assertTrue("Matched new value",
+                    newValue ==
+                    ((Boolean) bean.get("booleanProperty")).booleanValue());
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a double property.
+     */
+    public void testSetSimpleDouble() {
+
+        try {
+            double oldValue =
+                    ((Double) bean.get("doubleProperty")).doubleValue();
+            double newValue = oldValue + 1.0;
+            bean.set("doubleProperty", new Double(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Double) bean.get("doubleProperty")).doubleValue(),
+                    (double) 0.005);
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a float property.
+     */
+    public void testSetSimpleFloat() {
+
+        try {
+            float oldValue =
+                    ((Float) bean.get("floatProperty")).floatValue();
+            float newValue = oldValue + (float) 1.0;
+            bean.set("floatProperty", new Float(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Float) bean.get("floatProperty")).floatValue(),
+                    (float) 0.005);
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a int property.
+     */
+    public void testSetSimpleInt() {
+
+        try {
+            int oldValue =
+                    ((Integer) bean.get("intProperty")).intValue();
+            int newValue = oldValue + 1;
+            bean.set("intProperty", new Integer(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Integer) bean.get("intProperty")).intValue());
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a long property.
+     */
+    public void testSetSimpleLong() {
+
+        try {
+            long oldValue =
+                    ((Long) bean.get("longProperty")).longValue();
+            long newValue = oldValue + 1;
+            bean.set("longProperty", new Long(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Long) bean.get("longProperty")).longValue());
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a short property.
+     */
+    public void testSetSimpleShort() {
+
+        try {
+            short oldValue =
+                    ((Short) bean.get("shortProperty")).shortValue();
+            short newValue = (short) (oldValue + 1);
+            bean.set("shortProperty", new Short(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Short) bean.get("shortProperty")).shortValue());
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a String property.
+     */
+    public void testSetSimpleString() {
+
+        try {
+            String oldValue = (String) bean.get("stringProperty");
+            String newValue = oldValue + " Extra Value";
+            bean.set("stringProperty", newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    (String) bean.get("stringProperty"));
+        } catch (Throwable e) {
+            fail("Exception: " + e);
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Create and return a <code>DynaClass</code> instance for our test
+     * <code>DynaBean</code>.
+     */
+    protected DynaClass createDynaClass() {
+
+        int intArray[] = new int[0];
+        String stringArray[] = new String[0];
+
+        DynaClass dynaClass = new BasicDynaClass
+                ("TestDynaClass", null,
+                        new DynaProperty[]{
+                            new DynaProperty("booleanProperty", Boolean.TYPE),
+                            new DynaProperty("booleanSecond", Boolean.TYPE),
+                            new DynaProperty("doubleProperty", Double.TYPE),
+                            new DynaProperty("floatProperty", Float.TYPE),
+                            new DynaProperty("intArray", intArray.getClass()),
+                            new DynaProperty("intIndexed", intArray.getClass()),
+                            new DynaProperty("intProperty", Integer.TYPE),
+                            new DynaProperty("listIndexed", List.class),
+                            new DynaProperty("longProperty", Long.TYPE),
+                            new DynaProperty("mappedProperty", Map.class),
+                            new DynaProperty("mappedIntProperty", Map.class),
+                            new DynaProperty("nullProperty", String.class),
+                            new DynaProperty("shortProperty", Short.TYPE),
+                            new DynaProperty("stringArray", stringArray.getClass()),
+                            new DynaProperty("stringIndexed", stringArray.getClass()),
+                            new DynaProperty("stringProperty", String.class),
+                        });
+        return (dynaClass);
+
+    }
+
+
+    /**
+     * Base for testGetDescriptorXxxxx() series of tests.
+     *
+     * @param name Name of the property to be retrieved
+     * @param type Expected class type of this property
+     */
+    protected void testGetDescriptorBase(String name, Class type) {
+
+        try {
+            DynaProperty descriptor =
+                    bean.getDynaClass().getDynaProperty(name);
+            assertNotNull("Got descriptor", descriptor);
+            assertEquals("Got correct type", type, descriptor.getType());
+        } catch (Throwable t) {
+            fail("Threw an exception: " + t);
+        }
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsBenchCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsBenchCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsBenchCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * JUnit Test Case containing microbenchmarks for BeanUtils.
+ */
+
+public class BeanUtilsBenchCase extends TestCase {
+
+
+    // ------------------------------------------------------------ Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public BeanUtilsBenchCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // ------------------------------------------------------ Instance Variables
+
+
+    // Basic loop counter
+    private long counter = 100000;
+
+    // DynaClass for inDyna and outDyna
+    private DynaClass dynaClass = null;
+
+    // Input objects that have identical sets of properties and values.
+    private BenchBean inBean = null;
+    private DynaBean inDyna = null;
+    private Map inMap = null;  // Map of Objects requiring no conversion
+    private Map inStrs = null; // Map of Strings requiring conversion
+
+    // Output objects that have identical sets of properties.
+    private BenchBean outBean = null;
+    private DynaBean outDyna = null;
+
+    // BeanUtilsBean instance to be used
+    private BeanUtilsBean bu = null;
+
+
+    // ---------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        // Set up loop counter (if property specified)
+        String prop = System.getProperty("counter");
+        if (prop != null) {
+            counter = Long.parseLong(prop);
+        }
+
+        // Set up DynaClass for our DynaBean instances
+        dynaClass = new BasicDynaClass
+            ("BenchDynaClass", null,
+             new DynaProperty[]{
+                 new DynaProperty("booleanProperty", Boolean.TYPE),
+                 new DynaProperty("byteProperty", Byte.TYPE),
+                 new DynaProperty("doubleProperty", Double.TYPE),
+                 new DynaProperty("floatProperty", Float.TYPE),
+                 new DynaProperty("intProperty", Integer.TYPE),
+                 new DynaProperty("longProperty", Long.TYPE),
+                 new DynaProperty("shortProperty", Short.TYPE),
+                 new DynaProperty("stringProperty", String.class),
+             });
+
+        // Create input instances
+        inBean = new BenchBean();
+        inMap = new HashMap();
+        inMap.put("booleanProperty", new Boolean(inBean.getBooleanProperty()));
+        inMap.put("byteProperty", new Byte(inBean.getByteProperty()));
+        inMap.put("doubleProperty", new Double(inBean.getDoubleProperty()));
+        inMap.put("floatProperty", new Float(inBean.getFloatProperty()));
+        inMap.put("intProperty", new Integer(inBean.getIntProperty()));
+        inMap.put("longProperty", new Long(inBean.getLongProperty()));
+        inMap.put("shortProperty", new Short(inBean.getShortProperty()));
+        inMap.put("stringProperty", inBean.getStringProperty());
+        inDyna = dynaClass.newInstance();
+        Iterator inKeys = inMap.keySet().iterator();
+        while (inKeys.hasNext()) {
+            String inKey = (String) inKeys.next();
+            inDyna.set(inKey, inMap.get(inKey));
+        }
+        inStrs = new HashMap();
+        inKeys = inMap.keySet().iterator();
+        while (inKeys.hasNext()) {
+            String inKey = (String) inKeys.next();
+            inStrs.put(inKey, inMap.get(inKey).toString());
+        }
+
+        // Create output instances
+        outBean = new BenchBean();
+        outDyna = dynaClass.newInstance();
+        Iterator outKeys = inMap.keySet().iterator();
+        while (outKeys.hasNext()) {
+            String outKey = (String) outKeys.next();
+            outDyna.set(outKey, inMap.get(outKey));
+        }
+
+        // Set up BeanUtilsBean instance we will use
+        bu = BeanUtilsBean.getInstance();
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(BeanUtilsBenchCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        dynaClass = null;
+        inBean = null;
+        inDyna = null;
+        inMap = null;
+        outBean = null;
+        outDyna = null;
+        bu = null;
+
+    }
+
+
+
+    // ------------------------------------------------- Individual Test Methods
+
+
+    // Time copyProperties() from a bean
+    public void testCopyPropertiesBean() throws Exception {
+
+        long start;
+        long stop;
+
+        // Bean->Bean
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inBean);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inBean);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(bean,bean), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Bean->Dyna
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inBean);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inBean);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(dyna,bean), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time copyProperties() from a DynaBean
+    public void testCopyPropertiesDyna() throws Exception {
+
+        long start;
+        long stop;
+
+        // Dyna->Bean
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inDyna);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inDyna);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(bean,dyna), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Dyna->Dyna
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inDyna);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inDyna);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(dyna,dyna), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time copyProperties() from a Map of Objects
+    public void testCopyPropertiesMap() throws Exception {
+
+        long start;
+        long stop;
+
+        // Map->Bean
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inMap);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inMap);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(bean, map), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Map->Dyna
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inMap);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inMap);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(dyna, map), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time copyProperties() from a Map of Strings
+    public void testCopyPropertiesStrs() throws Exception {
+
+        long start;
+        long stop;
+
+        // Strs->Bean
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inStrs);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outBean, inStrs);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(bean,strs), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Strs->Dyna
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inStrs);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.copyProperties(outDyna, inStrs);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.copyProperties(dyna,strs), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time populate() from a Map of Objects
+    public void testPopulateMap() throws Exception {
+
+        long start;
+        long stop;
+
+        // Map->Bean
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outBean, inMap);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outBean, inMap);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.populate(bean, map), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Map->Dyna
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outDyna, inMap);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outDyna, inMap);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.populate(dyna, map), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time populate() from a Map of Strings
+    // NOTE - This simulates what Struts does when processing form beans
+    public void testPopulateStrs() throws Exception {
+
+        long start;
+        long stop;
+
+        // Strs->Bean
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outBean, inStrs);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outBean, inStrs);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.populate(bean,strs), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Strs->Dyna
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outDyna, inStrs);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            bu.populate(outDyna, inStrs);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("BU.populate(dyna,strs), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // --------------------------------------------------------- Support Methods
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,1341 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>
+ *  Test Case for the BeanUtils class.  The majority of these tests use
+ *  instances of the TestBean class, so be sure to update the tests if you
+ *  change the characteristics of that class.
+ * </p>
+ *
+ * <p>
+ *  Template for this stolen from Craigs PropertyUtilsTestCase
+ * </p>
+ *
+ * <p>
+ *   Note that the tests are dependant upon the static aspects
+ *   (such as array sizes...) of the TestBean.java class, so ensure
+ *   than all changes to TestBean are reflected here.
+ * </p>
+ *
+ * <p>
+ *  So far, this test case has tests for the following methods of the
+ *  <code>BeanUtils</code> class:
+ * </p>
+ * <ul>
+ *   <li>getArrayProperty(Object bean, String name)</li>
+ * </ul>
+ *
+ * @author <a href="mailto:geirm at optonline.net">Geir Magnusson Jr.</a>
+ * @version $Revision: 1.29 $
+ */
+
+public class BeanUtilsTestCase extends TestCase {
+
+    // ---------------------------------------------------- Instance Variables
+
+    /**
+     * The test bean for each test.
+     */
+    protected TestBean bean = null;
+
+
+    /**
+     * The set of properties that should be described.
+     */
+    protected String describes[] =
+    { "booleanProperty",
+      "booleanSecond",
+      "byteProperty",
+      "doubleProperty",
+      "dupProperty",
+      "floatProperty",
+      "intArray",
+      //      "intIndexed",
+      "longProperty",
+      "listIndexed",
+      "longProperty",
+      //      "mappedProperty",
+      //      "mappedIntProperty",
+      "nested",
+      "nullProperty",
+      "readOnlyProperty",
+      "shortProperty",
+      "stringArray",
+      //      "stringIndexed",
+      "stringProperty"
+    };
+
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public BeanUtilsTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+        bean = new TestBean();
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(BeanUtilsTestCase.class));
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        bean = null;
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Test the copyProperties() method from a DynaBean.
+     */
+    public void testCopyPropertiesDynaBean() {
+
+        // Set up an origin bean with customized properties
+        DynaClass dynaClass = DynaBeanUtilsTestCase.createDynaClass();
+        DynaBean orig = null;
+        try {
+            orig = dynaClass.newInstance();
+        } catch (Exception e) {
+            fail("newInstance(): " + e);
+        }
+        orig.set("booleanProperty", Boolean.FALSE);
+        orig.set("byteProperty", new Byte((byte) 111));
+        orig.set("doubleProperty", new Double(333.33));
+        orig.set("dupProperty",
+                 new String[] { "New 0", "New 1", "New 2" });
+        orig.set("intArray", new int[] { 100, 200, 300 });
+        orig.set("intProperty", new Integer(333));
+        orig.set("longProperty", new Long(3333));
+        orig.set("shortProperty", new Short((short) 33));
+        orig.set("stringArray", new String[] { "New 0", "New 1" });
+        orig.set("stringProperty", "Custom string");
+
+        // Copy the origin bean to our destination test bean
+        try {
+            BeanUtils.copyProperties(bean, orig);
+        } catch (Exception e) {
+            fail("Threw exception: " + e);
+        }
+
+        // Validate the results for scalar properties
+        assertEquals("Copied boolean property",
+                     false,
+                     bean.getBooleanProperty());
+        assertEquals("Copied byte property",
+                     (byte) 111,
+                     bean.getByteProperty());
+        assertEquals("Copied double property",
+                     333.33,
+                     bean.getDoubleProperty(),
+                     0.005);
+        assertEquals("Copied int property",
+                     333,
+                     bean.getIntProperty());
+        assertEquals("Copied long property",
+                     (long) 3333,
+                     bean.getLongProperty());
+        assertEquals("Copied short property",
+                     (short) 33,
+                     bean.getShortProperty());
+        assertEquals("Copied string property",
+                     "Custom string",
+                     bean.getStringProperty());
+
+        // Validate the results for array properties
+        String dupProperty[] = bean.getDupProperty();
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = bean.getIntArray();
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 100, intArray[0]);
+        assertEquals("intArray[1]", 200, intArray[1]);
+        assertEquals("intArray[2]", 300, intArray[2]);
+        String stringArray[] = bean.getStringArray();
+        assertNotNull("stringArray present", stringArray);
+        assertEquals("stringArray length", 2, stringArray.length);
+        assertEquals("stringArray[0]", "New 0", stringArray[0]);
+        assertEquals("stringArray[1]", "New 1", stringArray[1]);
+
+    }
+
+
+    /**
+     * Test copyProperties() when the origin is a a <code>Map</code>.
+     */
+    public void testCopyPropertiesMap() {
+
+        Map map = new HashMap();
+        map.put("booleanProperty", "false");
+        map.put("byteProperty", "111");
+        map.put("doubleProperty", "333.0");
+        map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
+        map.put("floatProperty", "222.0");
+        map.put("intArray", new String[] { "0", "100", "200" });
+        map.put("intProperty", "111");
+        map.put("longProperty", "444");
+        map.put("shortProperty", "555");
+        map.put("stringProperty", "New String Property");
+
+        try {
+            BeanUtils.copyProperties(bean, map);
+        } catch (Throwable t) {
+            fail("Threw " + t.toString());
+        }
+
+        // Scalar properties
+        assertEquals("booleanProperty", false,
+                     bean.getBooleanProperty());
+        assertEquals("byteProperty", (byte) 111,
+                     bean.getByteProperty());
+        assertEquals("doubleProperty", 333.0,
+                     bean.getDoubleProperty(), 0.005);
+        assertEquals("floatProperty", (float) 222.0,
+                     bean.getFloatProperty(), (float) 0.005);
+        assertEquals("longProperty", 111,
+                     bean.getIntProperty());
+        assertEquals("longProperty", (long) 444,
+                     bean.getLongProperty());
+        assertEquals("shortProperty", (short) 555,
+                     bean.getShortProperty());
+        assertEquals("stringProperty", "New String Property",
+                     bean.getStringProperty());
+
+        // Indexed Properties
+        String dupProperty[] = bean.getDupProperty();
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = bean.getIntArray();
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 0, intArray[0]);
+        assertEquals("intArray[1]", 100, intArray[1]);
+        assertEquals("intArray[2]", 200, intArray[2]);
+
+    }
+
+
+    /**
+     * Test the copyProperties() method from a standard JavaBean.
+     */
+    public void testCopyPropertiesStandard() {
+
+        // Set up an origin bean with customized properties
+        TestBean orig = new TestBean();
+        orig.setBooleanProperty(false);
+        orig.setByteProperty((byte) 111);
+        orig.setDoubleProperty(333.33);
+        orig.setDupProperty(new String[] { "New 0", "New 1", "New 2" });
+        orig.setIntArray(new int[] { 100, 200, 300 });
+        orig.setIntProperty(333);
+        orig.setLongProperty(3333);
+        orig.setShortProperty((short) 33);
+        orig.setStringArray(new String[] { "New 0", "New 1" });
+        orig.setStringProperty("Custom string");
+
+        // Copy the origin bean to our destination test bean
+        try {
+            BeanUtils.copyProperties(bean, orig);
+        } catch (Exception e) {
+            fail("Threw exception: " + e);
+        }
+
+        // Validate the results for scalar properties
+        assertEquals("Copied boolean property",
+                     false,
+                     bean.getBooleanProperty());
+        assertEquals("Copied byte property",
+                     (byte) 111,
+                     bean.getByteProperty());
+        assertEquals("Copied double property",
+                     333.33,
+                     bean.getDoubleProperty(),
+                     0.005);
+        assertEquals("Copied int property",
+                     333,
+                     bean.getIntProperty());
+        assertEquals("Copied long property",
+                     (long) 3333,
+                     bean.getLongProperty());
+        assertEquals("Copied short property",
+                     (short) 33,
+                     bean.getShortProperty());
+        assertEquals("Copied string property",
+                     "Custom string",
+                     bean.getStringProperty());
+
+        // Validate the results for array properties
+        String dupProperty[] = bean.getDupProperty();
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = bean.getIntArray();
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 100, intArray[0]);
+        assertEquals("intArray[1]", 200, intArray[1]);
+        assertEquals("intArray[2]", 300, intArray[2]);
+        String stringArray[] = bean.getStringArray();
+        assertNotNull("stringArray present", stringArray);
+        assertEquals("stringArray length", 2, stringArray.length);
+        assertEquals("stringArray[0]", "New 0", stringArray[0]);
+        assertEquals("stringArray[1]", "New 1", stringArray[1]);
+
+    }
+
+
+    /**
+     * Test the describe() method.
+     */
+    public void testDescribe() {
+
+        Map map = null;
+        try {
+            map = BeanUtils.describe(bean);
+        } catch (Exception e) {
+            fail("Threw exception " + e);
+        }
+
+        // Verify existence of all the properties that should be present
+        for (int i = 0; i < describes.length; i++) {
+            assertTrue("Property '" + describes[i] + "' is present",
+                       map.containsKey(describes[i]));
+        }
+        assertTrue("Property 'writeOnlyProperty' is not present",
+                   !map.containsKey("writeOnlyProperty"));
+
+        // Verify the values of scalar properties
+        assertEquals("Value of 'booleanProperty'",
+                     "true",
+                     (String) map.get("booleanProperty"));
+        assertEquals("Value of 'byteProperty'",
+                     "121",
+                     (String) map.get("byteProperty"));
+        assertEquals("Value of 'doubleProperty'",
+                     "321.0",
+                     (String) map.get("doubleProperty"));
+        assertEquals("Value of 'floatProperty'",
+                     "123.0",
+                     (String) map.get("floatProperty"));
+        assertEquals("Value of 'intProperty'",
+                     "123",
+                     (String) map.get("intProperty"));
+        assertEquals("Value of 'longProperty'",
+                     "321",
+                     (String) map.get("longProperty"));
+        assertEquals("Value of 'shortProperty'",
+                     "987",
+                     (String) map.get("shortProperty"));
+        assertEquals("Value of 'stringProperty'",
+                     "This is a string",
+                     (String) map.get("stringProperty"));
+
+    }
+
+
+    /**
+     *  tests the string and int arrays of TestBean
+     */
+    public void testGetArrayProperty() {
+        try {
+            String arr[] = BeanUtils.getArrayProperty(bean, "stringArray");
+            String comp[] = bean.getStringArray();
+
+            assertTrue("String array length = " + comp.length,
+                    (comp.length == arr.length));
+
+            arr = BeanUtils.getArrayProperty(bean, "intArray");
+            int iarr[] = bean.getIntArray();
+
+            assertTrue("String array length = " + iarr.length,
+                    (iarr.length == arr.length));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     *  tests getting an indexed property
+     */
+    public void testGetIndexedProperty1() {
+        try {
+            String val = BeanUtils.getIndexedProperty(bean, "intIndexed[3]");
+            String comp = String.valueOf(bean.getIntIndexed(3));
+            assertTrue("intIndexed[3] == " + comp, val.equals(comp));
+
+            val = BeanUtils.getIndexedProperty(bean, "stringIndexed[3]");
+            comp = bean.getStringIndexed(3);
+            assertTrue("stringIndexed[3] == " + comp, val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting an indexed property
+     */
+    public void testGetIndexedProperty2() {
+        try {
+            String val = BeanUtils.getIndexedProperty(bean, "intIndexed", 3);
+            String comp = String.valueOf(bean.getIntIndexed(3));
+
+            assertTrue("intIndexed,3 == " + comp, val.equals(comp));
+
+            val = BeanUtils.getIndexedProperty(bean, "stringIndexed", 3);
+            comp = bean.getStringIndexed(3);
+
+            assertTrue("stringIndexed,3 == " + comp, val.equals(comp));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting a nested property
+     */
+    public void testGetNestedProperty() {
+        try {
+            String val = BeanUtils.getNestedProperty(bean, "nested.stringProperty");
+            String comp = bean.getNested().getStringProperty();
+            assertTrue("nested.StringProperty == " + comp,
+                    val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting a 'whatever' property
+     */
+    public void testGetGeneralProperty() {
+        try {
+            String val = BeanUtils.getProperty(bean, "nested.intIndexed[2]");
+            String comp = String.valueOf(bean.getIntIndexed(2));
+
+            assertTrue("nested.intIndexed[2] == " + comp,
+                    val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting a 'whatever' property
+     */
+    public void testGetSimpleProperty() {
+        try {
+            String val = BeanUtils.getSimpleProperty(bean, "shortProperty");
+            String comp = String.valueOf(bean.getShortProperty());
+
+            assertTrue("shortProperty == " + comp,
+                    val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     * Test populate() method on individual array elements.
+     */
+    public void testPopulateArrayElements() {
+
+        try {
+
+            HashMap map = new HashMap();
+            map.put("intIndexed[0]", "100");
+            map.put("intIndexed[2]", "120");
+            map.put("intIndexed[4]", "140");
+
+            BeanUtils.populate(bean, map);
+
+            assertEquals("intIndexed[0] is 100",
+                         100, bean.getIntIndexed(0));
+            assertEquals("intIndexed[1] is 10",
+                         10, bean.getIntIndexed(1));
+            assertEquals("intIndexed[2] is 120",
+                         120, bean.getIntIndexed(2));
+            assertEquals("intIndexed[3] is 30",
+                         30, bean.getIntIndexed(3));
+            assertEquals("intIndexed[4] is 140",
+                         140, bean.getIntIndexed(4));
+
+            map.clear();
+            map.put("stringIndexed[1]", "New String 1");
+            map.put("stringIndexed[3]", "New String 3");
+
+            BeanUtils.populate(bean, map);
+
+            assertEquals("stringIndexed[0] is \"String 0\"",
+                         "String 0", bean.getStringIndexed(0));
+            assertEquals("stringIndexed[1] is \"New String 1\"",
+                         "New String 1", bean.getStringIndexed(1));
+            assertEquals("stringIndexed[2] is \"String 2\"",
+                         "String 2", bean.getStringIndexed(2));
+            assertEquals("stringIndexed[3] is \"New String 3\"",
+                         "New String 3", bean.getStringIndexed(3));
+            assertEquals("stringIndexed[4] is \"String 4\"",
+                         "String 4", bean.getStringIndexed(4));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() method on array properties as a whole.
+     */
+    public void testPopulateArrayProperties() {
+
+        try {
+
+            HashMap map = new HashMap();
+            int intArray[] = new int[] { 123, 456, 789 };
+            map.put("intArray", intArray);
+            String stringArray[] = new String[]
+                { "New String 0", "New String 1" };
+            map.put("stringArray", stringArray);
+
+            BeanUtils.populate(bean, map);
+
+            intArray = bean.getIntArray();
+            assertNotNull("intArray is present", intArray);
+            assertEquals("intArray length",
+                         3, intArray.length);
+            assertEquals("intArray[0]", 123, intArray[0]);
+            assertEquals("intArray[1]", 456, intArray[1]);
+            assertEquals("intArray[2]", 789, intArray[2]);
+            stringArray = bean.getStringArray();
+            assertNotNull("stringArray is present", stringArray);
+            assertEquals("stringArray length", 2, stringArray.length);
+            assertEquals("stringArray[0]", "New String 0", stringArray[0]);
+            assertEquals("stringArray[1]", "New String 1", stringArray[1]);
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() on mapped properties.
+     */
+    public void testPopulateMapped() {
+
+        try {
+
+            HashMap map = new HashMap();
+            map.put("mappedProperty(First Key)", "New First Value");
+            map.put("mappedProperty(Third Key)", "New Third Value");
+
+            BeanUtils.populate(bean, map);
+
+            assertEquals("mappedProperty(First Key)",
+                         "New First Value",
+                         bean.getMappedProperty("First Key"));
+            assertEquals("mappedProperty(Second Key)",
+                         "Second Value",
+                         bean.getMappedProperty("Second Key"));
+            assertEquals("mappedProperty(Third Key)",
+                         "New Third Value",
+                         bean.getMappedProperty("Third Key"));
+            assertNull("mappedProperty(Fourth Key",
+                       bean.getMappedProperty("Fourth Key"));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() method on nested properties.
+     */
+    public void testPopulateNested() {
+
+        try {
+
+            HashMap map = new HashMap();
+            map.put("nested.booleanProperty", "false");
+            // booleanSecond is left at true
+            map.put("nested.doubleProperty", "432.0");
+            // floatProperty is left at 123.0
+            map.put("nested.intProperty", "543");
+            // longProperty is left at 321
+            map.put("nested.shortProperty", "654");
+            // stringProperty is left at "This is a string"
+            map.put("nested.writeOnlyProperty", "New writeOnlyProperty value");
+
+            BeanUtils.populate(bean, map);
+
+            assertTrue("booleanProperty is false",
+                       !bean.getNested().getBooleanProperty());
+            assertTrue("booleanSecond is true",
+                       bean.getNested().isBooleanSecond());
+            assertEquals("doubleProperty is 432.0",
+                         (double) 432.0,
+                         bean.getNested().getDoubleProperty(),
+                         (double) 0.005);
+            assertEquals("floatProperty is 123.0",
+                         (float) 123.0,
+                         bean.getNested().getFloatProperty(),
+                         (float) 0.005);
+            assertEquals("intProperty is 543",
+                         543, bean.getNested().getIntProperty());
+            assertEquals("longProperty is 321",
+                         (long) 321, bean.getNested().getLongProperty());
+            assertEquals("shortProperty is 654",
+                         (short) 654, bean.getNested().getShortProperty());
+            assertEquals("stringProperty is \"This is a string\"",
+                         "This is a string",
+                         bean.getNested().getStringProperty());
+            assertEquals("writeOnlyProperty is \"New writeOnlyProperty value\"",
+                         "New writeOnlyProperty value",
+                         bean.getNested().getWriteOnlyPropertyValue());
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() method on scalar properties.
+     */
+    public void testPopulateScalar() {
+
+        try {
+
+            bean.setNullProperty("Non-null value");
+
+            HashMap map = new HashMap();
+            map.put("booleanProperty", "false");
+            // booleanSecond is left at true
+            map.put("byteProperty", "111");
+            map.put("doubleProperty", "432.0");
+            // floatProperty is left at 123.0
+            map.put("intProperty", "543");
+            map.put("longProperty", "");
+            map.put("nullProperty", null);
+            map.put("shortProperty", "654");
+            // stringProperty is left at "This is a string"
+            map.put("writeOnlyProperty", "New writeOnlyProperty value");
+            map.put("readOnlyProperty", "New readOnlyProperty value");
+
+            BeanUtils.populate(bean, map);
+
+            assertTrue("booleanProperty is false", !bean.getBooleanProperty());
+            assertTrue("booleanSecond is true", bean.isBooleanSecond());
+            assertEquals("byteProperty is 111",
+                         (byte) 111, bean.getByteProperty());
+            assertEquals("doubleProperty is 432.0",
+                         (double) 432.0, bean.getDoubleProperty(),
+                         (double) 0.005);
+            assertEquals("floatProperty is 123.0",
+                         (float) 123.0, bean.getFloatProperty(),
+                         (float) 0.005);
+            assertEquals("intProperty is 543",
+                         543, bean.getIntProperty());
+            assertEquals("longProperty is 0",
+                         (long) 0, bean.getLongProperty());
+            assertNull("nullProperty is null",
+                       bean.getNullProperty());
+            assertEquals("shortProperty is 654",
+                         (short) 654, bean.getShortProperty());
+            assertEquals("stringProperty is \"This is a string\"",
+                         "This is a string", bean.getStringProperty());
+            assertEquals("writeOnlyProperty is \"New writeOnlyProperty value\"",
+                         "New writeOnlyProperty value",
+                         bean.getWriteOnlyPropertyValue());
+            assertEquals("readOnlyProperty is \"Read Only String Property\"",
+                         "Read Only String Property",
+                         bean.getReadOnlyProperty());
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test calling setProperty() with null property values.
+     */
+    public void testSetPropertyNullValues() throws Exception {
+
+        Object oldValue = null;
+        Object newValue = null;
+
+        // Scalar value into array
+        oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        BeanUtils.setProperty(bean, "stringArray", (String) null);
+        newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        assertNotNull("stringArray is not null", newValue);
+        assertTrue("stringArray of correct type",
+                   newValue instanceof String[]);
+        assertEquals("stringArray length",
+                     1, ((String[]) newValue).length);
+        assertTrue("stringArray[0] is null",
+                   ((String[]) newValue)[0] == null);
+        PropertyUtils.setProperty(bean, "stringArray", oldValue);
+
+        // Indexed value into array
+        oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        BeanUtils.setProperty(bean, "stringArray[2]", (String) null);
+        newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        assertNotNull("stringArray is not null", newValue);
+        assertTrue("stringArray of correct type",
+                   newValue instanceof String[]);
+        assertEquals("stringArray length",
+                     5, ((String[]) newValue).length);
+        assertTrue("stringArray[2] is null",
+                   ((String[]) newValue)[2] == null);
+        PropertyUtils.setProperty(bean, "stringArray", oldValue);
+
+        // Value into scalar
+        BeanUtils.setProperty(bean, "stringProperty", null);
+        assertTrue("stringProperty is now null",
+                   BeanUtils.getProperty(bean, "stringProperty") == null);
+
+    }
+
+
+    /**
+     * Test converting to and from primitive wrapper types.
+     */
+    public void testSetPropertyOnPrimitiveWrappers() throws Exception {
+
+        BeanUtils.setProperty(bean,"intProperty", new Integer(1));
+        assertEquals(1,bean.getIntProperty());
+        BeanUtils.setProperty(bean,"stringProperty", new Integer(1));
+        assertEquals(1, Integer.parseInt(bean.getStringProperty()));
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on byte.
+     */
+    public void testSetPropertyByte() throws Exception {
+
+        BeanUtils.setProperty(bean, "byteProperty", new Byte((byte) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+/*
+        BeanUtils.setProperty(bean, "byteProperty", new Double((double) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.setProperty(bean, "byteProperty", new Float((float) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+*/
+        BeanUtils.setProperty(bean, "byteProperty", new Integer((int) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.setProperty(bean, "byteProperty", new Long((long) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.setProperty(bean, "byteProperty", new Short((short) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on double.
+     */
+    public void testSetPropertyDouble() throws Exception {
+
+        BeanUtils.setProperty(bean, "doubleProperty", new Byte((byte) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Double((double) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Float((float) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Integer((int) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Long((long) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Short((short) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on float.
+     */
+    public void testSetPropertyFloat() throws Exception {
+
+        BeanUtils.setProperty(bean, "floatProperty", new Byte((byte) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Double((double) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Float((float) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Integer((int) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Long((long) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Short((short) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on int.
+     */
+    public void testSetPropertyInteger() throws Exception {
+
+        BeanUtils.setProperty(bean, "longProperty", new Byte((byte) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+/*
+        BeanUtils.setProperty(bean, "longProperty", new Double((double) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.setProperty(bean, "longProperty", new Float((float) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+*/
+        BeanUtils.setProperty(bean, "longProperty", new Integer((int) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.setProperty(bean, "longProperty", new Long((long) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.setProperty(bean, "longProperty", new Short((short) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on long.
+     */
+    public void testSetPropertyLong() throws Exception {
+
+        BeanUtils.setProperty(bean, "longProperty", new Byte((byte) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+/*
+        BeanUtils.setProperty(bean, "longProperty", new Double((double) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.setProperty(bean, "longProperty", new Float((float) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+*/
+        BeanUtils.setProperty(bean, "longProperty", new Integer((int) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.setProperty(bean, "longProperty", new Long((long) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.setProperty(bean, "longProperty", new Short((short) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+
+    }
+
+
+    /**
+     * Test setting a null property value.
+     */
+    public void testSetPropertyNull() throws Exception {
+
+        bean.setNullProperty("non-null value");
+        BeanUtils.setProperty(bean, "nullProperty", null);
+        assertNull("nullProperty is null", bean.getNullProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on short.
+     */
+    public void testSetPropertyShort() throws Exception {
+
+        BeanUtils.setProperty(bean, "shortProperty", new Byte((byte) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+/*
+        BeanUtils.setProperty(bean, "shortProperty", new Double((double) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.setProperty(bean, "shortProperty", new Float((float) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+*/
+        BeanUtils.setProperty(bean, "shortProperty", new Integer((int) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.setProperty(bean, "shortProperty", new Long((long) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.setProperty(bean, "shortProperty", new Short((short) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on byte.
+     */
+    public void testCopyPropertyByte() throws Exception {
+
+        BeanUtils.copyProperty(bean, "byteProperty", new Byte((byte) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.copyProperty(bean, "byteProperty", new Double((double) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.copyProperty(bean, "byteProperty", new Float((float) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.copyProperty(bean, "byteProperty", new Integer((int) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.copyProperty(bean, "byteProperty", new Long((long) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+        BeanUtils.copyProperty(bean, "byteProperty", new Short((short) 123));
+        assertEquals((byte) 123, bean.getByteProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on double.
+     */
+    public void testCopyPropertyDouble() throws Exception {
+
+        BeanUtils.copyProperty(bean, "doubleProperty", new Byte((byte) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "doubleProperty", new Double((double) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "doubleProperty", new Float((float) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "doubleProperty", new Integer((int) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "doubleProperty", new Long((long) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "doubleProperty", new Short((short) 123));
+        assertEquals((double) 123, bean.getDoubleProperty(), 0.005);
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on float.
+     */
+    public void testCopyPropertyFloat() throws Exception {
+
+        BeanUtils.copyProperty(bean, "floatProperty", new Byte((byte) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "floatProperty", new Double((double) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "floatProperty", new Float((float) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "floatProperty", new Integer((int) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "floatProperty", new Long((long) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+        BeanUtils.copyProperty(bean, "floatProperty", new Short((short) 123));
+        assertEquals((float) 123, bean.getFloatProperty(), 0.005);
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on int.
+     */
+    public void testCopyPropertyInteger() throws Exception {
+
+        BeanUtils.copyProperty(bean, "longProperty", new Byte((byte) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Double((double) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Float((float) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Integer((int) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Long((long) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Short((short) 123));
+        assertEquals((int) 123, bean.getIntProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on long.
+     */
+    public void testCopyPropertyLong() throws Exception {
+
+        BeanUtils.copyProperty(bean, "longProperty", new Byte((byte) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Double((double) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Float((float) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Integer((int) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Long((long) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+        BeanUtils.copyProperty(bean, "longProperty", new Short((short) 123));
+        assertEquals((long) 123, bean.getLongProperty());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on short.
+     */
+    public void testCopyPropertyShort() throws Exception {
+
+        BeanUtils.copyProperty(bean, "shortProperty", new Byte((byte) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.copyProperty(bean, "shortProperty", new Double((double) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.copyProperty(bean, "shortProperty", new Float((float) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.copyProperty(bean, "shortProperty", new Integer((int) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.copyProperty(bean, "shortProperty", new Long((long) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+        BeanUtils.copyProperty(bean, "shortProperty", new Short((short) 123));
+        assertEquals((short) 123, bean.getShortProperty());
+
+    }
+
+
+    /**
+     * Test copying a property using a nested indexed array expression,
+     * with and without conversions.
+     */
+    public void testCopyPropertyNestedIndexedArray() throws Exception {
+
+        int origArray[] = { 0, 10, 20, 30, 40 };
+        int intArray[] = { 0, 0, 0 };
+        bean.getNested().setIntArray(intArray);
+        int intChanged[] = { 0, 0, 0 };
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Integer(1));
+        checkIntArray(bean.getIntArray(), origArray);
+        intChanged[1] = 1;
+        checkIntArray(bean.getNested().getIntArray(), intChanged);
+
+        // Widening conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Byte((byte) 2));
+        checkIntArray(bean.getIntArray(), origArray);
+        intChanged[1] = 2;
+        checkIntArray(bean.getNested().getIntArray(), intChanged);
+
+        // Narrowing conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Long((long) 3));
+        checkIntArray(bean.getIntArray(), origArray);
+        intChanged[1] = 3;
+        checkIntArray(bean.getNested().getIntArray(), intChanged);
+
+        // String conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", "4");
+        checkIntArray(bean.getIntArray(), origArray);
+        intChanged[1] = 4;
+        checkIntArray(bean.getNested().getIntArray(), intChanged);
+
+    }
+
+
+    /**
+     * Test copying a property using a nested mapped map property.
+     */
+    public void testCopyPropertyNestedMappedMap() throws Exception {
+
+        Map origMap = new HashMap();
+        origMap.put("First Key", "First Value");
+        origMap.put("Second Key", "Second Value");
+        Map changedMap = new HashMap();
+        changedMap.put("First Key", "First Value");
+        changedMap.put("Second Key", "Second Value");
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "nested.mapProperty(Second Key)",
+                               "New Second Value");
+        checkMap(bean.getMapProperty(), origMap);
+        changedMap.put("Second Key", "New Second Value");
+        checkMap(bean.getNested().getMapProperty(), changedMap);
+
+    }
+
+
+    /**
+     * Test copying a property using a nested simple expression, with and
+     * without conversions.
+     */
+    public void testCopyPropertyNestedSimple() throws Exception {
+
+        bean.setIntProperty(0);
+        bean.getNested().setIntProperty(0);
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", new Integer(1));
+        assertNotNull(bean.getNested());
+        assertEquals(0, bean.getIntProperty());
+        assertEquals(1, bean.getNested().getIntProperty());
+
+        // Widening conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", new Byte((byte) 2));
+        assertNotNull(bean.getNested());
+        assertEquals(0, bean.getIntProperty());
+        assertEquals(2, bean.getNested().getIntProperty());
+
+        // Narrowing conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", new Long((long) 3));
+        assertNotNull(bean.getNested());
+        assertEquals(0, bean.getIntProperty());
+        assertEquals(3, bean.getNested().getIntProperty());
+
+        // String conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", "4");
+        assertNotNull(bean.getNested());
+        assertEquals(0, bean.getIntProperty());
+        assertEquals(4, bean.getNested().getIntProperty());
+
+    }
+
+
+    /**
+     * Test copying a null property value.
+     */
+    public void testCopyPropertyNull() throws Exception {
+
+        bean.setNullProperty("non-null value");
+        BeanUtils.copyProperty(bean, "nullProperty", null);
+        assertNull("nullProperty is null", bean.getNullProperty());
+
+    }
+
+
+    /**
+     * Test copying a new value to a write-only property, with and without
+     * conversions.
+     */
+    public void testCopyPropertyWriteOnly() throws Exception {
+
+        bean.setWriteOnlyProperty("Original value");
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "writeOnlyProperty", "New value");
+        assertEquals("New value", bean.getWriteOnlyPropertyValue());
+
+        // Integer->String conversion required
+        BeanUtils.copyProperty(bean, "writeOnlyProperty", new Integer(123));
+        assertEquals("123", bean.getWriteOnlyPropertyValue());
+
+    }
+
+
+    /**
+     * Test setting a new value to a write-only property, with and without
+     * conversions.
+     */
+    public void testSetPropertyWriteOnly() throws Exception {
+
+        bean.setWriteOnlyProperty("Original value");
+
+        // No conversion required
+        BeanUtils.setProperty(bean, "writeOnlyProperty", "New value");
+        assertEquals("New value", bean.getWriteOnlyPropertyValue());
+
+        // Integer->String conversion required
+        BeanUtils.setProperty(bean, "writeOnlyProperty", new Integer(123));
+        assertEquals("123", bean.getWriteOnlyPropertyValue());
+
+    }
+
+    /** Tests that separate instances can register separate instances */
+    public void testSeparateInstances() throws Exception {
+        BeanUtilsBean utilsOne = new BeanUtilsBean(
+                                                new ConvertUtilsBean(), 
+                                                new PropertyUtilsBean());
+        BeanUtilsBean utilsTwo = new BeanUtilsBean(
+                                                new ConvertUtilsBean(), 
+                                                new PropertyUtilsBean());        
+        
+        
+        TestBean bean = new TestBean();
+        
+        // Make sure what we're testing works
+        bean.setBooleanProperty(false);
+        utilsOne.setProperty(bean, "booleanProperty", "true");
+        assertEquals("Set property failed (1)", bean.getBooleanProperty(), true);
+        
+        bean.setBooleanProperty(false);
+        utilsTwo.setProperty(bean, "booleanProperty", "true");
+        assertEquals("Set property failed (2)", bean.getBooleanProperty(), true);       
+        
+        // now change the registered conversion
+        
+        utilsOne.getConvertUtils().register(new ThrowExceptionConverter(), Boolean.TYPE);
+        try {
+            
+            bean.setBooleanProperty(false);
+            utilsOne.setProperty(bean, "booleanProperty", "true");
+            fail("Registered conversion not used.");
+            
+        } catch (PassTestException e) { /* Do nothing */ }
+        
+        // make sure that this conversion has no been registered in the other instance
+        try {
+        
+            bean.setBooleanProperty(false);
+            utilsTwo.setProperty(bean, "booleanProperty", "true");
+            assertEquals("Set property failed (3)", bean.getBooleanProperty(), true);
+            
+        } catch (PassTestException e) {
+            fail("Registed converter is used by other instances");
+        }
+    }
+
+    public void testArrayPropertyConversion() throws Exception {
+        BeanUtilsBean beanUtils = new BeanUtilsBean(	
+                                                    new ConvertUtilsBean(), 
+                                                    new PropertyUtilsBean());
+        beanUtils.getConvertUtils().register(
+            new Converter () {
+                public Object convert(Class type, Object value) {
+                    return "Spam, spam, spam, spam!";
+                }
+            },
+            String.class);
+            
+        TestBean bean = new TestBean();
+        String [] results = beanUtils.getArrayProperty(bean, "intArray");
+                
+        int[] values = bean.getIntArray();
+        assertEquals(
+                    "Converted array size not equal to property array size.",
+                    results.length,
+                    values.length);
+        for (int i=0, size=values.length ;  i<size; i++) {
+            assertEquals(
+                    "Value " + i + " incorrectly converted ", 
+                    "Spam, spam, spam, spam!",
+                    results[i]);
+        }
+    }
+
+    // Ensure that the actual int[] matches the expected int[]
+    protected void checkIntArray(int actual[], int expected[]) {
+        assertNotNull("actual array not null", actual);
+        assertEquals("actual array length", expected.length, actual.length);
+        for (int i = 0; i < actual.length; i++) {
+            assertEquals("actual array value[" + i + "]",
+                         expected[i], actual[i]);
+        }
+    }
+
+
+    // Ensure that the actual Map matches the expected Map
+    protected void checkMap(Map actual, Map expected) {
+        assertNotNull("actual map not null", actual);
+        assertEquals("actual map size", expected.size(), actual.size());
+        Iterator keys = expected.keySet().iterator();
+        while (keys.hasNext()) {
+            Object key = keys.next();
+            assertEquals("actual map value(" + key + ")",
+                         expected.get(key), actual.get(key));
+        }
+    }
+
+    public void testMappedProperty() throws Exception {
+        MappedPropertyTestBean bean = new MappedPropertyTestBean();
+        
+        BeanUtils.setProperty(bean, "mapproperty(this.that.the-other)", "some.dotty.value");
+        
+        assertEquals(
+                        "Mapped property set correctly", 
+                        "some.dotty.value", 
+                        bean.getMapproperty("this.that.the-other"));
+    }	
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanWithInnerBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanWithInnerBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanWithInnerBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+import java.util.Properties;
+
+/**
+ * Bean with inner bean.
+ *
+ * @author John E. Conlon
+ * @author Robert Burrell Donkin
+ */
+public class BeanWithInnerBean {
+  private InnerBean innerBean = new InnerBean();
+
+  public BeanWithInnerBean() {}
+    public InnerBean getInnerBean(){
+      return innerBean;
+    }
+
+  public class InnerBean {
+    private Properties fish = new Properties();
+
+    public String getFish(String key){
+      return fish.getProperty(key);
+    }
+    public void setFish(String key, String value){
+      fish.setProperty(key, value);
+    }
+  }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanificationTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanificationTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BeanificationTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,541 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+import java.util.*;
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.commons.collections.ReferenceMap;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>
+ * Test Case for changes made during Beanutils Beanification
+ * </p>
+ *
+ * @author Robert Burrell Donkin
+ * @author Juozas Baliuka
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class BeanificationTestCase extends TestCase {
+    
+    // ---------------------------------------------------- Constants
+    
+    /** Maximum number of iterations before our test fails */
+    public static final int MAX_GC_ITERATIONS = 50;
+    
+    // ---------------------------------------------------- Instance Variables
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public BeanificationTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        ConvertUtils.deregister();
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(BeanificationTestCase.class));
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        ;    // No action required
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+    
+    /** Test of the methodology we'll use for some of the later tests */
+    public void testMemoryTestMethodology() throws Exception {
+        // test methodology
+        // many thanks to Juozas Baliuka for suggesting this method
+        ClassLoader loader = new ClassLoader() {};
+        WeakReference reference = new  WeakReference(loader);
+        Class myClass = loader.loadClass("org.apache.commons.beanutils.BetaBean");
+        
+        assertNotNull("Weak reference released early", reference.get());
+        
+        // dereference class loader and class:
+        loader = null;
+        myClass = null;
+        
+        int iterations = 0;
+        int bytz = 2;
+        while(true) {
+            System.gc();
+            if(iterations++ > MAX_GC_ITERATIONS){
+                fail("Max iterations reached before resource released.");
+            }
+            if( reference.get() == null ) {
+                break;
+                
+            } else {
+                // create garbage:
+                byte[] b =  new byte[bytz];
+                bytz = bytz * 2;
+            }
+        }
+    }
+    
+    /** Tests whether classloaders and beans are released from memory by the map used by beanutils */
+    public void testMemoryLeak2() throws Exception {
+        // tests when the map used by beanutils has the right behaviour
+        
+        if (isPre14JVM()) {
+            System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
+            return;
+        }
+        
+        // many thanks to Juozas Baliuka for suggesting this methodology
+        TestClassLoader loader = new TestClassLoader();
+        ReferenceQueue queue = new ReferenceQueue();
+        WeakReference loaderReference = new WeakReference(loader, queue);
+        Integer test = new Integer(1);
+        
+        WeakReference testReference = new WeakReference(test, queue);
+        //Map map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD, true);
+        Map map = new WeakHashMap();
+        map.put(loader, test);
+        
+        assertEquals("In map", test, map.get(loader));
+        assertNotNull("Weak reference released early (1)", loaderReference.get());
+        assertNotNull("Weak reference released early (2)", testReference.get());
+        
+        // dereference strong references
+        loader = null;
+        test = null;
+        
+        int iterations = 0;
+        int bytz = 2;
+        while(true) {
+            System.gc();
+            if(iterations++ > MAX_GC_ITERATIONS){
+                fail("Max iterations reached before resource released.");
+            }
+            map.isEmpty();
+            
+            if( 
+                loaderReference.get() == null &&
+                testReference.get() == null) {
+                break;
+                
+            } else {
+                // create garbage:
+                byte[] b =  new byte[bytz];
+                bytz = bytz * 2;
+            }
+        }
+    }
+    
+    /** Tests whether classloaders and beans are released from memory */
+    public void testMemoryLeak() throws Exception {
+        if (isPre14JVM()) {
+            System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
+            return;
+        }
+        
+        // many thanks to Juozas Baliuka for suggesting this methodology
+        TestClassLoader loader = new TestClassLoader();
+        WeakReference loaderReference = new  WeakReference(loader);
+        BeanUtilsBean.getInstance();
+
+        class GetBeanUtilsBeanThread extends Thread {
+            
+            BeanUtilsBean beanUtils;
+            ConvertUtilsBean convertUtils;
+            PropertyUtilsBean propertyUtils;
+        
+            GetBeanUtilsBeanThread() {}
+            
+            public void run() {
+                beanUtils = BeanUtilsBean.getInstance();
+                convertUtils = ConvertUtilsBean.getInstance();
+                propertyUtils = PropertyUtilsBean.getInstance();
+                // XXX Log keeps a reference around!
+                LogFactory.releaseAll();
+            }
+            
+            public String toString() {
+                return "GetBeanUtilsBeanThread";
+            }
+        }
+        
+    
+        GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread();
+        WeakReference threadWeakReference = new WeakReference(thread);
+        thread.setContextClassLoader(loader);
+
+        thread.start();
+        thread.join();
+        
+        WeakReference beanUtilsReference = new WeakReference(thread.beanUtils);
+        WeakReference propertyUtilsReference =  new WeakReference(thread.propertyUtils);
+        WeakReference convertUtilsReference = new WeakReference(thread.convertUtils);
+        
+        assertNotNull("Weak reference released early (1)", loaderReference.get());
+        assertNotNull("Weak reference released early (2)", beanUtilsReference.get());
+        assertNotNull("Weak reference released early (3)", propertyUtilsReference.get());
+        assertNotNull("Weak reference released early (4)", convertUtilsReference.get());
+        
+        // dereference strong references
+        loader = null;
+        thread.setContextClassLoader(null);
+        thread = null;
+        
+        int iterations = 0;
+        int bytz = 2;
+        while(true) {
+            BeanUtilsBean.getInstance();
+            System.gc();
+            if(iterations++ > MAX_GC_ITERATIONS){
+                fail("Max iterations reached before resource released.");
+            }
+
+            if( 
+                loaderReference.get() == null &&
+                beanUtilsReference.get() == null && 
+                propertyUtilsReference.get() == null && 
+                convertUtilsReference.get() == null) {
+                break;
+                
+            } else {
+                // create garbage:
+                byte[] b =  new byte[bytz];
+                bytz = bytz * 2;
+            }
+        }
+    }
+    
+    /** 
+     * Tests whether difference instances are loaded by different 
+     * context classloaders.
+     */
+    public void testGetByContextClassLoader() throws Exception {
+            
+        class GetBeanUtilsBeanThread extends Thread {
+            
+            private Signal signal;
+        
+            GetBeanUtilsBeanThread(Signal signal) {
+                this.signal = signal;
+            }
+            
+            public void run() {
+                signal.setSignal(2);
+                signal.setBean(BeanUtilsBean.getInstance());
+                signal.setConvertUtils(ConvertUtilsBean.getInstance());
+                signal.setPropertyUtils(PropertyUtilsBean.getInstance());
+            }
+            
+            public String toString() {
+                return "GetBeanUtilsBeanThread";
+            }
+        }
+            
+        Signal signal = new Signal();
+        signal.setSignal(1);
+        
+        GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread(signal);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        thread.start();
+        thread.join();
+        
+        assertEquals("Signal not set by test thread", 2, signal.getSignal());
+        assertTrue(
+                    "Different BeanUtilsBean instances per context classloader", 
+                    BeanUtilsBean.getInstance() != signal.getBean());
+        assertTrue(
+                    "Different ConvertUtilsBean instances per context classloader", 
+                    ConvertUtilsBean.getInstance() != signal.getConvertUtils());                    
+        assertTrue(
+                    "Different PropertyUtilsBean instances per context classloader", 
+                    PropertyUtilsBean.getInstance() != signal.getPropertyUtils());        
+    }
+    
+    
+    /** 
+     * Tests whether difference instances are loaded by different 
+     * context classloaders.
+     */
+    public void testContextClassLoaderLocal() throws Exception {
+            
+        class CCLLTesterThread extends Thread {
+            
+            private Signal signal;
+            private ContextClassLoaderLocal ccll;
+        
+            CCLLTesterThread(Signal signal, ContextClassLoaderLocal ccll) {
+                this.signal = signal;
+                this.ccll = ccll;
+            }
+            
+            public void run() {
+                ccll.set(new Integer(1789));
+                signal.setSignal(2);
+                signal.setMarkerObject(ccll.get());
+            }
+            
+            public String toString() {
+                return "CCLLTesterThread";
+            }
+        }
+            
+        ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
+        ccll.set(new Integer(1776));
+        assertEquals("Start thread sets value", new Integer(1776), ccll.get());  
+        
+        Signal signal = new Signal();
+        signal.setSignal(1);
+        
+        CCLLTesterThread thread = new CCLLTesterThread(signal, ccll);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        thread.start();
+        thread.join();
+        
+        assertEquals("Signal not set by test thread", 2, signal.getSignal());     
+        assertEquals("Second thread preserves value", new Integer(1776), ccll.get()); 
+        assertEquals("Second thread gets value it set", new Integer(1789), signal.getMarkerObject()); 
+    }
+    
+    /** Tests whether calls are independent for different classloaders */
+    public void testContextClassloaderIndependence() throws Exception {
+    
+        class TestIndependenceThread extends Thread {
+            private Signal signal;
+            private PrimitiveBean bean;
+        
+            TestIndependenceThread(Signal signal, PrimitiveBean bean) {
+                this.signal = signal;
+                this.bean = bean;
+            }
+            
+            public void run() {
+                try {
+                    signal.setSignal(3);
+                    ConvertUtils.register(new Converter() {
+                                            public Object convert(Class type, Object value) {
+                                                return new Integer(9);
+                                            }
+                                                }, Integer.TYPE);
+                    BeanUtils.setProperty(bean, "int", new Integer(1));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    signal.setException(e);
+                }
+            }
+            
+            public String toString() {
+                return "TestIndependenceThread";
+            }
+        }
+        
+        PrimitiveBean bean = new PrimitiveBean();
+        BeanUtils.setProperty(bean, "int", new Integer(1));
+        assertEquals("Wrong property value (1)", 1, bean.getInt());
+
+        ConvertUtils.register(new Converter() {
+                                public Object convert(Class type, Object value) {
+                                    return new Integer(5);
+                                }
+                                    }, Integer.TYPE);
+        BeanUtils.setProperty(bean, "int", new Integer(1));
+        assertEquals("Wrong property value(2)", 5, bean.getInt());
+    
+        Signal signal = new Signal();
+        signal.setSignal(1);
+        TestIndependenceThread thread = new TestIndependenceThread(signal, bean);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        thread.start();
+        thread.join();
+        
+        assertNull("Exception thrown by test thread:" + signal.getException(), signal.getException());
+        assertEquals("Signal not set by test thread", 3, signal.getSignal());
+        assertEquals("Wrong property value(3)", 9, bean.getInt());
+        
+    }
+    
+    /** Tests whether different threads can set beanutils instances correctly */
+    public void testBeanUtilsBeanSetInstance() throws Exception {
+            
+        class SetInstanceTesterThread extends Thread {
+            
+            private Signal signal;
+            private BeanUtilsBean bean;
+        
+            SetInstanceTesterThread(Signal signal, BeanUtilsBean bean) {
+                this.signal = signal;
+                this.bean = bean;
+            }
+            
+            public void run() {
+                BeanUtilsBean.setInstance(bean);
+                signal.setSignal(21);
+                signal.setBean(BeanUtilsBean.getInstance());
+            }
+            
+            public String toString() {
+                return "SetInstanceTesterThread";
+            }
+        }
+        
+        Signal signal = new Signal();
+        signal.setSignal(1);
+
+        BeanUtilsBean beanOne = new BeanUtilsBean();
+        BeanUtilsBean beanTwo = new BeanUtilsBean();
+        
+        SetInstanceTesterThread thread = new SetInstanceTesterThread(signal, beanTwo);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        BeanUtilsBean.setInstance(beanOne);
+        assertEquals("Start thread gets right instance", beanOne, BeanUtilsBean.getInstance()); 
+        
+        thread.start();
+        thread.join();
+        
+        assertEquals("Signal not set by test thread", 21, signal.getSignal());     
+        assertEquals("Second thread preserves value", beanOne, BeanUtilsBean.getInstance()); 
+        assertEquals("Second thread gets value it set", beanTwo, signal.getBean()); 
+    }
+    
+    /** Tests whether the unset method works*/
+    public void testContextClassLoaderUnset() throws Exception {
+        BeanUtilsBean beanOne = new BeanUtilsBean();
+        ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
+        ccll.set(beanOne);
+        assertEquals("Start thread gets right instance", beanOne, ccll.get()); 
+        ccll.unset();
+        assertTrue("Unset works", !beanOne.equals(ccll.get())); 
+    }
+    
+    private boolean isPre14JVM() {
+        // some pre 1.4 JVM have buggy WeakHashMap implementations 
+        // this is used to test for those JVM
+        String version = System.getProperty("java.specification.version");
+        StringTokenizer tokenizer = new StringTokenizer(version,".");
+        if (tokenizer.nextToken().equals("1")) {
+            String minorVersion = tokenizer.nextToken();
+            if (minorVersion.equals("0")) return true;
+            if (minorVersion.equals("1")) return true;
+            if (minorVersion.equals("2")) return true;
+            if (minorVersion.equals("3")) return true;
+        }
+        return false;
+    }
+    
+    // ---- Auxillary classes
+    
+    class TestClassLoader extends ClassLoader {
+        public String toString() {
+            return "TestClassLoader";
+        }
+    }
+    
+    class Signal {
+        private Exception e;
+        private int signal = 0;
+        private BeanUtilsBean bean;
+        private PropertyUtilsBean propertyUtils;
+        private ConvertUtilsBean convertUtils;
+        private Object marker;
+        
+        public Exception getException() {
+            return e;
+        }
+        
+        public void setException(Exception e) {
+            this.e = e;
+        }
+        
+        public int getSignal() {
+            return signal;
+        }
+        
+        public void setSignal(int signal) {
+            this.signal = signal;
+        }
+        
+        public Object getMarkerObject() {
+            return marker;
+        }
+        
+        public void setMarkerObject(Object marker) {
+            this.marker = marker;
+        }
+        
+        public BeanUtilsBean getBean() {
+            return bean;
+        }
+        
+        public void setBean(BeanUtilsBean bean) {
+            this.bean = bean;
+        }
+        
+        public PropertyUtilsBean getPropertyUtils() {
+            return propertyUtils;
+        }
+        
+        public void setPropertyUtils(PropertyUtilsBean propertyUtils) {
+            this.propertyUtils = propertyUtils;
+        }
+        
+        public ConvertUtilsBean getConvertUtils() {
+            return convertUtils;
+        }
+        
+        public void setConvertUtils(ConvertUtilsBean convertUtils) {
+            this.convertUtils = convertUtils;
+        }
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BenchBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BenchBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BenchBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * Plain old java bean (POJO) for microbenchmarks.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class BenchBean {
+
+
+    // -------------------------------------------------------------- Properties
+
+
+    /**
+     * A boolean property.
+     */
+    private boolean booleanProperty = true;
+
+    public boolean getBooleanProperty() {
+        return (booleanProperty);
+    }
+
+    public void setBooleanProperty(boolean booleanProperty) {
+        this.booleanProperty = booleanProperty;
+    }
+
+
+    /**
+     * A byte property.
+     */
+    private byte byteProperty = (byte) 121;
+
+    public byte getByteProperty() {
+        return (this.byteProperty);
+    }
+
+    public void setByteProperty(byte byteProperty) {
+        this.byteProperty = byteProperty;
+    }
+
+
+    /**
+     * A double property.
+     */
+    private double doubleProperty = 321.0;
+
+    public double getDoubleProperty() {
+        return (this.doubleProperty);
+    }
+
+    public void setDoubleProperty(double doubleProperty) {
+        this.doubleProperty = doubleProperty;
+    }
+
+
+    /**
+     * A float property.
+     */
+    private float floatProperty = (float) 123.0;
+
+    public float getFloatProperty() {
+        return (this.floatProperty);
+    }
+
+    public void setFloatProperty(float floatProperty) {
+        this.floatProperty = floatProperty;
+    }
+
+
+    /**
+     * An integer property.
+     */
+    private int intProperty = 123;
+
+    public int getIntProperty() {
+        return (this.intProperty);
+    }
+
+    public void setIntProperty(int intProperty) {
+        this.intProperty = intProperty;
+    }
+
+
+    /**
+     * A long property.
+     */
+    private long longProperty = 321;
+
+    public long getLongProperty() {
+        return (this.longProperty);
+    }
+
+    public void setLongProperty(long longProperty) {
+        this.longProperty = longProperty;
+    }
+
+
+    /**
+     * A short property.
+     */
+    private short shortProperty = (short) 987;
+
+    public short getShortProperty() {
+        return (this.shortProperty);
+    }
+
+    public void setShortProperty(short shortProperty) {
+        this.shortProperty = shortProperty;
+    }
+
+
+    /**
+     * A String property.
+     */
+    private String stringProperty = "This is a string";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BetaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BetaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/BetaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+public class BetaBean extends AbstractChild {
+    
+    private String secret = "utah";
+    
+    public String getSecret() {
+        return secret;
+    }
+    
+    public void setNoGetterProperty(String secret) {
+        this.secret = secret;
+    }
+    
+    public void setNoGetterMappedProperty(String secret, String key) {
+        this.secret = "MAP:" + secret;
+    }
+    
+    public BetaBean(String name) {
+        setName(name);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/Child.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/Child.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/Child.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+public interface Child {
+    
+    public String getName();
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConstructorUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConstructorUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConstructorUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p> Test case for <code>ConstructorUtils</code> </p>
+ *
+ */
+public class ConstructorUtilsTestCase extends TestCase {
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public ConstructorUtilsTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(ConstructorUtilsTestCase.class));
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+    public void testInvokeConstructor() throws Exception {
+        {
+            Object obj = ConstructorUtils.invokeConstructor(TestBean.class,"TEST");
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+        {
+            Object obj = ConstructorUtils.invokeConstructor(TestBean.class,new Float(17.3f));
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(17.3f,((TestBean)obj).getFloatProperty(),0.0f);
+        }
+    }
+
+    public void testInvokeConstructorWithArgArray() throws Exception {
+        Object[] args = { new Float(17.3f), "TEST" };
+        Object obj = ConstructorUtils.invokeConstructor(TestBean.class,args);
+        assertNotNull(obj);
+        assertTrue(obj instanceof TestBean);
+        assertEquals(17.3f,((TestBean)obj).getFloatProperty(),0.0f);
+        assertEquals("TEST",((TestBean)obj).getStringProperty());
+    }
+
+    public void testInvokeConstructorWithTypeArray() throws Exception {
+        {
+            Object[] args = { Boolean.TRUE, "TEST" };
+            Class[] types = { Boolean.TYPE, String.class };
+            Object obj = ConstructorUtils.invokeConstructor(TestBean.class,args,types);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(true,((TestBean)obj).getBooleanProperty());
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+        {
+            Object[] args = { Boolean.TRUE, "TEST" };
+            Class[] types = { Boolean.class, String.class };
+            Object obj = ConstructorUtils.invokeConstructor(TestBean.class,args,types);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(true,((TestBean)obj).isBooleanSecond());
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+    }
+
+    public void testInvokeExactConstructor() throws Exception {
+        {
+            Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,"TEST");
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+        {
+            try {
+                Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,new Float(17.3f));
+                fail("Expected NoSuchMethodException");
+            } catch(NoSuchMethodException e) {
+                // expected
+            }
+        }
+        {
+            Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,Boolean.TRUE);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(true,((TestBean)obj).isBooleanSecond());
+        }
+    }
+
+    public void testInvokeExactConstructorWithArgArray() throws Exception {
+        {
+            Object[] args = { new Float(17.3f), "TEST" };
+            try {
+                Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,args);
+                fail("Expected NoSuchMethodException");
+            } catch(NoSuchMethodException e) {
+                // expected
+            }
+        }
+        {
+            Object[] args = { Boolean.TRUE, "TEST" };
+            Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,args);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(true,((TestBean)obj).isBooleanSecond());
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+    }
+    
+    public void testInvokeExactConstructorWithTypeArray() throws Exception {
+        {
+            Object[] args = { Boolean.TRUE, "TEST" };
+            Class[] types = { Boolean.TYPE, String.class };
+            Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,args,types);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(true,((TestBean)obj).getBooleanProperty());
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+        {
+            Object[] args = { Boolean.TRUE, "TEST" };
+            Class[] types = { Boolean.class, String.class };
+            Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,args,types);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(true,((TestBean)obj).isBooleanSecond());
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+        {
+            Object[] args = { new Float(17.3f), "TEST" };
+            Class[] types = { Float.TYPE, String.class };
+            Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,args,types);
+            assertNotNull(obj);
+            assertTrue(obj instanceof TestBean);
+            assertEquals(17.3f,((TestBean)obj).getFloatProperty(),0.0f);
+            assertEquals("TEST",((TestBean)obj).getStringProperty());
+        }
+        {
+            Object[] args = { new Float(17.3f), "TEST" };
+            Class[] types = { Float.class, String.class };
+            try {
+                Object obj = ConstructorUtils.invokeExactConstructor(TestBean.class,args,types);
+                fail("Expected NoSuchMethodException");
+            } catch(NoSuchMethodException e) {
+                // expected
+            }
+        }
+    }
+
+    public void testGetAccessibleConstructor() throws Exception {
+        {
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(TestBean.class,String.class);       
+            assertNotNull(ctor);
+            assertTrue(Modifier.isPublic(ctor.getModifiers()));
+        }
+        {
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(TestBean.class,Integer.class);       
+            assertNotNull(ctor);
+            assertTrue(Modifier.isPublic(ctor.getModifiers()));
+        }
+        {
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(TestBean.class,Integer.TYPE);       
+            assertNull(ctor);
+        }
+    }
+
+    public void testGetAccessibleConstructorWithTypeArray() throws Exception {
+        {
+            Class[] types = { Boolean.TYPE, String.class };
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(TestBean.class,types);       
+            assertNotNull(ctor);
+            assertTrue(Modifier.isPublic(ctor.getModifiers()));
+        }
+        {
+            Class[] types = { Boolean.TYPE, Boolean.TYPE, String.class };
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(TestBean.class,types);       
+            assertNull(ctor);
+        }
+    }
+
+    public void testGetAccessibleConstructorWithConstructorArg() throws Exception {
+        {
+            Class[] types = { Integer.class };
+            Constructor c1 = TestBean.class.getConstructor(types);
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(c1);       
+            assertNotNull(ctor);
+            assertTrue(Modifier.isPublic(ctor.getModifiers()));
+        }
+        {
+            Class[] types = { Integer.class };
+            Constructor c1 = TestBean.class.getDeclaredConstructor(types);
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(c1);       
+            assertNotNull(ctor);
+            assertTrue(Modifier.isPublic(ctor.getModifiers()));
+        }
+        {
+            Class[] types = { Integer.TYPE };
+            Constructor c1 = TestBean.class.getDeclaredConstructor(types);
+            Constructor ctor = ConstructorUtils.getAccessibleConstructor(c1);       
+            assertNull(ctor);
+        }
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConvertUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConvertUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ConvertUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,654 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.HashMap;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.commons.beanutils.converters.BooleanConverter;
+
+
+/**
+ * <p>
+ *  Test Case for the ConvertUtils class.
+ * </p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.10 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class ConvertUtilsTestCase extends TestCase {
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public ConvertUtilsTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        ConvertUtils.deregister();
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(ConvertUtilsTestCase.class));
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        ;    // No action required
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Negative String to primitive integer array tests.
+     */
+    public void testNegativeIntegerArray() {
+
+        Object value = null;
+        int intArray[] = new int[0];
+
+        value = ConvertUtils.convert((String) null, intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = ConvertUtils.convert("a", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = ConvertUtils.convert("{ a }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = ConvertUtils.convert("1a3", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = ConvertUtils.convert("{ 1a3 }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = ConvertUtils.convert("0,1a3", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = ConvertUtils.convert("{ 0, 1a3 }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+
+
+    }
+
+
+    /**
+     * Negative scalar conversion tests.  These rely on the standard
+     * default value conversions in ConvertUtils.
+     */
+    public void testNegativeScalar() {
+
+        Object value = null;
+
+        value = ConvertUtils.convert("foo", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("foo", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("foo", Byte.TYPE);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 0);
+
+        value = ConvertUtils.convert("foo", Byte.class);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 0);
+
+        try {
+            value = ConvertUtils.convert
+                ("org.apache.commons.beanutils.Undefined", Class.class);
+            fail("Should have thrown conversion exception");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        value = ConvertUtils.convert("foo", Double.TYPE);
+        assertTrue(value instanceof Double);
+        assertEquals(((Double) value).doubleValue(), (double) 0.0,
+                     (double) 0.005);
+
+        value = ConvertUtils.convert("foo", Double.class);
+        assertTrue(value instanceof Double);
+        assertEquals(((Double) value).doubleValue(), (double) 0.0,
+                     (double) 0.005);
+
+        value = ConvertUtils.convert("foo", Float.TYPE);
+        assertTrue(value instanceof Float);
+        assertEquals(((Float) value).floatValue(), (float) 0.0,
+                     (float) 0.005);
+
+        value = ConvertUtils.convert("foo", Float.class);
+        assertTrue(value instanceof Float);
+        assertEquals(((Float) value).floatValue(), (float) 0.0,
+                     (float) 0.005);
+
+        value = ConvertUtils.convert("foo", Integer.TYPE);
+        assertTrue(value instanceof Integer);
+        assertEquals(((Integer) value).intValue(), (int) 0);
+
+        value = ConvertUtils.convert("foo", Integer.class);
+        assertTrue(value instanceof Integer);
+        assertEquals(((Integer) value).intValue(), (int) 0);
+
+        value = ConvertUtils.convert("foo", Byte.TYPE);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 0);
+
+        value = ConvertUtils.convert("foo", Long.class);
+        assertTrue(value instanceof Long);
+        assertEquals(((Long) value).longValue(), (long) 0);
+
+        value = ConvertUtils.convert("foo", Short.TYPE);
+        assertTrue(value instanceof Short);
+        assertEquals(((Short) value).shortValue(), (short) 0);
+
+        value = ConvertUtils.convert("foo", Short.class);
+        assertTrue(value instanceof Short);
+        assertEquals(((Short) value).shortValue(), (short) 0);
+
+    }
+
+
+    /**
+     * Negative String to String array tests.
+     */
+    public void testNegativeStringArray() {
+
+        Object value = null;
+        String stringArray[] = new String[0];
+
+        value = ConvertUtils.convert((String) null, stringArray.getClass());
+        checkStringArray(value, stringArray);
+
+    }
+
+
+    /**
+     * Test conversion of object to string for arrays.
+     */
+    public void testObjectToStringArray() {
+
+        int intArray0[] = new int[0];
+        int intArray1[] = { 123 };
+        int intArray2[] = { 123, 456 };
+        String stringArray0[] = new String[0];
+        String stringArray1[] = { "abc" };
+        String stringArray2[] = { "abc", "def" };
+
+        assertEquals("intArray0", null,
+                     ConvertUtils.convert(intArray0));
+        assertEquals("intArray1", "123",
+                     ConvertUtils.convert(intArray1));
+        assertEquals("intArray2", "123",
+                     ConvertUtils.convert(intArray2));
+
+        assertEquals("stringArray0", null,
+                     ConvertUtils.convert(stringArray0));
+        assertEquals("stringArray1", "abc",
+                     ConvertUtils.convert(stringArray1));
+        assertEquals("stringArray2", "abc",
+                     ConvertUtils.convert(stringArray2));
+
+    }
+
+
+    /**
+     * Test conversion of object to string for scalars.
+     */
+    public void testObjectToStringScalar() {
+
+        assertEquals("Boolean->String", "false",
+                     ConvertUtils.convert(Boolean.FALSE));
+        assertEquals("Boolean->String", "true",
+                     ConvertUtils.convert(Boolean.TRUE));
+        assertEquals("Byte->String", "123",
+                     ConvertUtils.convert(new Byte((byte) 123)));
+        assertEquals("Character->String", "a",
+                     ConvertUtils.convert(new Character('a')));
+        assertEquals("Double->String", "123.0",
+                     ConvertUtils.convert(new Double((double) 123.0)));
+        assertEquals("Float->String", "123.0",
+                     ConvertUtils.convert(new Float((float) 123.0)));
+        assertEquals("Integer->String", "123",
+                     ConvertUtils.convert(new Integer((int) 123)));
+        assertEquals("Long->String", "123",
+                     ConvertUtils.convert(new Long((long) 123)));
+        assertEquals("Short->String", "123",
+                     ConvertUtils.convert(new Short((short) 123)));
+        assertEquals("String->String", "abc",
+                     ConvertUtils.convert("abc"));
+        assertEquals("String->String null", null,
+                     ConvertUtils.convert(null));
+
+    }
+
+
+    /**
+     * Positive array conversion tests.
+     */
+    public void testPositiveArray() {
+
+        String values1[] = { "10", "20", "30" };
+        Object value = ConvertUtils.convert(values1, Integer.TYPE);
+        int shape[] = new int[0];
+        assertEquals(shape.getClass(), value.getClass());
+        int results1[] = (int[]) value;
+        assertEquals(results1[0], 10);
+        assertEquals(results1[1], 20);
+        assertEquals(results1[2], 30);
+
+        String values2[] = { "100", "200", "300" };
+        value = ConvertUtils.convert(values2, shape.getClass());
+        assertEquals(shape.getClass(), value.getClass());
+        int results2[] = (int[]) value;
+        assertEquals(results2[0], 100);
+        assertEquals(results2[1], 200);
+        assertEquals(results2[2], 300);
+
+    }
+
+
+    /**
+     * Positive String to primitive integer array tests.
+     */
+    public void testPositiveIntegerArray() {
+
+        Object value = null;
+        int intArray[] = new int[0];
+        int intArray1[] = new int[] { 0 };
+        int intArray2[] = new int[] { 0, 10 };
+
+        value = ConvertUtils.convert("{  }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+
+        value = ConvertUtils.convert("0", intArray.getClass());
+        checkIntegerArray(value, intArray1);
+        value = ConvertUtils.convert(" 0 ", intArray.getClass());
+        checkIntegerArray(value, intArray1);
+        value = ConvertUtils.convert("{ 0 }", intArray.getClass());
+        checkIntegerArray(value, intArray1);
+
+        value = ConvertUtils.convert("0,10", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = ConvertUtils.convert("0 10", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = ConvertUtils.convert("{0,10}", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = ConvertUtils.convert("{0 10}", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = ConvertUtils.convert("{ 0, 10 }", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = ConvertUtils.convert("{ 0 10 }", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+
+    }
+
+
+    /**
+     * Positive scalar conversion tests.
+     */
+    public void testPositiveScalar() {
+
+        Object value = null;
+
+        value = ConvertUtils.convert("true", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("true", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("yes", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("yes", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("y", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("y", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("on", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("on", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), true);
+
+        value = ConvertUtils.convert("false", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("false", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("no", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("no", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("n", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("n", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("off", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("off", Boolean.class);
+        assertTrue(value instanceof Boolean);
+        assertEquals(((Boolean) value).booleanValue(), false);
+
+        value = ConvertUtils.convert("123", Byte.TYPE);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 123);
+
+        value = ConvertUtils.convert("123", Byte.class);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 123);
+
+        value = ConvertUtils.convert("a", Character.TYPE);
+        assertTrue(value instanceof Character);
+        assertEquals(((Character) value).charValue(), 'a');
+
+        value = ConvertUtils.convert("a", Character.class);
+        assertTrue(value instanceof Character);
+        assertEquals(((Character) value).charValue(), 'a');
+
+        value = ConvertUtils.convert("java.lang.String", Class.class);
+        assertTrue(value instanceof Class);
+        assertEquals(String.class, (Class) value);
+
+        value = ConvertUtils.convert("123.456", Double.TYPE);
+        assertTrue(value instanceof Double);
+        assertEquals(((Double) value).doubleValue(), (double) 123.456,
+                     (double) 0.005);
+
+        value = ConvertUtils.convert("123.456", Double.class);
+        assertTrue(value instanceof Double);
+        assertEquals(((Double) value).doubleValue(), (double) 123.456,
+                     (double) 0.005);
+
+        value = ConvertUtils.convert("123.456", Float.TYPE);
+        assertTrue(value instanceof Float);
+        assertEquals(((Float) value).floatValue(), (float) 123.456,
+                     (float) 0.005);
+
+        value = ConvertUtils.convert("123.456", Float.class);
+        assertTrue(value instanceof Float);
+        assertEquals(((Float) value).floatValue(), (float) 123.456,
+                     (float) 0.005);
+
+        value = ConvertUtils.convert("123", Integer.TYPE);
+        assertTrue(value instanceof Integer);
+        assertEquals(((Integer) value).intValue(), (int) 123);
+
+        value = ConvertUtils.convert("123", Integer.class);
+        assertTrue(value instanceof Integer);
+        assertEquals(((Integer) value).intValue(), (int) 123);
+
+        value = ConvertUtils.convert("123", Long.TYPE);
+        assertTrue(value instanceof Long);
+        assertEquals(((Long) value).longValue(), (long) 123);
+
+        value = ConvertUtils.convert("123", Long.class);
+        assertTrue(value instanceof Long);
+        assertEquals(((Long) value).longValue(), (long) 123);
+
+        value = ConvertUtils.convert("123", Short.TYPE);
+        assertTrue(value instanceof Short);
+        assertEquals(((Short) value).shortValue(), (short) 123);
+
+        value = ConvertUtils.convert("123", Short.class);
+        assertTrue(value instanceof Short);
+        assertEquals(((Short) value).shortValue(), (short) 123);
+
+        String input = null;
+
+        input = "2002-03-17";
+        value = ConvertUtils.convert(input, Date.class);
+        assertTrue(value instanceof Date);
+        assertEquals(input, value.toString());
+
+        input = "20:30:40";
+        value = ConvertUtils.convert(input, Time.class);
+        assertTrue(value instanceof Time);
+        assertEquals(input, value.toString());
+
+        input = "2002-03-17 20:30:40.0";
+        value = ConvertUtils.convert(input, Timestamp.class);
+        assertTrue(value instanceof Timestamp);
+        assertEquals(input, value.toString());
+
+    }
+
+
+    /**
+     * Positive String to String array tests.
+     */
+    public void testPositiveStringArray() {
+
+        Object value = null;
+        String stringArray[] = new String[0];
+        String stringArray1[] = new String[]
+            { "abc" };
+        String stringArray2[] = new String[]
+            { "abc", "de,f" };
+
+        value = ConvertUtils.convert("", stringArray.getClass());
+        checkStringArray(value, stringArray);
+        value = ConvertUtils.convert(" ", stringArray.getClass());
+        checkStringArray(value, stringArray);
+        value = ConvertUtils.convert("{}", stringArray.getClass());
+        checkStringArray(value, stringArray);
+        value = ConvertUtils.convert("{  }", stringArray.getClass());
+        checkStringArray(value, stringArray);
+
+        value = ConvertUtils.convert("abc", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = ConvertUtils.convert("{abc}", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = ConvertUtils.convert("\"abc\"", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = ConvertUtils.convert("{\"abc\"}", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = ConvertUtils.convert("'abc'", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = ConvertUtils.convert("{'abc'}", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+
+        value = ConvertUtils.convert("abc 'de,f'",
+                                     stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = ConvertUtils.convert("{abc, 'de,f'}",
+                                     stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = ConvertUtils.convert("\"abc\",\"de,f\"",
+                                     stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = ConvertUtils.convert("{\"abc\" 'de,f'}",
+                                     stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = ConvertUtils.convert("'abc' 'de,f'",
+                                     stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = ConvertUtils.convert("{'abc', \"de,f\"}",
+                                     stringArray.getClass());
+        checkStringArray(value, stringArray2);
+
+
+    }
+
+    public void testSeparateConvertInstances() throws Exception {
+        ConvertUtilsBean utilsOne = new ConvertUtilsBean();
+        ConvertUtilsBean utilsTwo = new ConvertUtilsBean();
+
+        // make sure that the test work ok before anything's changed
+        Object
+        value = utilsOne.convert("true", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(
+                    "Standard conversion failed (1)",
+                    ((Boolean) value).booleanValue(),
+                    true);
+
+        value = utilsTwo.convert("true", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(
+                    "Standard conversion failed (2)",
+                    ((Boolean) value).booleanValue(),
+                    true);
+
+        // now register a test
+
+        utilsOne.register(new ThrowExceptionConverter(), Boolean.TYPE);
+        try {
+
+            utilsOne.convert("true", Boolean.TYPE);
+            fail("Register converter failed.");
+
+        } catch (PassTestException e) { /* This shows that the registration has worked */ }
+
+        try {
+            // nothing should have changed
+            value = utilsTwo.convert("true", Boolean.TYPE);
+            assertTrue(value instanceof Boolean);
+            assertEquals(
+                        "Standard conversion failed (3)",
+                        ((Boolean) value).booleanValue(),
+                        true);
+
+        } catch (PassTestException e) {
+            // This is a failure since utilsTwo should still have
+            // standard converters registered
+            fail("Registering a converter for an instance should not effect another instance.");
+        }
+
+        // nothing we'll test deregister
+        utilsOne.deregister();
+        value = utilsOne.convert("true", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals("Instance deregister failed.", ((Boolean) value).booleanValue(), true);
+
+        value = utilsTwo.convert("true", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(
+                    "Standard conversion failed (4)",
+                    ((Boolean) value).booleanValue(),
+                    true);
+    }
+
+    public void testDeregisteringSingleConverter() throws Exception {
+        ConvertUtils convertUtils = new ConvertUtils();
+
+        // make sure that the test work ok before anything's changed
+        Object
+        value = convertUtils.convert("true", Boolean.TYPE);
+        assertTrue(value instanceof Boolean);
+        assertEquals(
+                    "Standard conversion failed (1)",
+                    ((Boolean) value).booleanValue(),
+                    true);
+
+        // we'll test deregister
+        convertUtils.deregister(Boolean.TYPE);
+        assertNull("Converter should be null",convertUtils.lookup(Boolean.TYPE));
+
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+
+    private void checkIntegerArray(Object value, int intArray[]) {
+
+        assertNotNull("Returned value is not null", value);
+        assertEquals("Returned value is int[]",
+                     intArray.getClass(), value.getClass());
+        int results[] = (int[]) value;
+        assertEquals("Returned array length", intArray.length, results.length);
+        for (int i = 0; i < intArray.length; i++) {
+            assertEquals("Returned array value " + i,
+                         intArray[i], results[i]);
+        }
+
+    }
+
+
+    private void checkStringArray(Object value, String stringArray[]) {
+
+        assertNotNull("Returned value is not null", value);
+        assertEquals("Returned value is String[]",
+                     stringArray.getClass(), value.getClass());
+        String results[] = (String[]) value;
+        assertEquals("Returned array length",
+                     stringArray.length, results.length);
+        for (int i = 0; i < stringArray.length; i++) {
+            assertEquals("Returned array value " + i,
+                         stringArray[i], results[i]);
+        }
+
+    }
+
+
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaBeanUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaBeanUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaBeanUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,1266 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * Test case for BeanUtils when the underlying bean is actually a DynaBean.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.22 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class DynaBeanUtilsTestCase extends TestCase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The basic test bean for each test.
+     */
+    protected DynaBean bean = null;
+
+
+    /**
+     * The nested bean pointed at by the "nested" property.
+     */
+    protected TestBean nested = null;
+
+
+    /**
+     * The set of properties that should be described.
+     */
+    protected String describes[] =
+    { "booleanProperty",
+      "booleanSecond",
+      "byteProperty",
+      "doubleProperty",
+      "dupProperty",
+      "floatProperty",
+      "intArray",
+      "intIndexed",
+      "intProperty",
+      "listIndexed",
+      "longProperty",
+      "mapProperty",
+      "mappedProperty",
+      "mappedIntProperty",
+      "nested",
+      "nullProperty",
+      //      "readOnlyProperty",
+      "shortProperty",
+      "stringArray",
+      "stringIndexed",
+      "stringProperty"
+    };
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public DynaBeanUtilsTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        // Instantiate a new DynaBean instance
+        DynaClass dynaClass = createDynaClass();
+        bean = dynaClass.newInstance();
+
+        // Initialize the DynaBean's property values (like TestBean)
+        bean.set("booleanProperty", new Boolean(true));
+        bean.set("booleanSecond", new Boolean(true));
+        bean.set("byteProperty", new Byte((byte) 121));
+        bean.set("doubleProperty", new Double(321.0));
+        bean.set("floatProperty", new Float((float) 123.0));
+        String dupProperty[] = { "Dup 0", "Dup 1", "Dup 2", "Dup 3", "Dup 4"};
+        bean.set("dupProperty", dupProperty);
+        int intArray[] = { 0, 10, 20, 30, 40 };
+        bean.set("intArray", intArray);
+        int intIndexed[] = { 0, 10, 20, 30, 40 };
+        bean.set("intIndexed", intIndexed);
+        bean.set("intProperty", new Integer(123));
+        List listIndexed = new ArrayList();
+        listIndexed.add("String 0");
+        listIndexed.add("String 1");
+        listIndexed.add("String 2");
+        listIndexed.add("String 3");
+        listIndexed.add("String 4");
+        bean.set("listIndexed", listIndexed);
+        bean.set("longProperty", new Long((long) 321));
+        HashMap mapProperty = new HashMap();
+        mapProperty.put("First Key", "First Value");
+        mapProperty.put("Second Key", "Second Value");
+        bean.set("mapProperty", mapProperty);
+        HashMap mappedProperty = new HashMap();
+        mappedProperty.put("First Key", "First Value");
+        mappedProperty.put("Second Key", "Second Value");
+        bean.set("mappedProperty", mappedProperty);
+        HashMap mappedIntProperty = new HashMap();
+        mappedIntProperty.put("One", new Integer(1));
+        mappedIntProperty.put("Two", new Integer(2));
+        bean.set("mappedIntProperty", mappedIntProperty);
+        nested = new TestBean();
+        bean.set("nested", nested);
+        // Property "nullProperty" is not initialized, so it should return null
+        bean.set("shortProperty", new Short((short) 987));
+        String stringArray[] =
+                { "String 0", "String 1", "String 2", "String 3", "String 4" };
+        bean.set("stringArray", stringArray);
+        String stringIndexed[] =
+                { "String 0", "String 1", "String 2", "String 3", "String 4" };
+        bean.set("stringIndexed", stringIndexed);
+        bean.set("stringProperty", "This is a string");
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(DynaBeanUtilsTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        bean = null;
+        nested = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+    /**
+     * Test the cloneBean() method from a DynaBean.
+     */
+    public void testCloneDynaBean() {
+
+        // Set up an origin bean with customized properties
+        DynaClass dynaClass = DynaBeanUtilsTestCase.createDynaClass();
+        DynaBean orig = null;
+        try {
+            orig = dynaClass.newInstance();
+        } catch (Exception e) {
+            fail("newInstance(): " + e);
+        }
+        orig.set("booleanProperty", Boolean.FALSE);
+        orig.set("byteProperty", new Byte((byte)111));
+        orig.set("doubleProperty", new Double(333.33));
+        orig.set("dupProperty", new String[] { "New 0", "New 1", "New 2" });
+        orig.set("intArray", new int[] { 100, 200, 300 });
+        orig.set("intProperty", new Integer(333));
+        orig.set("longProperty", new Long(3333));
+        orig.set("shortProperty", new Short((short) 33));
+        orig.set("stringArray", new String[] { "New 0", "New 1" });
+        orig.set("stringProperty", "Custom string");
+
+        // Copy the origin bean to our destination test bean
+        DynaBean clonedBean = null;
+        try {
+            clonedBean = (DynaBean) BeanUtils.cloneBean(orig);
+        } catch (Exception e) {
+            fail("Threw exception: " + e);
+        }
+
+        // Validate the results for scalar properties
+        assertEquals("Cloned boolean property",
+                     false,
+                     ((Boolean) clonedBean.get("booleanProperty")).booleanValue());
+        assertEquals("Cloned byte property",
+                     (byte) 111,
+                     ((Byte) clonedBean.get("byteProperty")).byteValue());
+        assertEquals("Cloned double property",
+                     333.33,
+                     ((Double) clonedBean.get("doubleProperty")).doubleValue(),
+                     0.005);
+        assertEquals("Cloned int property",
+                     333,
+                     ((Integer) clonedBean.get("intProperty")).intValue());
+        assertEquals("Cloned long property",
+                     (long) 3333,
+                     ((Long) clonedBean.get("longProperty")).longValue());
+        assertEquals("Cloned short property",
+                     (short) 33,
+                     ((Short) clonedBean.get("shortProperty")).shortValue());
+        assertEquals("Cloned string property",
+                     "Custom string",
+                     (String) clonedBean.get("stringProperty"));
+
+        // Validate the results for array properties
+        String dupProperty[] = (String[]) clonedBean.get("dupProperty");
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = (int[]) clonedBean.get("intArray");
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 100, intArray[0]);
+        assertEquals("intArray[1]", 200, intArray[1]);
+        assertEquals("intArray[2]", 300, intArray[2]);
+        String stringArray[] = (String[]) clonedBean.get("stringArray");
+        assertNotNull("stringArray present", stringArray);
+        assertEquals("stringArray length", 2, stringArray.length);
+        assertEquals("stringArray[0]", "New 0", stringArray[0]);
+        assertEquals("stringArray[1]", "New 1", stringArray[1]);
+
+    }
+
+    /**
+     * Test the copyProperties() method from a DynaBean.
+     */
+    public void testCopyPropertiesDynaBean() {
+
+        // Set up an origin bean with customized properties
+        DynaClass dynaClass = DynaBeanUtilsTestCase.createDynaClass();
+        DynaBean orig = null;
+        try {
+            orig = dynaClass.newInstance();
+        } catch (Exception e) {
+            fail("newInstance(): " + e);
+        }
+        orig.set("booleanProperty", Boolean.FALSE);
+        orig.set("byteProperty", new Byte((byte)111));
+        orig.set("doubleProperty", new Double(333.33));
+        orig.set("dupProperty", new String[] { "New 0", "New 1", "New 2" });
+        orig.set("intArray", new int[] { 100, 200, 300 });
+        orig.set("intProperty", new Integer(333));
+        orig.set("longProperty", new Long(3333));
+        orig.set("shortProperty", new Short((short) 33));
+        orig.set("stringArray", new String[] { "New 0", "New 1" });
+        orig.set("stringProperty", "Custom string");
+
+        // Copy the origin bean to our destination test bean
+        try {
+            BeanUtils.copyProperties(bean, orig);
+        } catch (Exception e) {
+            fail("Threw exception: " + e);
+        }
+
+        // Validate the results for scalar properties
+        assertEquals("Copied boolean property",
+                     false,
+                     ((Boolean) bean.get("booleanProperty")).booleanValue());
+        assertEquals("Copied byte property",
+                     (byte) 111,
+                     ((Byte) bean.get("byteProperty")).byteValue());
+        assertEquals("Copied double property",
+                     333.33,
+                     ((Double) bean.get("doubleProperty")).doubleValue(),
+                     0.005);
+        assertEquals("Copied int property",
+                     333,
+                     ((Integer) bean.get("intProperty")).intValue());
+        assertEquals("Copied long property",
+                     (long) 3333,
+                     ((Long) bean.get("longProperty")).longValue());
+        assertEquals("Copied short property",
+                     (short) 33,
+                     ((Short) bean.get("shortProperty")).shortValue());
+        assertEquals("Copied string property",
+                     "Custom string",
+                     (String) bean.get("stringProperty"));
+
+        // Validate the results for array properties
+        String dupProperty[] = (String[]) bean.get("dupProperty");
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = (int[]) bean.get("intArray");
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 100, intArray[0]);
+        assertEquals("intArray[1]", 200, intArray[1]);
+        assertEquals("intArray[2]", 300, intArray[2]);
+        String stringArray[] = (String[]) bean.get("stringArray");
+        assertNotNull("stringArray present", stringArray);
+        assertEquals("stringArray length", 2, stringArray.length);
+        assertEquals("stringArray[0]", "New 0", stringArray[0]);
+        assertEquals("stringArray[1]", "New 1", stringArray[1]);
+
+    }
+
+
+    /**
+     * Test copyProperties() when the origin is a a <code>Map</code>.
+     */
+    public void testCopyPropertiesMap() {
+
+        Map map = new HashMap();
+        map.put("booleanProperty", "false");
+        map.put("byteProperty", "111");
+        map.put("doubleProperty", "333.0");
+        map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
+        map.put("floatProperty", "222.0");
+        map.put("intArray", new String[] { "0", "100", "200" });
+        map.put("intProperty", "111");
+        map.put("longProperty", "444");
+        map.put("shortProperty", "555");
+        map.put("stringProperty", "New String Property");
+
+        try {
+            BeanUtils.copyProperties(bean, map);
+        } catch (Throwable t) {
+            fail("Threw " + t.toString());
+        }
+
+        // Scalar properties
+        assertEquals("booleanProperty", false,
+                     ((Boolean) bean.get("booleanProperty")).booleanValue());
+        assertEquals("byteProperty", (byte) 111,
+                     ((Byte) bean.get("byteProperty")).byteValue());
+        assertEquals("doubleProperty", 333.0,
+                     ((Double) bean.get("doubleProperty")).doubleValue(),
+                     0.005);
+        assertEquals("floatProperty", (float) 222.0,
+                     ((Float) bean.get("floatProperty")).floatValue(),
+                     (float) 0.005);
+        assertEquals("intProperty", 111,
+                     ((Integer) bean.get("intProperty")).intValue());
+        assertEquals("longProperty", (long) 444,
+                     ((Long) bean.get("longProperty")).longValue());
+        assertEquals("shortProperty", (short) 555,
+                     ((Short) bean.get("shortProperty")).shortValue());
+        assertEquals("stringProperty", "New String Property",
+                     (String) bean.get("stringProperty"));
+
+        // Indexed Properties
+        String dupProperty[] = (String[]) bean.get("dupProperty");
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = (int[]) bean.get("intArray");
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 0, intArray[0]);
+        assertEquals("intArray[1]", 100, intArray[1]);
+        assertEquals("intArray[2]", 200, intArray[2]);
+
+    }
+
+
+    /**
+     * Test the copyProperties() method from a standard JavaBean.
+     */
+    public void testCopyPropertiesStandard() {
+
+        // Set up an origin bean with customized properties
+        TestBean orig = new TestBean();
+        orig.setBooleanProperty(false);
+        orig.setByteProperty((byte) 111);
+        orig.setDoubleProperty(333.33);
+        orig.setDupProperty(new String[] { "New 0", "New 1", "New 2" });
+        orig.setIntArray(new int[] { 100, 200, 300 });
+        orig.setIntProperty(333);
+        orig.setLongProperty(3333);
+        orig.setShortProperty((short) 33);
+        orig.setStringArray(new String[] { "New 0", "New 1" });
+        orig.setStringProperty("Custom string");
+
+        // Copy the origin bean to our destination test bean
+        try {
+            BeanUtils.copyProperties(bean, orig);
+        } catch (Exception e) {
+            fail("Threw exception: " + e);
+        }
+
+        // Validate the results for scalar properties
+        assertEquals("Copied boolean property",
+                     false,
+                     ((Boolean) bean.get("booleanProperty")).booleanValue());
+        assertEquals("Copied byte property",
+                     (byte) 111,
+                     ((Byte) bean.get("byteProperty")).byteValue());
+        assertEquals("Copied double property",
+                     333.33,
+                     ((Double) bean.get("doubleProperty")).doubleValue(),
+                     0.005);
+        assertEquals("Copied int property",
+                     333,
+                     ((Integer) bean.get("intProperty")).intValue());
+        assertEquals("Copied long property",
+                     (long) 3333,
+                     ((Long) bean.get("longProperty")).longValue());
+        assertEquals("Copied short property",
+                     (short) 33,
+                     ((Short) bean.get("shortProperty")).shortValue());
+        assertEquals("Copied string property",
+                     "Custom string",
+                     (String) bean.get("stringProperty"));
+
+        // Validate the results for array properties
+        String dupProperty[] = (String[]) bean.get("dupProperty");
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = (int[]) bean.get("intArray");
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 100, intArray[0]);
+        assertEquals("intArray[1]", 200, intArray[1]);
+        assertEquals("intArray[2]", 300, intArray[2]);
+        String stringArray[] = (String[]) bean.get("stringArray");
+        assertNotNull("stringArray present", stringArray);
+        assertEquals("stringArray length", 2, stringArray.length);
+        assertEquals("stringArray[0]", "New 0", stringArray[0]);
+        assertEquals("stringArray[1]", "New 1", stringArray[1]);
+
+    }
+
+
+    /**
+     * Test the describe() method.
+     */
+    public void testDescribe() {
+
+        Map map = null;
+        try {
+            map = PropertyUtils.describe(bean);
+        } catch (Exception e) {
+            fail("Threw exception " + e);
+        }
+
+        // Verify existence of all the properties that should be present
+        for (int i = 0; i < describes.length; i++) {
+            assertTrue("Property '" + describes[i] + "' is present",
+                       map.containsKey(describes[i]));
+        }
+        assertTrue("Property 'writeOnlyProperty' is not present",
+                   !map.containsKey("writeOnlyProperty"));
+
+        // Verify the values of scalar properties
+        assertEquals("Value of 'booleanProperty'",
+                     Boolean.TRUE,
+                     (Boolean) map.get("booleanProperty"));
+        assertEquals("Value of 'byteProperty'",
+                     new Byte((byte) 121),
+                     (Byte) map.get("byteProperty"));
+        assertEquals("Value of 'doubleProperty'",
+                     new Double(321.0),
+                     (Double) map.get("doubleProperty"));
+        assertEquals("Value of 'floatProperty'",
+                     new Float((float) 123.0),
+                     (Float) map.get("floatProperty"));
+        assertEquals("Value of 'intProperty'",
+                     new Integer(123),
+                     (Integer) map.get("intProperty"));
+        assertEquals("Value of 'longProperty'",
+                     new Long(321),
+                     (Long) map.get("longProperty"));
+        assertEquals("Value of 'shortProperty'",
+                     new Short((short) 987),
+                     (Short) map.get("shortProperty"));
+        assertEquals("Value of 'stringProperty'",
+                     "This is a string",
+                     (String) map.get("stringProperty"));
+
+    }
+
+
+    /**
+     * Test populate() method on array properties as a whole.
+     */
+    public void testPopulateArrayProperties() {
+
+        try {
+
+            HashMap map = new HashMap();
+            //            int intArray[] = new int[] { 123, 456, 789 };
+            String intArrayIn[] = new String[] { "123", "456", "789" };
+            map.put("intArray", intArrayIn);
+            String stringArray[] = new String[]
+                { "New String 0", "New String 1" };
+            map.put("stringArray", stringArray);
+
+            BeanUtils.populate(bean, map);
+
+            int intArray[] = (int[]) bean.get("intArray");
+            assertNotNull("intArray is present", intArray);
+            assertEquals("intArray length",
+                         3, intArray.length);
+            assertEquals("intArray[0]", 123, intArray[0]);
+            assertEquals("intArray[1]", 456, intArray[1]);
+            assertEquals("intArray[2]", 789, intArray[2]);
+            stringArray = (String[]) bean.get("stringArray");
+            assertNotNull("stringArray is present", stringArray);
+            assertEquals("stringArray length", 2, stringArray.length);
+            assertEquals("stringArray[0]", "New String 0", stringArray[0]);
+            assertEquals("stringArray[1]", "New String 1", stringArray[1]);
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     *  tests the string and int arrays of TestBean
+     */
+    public void testGetArrayProperty() {
+        try {
+            String arr[] = BeanUtils.getArrayProperty(bean, "stringArray");
+            String comp[] = (String[]) bean.get("stringArray");
+
+            assertTrue("String array length = " + comp.length,
+                    (comp.length == arr.length));
+
+            arr = BeanUtils.getArrayProperty(bean, "intArray");
+            int iarr[] = (int[]) bean.get("intArray");
+
+            assertTrue("String array length = " + iarr.length,
+                    (iarr.length == arr.length));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     *  tests getting an indexed property
+     */
+    public void testGetIndexedProperty1() {
+        try {
+            String val = BeanUtils.getIndexedProperty(bean, "intIndexed[3]");
+            String comp = String.valueOf(bean.get("intIndexed", 3));
+            assertTrue("intIndexed[3] == " + comp, val.equals(comp));
+
+            val = BeanUtils.getIndexedProperty(bean, "stringIndexed[3]");
+            comp = (String) bean.get("stringIndexed", 3);
+            assertTrue("stringIndexed[3] == " + comp, val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting an indexed property
+     */
+    public void testGetIndexedProperty2() {
+        try {
+            String val = BeanUtils.getIndexedProperty(bean, "intIndexed", 3);
+            String comp = String.valueOf(bean.get("intIndexed", 3));
+
+            assertTrue("intIndexed,3 == " + comp, val.equals(comp));
+
+            val = BeanUtils.getIndexedProperty(bean, "stringIndexed", 3);
+            comp = (String) bean.get("stringIndexed", 3);
+
+            assertTrue("stringIndexed,3 == " + comp, val.equals(comp));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting a nested property
+     */
+    public void testGetNestedProperty() {
+        try {
+            String val = BeanUtils.getNestedProperty(bean, "nested.stringProperty");
+            String comp = nested.getStringProperty();
+            assertTrue("nested.StringProperty == " + comp,
+                    val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting a 'whatever' property
+     */
+    public void testGetGeneralProperty() {
+        try {
+            String val = BeanUtils.getProperty(bean, "nested.intIndexed[2]");
+            String comp = String.valueOf(bean.get("intIndexed", 2));
+
+            assertTrue("nested.intIndexed[2] == " + comp,
+                    val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     *  tests getting a 'whatever' property
+     */
+    public void testGetSimpleProperty() {
+        try {
+            String val = BeanUtils.getSimpleProperty(bean, "shortProperty");
+            String comp = String.valueOf(bean.get("shortProperty"));
+
+            assertTrue("shortProperty == " + comp,
+                    val.equals(comp));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+    }
+
+
+    /**
+     * Test populate() method on individual array elements.
+     */
+    public void testPopulateArrayElements() {
+
+        try {
+
+            HashMap map = new HashMap();
+            map.put("intIndexed[0]", "100");
+            map.put("intIndexed[2]", "120");
+            map.put("intIndexed[4]", "140");
+
+            BeanUtils.populate(bean, map);
+            Integer intIndexed0 = (Integer) bean.get("intIndexed", 0);
+            assertEquals("intIndexed[0] is 100",
+                         100, intIndexed0.intValue());
+            Integer intIndexed1 = (Integer) bean.get("intIndexed", 1);
+            assertEquals("intIndexed[1] is 10",
+                         10, intIndexed1.intValue());
+            Integer intIndexed2 = (Integer) bean.get("intIndexed", 2);
+            assertEquals("intIndexed[2] is 120",
+                         120, intIndexed2.intValue());
+            Integer intIndexed3 = (Integer) bean.get("intIndexed", 3);
+            assertEquals("intIndexed[3] is 30",
+                         30, intIndexed3.intValue());
+            Integer intIndexed4 = (Integer) bean.get("intIndexed", 4);
+            assertEquals("intIndexed[4] is 140",
+                         140, intIndexed4.intValue());
+
+            map.clear();
+            map.put("stringIndexed[1]", "New String 1");
+            map.put("stringIndexed[3]", "New String 3");
+
+            BeanUtils.populate(bean, map);
+
+            assertEquals("stringIndexed[0] is \"String 0\"",
+                         "String 0",
+                         (String) bean.get("stringIndexed", 0));
+            assertEquals("stringIndexed[1] is \"New String 1\"",
+                         "New String 1",
+                         (String) bean.get("stringIndexed", 1));
+            assertEquals("stringIndexed[2] is \"String 2\"",
+                         "String 2",
+                         (String) bean.get("stringIndexed", 2));
+            assertEquals("stringIndexed[3] is \"New String 3\"",
+                         "New String 3",
+                         (String) bean.get("stringIndexed", 3));
+            assertEquals("stringIndexed[4] is \"String 4\"",
+                         "String 4",
+                         (String) bean.get("stringIndexed", 4));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() on mapped properties.
+     */
+    public void testPopulateMapped() {
+
+        try {
+
+            HashMap map = new HashMap();
+            map.put("mappedProperty(First Key)", "New First Value");
+            map.put("mappedProperty(Third Key)", "New Third Value");
+
+            BeanUtils.populate(bean, map);
+
+            assertEquals("mappedProperty(First Key)",
+                         "New First Value",
+                         (String) bean.get("mappedProperty", "First Key"));
+            assertEquals("mappedProperty(Second Key)",
+                         "Second Value",
+                         (String) bean.get("mappedProperty", "Second Key"));
+            assertEquals("mappedProperty(Third Key)",
+                         "New Third Value",
+                         (String) bean.get("mappedProperty", "Third Key"));
+            assertNull("mappedProperty(Fourth Key",
+                       (String) bean.get("mappedProperty", "Fourth Key"));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() method on nested properties.
+     */
+    public void testPopulateNested() {
+
+        try {
+
+            HashMap map = new HashMap();
+            map.put("nested.booleanProperty", "false");
+            // booleanSecond is left at true
+            map.put("nested.doubleProperty", "432.0");
+            // floatProperty is left at 123.0
+            map.put("nested.intProperty", "543");
+            // longProperty is left at 321
+            map.put("nested.shortProperty", "654");
+            // stringProperty is left at "This is a string"
+
+            BeanUtils.populate(bean, map);
+
+            TestBean nested = (TestBean) bean.get("nested");
+            assertTrue("booleanProperty is false",
+                       !nested.getBooleanProperty());
+            assertTrue("booleanSecond is true",
+                       nested.isBooleanSecond());
+            assertEquals("doubleProperty is 432.0",
+                         (double) 432.0,
+                         nested.getDoubleProperty(),
+                         (double) 0.005);
+            assertEquals("floatProperty is 123.0",
+                         (float) 123.0,
+                         nested.getFloatProperty(),
+                         (float) 0.005);
+            assertEquals("intProperty is 543",
+                         543, nested.getIntProperty());
+            assertEquals("longProperty is 321",
+                         (long) 321, nested.getLongProperty());
+            assertEquals("shortProperty is 654",
+                         (short) 654, nested.getShortProperty());
+            assertEquals("stringProperty is \"This is a string\"",
+                         "This is a string",
+                         nested.getStringProperty());
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test populate() method on scalar properties.
+     */
+    public void testPopulateScalar() {
+
+        try {
+
+            bean.set("nullProperty", "non-null value");
+
+            HashMap map = new HashMap();
+            map.put("booleanProperty", "false");
+            // booleanSecond is left at true
+            map.put("doubleProperty", "432.0");
+            // floatProperty is left at 123.0
+            map.put("intProperty", "543");
+            // longProperty is left at 321
+            map.put("nullProperty", null);
+            map.put("shortProperty", "654");
+            // stringProperty is left at "This is a string"
+
+            BeanUtils.populate(bean, map);
+
+            Boolean booleanProperty = (Boolean) bean.get("booleanProperty");
+            assertTrue("booleanProperty is false", !booleanProperty.booleanValue());
+            Boolean booleanSecond = (Boolean) bean.get("booleanSecond");
+            assertTrue("booleanSecond is true", booleanSecond.booleanValue());
+            Double doubleProperty = (Double) bean.get("doubleProperty");
+            assertEquals("doubleProperty is 432.0",
+                         (double) 432.0, doubleProperty.doubleValue(),
+                         (double) 0.005);
+            Float floatProperty = (Float) bean.get("floatProperty");
+            assertEquals("floatProperty is 123.0",
+                         (float) 123.0, floatProperty.floatValue(),
+                         (float) 0.005);
+            Integer intProperty = (Integer) bean.get("intProperty");
+            assertEquals("intProperty is 543",
+                         543, intProperty.intValue());
+            Long longProperty = (Long) bean.get("longProperty");
+            assertEquals("longProperty is 321",
+                         (long) 321, longProperty.longValue());
+            assertNull("nullProperty is null", bean.get("nullProperty"));
+            Short shortProperty = (Short) bean.get("shortProperty");
+            assertEquals("shortProperty is 654",
+                         (short) 654, shortProperty.shortValue());
+            assertEquals("stringProperty is \"This is a string\"",
+                         "This is a string",
+                         (String) bean.get("stringProperty"));
+
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        }
+
+    }
+
+
+    /**
+     * Test calling setProperty() with null property values.
+     */
+    public void testSetPropertyNullValues() throws Exception {
+
+        Object oldValue = null;
+        Object newValue = null;
+
+        // Scalar value into array
+        oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        BeanUtils.setProperty(bean, "stringArray", (String) null);
+        newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        assertNotNull("stringArray is not null", newValue);
+        assertTrue("stringArray of correct type",
+                   newValue instanceof String[]);
+        assertEquals("stringArray length",
+                     1, ((String[]) newValue).length);
+        assertTrue("stringArray[0] is null",
+                   ((String[]) newValue)[0] == null);
+        PropertyUtils.setProperty(bean, "stringArray", oldValue);
+
+        // Indexed value into array
+        oldValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        BeanUtils.setProperty(bean, "stringArray[2]", (String) null);
+        newValue = PropertyUtils.getSimpleProperty(bean, "stringArray");
+        assertNotNull("stringArray is not null", newValue);
+        assertTrue("stringArray of correct type",
+                   newValue instanceof String[]);
+        assertEquals("stringArray length",
+                     5, ((String[]) newValue).length);
+        assertTrue("stringArray[2] is null",
+                   ((String[]) newValue)[2] == null);
+        PropertyUtils.setProperty(bean, "stringArray", oldValue);
+
+        // Value into scalar
+        BeanUtils.setProperty(bean, "stringProperty", null);
+        assertTrue("stringProperty is now null",
+                   BeanUtils.getProperty(bean, "stringProperty") == null);
+
+    }
+
+
+    /**
+     * Test converting to and from primitive wrapper types.
+     */
+    public void testSetPropertyOnPrimitiveWrappers() throws Exception {
+
+        BeanUtils.setProperty(bean,"intProperty", new Integer(1));
+        assertEquals(1,((Integer) bean.get("intProperty")).intValue());
+        BeanUtils.setProperty(bean,"stringProperty", new Integer(1));
+        assertEquals(1, Integer.parseInt((String) bean.get("stringProperty")));
+
+    }
+
+
+    /**
+     * Test setting a null property value.
+     */
+    public void testSetPropertyNull() throws Exception {
+
+        bean.set("nullProperty", "non-null value");
+        BeanUtils.setProperty(bean, "nullProperty", null);
+        assertNull("nullProperty is null", bean.get("nullProperty"));
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on byte.
+     */
+    public void testCopyPropertyByte() throws Exception {
+
+        BeanUtils.setProperty(bean, "byteProperty", new Byte((byte) 123));
+        assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
+/*
+        BeanUtils.setProperty(bean, "byteProperty", new Double((double) 123));
+        assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
+        BeanUtils.setProperty(bean, "byteProperty", new Float((float) 123));
+        assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
+*/
+        BeanUtils.setProperty(bean, "byteProperty", new Integer((int) 123));
+        assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
+        BeanUtils.setProperty(bean, "byteProperty", new Long((long) 123));
+        assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
+        BeanUtils.setProperty(bean, "byteProperty", new Short((short) 123));
+        assertEquals((byte) 123, ((Byte) bean.get("byteProperty")).byteValue());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on double.
+     */
+    public void testCopyPropertyDouble() throws Exception {
+
+        BeanUtils.setProperty(bean, "doubleProperty", new Byte((byte) 123));
+        assertEquals((double) 123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Double((double) 123));
+        assertEquals((double) 123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Float((float) 123));
+        assertEquals((double) 123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Integer((int) 123));
+        assertEquals((double) 123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Long((long) 123));
+        assertEquals((double) 123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
+        BeanUtils.setProperty(bean, "doubleProperty", new Short((short) 123));
+        assertEquals((double) 123, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005);
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on float.
+     */
+    public void testCopyPropertyFloat() throws Exception {
+
+        BeanUtils.setProperty(bean, "floatProperty", new Byte((byte) 123));
+        assertEquals((float) 123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Double((double) 123));
+        assertEquals((float) 123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Float((float) 123));
+        assertEquals((float) 123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Integer((int) 123));
+        assertEquals((float) 123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Long((long) 123));
+        assertEquals((float) 123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
+        BeanUtils.setProperty(bean, "floatProperty", new Short((short) 123));
+        assertEquals((float) 123, ((Float) bean.get("floatProperty")).floatValue(), 0.005);
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on int.
+     */
+    public void testCopyPropertyInteger() throws Exception {
+
+        BeanUtils.setProperty(bean, "longProperty", new Byte((byte) 123));
+        assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
+/*
+        BeanUtils.setProperty(bean, "longProperty", new Double((double) 123));
+        assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
+        BeanUtils.setProperty(bean, "longProperty", new Float((float) 123));
+        assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
+*/
+        BeanUtils.setProperty(bean, "longProperty", new Integer((int) 123));
+        assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
+        BeanUtils.setProperty(bean, "longProperty", new Long((long) 123));
+        assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
+        BeanUtils.setProperty(bean, "longProperty", new Short((short) 123));
+        assertEquals((int) 123, ((Integer) bean.get("intProperty")).intValue());
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on long.
+     */
+    public void testCopyPropertyLong() throws Exception {
+
+        BeanUtils.setProperty(bean, "longProperty", new Byte((byte) 123));
+        assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
+/*
+        BeanUtils.setProperty(bean, "longProperty", new Double((double) 123));
+        assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
+        BeanUtils.setProperty(bean, "longProperty", new Float((float) 123));
+        assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
+*/
+        BeanUtils.setProperty(bean, "longProperty", new Integer((int) 123));
+        assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
+        BeanUtils.setProperty(bean, "longProperty", new Long((long) 123));
+        assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
+        BeanUtils.setProperty(bean, "longProperty", new Short((short) 123));
+        assertEquals((long) 123, ((Long) bean.get("longProperty")).longValue());
+
+    }
+
+
+    /**
+     * Test copying a null property value.
+     */
+    public void testCopyPropertyNull() throws Exception {
+
+        bean.set("nullProperty", "non-null value");
+        BeanUtils.copyProperty(bean, "nullProperty", null);
+        assertNull("nullProperty is null", bean.get("nullProperty"));
+
+    }
+
+
+    /**
+     * Test narrowing and widening conversions on short.
+     */
+    public void testCopyPropertyShort() throws Exception {
+
+        BeanUtils.setProperty(bean, "shortProperty", new Byte((byte) 123));
+        assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
+/*
+        BeanUtils.setProperty(bean, "shortProperty", new Double((double) 123));
+        assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
+        BeanUtils.setProperty(bean, "shortProperty", new Float((float) 123));
+        assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
+*/
+        BeanUtils.setProperty(bean, "shortProperty", new Integer((int) 123));
+        assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
+        BeanUtils.setProperty(bean, "shortProperty", new Long((long) 123));
+        assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
+        BeanUtils.setProperty(bean, "shortProperty", new Short((short) 123));
+        assertEquals((short) 123, ((Short) bean.get("shortProperty")).shortValue());
+
+    }
+
+
+    /**
+     * Test copying a property using a nested indexed array expression,
+     * with and without conversions.
+     */
+    public void testCopyPropertyNestedIndexedArray() throws Exception {
+
+        int origArray[] = { 0, 10, 20, 30, 40};
+        int intArray[] = { 0, 0, 0 };
+        ((TestBean) bean.get("nested")).setIntArray(intArray);
+        int intChanged[] = { 0, 0, 0 };
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Integer(1));
+        checkIntArray((int[]) bean.get("intArray"), origArray);
+        intChanged[1] = 1;
+        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
+                      intChanged);
+
+        // Widening conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Byte((byte) 2));
+        checkIntArray((int[]) bean.get("intArray"), origArray);
+        intChanged[1] = 2;
+        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
+                      intChanged);
+
+        // Narrowing conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", new Long((long) 3));
+        checkIntArray((int[]) bean.get("intArray"), origArray);
+        intChanged[1] = 3;
+        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
+                      intChanged);
+
+        // String conversion required
+        BeanUtils.copyProperty(bean, "nested.intArray[1]", "4");
+        checkIntArray((int[]) bean.get("intArray"), origArray);
+        intChanged[1] = 4;
+        checkIntArray(((TestBean) bean.get("nested")).getIntArray(),
+                      intChanged);
+
+    }
+
+
+    /**
+     * Test copying a property using a nested mapped map property.
+     */
+    public void testCopyPropertyNestedMappedMap() throws Exception {
+
+        Map origMap = new HashMap();
+        origMap.put("First Key", "First Value");
+        origMap.put("Second Key", "Second Value");
+        Map changedMap = new HashMap();
+        changedMap.put("First Key", "First Value");
+        changedMap.put("Second Key", "Second Value");
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "nested.mapProperty(Second Key)",
+                               "New Second Value");
+        checkMap((Map) bean.get("mapProperty"), origMap);
+        changedMap.put("Second Key", "New Second Value");
+        checkMap(((TestBean) bean.get("nested")).getMapProperty(), changedMap);
+
+    }
+
+
+    /**
+     * Test copying a property using a nested simple expression, with and
+     * without conversions.
+     */
+    public void testCopyPropertyNestedSimple() throws Exception {
+
+        bean.set("intProperty", new Integer(0));
+        nested.setIntProperty(0);
+
+        // No conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", new Integer(1));
+        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
+        assertEquals(1, nested.getIntProperty());
+
+        // Widening conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", new Byte((byte) 2));
+        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
+        assertEquals(2, nested.getIntProperty());
+
+        // Narrowing conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", new Long((long) 3));
+        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
+        assertEquals(3, nested.getIntProperty());
+
+        // String conversion required
+        BeanUtils.copyProperty(bean, "nested.intProperty", "4");
+        assertEquals(0, ((Integer) bean.get("intProperty")).intValue());
+        assertEquals(4, nested.getIntProperty());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    // Ensure that the nested intArray matches the specified values
+    protected void checkIntArray(int actual[], int expected[]) {
+        assertNotNull("actual array not null", actual);
+        assertEquals("actual array length", expected.length, actual.length);
+        for (int i = 0; i < actual.length; i++) {
+            assertEquals("actual array value[" + i + "]",
+                         expected[i], actual[i]);
+        }
+    }
+
+
+    // Ensure that the actual Map matches the expected Map
+    protected void checkMap(Map actual, Map expected) {
+        assertNotNull("actual map not null", actual);
+        assertEquals("actual map size", expected.size(), actual.size());
+        Iterator keys = expected.keySet().iterator();
+        while (keys.hasNext()) {
+            Object key = keys.next();
+            assertEquals("actual map value(" + key + ")",
+                         expected.get(key), actual.get(key));
+        }
+    }
+
+
+    /**
+     * Create and return a <code>DynaClass</code> instance for our test
+     * <code>DynaBean</code>.
+     */
+    protected static DynaClass createDynaClass() {
+
+        int intArray[] = new int[0];
+        String stringArray[] = new String[0];
+
+        DynaClass dynaClass = new BasicDynaClass
+                ("TestDynaClass", null,
+                        new DynaProperty[]{
+                            new DynaProperty("booleanProperty", Boolean.TYPE),
+                            new DynaProperty("booleanSecond", Boolean.TYPE),
+                            new DynaProperty("byteProperty", Byte.TYPE),
+                            new DynaProperty("doubleProperty", Double.TYPE),
+                            new DynaProperty("dupProperty", stringArray.getClass()),
+                            new DynaProperty("floatProperty", Float.TYPE),
+                            new DynaProperty("intArray", intArray.getClass()),
+                            new DynaProperty("intIndexed", intArray.getClass()),
+                            new DynaProperty("intProperty", Integer.TYPE),
+                            new DynaProperty("listIndexed", List.class),
+                            new DynaProperty("longProperty", Long.TYPE),
+                            new DynaProperty("mapProperty", Map.class),
+                            new DynaProperty("mappedProperty", Map.class),
+                            new DynaProperty("mappedIntProperty", Map.class),
+                            new DynaProperty("nested", TestBean.class),
+                            new DynaProperty("nullProperty", String.class),
+                            new DynaProperty("shortProperty", Short.TYPE),
+                            new DynaProperty("stringArray", stringArray.getClass()),
+                            new DynaProperty("stringIndexed", stringArray.getClass()),
+                            new DynaProperty("stringProperty", String.class),
+                        });
+        return (dynaClass);
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaPropertyUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaPropertyUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaPropertyUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,2648 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * Test accessing DynaBeans transparently via PropertyUtils.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.12 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class DynaPropertyUtilsTestCase extends TestCase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The basic test bean for each test.
+     */
+    protected DynaBean bean = null;
+
+
+    /**
+     * The set of properties that should be described.
+     */
+    protected String describes[] =
+    { "booleanProperty",
+      "booleanSecond",
+      "doubleProperty",
+      "floatProperty",
+      "intArray",
+      "intIndexed",
+      "intProperty",
+      "listIndexed",
+      "longProperty",
+      "mappedObjects",
+      "mappedProperty",
+      "mappedIntProperty",
+      "nested",
+      "nullProperty",
+      //      "readOnlyProperty",
+      "shortProperty",
+      "stringArray",
+      "stringIndexed",
+      "stringProperty"
+    };
+
+
+    /**
+     * The nested bean pointed at by the "nested" property.
+     */
+    protected TestBean nested = null;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public DynaPropertyUtilsTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        // Instantiate a new DynaBean instance
+        DynaClass dynaClass = createDynaClass();
+        bean = dynaClass.newInstance();
+
+        // Initialize the DynaBean's property values (like TestBean)
+        bean.set("booleanProperty", new Boolean(true));
+        bean.set("booleanSecond", new Boolean(true));
+        bean.set("doubleProperty", new Double(321.0));
+        bean.set("floatProperty", new Float((float) 123.0));
+        int intArray[] = { 0, 10, 20, 30, 40 };
+        bean.set("intArray", intArray);
+        int intIndexed[] = { 0, 10, 20, 30, 40 };
+        bean.set("intIndexed", intIndexed);
+        bean.set("intProperty", new Integer(123));
+        List listIndexed = new ArrayList();
+        listIndexed.add("String 0");
+        listIndexed.add("String 1");
+        listIndexed.add("String 2");
+        listIndexed.add("String 3");
+        listIndexed.add("String 4");
+        bean.set("listIndexed", listIndexed);
+        bean.set("longProperty", new Long((long) 321));
+        HashMap mapProperty = new HashMap();
+        mapProperty.put("First Key", "First Value");
+        mapProperty.put("Second Key", "Second Value");
+        bean.set("mapProperty", mapProperty);
+        HashMap mappedObjects = new HashMap();
+        mappedObjects.put("First Key", "First Value");
+        mappedObjects.put("Second Key", "Second Value");
+        bean.set("mappedObjects", mappedObjects);
+        HashMap mappedProperty = new HashMap();
+        mappedProperty.put("First Key", "First Value");
+        mappedProperty.put("Second Key", "Second Value");
+        bean.set("mappedProperty", mappedProperty);
+        HashMap mappedIntProperty = new HashMap();
+        mappedIntProperty.put("One", new Integer(1));
+        mappedIntProperty.put("Two", new Integer(2));
+        bean.set("mappedIntProperty", mappedIntProperty);
+        nested = new TestBean();
+        bean.set("nested", nested);
+        // Property "nullProperty" is not initialized, so it should return null
+        bean.set("shortProperty", new Short((short) 987));
+        String stringArray[] =
+                { "String 0", "String 1", "String 2", "String 3", "String 4" };
+        bean.set("stringArray", stringArray);
+        String stringIndexed[] =
+                { "String 0", "String 1", "String 2", "String 3", "String 4" };
+        bean.set("stringIndexed", stringIndexed);
+        bean.set("stringProperty", "This is a string");
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(DynaPropertyUtilsTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        bean = null;
+        nested = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Test copyProperties() when the origin is a a <code>Map</code>.
+     */
+    public void testCopyPropertiesMap() {
+
+        Map map = new HashMap();
+        map.put("booleanProperty", Boolean.FALSE);
+        map.put("doubleProperty", new Double(333.0));
+        map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
+        map.put("floatProperty", new Float((float) 222.0));
+        map.put("intArray", new int[] { 0, 100, 200 });
+        map.put("intProperty", new Integer(111));
+        map.put("longProperty", new Long(444));
+        map.put("shortProperty", new Short((short) 555));
+        map.put("stringProperty", "New String Property");
+
+        try {
+            PropertyUtils.copyProperties(bean, map);
+        } catch (Throwable t) {
+            fail("Threw " + t.toString());
+        }
+
+        // Scalar properties
+        assertEquals("booleanProperty", false,
+                     ((Boolean) bean.get("booleanProperty")).booleanValue());
+        assertEquals("doubleProperty", 333.0,
+                     ((Double) bean.get("doubleProperty")).doubleValue(),
+                     0.005);
+        assertEquals("floatProperty", (float) 222.0,
+                     ((Float) bean.get("floatProperty")).floatValue(),
+                     (float) 0.005);
+        assertEquals("intProperty", 111,
+                     ((Integer) bean.get("intProperty")).intValue());
+        assertEquals("longProperty", (long) 444,
+                     ((Long) bean.get("longProperty")).longValue());
+        assertEquals("shortProperty", (short) 555,
+                     ((Short) bean.get("shortProperty")).shortValue());
+        assertEquals("stringProperty", "New String Property",
+                     (String) bean.get("stringProperty"));
+                     
+        // Indexed Properties
+        String dupProperty[] = (String[]) bean.get("dupProperty");
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = (int[]) bean.get("intArray");
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 0, intArray[0]);
+        assertEquals("intArray[1]", 100, intArray[1]);
+        assertEquals("intArray[2]", 200, intArray[2]);
+
+    }
+
+
+    /**
+     * Test the describe() method.
+     */
+    public void testDescribe() {
+
+        Map map = null;
+        try {
+            map = PropertyUtils.describe(bean);
+        } catch (Exception e) {
+            fail("Threw exception " + e);
+        }
+
+        // Verify existence of all the properties that should be present
+        for (int i = 0; i < describes.length; i++) {
+            assertTrue("Property '" + describes[i] + "' is present",
+                       map.containsKey(describes[i]));
+        }
+        assertTrue("Property 'writeOnlyProperty' is not present",
+                   !map.containsKey("writeOnlyProperty"));
+
+        // Verify the values of scalar properties
+        assertEquals("Value of 'booleanProperty'",
+                     Boolean.TRUE,
+                     (Boolean) map.get("booleanProperty"));
+        assertEquals("Value of 'doubleProperty'",
+                     new Double(321.0),
+                     (Double) map.get("doubleProperty"));
+        assertEquals("Value of 'floatProperty'",
+                     new Float((float) 123.0),
+                     (Float) map.get("floatProperty"));
+        assertEquals("Value of 'intProperty'",
+                     new Integer(123),
+                     (Integer) map.get("intProperty"));
+        assertEquals("Value of 'longProperty'",
+                     new Long(321),
+                     (Long) map.get("longProperty"));
+        assertEquals("Value of 'shortProperty'",
+                     new Short((short) 987),
+                     (Short) map.get("shortProperty"));
+        assertEquals("Value of 'stringProperty'",
+                     "This is a string",
+                     (String) map.get("stringProperty"));
+
+    }
+
+
+    /**
+     * Corner cases on getIndexedProperty invalid arguments.
+     */
+    public void testGetIndexedArguments() {
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.getIndexedProperty(null, "intArray", 0);
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, null, 0);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.getIndexedProperty(null,
+                    "intArray[0]");
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "[0]");
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "intArray");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.getIndexedProperty(null, "intIndexed", 0);
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, null, 0);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.getIndexedProperty(null,
+                    "intIndexed[0]");
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "[0]");
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "intIndexed");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on getIndexedProperty valid arguments.
+     */
+    public void testGetIndexedValues() {
+
+        Object value = null;
+
+        // Use explicit key argument
+
+        for (int i = 0; i < 5; i++) {
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "intArray", i);
+                assertNotNull("intArray returned value " + i, value);
+                assertTrue("intArray returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intArray returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "intIndexed", i);
+                assertNotNull("intIndexed returned value " + i, value);
+                assertTrue("intIndexed returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intIndexed returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "listIndexed", i);
+                assertNotNull("listIndexed returned value " + i, value);
+                assertTrue("list returned String " + i,
+                        value instanceof String);
+                assertEquals("listIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("listIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "stringArray", i);
+                assertNotNull("stringArray returned value " + i, value);
+                assertTrue("stringArray returned String " + i,
+                        value instanceof String);
+                assertEquals("stringArray returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "stringIndexed", i);
+                assertNotNull("stringIndexed returned value " + i, value);
+                assertTrue("stringIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("stringIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringIndexed " + i + " threw " + t);
+            }
+
+        }
+
+        // Use key expression
+
+        for (int i = 0; i < 5; i++) {
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "intArray[" + i + "]");
+                assertNotNull("intArray returned value " + i, value);
+                assertTrue("intArray returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intArray returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "intIndexed[" + i + "]");
+                assertNotNull("intIndexed returned value " + i, value);
+                assertTrue("intIndexed returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intIndexed returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "listIndexed[" + i + "]");
+                assertNotNull("listIndexed returned value " + i, value);
+                assertTrue("listIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("listIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("listIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "stringArray[" + i + "]");
+                assertNotNull("stringArray returned value " + i, value);
+                assertTrue("stringArray returned String " + i,
+                        value instanceof String);
+                assertEquals("stringArray returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "stringIndexed[" + i + "]");
+                assertNotNull("stringIndexed returned value " + i, value);
+                assertTrue("stringIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("stringIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringIndexed " + i + " threw " + t);
+            }
+
+        }
+
+        // Index out of bounds tests
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed", -1);
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed", 5);
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringIndexed", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringIndexed", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getMappedProperty invalid arguments.
+     */
+    public void testGetMappedArguments() {
+
+        // Use explicit key argument
+
+        try {
+            PropertyUtils.getMappedProperty(null, "mappedProperty",
+                    "First Key");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, null, "First Key");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, "mappedProperty", null);
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        // Use key expression
+
+        try {
+            PropertyUtils.getMappedProperty(null,
+                    "mappedProperty(First Key)");
+            fail("Should throw IllegalArgumentException 4");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 4");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, "(Second Key)");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 5");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, "mappedProperty");
+            fail("Should throw IllegalArgumentException 6");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 6");
+        }
+
+    }
+
+
+    /**
+     * Test getting mapped values with periods in the key.
+     */
+    public void testGetMappedPeriods() {
+
+        bean.set("mappedProperty", "key.with.a.dot", "Special Value");
+        assertEquals("Can retrieve directly",
+                     "Special Value",
+                     (String) bean.get("mappedProperty", "key.with.a.dot"));
+        try {
+            assertEquals("Can retrieve via getMappedProperty",
+                         "Special Value",
+                         PropertyUtils.getMappedProperty
+                         (bean, "mappedProperty", "key.with.a.dot"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+        try {
+            assertEquals("Can retrieve via getNestedProperty",
+                         "Special Value",
+                         PropertyUtils.getNestedProperty
+                         (bean, "mappedProperty(key.with.a.dot)"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+        bean.set("mappedObjects", "nested.property", new TestBean());
+        assertNotNull("Can retrieve directly",
+                      bean.get("mappedObjects", "nested.property"));
+        try {
+            assertEquals("Can retrieve nested",
+                         "This is a string",
+                         PropertyUtils.getNestedProperty
+                         (bean,
+                          "mappedObjects(nested.property).stringProperty"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Test getting mapped values with slashes in the key.  This is different
+     * from periods because slashes are not syntactically significant.
+     */
+    public void testGetMappedSlashes() {
+
+        bean.set("mappedProperty", "key/with/a/slash", "Special Value");
+        assertEquals("Can retrieve directly",
+                     "Special Value",
+                     bean.get("mappedProperty", "key/with/a/slash"));
+        try {
+            assertEquals("Can retrieve via getMappedProperty",
+                         "Special Value",
+                         PropertyUtils.getMappedProperty
+                         (bean, "mappedProperty", "key/with/a/slash"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+        try {
+            assertEquals("Can retrieve via getNestedProperty",
+                         "Special Value",
+                         PropertyUtils.getNestedProperty
+                         (bean, "mappedProperty(key/with/a/slash)"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+        bean.set("mappedObjects", "nested/property", new TestBean());
+        assertNotNull("Can retrieve directly",
+                      bean.get("mappedObjects", "nested/property"));
+        try {
+            assertEquals("Can retrieve nested",
+                         "This is a string",
+                         PropertyUtils.getNestedProperty
+                         (bean,
+                          "mappedObjects(nested/property).stringProperty"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on getMappedProperty valid arguments.
+     */
+    public void testGetMappedValues() {
+
+        Object value = null;
+
+        // Use explicit key argument
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "First Key");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Second Key");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Third Key");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+        // Use key expression with parentheses
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(First Key)");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Second Key)");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Third Key)");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+        // Use key expression with dotted syntax
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.First Key");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Second Key");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Third Key");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getNestedProperty invalid arguments.
+     */
+    public void testGetNestedArguments() {
+
+        try {
+            PropertyUtils.getNestedProperty(null, "stringProperty");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getNestedProperty(bean, null);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a boolean property.
+     */
+    public void testGetNestedBoolean() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.booleanProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Boolean));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertTrue("Got correct value",
+                    ((Boolean) value).booleanValue() ==
+                    nested.getBooleanProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a double property.
+     */
+    public void testGetNestedDouble() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.doubleProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Double));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    ((Double) value).doubleValue(),
+                    nested.getDoubleProperty(),
+                    0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a float property.
+     */
+    public void testGetNestedFloat() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.floatProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Float));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    ((Float) value).floatValue(),
+                    nested.getFloatProperty(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on an int property.
+     */
+    public void testGetNestedInt() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.intProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Integer));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    ((Integer) value).intValue(),
+                    nested.getIntProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a long property.
+     */
+    public void testGetNestedLong() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.longProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Long));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    ((Long) value).longValue(),
+                    nested.getLongProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a read-only String property.
+     */
+    public void testGetNestedReadOnly() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.readOnlyProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    (String) value,
+                    nested.getReadOnlyProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a short property.
+     */
+    public void testGetNestedShort() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.shortProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Short));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    ((Short) value).shortValue(),
+                    nested.getShortProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a String property.
+     */
+    public void testGetNestedString() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.stringProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            TestBean nested = (TestBean) bean.get("nested");
+            assertEquals("Got correct value",
+                    ((String) value),
+                    nested.getStringProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getNestedProperty on an unknown property.
+     */
+    public void testGetNestedUnknown() {
+
+        try {
+            PropertyUtils.getNestedProperty(bean, "nested.unknown");
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getSimpleProperty invalid arguments.
+     */
+    public void testGetSimpleArguments() {
+
+        try {
+            PropertyUtils.getSimpleProperty(null, "stringProperty");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getSimpleProperty(bean, null);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a boolean property.
+     */
+    public void testGetSimpleBoolean() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "booleanProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Boolean));
+            assertTrue("Got correct value",
+                    ((Boolean) value).booleanValue() == true);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a double property.
+     */
+    public void testGetSimpleDouble() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "doubleProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Double));
+            assertEquals("Got correct value",
+                    ((Double) value).doubleValue(),
+                    (double) 321.0,
+                    (double) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a float property.
+     */
+    public void testGetSimpleFloat() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "floatProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Float));
+            assertEquals("Got correct value",
+                    ((Float) value).floatValue(),
+                    (float) 123.0,
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getSimpleProperty on an indexed property.
+     */
+    public void testGetSimpleIndexed() {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getSimpleProperty(bean,
+                    "intIndexed[0]");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on an int property.
+     */
+    public void testGetSimpleInt() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "intProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Integer));
+            assertEquals("Got correct value",
+                    ((Integer) value).intValue(),
+                    123);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a long property.
+     */
+    public void testGetSimpleLong() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "longProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Long));
+            assertEquals("Got correct value",
+                    ((Long) value).longValue(),
+                    (long) 321);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getSimpleProperty on a nested property.
+     */
+    public void testGetSimpleNested() {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getSimpleProperty(bean,
+                    "nested.stringProperty");
+            fail("Should have thrown IllegaArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a short property.
+     */
+    public void testGetSimpleShort() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "shortProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Short));
+            assertEquals("Got correct value",
+                    ((Short) value).shortValue(),
+                    (short) 987);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a String property.
+     */
+    public void testGetSimpleString() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "stringProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            assertEquals("Got correct value",
+                    (String) value,
+                    "This is a string");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getSimpleProperty on an unknown property.
+     */
+    public void testGetSimpleUnknown() {
+
+        try {
+            PropertyUtils.getSimpleProperty(bean, "unknown");
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Corner cases on setIndexedProperty invalid arguments.
+     */
+    public void testSetIndexedArguments() {
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.setIndexedProperty(null, "intArray", 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, null, 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.setIndexedProperty(null,
+                    "intArray[0]",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "[0]",
+                    new Integer(1));
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "intArray",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.setIndexedProperty(null, "intIndexed", 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, null, 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.setIndexedProperty(null,
+                    "intIndexed[0]",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "[0]",
+                    new Integer(1));
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "intIndexed",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on setIndexedProperty valid arguments.
+     */
+    public void testSetIndexedValues() {
+
+        Object value = null;
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray", 0,
+                    new Integer(1));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray", 0);
+            assertNotNull("Returned new value 0", value);
+            assertTrue("Returned Integer new value 0",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 0", 1,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed", 1,
+                    new Integer(11));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed", 1);
+            assertNotNull("Returned new value 1", value);
+            assertTrue("Returned Integer new value 1",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 1", 11,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed", 2,
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed", 2);
+            assertNotNull("Returned new value 2", value);
+            assertTrue("Returned String new value 2",
+                    value instanceof String);
+            assertEquals("Returned correct new value 2", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", 2,
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", 2);
+            assertNotNull("Returned new value 2", value);
+            assertTrue("Returned String new value 2",
+                    value instanceof String);
+            assertEquals("Returned correct new value 2", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", 3,
+                    "New Value 3");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", 3);
+            assertNotNull("Returned new value 3", value);
+            assertTrue("Returned String new value 3",
+                    value instanceof String);
+            assertEquals("Returned correct new value 3", "New Value 3",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray[4]",
+                    new Integer(1));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray[4]");
+            assertNotNull("Returned new value 4", value);
+            assertTrue("Returned Integer new value 4",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 4", 1,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed[3]",
+                    new Integer(11));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed[3]");
+            assertNotNull("Returned new value 5", value);
+            assertTrue("Returned Integer new value 5",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 5", 11,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed[1]",
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed[1]");
+            assertNotNull("Returned new value 6", value);
+            assertTrue("Returned String new value 6",
+                    value instanceof String);
+            assertEquals("Returned correct new value 6", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray[1]",
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray[2]");
+            assertNotNull("Returned new value 6", value);
+            assertTrue("Returned String new value 6",
+                    value instanceof String);
+            assertEquals("Returned correct new value 6", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray[0]",
+                    "New Value 3");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray[0]");
+            assertNotNull("Returned new value 7", value);
+            assertTrue("Returned String new value 7",
+                    value instanceof String);
+            assertEquals("Returned correct new value 7", "New Value 3",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        // Index out of bounds tests
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray", -1,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray", 5,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed", -1,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed", 5,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed", 5,
+                    "New String");
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed", -1,
+                    "New String");
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", -1,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", 5,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringIndexed", -1,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringIndexed", 5,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getMappedProperty invalid arguments.
+     */
+    public void testSetMappedArguments() {
+
+        // Use explicit key argument
+
+        try {
+            PropertyUtils.setMappedProperty(null, "mappedProperty",
+                    "First Key", "First Value");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, null, "First Key",
+                    "First Value");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "mappedProperty", null,
+                    "First Value");
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        // Use key expression
+
+        try {
+            PropertyUtils.setMappedProperty(null,
+                    "mappedProperty(First Key)",
+                    "First Value");
+            fail("Should throw IllegalArgumentException 4");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 4");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "(Second Key)",
+                    "Second Value");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 5");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "mappedProperty",
+                    "Third Value");
+            fail("Should throw IllegalArgumentException 6");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 6");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on setMappedProperty valid arguments.
+     */
+    public void testSetMappedValues() {
+
+        Object value = null;
+
+        // Use explicit key argument
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Fourth Key");
+            assertNull("Can not find fourth value", value);
+        } catch (Throwable t) {
+            fail("Finding fourth value threw " + t);
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "mappedProperty",
+                    "Fourth Key", "Fourth Value");
+        } catch (Throwable t) {
+            fail("Setting fourth value threw " + t);
+        }
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Fourth Key");
+            assertEquals("Can find fourth value", "Fourth Value", value);
+        } catch (Throwable t) {
+            fail("Finding fourth value threw " + t);
+        }
+
+        // Use key expression with parentheses
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Fifth Key)");
+            assertNull("Can not find fifth value", value);
+        } catch (Throwable t) {
+            fail("Finding fifth value threw " + t);
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean,
+                    "mappedProperty(Fifth Key)",
+                    "Fifth Value");
+        } catch (Throwable t) {
+            fail("Setting fifth value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Fifth Key)");
+            assertEquals("Can find fifth value", "Fifth Value", value);
+        } catch (Throwable t) {
+            fail("Finding fifth value threw " + t);
+        }
+
+        // Use key expression with dotted expression
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Sixth Key");
+            assertNull("Can not find sixth value", value);
+        } catch (Throwable t) {
+            fail("Finding fifth value threw " + t);
+        }
+
+        try {
+            PropertyUtils.setNestedProperty(bean,
+                    "mapProperty.Sixth Key",
+                    "Sixth Value");
+        } catch (Throwable t) {
+            fail("Setting sixth value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Sixth Key");
+            assertEquals("Can find sixth value", "Sixth Value", value);
+        } catch (Throwable t) {
+            fail("Finding sixth value threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on setNestedProperty invalid arguments.
+     */
+    public void testSetNestedArguments() {
+
+        try {
+            PropertyUtils.setNestedProperty(null, "stringProperty", "");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setNestedProperty(bean, null, "");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test setNextedProperty on a boolean property.
+     */
+    public void testSetNestedBoolean() {
+
+        try {
+            boolean oldValue = nested.getBooleanProperty();
+            boolean newValue = !oldValue;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.booleanProperty",
+                    new Boolean(newValue));
+            assertTrue("Matched new value",
+                    newValue ==
+                    nested.getBooleanProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a double property.
+     */
+    public void testSetNestedDouble() {
+
+        try {
+            double oldValue = nested.getDoubleProperty();
+            double newValue = oldValue + 1.0;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.doubleProperty",
+                    new Double(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getDoubleProperty(),
+                    0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a float property.
+     */
+    public void testSetNestedFloat() {
+
+        try {
+            float oldValue = nested.getFloatProperty();
+            float newValue = oldValue + (float) 1.0;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.floatProperty",
+                    new Float(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getFloatProperty(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a int property.
+     */
+    public void testSetNestedInt() {
+
+        try {
+            int oldValue = nested.getIntProperty();
+            int newValue = oldValue + 1;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.intProperty",
+                    new Integer(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getIntProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a long property.
+     */
+    public void testSetNestedLong() {
+
+        try {
+            long oldValue = nested.getLongProperty();
+            long newValue = oldValue + 1;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.longProperty",
+                    new Long(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getLongProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a read-only String property.
+     */
+    public void testSetNestedReadOnly() {
+
+        try {
+            String oldValue = nested.getWriteOnlyPropertyValue();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.readOnlyProperty",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a short property.
+     */
+    public void testSetNestedShort() {
+
+        try {
+            short oldValue = nested.getShortProperty();
+            short newValue = oldValue;
+            newValue++;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.shortProperty",
+                    new Short(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getShortProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a String property.
+     */
+    public void testSetNestedString() {
+
+        try {
+            String oldValue = nested.getStringProperty();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.stringProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getStringProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on an unknown property name.
+     */
+    public void testSetNestedUnknown() {
+
+        try {
+            String newValue = "New String Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.unknown",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a write-only String property.
+     */
+    public void testSetNestedWriteOnly() {
+
+        try {
+            String oldValue = nested.getWriteOnlyPropertyValue();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.writeOnlyProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    nested.getWriteOnlyPropertyValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on setSimpleProperty invalid arguments.
+     */
+    public void testSetSimpleArguments() {
+
+        try {
+            PropertyUtils.setSimpleProperty(null, "stringProperty", "");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setSimpleProperty(bean, null, "");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a boolean property.
+     */
+    public void testSetSimpleBoolean() {
+
+        try {
+            boolean oldValue = ((Boolean) bean.get("booleanProperty")).booleanValue();
+            boolean newValue = !oldValue;
+            PropertyUtils.setSimpleProperty(bean,
+                    "booleanProperty",
+                    new Boolean(newValue));
+            assertTrue("Matched new value",
+                    newValue ==
+                    ((Boolean) bean.get("booleanProperty")).booleanValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a double property.
+     */
+    public void testSetSimpleDouble() {
+
+        try {
+            double oldValue = ((Double) bean.get("doubleProperty")).doubleValue();
+            double newValue = oldValue + 1.0;
+            PropertyUtils.setSimpleProperty(bean,
+                    "doubleProperty",
+                    new Double(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Double) bean.get("doubleProperty")).doubleValue(),
+                    0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a float property.
+     */
+    public void testSetSimpleFloat() {
+
+        try {
+            float oldValue = ((Float) bean.get("floatProperty")).floatValue();
+            float newValue = oldValue + (float) 1.0;
+            PropertyUtils.setSimpleProperty(bean,
+                    "floatProperty",
+                    new Float(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Float) bean.get("floatProperty")).floatValue(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test setSimpleProperty on an indexed property.
+     */
+    public void testSetSimpleIndexed() {
+
+        try {
+            PropertyUtils.setSimpleProperty(bean,
+                    "stringIndexed[0]",
+                    "New String Value");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a int property.
+     */
+    public void testSetSimpleInt() {
+
+        try {
+            int oldValue = ((Integer) bean.get("intProperty")).intValue();
+            int newValue = oldValue + 1;
+            PropertyUtils.setSimpleProperty(bean,
+                    "intProperty",
+                    new Integer(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Integer) bean.get("intProperty")).intValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a long property.
+     */
+    public void testSetSimpleLong() {
+
+        try {
+            long oldValue = ((Long) bean.get("longProperty")).longValue();
+            long newValue = oldValue + 1;
+            PropertyUtils.setSimpleProperty(bean,
+                    "longProperty",
+                    new Long(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Long) bean.get("longProperty")).longValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test setSimpleProperty on a nested property.
+     */
+    public void testSetSimpleNested() {
+
+        try {
+            PropertyUtils.setSimpleProperty(bean,
+                    "nested.stringProperty",
+                    "New String Value");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a short property.
+     */
+    public void testSetSimpleShort() {
+
+        try {
+            short oldValue = ((Short) bean.get("shortProperty")).shortValue();
+            short newValue = oldValue;
+            newValue++;
+            PropertyUtils.setSimpleProperty(bean,
+                    "shortProperty",
+                    new Short(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    ((Short) bean.get("shortProperty")).shortValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a String property.
+     */
+    public void testSetSimpleString() {
+
+        try {
+            String oldValue = (String) bean.get("stringProperty");
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setSimpleProperty(bean,
+                    "stringProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    (String) bean.get("stringProperty"));
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on an unknown property name.
+     */
+    public void testSetSimpleUnknown() {
+
+        try {
+            String newValue = "New String Value";
+            PropertyUtils.setSimpleProperty(bean,
+                    "unknown",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Create and return a <code>DynaClass</code> instance for our test
+     * <code>DynaBean</code>.
+     */
+    protected DynaClass createDynaClass() {
+
+        int intArray[] = new int[0];
+        String stringArray[] = new String[0];
+
+        DynaClass dynaClass = new BasicDynaClass
+                ("TestDynaClass", null,
+                        new DynaProperty[]{
+                            new DynaProperty("booleanProperty", Boolean.TYPE),
+                            new DynaProperty("booleanSecond", Boolean.TYPE),
+                            new DynaProperty("doubleProperty", Double.TYPE),
+                            new DynaProperty("dupProperty", stringArray.getClass()),
+                            new DynaProperty("floatProperty", Float.TYPE),
+                            new DynaProperty("intArray", intArray.getClass()),
+                            new DynaProperty("intIndexed", intArray.getClass()),
+                            new DynaProperty("intProperty", Integer.TYPE),
+                            new DynaProperty("listIndexed", List.class),
+                            new DynaProperty("longProperty", Long.TYPE),
+                            new DynaProperty("mapProperty", Map.class),
+                            new DynaProperty("mappedObjects", Map.class),
+                            new DynaProperty("mappedProperty", Map.class),
+                            new DynaProperty("mappedIntProperty", Map.class),
+                            new DynaProperty("nested", TestBean.class),
+                            new DynaProperty("nullProperty", String.class),
+                            new DynaProperty("shortProperty", Short.TYPE),
+                            new DynaProperty("stringArray", stringArray.getClass()),
+                            new DynaProperty("stringIndexed", stringArray.getClass()),
+                            new DynaProperty("stringProperty", String.class),
+                        });
+        return (dynaClass);
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaResultSetTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaResultSetTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaResultSetTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * Test accessing ResultSets via DynaBeans.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class DynaResultSetTestCase extends TestCase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The mock result set DynaClass to be tested.
+     */
+    protected ResultSetDynaClass dynaClass = null;
+
+
+    /**
+     * Names of the columns for this test.  Must match the order they are
+     * defined in {@link TestResultSetMetaData}, and must be all lower case.
+     */
+    protected String columns[] =
+    { "bigdecimalproperty", "booleanproperty",
+      "byteproperty", "dateproperty",
+      "doubleproperty", "floatproperty",
+      "intproperty", "longproperty",
+      "nullproperty", "shortproperty",
+      "stringproperty", "timeproperty",
+      "timestampproperty" };
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public DynaResultSetTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        dynaClass = new ResultSetDynaClass(new TestResultSet());
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(DynaResultSetTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        dynaClass = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    public void testGetName() {
+
+        assertEquals("DynaClass name",
+                     "org.apache.commons.beanutils.ResultSetDynaClass",
+                     dynaClass.getName());
+
+
+    }
+
+
+    public void testGetDynaProperty() {
+
+        // Invalid argument test
+        try {
+            dynaClass.getDynaProperty(null);
+            fail("Did not throw IllegaArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected result
+        }
+
+        // Negative test
+        DynaProperty dynaProp = dynaClass.getDynaProperty("unknownProperty");
+        assertTrue("unknown property returns null",
+                   (dynaProp == null));
+
+        // Positive test
+        dynaProp = dynaClass.getDynaProperty("stringproperty");
+        assertNotNull("string property exists", dynaProp);
+        assertEquals("string property name", "stringproperty",
+                     dynaProp.getName());
+        assertEquals("string property class", String.class,
+                     dynaProp.getType());
+
+    }
+
+
+    public void testGetDynaProperties() {
+
+        DynaProperty dynaProps[] = dynaClass.getDynaProperties();
+        assertNotNull("dynaProps exists", dynaProps);
+        assertEquals("dynaProps length", columns.length, dynaProps.length);
+        for (int i = 0; i < columns.length; i++) {
+            assertEquals("Property " + columns[i],
+                         columns[i], dynaProps[i].getName());
+        }
+
+    }
+
+
+    public void testNewInstance() {
+
+        try {
+            dynaClass.newInstance();
+            fail("Did not throw UnsupportedOperationException()");
+        } catch (UnsupportedOperationException e) {
+            ; // Expected result
+        } catch (Exception e) {
+            fail("Threw exception " + e);
+        }
+
+    }
+
+
+    public void testIteratorCount() {
+
+        Iterator rows = dynaClass.iterator();
+        assertNotNull("iterator exists", rows);
+        int n = 0;
+        while (rows.hasNext()) {
+            rows.next();
+            n++;
+            if (n > 10) {
+                fail("Returned too many rows");
+            }
+        }
+        assertEquals("iterator rows", 5, n);
+
+    }
+
+
+    public void testIteratorResults() {
+
+        // Grab the third row
+        Iterator rows = dynaClass.iterator();
+        rows.next();
+        rows.next();
+        DynaBean row = (DynaBean) rows.next();
+
+        // Invalid argument test
+        try {
+            row.get("unknownProperty");
+            fail("Did not throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected result
+        }
+
+        // Verify property values
+
+        Object bigDecimalProperty = row.get("bigdecimalproperty");
+        assertNotNull("bigDecimalProperty exists", bigDecimalProperty);
+        assertTrue("bigDecimalProperty type",
+                   bigDecimalProperty instanceof BigDecimal);
+        assertEquals("bigDecimalProperty value",
+                     123.45,
+                     ((BigDecimal) bigDecimalProperty).doubleValue(),
+                     0.005);
+
+        Object intProperty = row.get("intproperty");
+        assertNotNull("intProperty exists", intProperty);
+        assertTrue("intProperty type",
+                   intProperty instanceof Integer);
+        assertEquals("intProperty value",
+                     103,
+                     ((Integer) intProperty).intValue());
+
+        Object nullProperty = row.get("nullproperty");
+        assertNull("nullProperty null", nullProperty);
+
+        Object stringProperty = row.get("stringproperty");
+        assertNotNull("stringProperty exists", stringProperty);
+        assertTrue("stringProperty type",
+                   stringProperty instanceof String);
+        assertEquals("stringProperty value",
+                     "This is a string",
+                     (String) stringProperty);
+
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaRowSetTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaRowSetTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/DynaRowSetTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * Test accessing RowSets via DynaBeans.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class DynaRowSetTestCase extends TestCase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The mock result set DynaClass to be tested.
+     */
+    protected RowSetDynaClass dynaClass = null;
+
+
+    /**
+     * Names of the columns for this test.  Must match the order they are
+     * defined in {@link TestResultSetMetaData}, and must be all lower case.
+     */
+    protected String columns[] =
+    { "bigdecimalproperty", "booleanproperty",
+      "byteproperty", "dateproperty",
+      "doubleproperty", "floatproperty",
+      "intproperty", "longproperty",
+      "nullproperty", "shortproperty",
+      "stringproperty", "timeproperty",
+      "timestampproperty" };
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public DynaRowSetTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        dynaClass = new RowSetDynaClass(new TestResultSet());
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(DynaRowSetTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        dynaClass = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    public void testGetName() {
+
+        assertEquals("DynaClass name",
+                     "org.apache.commons.beanutils.RowSetDynaClass",
+                     dynaClass.getName());
+
+
+    }
+
+
+    public void testGetDynaProperty() {
+
+        // Invalid argument test
+        try {
+            dynaClass.getDynaProperty(null);
+            fail("Did not throw IllegaArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected result
+        }
+
+        // Negative test
+        DynaProperty dynaProp = dynaClass.getDynaProperty("unknownProperty");
+        assertTrue("unknown property returns null",
+                   (dynaProp == null));
+
+        // Positive test
+        dynaProp = dynaClass.getDynaProperty("stringproperty");
+        assertNotNull("string property exists", dynaProp);
+        assertEquals("string property name", "stringproperty",
+                     dynaProp.getName());
+        assertEquals("string property class", String.class,
+                     dynaProp.getType());
+
+    }
+
+
+    public void testGetDynaProperties() {
+
+        DynaProperty dynaProps[] = dynaClass.getDynaProperties();
+        assertNotNull("dynaProps exists", dynaProps);
+        assertEquals("dynaProps length", columns.length, dynaProps.length);
+        for (int i = 0; i < columns.length; i++) {
+            assertEquals("Property " + columns[i],
+                         columns[i], dynaProps[i].getName());
+        }
+
+    }
+
+
+    public void testNewInstance() {
+
+        try {
+            dynaClass.newInstance();
+            fail("Did not throw UnsupportedOperationException()");
+        } catch (UnsupportedOperationException e) {
+            ; // Expected result
+        } catch (Exception e) {
+            fail("Threw exception " + e);
+        }
+
+    }
+
+
+    public void testListCount() {
+
+        List rows = dynaClass.getRows();
+        assertNotNull("list exists", rows);
+        assertEquals("list row count", 5, rows.size());
+
+    }
+
+
+    public void testListResults() {
+
+        // Grab the third row
+        List rows = dynaClass.getRows();
+        DynaBean row = (DynaBean) rows.get(2);
+
+        // Invalid argument test
+        try {
+            row.get("unknownProperty");
+            fail("Did not throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected result
+        }
+
+        // Verify property values
+
+        Object bigDecimalProperty = row.get("bigdecimalproperty");
+        assertNotNull("bigDecimalProperty exists", bigDecimalProperty);
+        assertTrue("bigDecimalProperty type",
+                   bigDecimalProperty instanceof BigDecimal);
+        assertEquals("bigDecimalProperty value",
+                     123.45,
+                     ((BigDecimal) bigDecimalProperty).doubleValue(),
+                     0.005);
+
+        Object intProperty = row.get("intproperty");
+        assertNotNull("intProperty exists", intProperty);
+        assertTrue("intProperty type",
+                   intProperty instanceof Integer);
+        assertEquals("intProperty value",
+                     103,
+                     ((Integer) intProperty).intValue());
+
+        Object nullProperty = row.get("nullproperty");
+        assertNull("nullProperty null", nullProperty);
+
+        Object stringProperty = row.get("stringproperty");
+        assertNotNull("stringProperty exists", stringProperty);
+        assertTrue("stringProperty type",
+                   stringProperty instanceof String);
+        assertEquals("stringProperty value",
+                     "This is a string",
+                     (String) stringProperty);
+
+
+    }
+
+    public void testLimitedRows() throws Exception {
+        
+        // created one with low limit
+        RowSetDynaClass limitedDynaClass = new RowSetDynaClass(new TestResultSet(), 3);
+        List rows = limitedDynaClass.getRows();
+        assertNotNull("list exists", rows);
+        assertEquals("limited row count", 3, rows.size());
+        
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ExtendMapBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ExtendMapBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ExtendMapBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+import java.util.Hashtable;
+
+
+/**
+ * Used to test 
+ *
+ * @author Robert Burrell
+ */
+
+public class ExtendMapBean extends Hashtable {
+    
+    private String dbName = "[UNSET]";
+    
+    public ExtendMapBean() {}
+    
+    public String getUnusuallyNamedProperty()
+    {
+        return dbName;
+    }
+
+    public void setUnusuallyNamedProperty(String dbName)
+    {
+        this.dbName = dbName;
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaBeanTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaBeanTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaBeanTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,483 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.lang.reflect.InvocationTargetException;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * <p>Test Case for the <code>LazyDynaBean</code> implementation class.</p>
+ *
+ * @author Niall Pemberton
+ */
+public class LazyDynaBeanTestCase extends TestCase {
+
+    protected LazyDynaBean  bean      = null;
+    protected LazyDynaClass dynaClass = null;
+    protected String testProperty     = "myProperty";
+    protected String testPropertyA    = "myProperty-A";
+    protected String testPropertyB    = "myProperty-B";
+    protected String testString1      = "myStringValue-1";
+    protected String testString2      = "myStringValue-2";
+    protected Integer testInteger1    = new Integer(30);
+    protected Integer testInteger2    = new Integer(40);
+    protected String testKey          = "myKey";
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public LazyDynaBeanTestCase(String name) {
+        super(name);
+    }
+
+    // -------------------------------------------------- Overall Test Methods
+
+    /**
+     * Run thus Test
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(suite());
+    }
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(LazyDynaBeanTestCase.class));
+    }
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+        bean = new LazyDynaBean();
+        dynaClass = (LazyDynaClass)bean.getDynaClass();
+        dynaClass.setReturnNull(true);
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+      bean = null;
+    }
+
+    // ------------------------------------------------ Individual Test Methods
+
+    /**
+     * Test Getting/Setting a Simple Property
+     */
+    public void testSimpleProperty() {
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Value is null", bean.get(testProperty));
+
+        // Set a new property - should add new property and set value
+        bean.set(testProperty, testInteger1);
+        assertEquals("Check First Value is correct", testInteger1, bean.get(testProperty));
+        assertEquals("Check Property type is correct", Integer.class, dynaClass.getDynaProperty(testProperty).getType());
+
+        // Set the property again - should set the new value
+        bean.set(testProperty, testInteger2);
+        assertEquals("Check Second Value is correct", testInteger2, bean.get(testProperty));
+
+        // Set the property again - with a different type, should fail
+        try {
+            bean.set(testProperty, testString1);
+            fail("expected ConversionException trying to set an Integer property to a String");
+        } catch (ConversionException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test Setting a Simple Property when MutableDynaClass is set to restricted
+     */
+    public void testSimplePropertyRestricted() {
+
+        // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
+        dynaClass.setRestricted(true);
+        assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Value is null", bean.get(testProperty));
+
+        // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
+        try {
+            bean.set(testProperty, testString1);
+            fail("expected IllegalArgumentException trying to add new property to restricted DynaClass");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test Getting/Setting a 'Mapped' Property - default HashMap property
+     */
+    public void testMappedPropertyDefault() {
+
+        // Check the property & value doesn't exist
+        assertNull("Check Mapped Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Map is null", bean.get(testProperty));
+        assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
+
+        // Set a new mapped property - should add new HashMap property and set the mapped value
+        bean.set(testProperty, testKey, testInteger1);
+        assertEquals("Check Mapped Property exists", HashMap.class, bean.get(testProperty).getClass());
+        assertEquals("Check First Mapped Value is correct(a)", testInteger1, bean.get(testProperty, testKey));
+        assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((HashMap)bean.get(testProperty)).get(testKey));
+
+        // Set the property again - should set the new value
+        bean.set(testProperty, testKey, testInteger2);
+        assertEquals("Check Second Mapped Value is correct(a)", testInteger2, bean.get(testProperty, testKey));
+        assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((HashMap)bean.get(testProperty)).get(testKey));
+    }
+
+    /**
+     * Test Getting/Setting a 'Mapped' Property - use TreeMap property
+     */
+    public void testMappedPropertyTreeMap() {
+
+        // Check the property & value doesn't exist
+        assertNull("Check Mapped Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+
+        // Add a 'TreeMap' property to the DynaClass
+        dynaClass.add(testProperty, TreeMap.class);
+        assertTrue("Check Property is mapped", dynaClass.getDynaProperty(testProperty).isMapped());
+        assertEquals("Check Property is correct type", TreeMap.class, dynaClass.getDynaProperty(testProperty).getType());
+        assertEquals("Check Mapped Property exists", TreeMap.class, bean.get(testProperty).getClass());
+//        assertNull("Check mapped property is null", bean.get(testProperty));
+
+        // Set a new mapped property - should instatiate a new TreeMap property and set the mapped value
+        bean.set(testProperty, testKey, testInteger1);
+        assertEquals("Check Mapped Property exists", TreeMap.class, bean.get(testProperty).getClass());
+        assertEquals("Check First Mapped Value is correct(a)", testInteger1, bean.get(testProperty, testKey));
+        assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((TreeMap)bean.get(testProperty)).get(testKey));
+
+        // Set the property again - should set the new value
+        bean.set(testProperty, testKey, testInteger2);
+        assertEquals("Check Second Mapped Value is correct(a)", testInteger2, bean.get(testProperty, testKey));
+        assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((TreeMap)bean.get(testProperty)).get(testKey));
+    }
+
+    /**
+     * Test Setting a 'Mapped' Property using PropertyUtils
+     */
+    public void testMappedPropertyUtils() {
+
+        dynaClass.setReturnNull(false);
+
+        // Check the property & value doesn't exist
+        assertFalse("Check Mapped Property doesn't exist", dynaClass.isDynaProperty(testProperty));
+        assertNull("Check Map is null", bean.get(testProperty));
+        assertNull("Check Mapped Value is null", bean.get(testProperty, testKey));
+
+        // Set the mapped property using PropertyUtils
+        try {
+          PropertyUtils.setProperty(bean, testProperty+"("+testKey+")", testString1);
+        }
+        catch (NoSuchMethodException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (InvocationTargetException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (IllegalAccessException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+
+        // Check property value correctly set
+        assertEquals("Check Mapped Bean Value is correct", testString1, bean.get(testProperty, testKey));
+
+    }
+
+    /**
+     * Test Setting a Mapped Property when MutableDynaClass is set to restricted
+     */
+    public void testMappedPropertyRestricted() {
+
+        // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
+        dynaClass.setRestricted(true);
+        assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Value is null", bean.get(testProperty));
+
+        // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
+        try {
+            bean.set(testProperty, testKey, testInteger1);
+            fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test setting mapped property for type which is not Map
+     */
+    public void testMappedInvalidType() {
+        dynaClass.add(testProperty, String.class);
+        assertFalse("Check Property is not mapped", dynaClass.getDynaProperty(testProperty).isMapped());
+        try {
+            bean.set(testProperty, testKey, testInteger1);
+            fail("set(property, key, value) should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test Getting/Setting an 'Indexed' Property - default ArrayList property
+     */
+    public void testIndexedPropertyDefault() {
+
+        int index = 3;
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", bean.get(testProperty));
+        assertNull("Check Indexed value is null", bean.get(testProperty, index));
+
+        // Set the property, should create new ArrayList and set appropriate indexed value
+        bean.set(testProperty, index, testInteger1);
+        assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
+        assertEquals("Check Indexed Property is correct type", ArrayList.class, bean.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct", testInteger1, bean.get(testProperty, index));
+        assertEquals("Check First Array length is correct", new Integer(index+1),  new Integer(((ArrayList)bean.get(testProperty)).size()));
+
+        // Set a second indexed value, should automatically grow the ArrayList and set appropriate indexed value
+        index = index + 2;
+        bean.set(testProperty, index, testString1);
+        assertEquals("Check Second Indexed Value is correct", testString1, bean.get(testProperty, index));
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((ArrayList)bean.get(testProperty)).size()));
+    }
+
+    /**
+     * Test Getting/Setting a List 'Indexed' Property - use alternative List (LinkedList)
+     */
+    public void testIndexedLinkedList() {
+
+        int   index     = 3;
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", bean.get(testProperty));
+
+        // Add a 'LinkedList' property to the DynaClass
+        dynaClass.add(testProperty, LinkedList.class);
+        assertTrue("Check Property is indexed", dynaClass.getDynaProperty(testProperty).isIndexed());
+        assertEquals("Check Property is correct type", LinkedList.class, dynaClass.getDynaProperty(testProperty).getType());
+        assertEquals("Check Property type is correct", LinkedList.class, bean.get(testProperty).getClass());
+
+        // Set the property, should instantiate a new LinkedList and set appropriate indexed value
+        bean.set(testProperty, index, testString1);
+        assertEquals("Check Property type is correct", LinkedList.class, bean.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct", testString1, bean.get(testProperty, index));
+        assertEquals("Check First Array length is correct", new Integer(index+1),  new Integer(((LinkedList)bean.get(testProperty)).size()));
+
+        // Set a second indexed value, should automatically grow the LinkedList and set appropriate indexed value
+        index = index + 2;
+        bean.set(testProperty, index, testInteger1);
+        assertEquals("Check Second Indexed Value is correct", testInteger1, bean.get(testProperty, index));
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((LinkedList)bean.get(testProperty)).size()));
+    }
+
+    /**
+     * Test Getting/Setting a primitive array 'Indexed' Property - use int[]
+     */
+    public void testIndexedPrimitiveArray() {
+
+        int   index     = 3;
+        int[] primitiveArray = new int[0];
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", bean.get(testProperty));
+
+        // Add a DynaProperty of type int[]
+        dynaClass.add(testProperty, primitiveArray.getClass());
+        assertEquals("Check Indexed Property exists", primitiveArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
+        assertEquals("Check Indexed Property is correct type", primitiveArray.getClass(), bean.get(testProperty).getClass());
+
+        // Set an indexed value
+        bean.set(testProperty, index, testInteger1);
+        assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
+        assertEquals("Check Indexed Property is correct type", primitiveArray.getClass(), bean.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct(a)", testInteger1, bean.get(testProperty, index));
+        assertEquals("Check First Indexed Value is correct(b)", testInteger1, new Integer(((int[])bean.get(testProperty))[index]));
+        assertEquals("Check Array length is correct", new Integer(index+1),  new Integer(((int[])bean.get(testProperty)).length));
+
+        // Set a second indexed value, should automatically grow the int[] and set appropriate indexed value
+        index = index + 2;
+        bean.set(testProperty, index, testInteger2);
+        assertEquals("Check Second Indexed Value is correct(a)", testInteger2, bean.get(testProperty, index));
+        assertEquals("Check Second Indexed Value is correct(b)", testInteger2, new Integer(((int[])bean.get(testProperty))[index]));
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((int[])bean.get(testProperty)).length));
+
+    }
+
+    /**
+     * Test Getting/Setting an Object array 'Indexed' Property - use String[]
+     */
+    public void testIndexedObjectArray() {
+
+        int   index     = 3;
+        Object objectArray = new String[0];
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", bean.get(testProperty));
+
+        // Add a DynaProperty of type String[]
+        dynaClass.add(testProperty, objectArray.getClass());
+        assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
+        assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
+
+        // Set an indexed value
+        bean.set(testProperty, index, testString1);
+        assertNotNull("Check Indexed Property is not null", bean.get(testProperty));
+        assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct(a)", testString1, bean.get(testProperty, index));
+        assertEquals("Check First Indexed Value is correct(b)", testString1, ((String[])bean.get(testProperty))[index]);
+        assertEquals("Check Array length is correct", new Integer(index+1),  new Integer(((String[])bean.get(testProperty)).length));
+
+        // Set a second indexed value, should automatically grow the String[] and set appropriate indexed value
+        index = index + 2;
+        bean.set(testProperty, index, testString2);
+        assertEquals("Check Second Indexed Value is correct(a)", testString2, bean.get(testProperty, index));
+        assertEquals("Check Second Indexed Value is correct(b)", testString2, ((String[])bean.get(testProperty))[index]);
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((String[])bean.get(testProperty)).length));
+    }
+
+    /**
+     * Test Getting/Setting an DynaBean[] array
+     */
+    public void testIndexedDynaBeanArray() {
+
+        int   index     = 3;
+        Object objectArray = new LazyDynaMap[0];
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", bean.get(testProperty));
+
+        // Add a DynaProperty of type String[]
+        dynaClass.add(testProperty, objectArray.getClass());
+        assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaClass.getDynaProperty(testProperty).getType());
+        assertEquals("Check Indexed Property is correct type", objectArray.getClass(), bean.get(testProperty).getClass());
+
+        // Retrieving from Array should initialize DynaBean
+        for (int i = index; i >= 0; i--) {
+            assertEquals("Check Array Components initialized", LazyDynaMap.class, bean.get(testProperty, index).getClass());
+        }
+
+        dynaClass.add(testPropertyB, objectArray.getClass());
+        LazyDynaMap newMap = new LazyDynaMap();
+        newMap.set(testPropertyB, testString2);
+        bean.set(testPropertyA, index, newMap);
+        assertEquals("Check Indexed Value is correct(a)", testString2, ((DynaBean)bean.get(testPropertyA, index)).get(testPropertyB));
+
+    }
+
+    /**
+     * Test Setting an 'Indexed' Property using PropertyUtils
+     */
+    public void testIndexedPropertyUtils() {
+
+        int   index     = 3;
+        dynaClass.setReturnNull(false);
+
+        // Check the property & value doesn't exist
+        assertFalse("Check Indexed Property doesn't exist", dynaClass.isDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", bean.get(testProperty));
+        assertNull("Check Indexed value is null", bean.get(testProperty, index));
+
+        // Use PropertyUtils to set the indexed value
+        try {
+          PropertyUtils.setProperty(bean, testProperty+"["+index+"]", testString1);
+        }
+        catch (NoSuchMethodException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (InvocationTargetException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (IllegalAccessException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+
+        // Check property value correctly set
+        assertEquals("Check Indexed Bean Value is correct", testString1, bean.get(testProperty, index));
+
+    }
+
+    /**
+     * Test Setting an Indexed Property when MutableDynaClass is set to restricted
+     */
+    public void testIndexedPropertyRestricted() {
+
+        int   index     = 3;
+
+        // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
+        dynaClass.setRestricted(true);
+        assertTrue("Check MutableDynaClass is restricted", dynaClass.isRestricted());
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaClass.getDynaProperty(testProperty));
+        assertNull("Check Value is null", bean.get(testProperty));
+
+        // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
+        try {
+            bean.set(testProperty, index, testInteger1);
+            fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test setting indexed property for type which is not List or Array
+     */
+    public void testIndexedInvalidType() {
+        int   index     = 3;
+        dynaClass.add(testProperty, String.class);
+        assertFalse("Check Property is not indexed", dynaClass.getDynaProperty(testProperty).isIndexed());
+        try {
+            bean.set(testProperty, index, testString1);
+            fail("set(property, index, value) should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaClassTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaClassTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaClassTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * <p>Test Case for the <code>LazyDynaClass</code> implementation class.</p>
+ *
+ * @author Niall Pemberton
+ */
+public class LazyDynaClassTestCase extends TestCase {
+
+    protected LazyDynaClass dynaClass = null;
+    protected String testProperty     = "myProperty";
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public LazyDynaClassTestCase(String name) {
+        super(name);
+    }
+
+    // -------------------------------------------------- Overall Test Methods
+
+    /**
+     * Run this Test
+     */
+    public static void main(String[] args) {
+      junit.textui.TestRunner.run(suite());
+    }
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+        dynaClass = new LazyDynaClass();
+    }
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(LazyDynaClassTestCase.class));
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        dynaClass = null;
+    }
+
+    // ------------------------------------------------ Individual Test Methods
+
+    /**
+     * Test add(name) method
+     */
+    public void testAddProperty1() {
+        dynaClass.add(testProperty);
+        DynaProperty dynaProperty = dynaClass.getDynaProperty(testProperty);
+        assertEquals("name is correct", testProperty, dynaProperty.getName());
+        assertEquals("type is correct", Object.class, dynaProperty.getType());
+    }
+
+    /**
+     * Test add(name, type) method
+     */
+    public void testAddProperty2() {
+        dynaClass.add(testProperty, String.class);
+        DynaProperty dynaProperty = dynaClass.getDynaProperty(testProperty);
+        assertEquals("name is correct", testProperty, dynaProperty.getName());
+        assertEquals("type is correct", String.class, dynaProperty.getType());
+    }
+
+    /**
+     * Test add(name, type, readable, writable) method
+     */
+    public void testAddProperty3() {
+        try {
+            dynaClass.add(testProperty, String.class, true, true);
+            fail("add(name, type, readable, writable) did not throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test add(name) method with 'null' name
+     */
+    public void testAddPropertyNullName1() {
+        try {
+            dynaClass.add((String)null);
+            fail("null property name not prevented");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test add(name, type) method with 'null' name
+     */
+    public void testAddPropertyNullName2() {
+        try {
+            dynaClass.add(null, String.class);
+            fail("null property name not prevented");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test add(name, type, readable, writable) method with 'null' name
+     */
+    public void testAddPropertyNullName3() {
+        try {
+            dynaClass.add(null, String.class, true, true);
+            fail("add(name, type, readable, writable) did not throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test add(name) method when restricted is set to 'true'
+     */
+    public void testAddPropertyRestricted1() {
+        dynaClass.setRestricted(true);
+        assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
+        try {
+            dynaClass.add(testProperty);
+            fail("add(name) did not throw IllegalStateException");
+        } catch (IllegalStateException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test add(name, type) method when restricted is set to 'true'
+     */
+    public void testAddPropertyRestricted2() {
+        dynaClass.setRestricted(true);
+        assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
+        try {
+            dynaClass.add(testProperty, String.class);
+            fail("add(name, type) did not throw IllegalStateException");
+        } catch (IllegalStateException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test add(name, type, readable, writable) method when restricted is set to 'true'
+     */
+    public void testAddPropertyRestricted3() {
+        dynaClass.setRestricted(true);
+        assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
+        try {
+            dynaClass.add(testProperty, String.class, true, true);
+            fail("add(name, type, readable, writable) did not throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException t) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test retrieving a property which doesn't exist (returnNull is 'false')
+     */
+    public void testGetPropertyDoesntExist1() {
+        dynaClass.setReturnNull(false);
+        assertFalse("returnNull is 'false'", dynaClass.isReturnNull());
+        DynaProperty dynaProperty = dynaClass.getDynaProperty(testProperty);
+        assertEquals("name is correct", testProperty, dynaProperty.getName());
+        assertEquals("type is correct", Object.class, dynaProperty.getType());
+        assertFalse("property doesnt exist", dynaClass.isDynaProperty(testProperty));
+    }
+
+
+    /**
+     * Test retrieving a property which doesn't exist (returnNull is 'true')
+     */
+    public void testGetPropertyDoesntExist2() {
+        dynaClass.setReturnNull(true);
+        assertTrue("returnNull is 'true'", dynaClass.isReturnNull());
+        assertNull("property is null", dynaClass.getDynaProperty(testProperty));
+    }
+
+    /**
+     * Test removing a property
+     */
+    public void testRemoveProperty() {
+        dynaClass.setReturnNull(true);
+        dynaClass.add(testProperty);
+        assertTrue("Property exists", dynaClass.isDynaProperty(testProperty));
+        assertNotNull("property is Not null", dynaClass.getDynaProperty(testProperty));
+        dynaClass.remove(testProperty);
+        assertFalse("Property doesn't exist", dynaClass.isDynaProperty(testProperty));
+        assertNull("property is null", dynaClass.getDynaProperty(testProperty));
+    }
+
+    /**
+     * Test removing a property, name is null
+     */
+    public void testRemovePropertyNullName() {
+        try {
+            dynaClass.remove(null);
+            fail("remove(null) did not throw IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test removing a property, DynaClass is restricted
+     */
+    public void testRemovePropertyRestricted() {
+        dynaClass.add(testProperty);
+        assertTrue("Property exists", dynaClass.isDynaProperty(testProperty));
+        dynaClass.setRestricted(true);
+        assertTrue("MutableDynaClass is restricted", dynaClass.isRestricted());
+        try {
+            dynaClass.remove(testProperty);
+            fail("remove property when MutableDynaClassis restricted did not throw IllegalStateException");
+        } catch (IllegalStateException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test removing a property which doesn't exist
+     */
+    public void testRemovePropertyDoesntExist() {
+        assertFalse("property doesn't exist", dynaClass.isDynaProperty(testProperty));
+        dynaClass.remove(testProperty);
+        assertFalse("property still doesn't exist", dynaClass.isDynaProperty(testProperty));
+    }
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaMapTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaMapTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/LazyDynaMapTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.beanutils;
+
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.lang.reflect.InvocationTargetException;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * <p>Test Case for the <code>LazyDynaMap</code> implementation class.</p>
+ *
+ * @author Niall Pemberton
+ */
+public class LazyDynaMapTestCase extends TestCase {
+
+    protected LazyDynaMap  dynaMap    = null;
+    protected String testProperty     = "myProperty";
+    protected String testPropertyA    = "myProperty-A";
+    protected String testPropertyB    = "myProperty-B";
+    protected String testString1      = "myStringValue-1";
+    protected String testString2      = "myStringValue-2";
+    protected Integer testInteger1    = new Integer(30);
+    protected Integer testInteger2    = new Integer(40);
+    protected String testKey          = "myKey";
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public LazyDynaMapTestCase(String name) {
+        super(name);
+    }
+
+    // -------------------------------------------------- Overall Test Methods
+
+    /**
+     * Run thus Test
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(suite());
+    }
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(LazyDynaMapTestCase.class));
+    }
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+        dynaMap = new LazyDynaMap();
+        dynaMap.setReturnNull(true);
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+      dynaMap = null;
+    }
+
+    // ------------------------------------------------ Individual Test Methods
+
+    /**
+     * General Tests
+     */
+    public void testGeneral() {
+//        LazyDynaMap bean = new LazyDynaMap("TestBean");
+        assertEquals("Check DynaClass name", "TestBean", new LazyDynaMap("TestBean").getName());
+
+    }
+
+    /**
+     * Test Getting/Setting a Simple Property
+     */
+    public void testSimpleProperty() {
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Value is null", dynaMap.get(testProperty));
+
+        // Set a new property - should add new property and set value
+        dynaMap.set(testProperty, testInteger1);
+        assertEquals("Check First Value is correct", testInteger1, dynaMap.get(testProperty));
+        assertEquals("Check Property type is correct", Integer.class, dynaMap.getDynaProperty(testProperty).getType());
+
+        // Set the property again - should set the new value
+        dynaMap.set(testProperty, testInteger2);
+        assertEquals("Check Second Value is correct", testInteger2, dynaMap.get(testProperty));
+
+        // Set the property again - with a different type, should succeed
+        dynaMap.set(testProperty, testString1);
+        assertEquals("Check Third Value is correct", testString1, dynaMap.get(testProperty));
+
+    }
+
+    /**
+     * Test Setting a Simple Property when MutableDynaClass is set to restricted
+     */
+    public void testSimplePropertyRestricted() {
+
+        // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
+        dynaMap.setRestricted(true);
+        assertTrue("Check MutableDynaClass is restricted", dynaMap.isRestricted());
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Value is null", dynaMap.get(testProperty));
+
+        // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
+        try {
+            dynaMap.set(testProperty, testString1);
+            fail("expected IllegalArgumentException trying to add new property to restricted DynaClass");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test Getting/Setting a 'Mapped' Property - default HashMap property
+     */
+    public void testMappedPropertyDefault() {
+
+        // Check the property & value doesn't exist
+        assertNull("Check Mapped Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Map is null", dynaMap.get(testProperty));
+        assertNull("Check Mapped Value is null", dynaMap.get(testProperty, testKey));
+
+        // Set a new mapped property - should add new HashMap property and set the mapped value
+        dynaMap.set(testProperty, testKey, testInteger1);
+        assertEquals("Check Mapped Property exists", HashMap.class, dynaMap.get(testProperty).getClass());
+        assertEquals("Check First Mapped Value is correct(a)", testInteger1, dynaMap.get(testProperty, testKey));
+        assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((HashMap)dynaMap.get(testProperty)).get(testKey));
+
+        // Set the property again - should set the new value
+        dynaMap.set(testProperty, testKey, testInteger2);
+        assertEquals("Check Second Mapped Value is correct(a)", testInteger2, dynaMap.get(testProperty, testKey));
+        assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((HashMap)dynaMap.get(testProperty)).get(testKey));
+    }
+
+    /**
+     * Test Getting/Setting a 'Mapped' Property - use TreeMap property
+     */
+    public void testMappedPropertyTreeMap() {
+
+        // Check the property & value doesn't exist
+        assertNull("Check Mapped Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Map is null", dynaMap.get(testProperty));
+
+        // Add a 'TreeMap' property to the DynaClass
+        dynaMap.add(testProperty, TreeMap.class);
+        assertTrue("Check Property is mapped", dynaMap.getDynaProperty(testProperty).isMapped());
+        assertEquals("Check Property is correct type", TreeMap.class, dynaMap.getDynaProperty(testProperty).getType());
+        assertEquals("Check Mapped Property now exists", TreeMap.class, dynaMap.get(testProperty).getClass());
+
+        // Set a new mapped property - should instatiate a new TreeMap property and set the mapped value
+        dynaMap.set(testProperty, testKey, testInteger1);
+        assertEquals("Check Mapped Property exists", TreeMap.class, dynaMap.get(testProperty).getClass());
+        assertEquals("Check First Mapped Value is correct(a)", testInteger1, dynaMap.get(testProperty, testKey));
+        assertEquals("Check First Mapped Value is correct(b)", testInteger1, ((TreeMap)dynaMap.get(testProperty)).get(testKey));
+
+        // Set the property again - should set the new value
+        dynaMap.set(testProperty, testKey, testInteger2);
+        assertEquals("Check Second Mapped Value is correct(a)", testInteger2, dynaMap.get(testProperty, testKey));
+        assertEquals("Check Second Mapped Value is correct(b)", testInteger2, ((TreeMap)dynaMap.get(testProperty)).get(testKey));
+    }
+
+    /**
+     * Test Setting a 'Mapped' Property using PropertyUtils
+     */
+    public void testMappedPropertyUtils() {
+
+        dynaMap.setReturnNull(false);
+
+        // Check the property & value doesn't exist
+        assertFalse("Check Mapped Property doesn't exist", dynaMap.isDynaProperty(testProperty));
+        assertNull("Check Map is null", dynaMap.get(testProperty));
+        assertNull("Check Mapped Value is null", dynaMap.get(testProperty, testKey));
+
+        // Set the mapped property using PropertyUtils
+        try {
+          PropertyUtils.setProperty(dynaMap, testProperty+"("+testKey+")", testString1);
+        }
+        catch (NoSuchMethodException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (InvocationTargetException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (IllegalAccessException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+
+        // Check property value correctly set
+        assertEquals("Check Mapped Bean Value is correct", testString1, dynaMap.get(testProperty, testKey));
+
+    }
+
+    /**
+     * Test Setting a Mapped Property when MutableDynaClass is set to restricted
+     */
+    public void testMappedPropertyRestricted() {
+
+        // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
+        dynaMap.setRestricted(true);
+        assertTrue("Check MutableDynaClass is restricted", dynaMap.isRestricted());
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Value is null", dynaMap.get(testProperty));
+
+        // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
+        try {
+            dynaMap.set(testProperty, testKey, testInteger1);
+            fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test setting mapped property for type which is not Map
+     */
+    public void testMappedInvalidType() {
+        dynaMap.set(testProperty, new Integer(1));
+        assertFalse("Check Property is not mapped", dynaMap.getDynaProperty(testProperty).isMapped());
+        try {
+            dynaMap.set(testProperty, testKey, testInteger1);
+            fail("set(property, key, value) should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+    /**
+     * Test Getting/Setting an 'Indexed' Property - default ArrayList property
+     */
+    public void testIndexedPropertyDefault() {
+
+        int index = 3;
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", dynaMap.get(testProperty));
+        assertNull("Check Indexed value is null", dynaMap.get(testProperty, index));
+
+        // Set the property, should create new ArrayList and set appropriate indexed value
+        dynaMap.set(testProperty, index, testInteger1);
+        assertNotNull("Check Indexed Property is not null", dynaMap.get(testProperty));
+        assertEquals("Check Indexed Property is correct type", ArrayList.class, dynaMap.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct", testInteger1, dynaMap.get(testProperty, index));
+        assertEquals("Check First Array length is correct", new Integer(index+1),  new Integer(((ArrayList)dynaMap.get(testProperty)).size()));
+
+        // Set a second indexed value, should automatically grow the ArrayList and set appropriate indexed value
+        index = index + 2;
+        dynaMap.set(testProperty, index, testString1);
+        assertEquals("Check Second Indexed Value is correct", testString1, dynaMap.get(testProperty, index));
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((ArrayList)dynaMap.get(testProperty)).size()));
+    }
+
+    /**
+     * Test Getting/Setting a List 'Indexed' Property - use alternative List (LinkedList)
+     */
+    public void testIndexedLinkedList() {
+
+        int   index     = 3;
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", dynaMap.get(testProperty));
+
+        // Add a 'LinkedList' property to the DynaClass - should instantiate a new LinkedList
+        dynaMap.add(testProperty, LinkedList.class);
+        assertTrue("Check Property is indexed", dynaMap.getDynaProperty(testProperty).isIndexed());
+        assertEquals("Check Property is correct type", LinkedList.class, dynaMap.getDynaProperty(testProperty).getType());
+        assertEquals("Check Indexed Property now exists", LinkedList.class, dynaMap.get(testProperty).getClass());
+
+        // Set the Indexed property, should grow the list to the correct size
+        dynaMap.set(testProperty, index, testString1);
+        assertEquals("Check Property type is correct", LinkedList.class, dynaMap.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct", testString1, dynaMap.get(testProperty, index));
+        assertEquals("Check First Array length is correct", new Integer(index+1),  new Integer(((LinkedList)dynaMap.get(testProperty)).size()));
+
+        // Set a second indexed value, should automatically grow the LinkedList and set appropriate indexed value
+        index = index + 2;
+        dynaMap.set(testProperty, index, testInteger1);
+        assertEquals("Check Second Indexed Value is correct", testInteger1, dynaMap.get(testProperty, index));
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((LinkedList)dynaMap.get(testProperty)).size()));
+    }
+
+    /**
+     * Test Getting/Setting a primitive array 'Indexed' Property - use int[]
+     */
+    public void testIndexedPrimitiveArray() {
+
+        int   index     = 3;
+        int[] primitiveArray = new int[0];
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", dynaMap.get(testProperty));
+
+        // Add a DynaProperty of type int[]
+        dynaMap.add(testProperty, primitiveArray.getClass());
+        assertEquals("Check Indexed Property exists", primitiveArray.getClass(), dynaMap.getDynaProperty(testProperty).getType());
+        assertTrue("Check Indexed Property exists", dynaMap.get(testProperty).getClass().isInstance(primitiveArray));
+
+        // Set an indexed value
+        dynaMap.set(testProperty, index, testInteger1);
+        assertNotNull("Check Indexed Property is not null", dynaMap.get(testProperty));
+        assertEquals("Check Indexed Property is correct type", primitiveArray.getClass(), dynaMap.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct(a)", testInteger1, dynaMap.get(testProperty, index));
+        assertEquals("Check First Indexed Value is correct(b)", testInteger1, new Integer(((int[])dynaMap.get(testProperty))[index]));
+        assertEquals("Check Array length is correct", new Integer(index+1),  new Integer(((int[])dynaMap.get(testProperty)).length));
+
+        // Set a second indexed value, should automatically grow the int[] and set appropriate indexed value
+        index = index + 2;
+        dynaMap.set(testProperty, index, testInteger2);
+        assertEquals("Check Second Indexed Value is correct(a)", testInteger2, dynaMap.get(testProperty, index));
+        assertEquals("Check Second Indexed Value is correct(b)", testInteger2, new Integer(((int[])dynaMap.get(testProperty))[index]));
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((int[])dynaMap.get(testProperty)).length));
+
+    }
+
+    /**
+     * Test Getting/Setting an Object array 'Indexed' Property - use String[]
+     */
+    public void testIndexedObjectArray() {
+
+        int   index     = 3;
+        Object objectArray = new String[0];
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", dynaMap.get(testProperty));
+
+        // Add a DynaProperty of type String[]
+        dynaMap.add(testProperty, objectArray.getClass());
+        assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaMap.getDynaProperty(testProperty).getType());
+        assertTrue("Check Indexed Property exists", dynaMap.get(testProperty).getClass().isInstance(objectArray));
+
+        // Set an indexed value
+        dynaMap.set(testProperty, index, testString1);
+        assertNotNull("Check Indexed Property is not null", dynaMap.get(testProperty));
+        assertEquals("Check Indexed Property is correct type", objectArray.getClass(), dynaMap.get(testProperty).getClass());
+        assertEquals("Check First Indexed Value is correct(a)", testString1, dynaMap.get(testProperty, index));
+        assertEquals("Check First Indexed Value is correct(b)", testString1, ((String[])dynaMap.get(testProperty))[index]);
+        assertEquals("Check Array length is correct", new Integer(index+1),  new Integer(((String[])dynaMap.get(testProperty)).length));
+
+        // Set a second indexed value, should automatically grow the String[] and set appropriate indexed value
+        index = index + 2;
+        dynaMap.set(testProperty, index, testString2);
+        assertEquals("Check Second Indexed Value is correct(a)", testString2, dynaMap.get(testProperty, index));
+        assertEquals("Check Second Indexed Value is correct(b)", testString2, ((String[])dynaMap.get(testProperty))[index]);
+        assertEquals("Check Second Array length is correct", new Integer(index+1),  new Integer(((String[])dynaMap.get(testProperty)).length));
+    }
+
+    /**
+     * Test Getting/Setting an DynaBean[] array
+     */
+    public void testIndexedDynaBeanArray() {
+
+        int   index     = 3;
+        Object objectArray = new LazyDynaBean[0];
+
+        // Check the property & value doesn't exist
+        assertNull("Check Indexed Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", dynaMap.get(testProperty));
+
+        // Add a DynaProperty of type String[]
+        dynaMap.add(testProperty, objectArray.getClass());
+        assertEquals("Check Indexed Property exists", objectArray.getClass(), dynaMap.getDynaProperty(testProperty).getType());
+        assertEquals("Check Indexed Property is correct type", objectArray.getClass(), dynaMap.get(testProperty).getClass());
+
+        // Retrieving from Array should initialize DynaBean
+        for (int i = index; i >= 0; i--) {
+            assertEquals("Check Array Components initialized", LazyDynaBean.class, dynaMap.get(testProperty, index).getClass());
+        }
+
+        dynaMap.add(testPropertyB, objectArray.getClass());
+        LazyDynaBean newBean = new LazyDynaBean();
+        newBean.set(testPropertyB, testString2);
+        dynaMap.set(testPropertyA, index, newBean);
+        assertEquals("Check Indexed Value is correct(a)", testString2, ((DynaBean)dynaMap.get(testPropertyA, index)).get(testPropertyB));
+
+    }
+
+    /**
+     * Test Setting an 'Indexed' Property using PropertyUtils
+     */
+    public void testIndexedPropertyUtils() {
+
+        int   index     = 3;
+        dynaMap.setReturnNull(false);
+
+        // Check the property & value doesn't exist
+        assertFalse("Check Indexed Property doesn't exist", dynaMap.isDynaProperty(testProperty));
+        assertNull("Check Indexed Property is null", dynaMap.get(testProperty));
+        assertNull("Check Indexed value is null", dynaMap.get(testProperty, index));
+
+        // Use PropertyUtils to set the indexed value
+        try {
+          PropertyUtils.setProperty(dynaMap, testProperty+"["+index+"]", testString1);
+        }
+        catch (NoSuchMethodException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (InvocationTargetException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+        catch (IllegalAccessException ex) {
+            fail("testIndexedPropertyUtils threw "+ex);
+        }
+
+        // Check property value correctly set
+        assertEquals("Check Indexed Bean Value is correct", testString1, dynaMap.get(testProperty, index));
+
+    }
+
+    /**
+     * Test Setting an Indexed Property when MutableDynaClass is set to restricted
+     */
+    public void testIndexedPropertyRestricted() {
+
+        int   index     = 3;
+
+        // Set the MutableDyanClass to 'restricted' (i.e. no new properties cab be added
+        dynaMap.setRestricted(true);
+        assertTrue("Check MutableDynaClass is restricted", dynaMap.isRestricted());
+
+        // Check the property & value doesn't exist
+        assertNull("Check Property doesn't exist", dynaMap.getDynaProperty(testProperty));
+        assertNull("Check Value is null", dynaMap.get(testProperty));
+
+        // Set the property - should fail because property doesn't exist and MutableDynaClass is restricted
+        try {
+            dynaMap.set(testProperty, index, testInteger1);
+            fail("expected IllegalArgumentException trying to add new property to restricted MutableDynaClass");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+
+    }
+
+    /**
+     * Test setting indexed property for type which is not List or Array
+     */
+    public void testIndexedInvalidType() {
+        int   index     = 3;
+        dynaMap.set(testProperty, "Test String");
+        assertFalse("Check Property is not indexed", dynaMap.getDynaProperty(testProperty).isIndexed());
+        try {
+            dynaMap.set(testProperty, index, testString1);
+            fail("set(property, index, value) should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+            // expected result
+        }
+    }
+
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MappedPropertyTestBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MappedPropertyTestBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MappedPropertyTestBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Just a java bean (JAJB) to try to replicate a reported bug 
+ *
+ * @author Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class MappedPropertyTestBean {
+
+    private Map map = new HashMap();
+
+    // -------------------------------------------------------------- Properties
+
+    public String getMapproperty(String key) {
+        return (String) map.get(key);
+    }
+
+    public void setMapproperty(String key, String value) {	
+        map.put(key, value);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/MethodUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,560 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.beanutils.priv.PrivateBeanFactory;
+import org.apache.commons.beanutils.priv.PublicSubBean;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p> Test case for <code>MethodUtils</code> </p>
+ *
+ */
+public class MethodUtilsTestCase extends TestCase {
+
+    // ---------------------------------------------------- Instance Variables
+
+    protected PrivateBeanFactory privateBeanFactory;
+
+    // ---------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public MethodUtilsTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+        privateBeanFactory = new PrivateBeanFactory();
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(MethodUtilsTestCase.class));
+    }
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        privateBeanFactory = null;
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+    /**
+     * <p> Test <code>getAccessibleMethod</code>.
+     */
+    public void testGetAccessibleMethod() {
+        // test MethodUtils.getAccessibleMethod
+        // we'll make things easier by using the convenience methods
+
+        // easy bit first - find a public method
+        // METHOD ONE
+        Method method = MethodUtils.getAccessibleMethod
+                (TestBean.class, "setStringProperty", String.class);
+
+        // check that we've found one that matches
+        assertNotNull(method);
+        assertEquals("method ONE is named correctly",
+                "setStringProperty", method.getName());
+        assertTrue("Method ONE is public",
+                Modifier.isPublic(method.getModifiers()));
+
+        // trickier this one - find a method in a direct interface
+        // METHOD TWO
+        method = MethodUtils.getAccessibleMethod
+                (privateBeanFactory.create().getClass(),
+                        "methodBar",
+                        String.class);
+
+        // check that we've found one that matches
+        assertNotNull(method);
+        assertEquals("Method TWO is named correctly",
+                "methodBar", method.getName());
+        assertTrue("Method TWO is public",
+                Modifier.isPublic(method.getModifiers()));
+
+        // trickier this one - find a method in a indirect interface
+        // METHOD THREE
+        method = MethodUtils.getAccessibleMethod
+                (privateBeanFactory.createSubclass().getClass(),
+                        "methodBaz",
+                        String.class);
+
+        // check that we've found one that matches
+        assertNotNull(method);
+        assertEquals("Method THREE is named correctly",
+                "methodBaz", method.getName());
+        assertTrue("Method THREE is public",
+                Modifier.isPublic(method.getModifiers()));
+
+    }
+
+
+    /**
+     * <p> Test <code>invokeExactMethod</code>.
+     */
+    public void testInvokeExactMethod() {
+        // test MethodUtils.invokeExactMethod
+        // easy bit first - invoke a public method
+        // METHOD ONE
+        try {
+
+            TestBean bean = new TestBean();
+            Object ret = MethodUtils.invokeExactMethod(bean, "setStringProperty", "TEST");
+            // check that the return's right and that the properties been set
+            assertNull(ret);
+            assertEquals("Method ONE was invoked", "TEST", bean.getStringProperty());
+
+        } catch (Throwable t) {
+            // ONE
+            fail("Exception in method ONE prevented invokation: " + t.toString());
+        }
+
+        // trickier this one - find a method in a direct interface
+        // METHOD TWO FAILURE
+        try {
+
+            Object ret = MethodUtils.invokeExactMethod(
+                    privateBeanFactory.create(),
+                    "methodBar",
+                    "ANOTHER TEST");
+
+            // check that we've found one that matches
+            assertEquals("Method TWO was invoked correctly", "ANOTHER TEST", ret);
+
+        } catch (Throwable t) {
+            // METHOD TWO FAILURE
+            fail("Exception in method TWO prevented invokation: " + t.toString());
+        }
+
+
+        // trickier this one - find a method in a indirect interface
+        // METHOD THREE
+        try {
+
+            Object ret = MethodUtils.invokeExactMethod(
+                    privateBeanFactory.createSubclass(),
+                    "methodBaz",
+                    "YET ANOTHER TEST");
+
+
+            // check that we've found one that matches
+            assertEquals("Method TWO was invoked correctly", "YET ANOTHER TEST", ret);
+
+
+        } catch (Throwable t) {
+            // METHOD THREE FAILURE
+            fail("Exception in method THREE prevented invokation: " + t.toString());
+
+        }
+    }
+    
+    /**
+     * <p> Test <code>invokeMethod</code>.
+     */
+    public void testInvokeMethod() throws Exception {
+        // i'm going to test that the actual calls work first and then try them via reflection
+        
+        AbstractParent parent = new AlphaBean("parent");
+        
+        // try testAddChild through abstract superclass
+        BetaBean childOne = new BetaBean("ChildOne");
+        
+        assertEquals("Oh no! Badly coded test case! (1)", "ChildOne", parent.testAddChild(childOne));
+        
+        // let's try MethodUtils version
+        assertEquals(
+                        "Cannot invoke through abstract class (1)", 
+                        "ChildOne", 
+                        MethodUtils.invokeMethod(parent, "testAddChild", childOne));
+
+        
+        // try adding through interface
+        AlphaBean childTwo = new AlphaBean("ChildTwo");
+        
+        assertEquals("Oh no! Badly coded test case! (2)", "ChildTwo", parent.testAddChild(childTwo));
+        
+        // let's try MethodUtils version
+        assertEquals(
+                        "Cannot invoke through interface (1)", 
+                        "ChildTwo", 
+                        MethodUtils.invokeMethod(parent, "testAddChild", childTwo));
+       
+        
+        Object[] params = new Object[2];
+
+        assertEquals("Oh no! Badly coded test case! (3)", "ChildOne", parent.testAddChild2("parameter", childOne));
+        
+        
+        // let's try MethodUtils version
+        params[0] = "parameter";
+        params[1] = childOne;
+        
+        assertEquals(
+                        "Cannot invoke through abstract class (1)", 
+                        "ChildOne", 
+                        MethodUtils.invokeMethod(parent, "testAddChild2", params));
+                        
+        assertEquals("Oh no! Badly coded test case! (4)", "ChildTwo", parent.testAddChild2("parameter", childTwo));
+        
+        // let's try MethodUtils version
+        params[0] = "parameter";
+        params[1] = childTwo;
+       
+        assertEquals(
+                        "Cannot invoke through abstract class (1)", 
+                        "ChildTwo", 
+                        MethodUtils.invokeMethod(parent, "testAddChild2", params));
+        
+        // test that exception is correctly thrown when a method cannot be found with matching params
+        try {
+            // the next line
+            parent = new AlphaBean("parent");
+            childOne = new BetaBean("ChildOne");
+            MethodUtils.invokeMethod(parent, "bogus", childOne);
+            // should get here!
+            fail("No exception thrown when no appropriate method exists");
+            
+        } catch (NoSuchMethodException e) {
+            // this is what we're expecting!
+        }
+        
+        MethodUtils.invokeMethod(parent, "getName", null);
+        MethodUtils.invokeMethod(parent, "getName", null, null);
+        MethodUtils.invokeExactMethod(parent, "getName", null);
+        MethodUtils.invokeExactMethod(parent, "getName", null, null);        
+    }
+
+    
+    /**
+     * <p> Test <code>invokeMethod</code> with a primitive.
+     */
+    public void testInvokeMethodWithPrimitives() throws Exception {
+        // first test that the bean works 
+        PrimitiveBean bean = new PrimitiveBean();
+        bean.setFloat(20.0f);
+        bean.setLong(10l);
+        bean.setBoolean(true);
+        bean.setInt(12);
+        bean.setDouble(25.5d);
+        
+        assertEquals("Bug in PrimitiveBean (1)", 20.0f, bean.getFloat(), 0.01f);
+        assertEquals("Bug in PrimitiveBean (2)", 10, bean.getLong());
+        assertEquals("Bug in PrimitiveBean (3)", true, bean.getBoolean());
+        assertEquals("Bug in PrimitiveBean (4)", 12, bean.getInt());
+        assertEquals("Bug in PrimitiveBean (5)", 25.5d, bean.getDouble(), 0.01f);
+        
+        bean = new PrimitiveBean();
+        MethodUtils.invokeMethod(bean, "setBoolean", new Boolean(true));
+        assertEquals("Call boolean property using invokeMethod", true, bean.getBoolean());
+
+        bean = new PrimitiveBean();
+        MethodUtils.invokeMethod(bean, "setFloat", new Float(20.0f));
+        assertEquals("Call float property using invokeMethod", 20.0f, bean.getFloat(), 0.01f);
+        
+        bean = new PrimitiveBean();
+        MethodUtils.invokeMethod(bean, "setLong", new Long(10));
+        assertEquals("Call float property using invokeMethod", 10, bean.getLong());
+        
+        bean = new PrimitiveBean();
+        MethodUtils.invokeMethod(bean, "setInt", new Integer(12));
+        assertEquals("Set float property using invokeMethod", 12, bean.getInt());
+        
+        bean = new PrimitiveBean();
+        MethodUtils.invokeMethod(bean, "setDouble", new Double(25.5d));
+        assertEquals("Set float property using invokeMethod", 25.5d, bean.getDouble(), 0.01d);
+    }
+
+
+    /**
+     * Simple tests for accessing static methods via invokeMethod().
+     */
+    public void testSimpleStatic1() {
+
+        TestBean bean = new TestBean();
+        Object value = null;
+        int current = TestBean.currentCounter();
+
+        try {
+
+            // Return initial value of the counter
+            value = MethodUtils.invokeMethod
+                (bean, "currentCounter", new Object[0], new Class[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+            // Increment via no-arguments version
+            MethodUtils.invokeMethod
+                (bean, "incrementCounter", new Object[0], new Class[0]);
+
+            // Validate updated value
+            current++;
+            value = MethodUtils.invokeMethod
+                (bean, "currentCounter", new Object[0], new Class[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+            // Increment via specified-argument version
+            MethodUtils.invokeMethod
+                (bean, "incrementCounter",
+                 new Object[] { new Integer(5) },
+                 new Class[] { Integer.TYPE });
+
+            // Validate updated value
+            current += 5;
+            value = MethodUtils.invokeMethod
+                (bean, "currentCounter", new Object[0], new Class[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+        } catch (Exception e) {
+            fail("Threw exception" + e);
+        }
+
+    }
+
+
+    /**
+     * Simple tests for accessing static methods via invokeExactMethod().
+     */
+    public void testSimpleStatic2() {
+
+        TestBean bean = new TestBean();
+        Object value = null;
+        int current = TestBean.currentCounter();
+
+        try {
+
+            // Return initial value of the counter
+            value = MethodUtils.invokeExactMethod
+                (bean, "currentCounter", new Object[0], new Class[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+            // Increment via no-arguments version
+            MethodUtils.invokeExactMethod
+                (bean, "incrementCounter", new Object[0], new Class[0]);
+
+            // Validate updated value
+            current++;
+            value = MethodUtils.invokeExactMethod
+                (bean, "currentCounter", new Object[0], new Class[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+            // Increment via specified-argument version
+            MethodUtils.invokeExactMethod
+                (bean, "incrementCounter",
+                 new Object[] { new Integer(5) },
+                 new Class[] { Integer.TYPE });
+
+            // Validate updated value
+            current += 5;
+            value = MethodUtils.invokeExactMethod
+                (bean, "currentCounter", new Object[0], new Class[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+
+        } catch (Exception e) {
+            fail("Threw exception" + e);
+        }
+
+    }
+
+
+    /**
+     * Simple tests for accessing static methods via getAccessibleMethod()
+     */
+    public void testSimpleStatic3() {
+
+        Object value = null;
+        int current = TestBean.currentCounter();
+
+        try {
+
+            // Acquire the methods we need
+            Method currentCounterMethod = MethodUtils.getAccessibleMethod
+                (TestBean.class, "currentCounter",
+                 new Class[0]);
+            assertNotNull("currentCounterMethod exists",
+                          currentCounterMethod);
+            assertEquals("currentCounterMethod name",
+                         "currentCounter",
+                         currentCounterMethod.getName());
+            assertEquals("currentCounterMethod args",
+                         0,
+                         currentCounterMethod.getParameterTypes().length);
+            assertTrue("currentCounterMethod public",
+                       Modifier.isPublic(currentCounterMethod.getModifiers()));
+            assertTrue("currentCounterMethod static",
+                       Modifier.isStatic(currentCounterMethod.getModifiers()));
+            Method incrementCounterMethod1 = MethodUtils.getAccessibleMethod
+                (TestBean.class, "incrementCounter",
+                 new Class[0]);
+            assertNotNull("incrementCounterMethod1 exists",
+                          incrementCounterMethod1);
+            assertEquals("incrementCounterMethod1 name",
+                         "incrementCounter",
+                         incrementCounterMethod1.getName());
+            assertEquals("incrementCounterMethod1 args",
+                         0,
+                         incrementCounterMethod1.getParameterTypes().length);
+            assertTrue("incrementCounterMethod1 public",
+                       Modifier.isPublic(incrementCounterMethod1.getModifiers()));
+            assertTrue("incrementCounterMethod1 static",
+                       Modifier.isStatic(incrementCounterMethod1.getModifiers()));
+            Method incrementCounterMethod2 = MethodUtils.getAccessibleMethod
+                (TestBean.class, "incrementCounter",
+                 new Class[] { Integer.TYPE });
+            assertNotNull("incrementCounterMethod2 exists",
+                          incrementCounterMethod2);
+            assertEquals("incrementCounterMethod2 name",
+                         "incrementCounter",
+                         incrementCounterMethod2.getName());
+            assertEquals("incrementCounterMethod2 args",
+                         1,
+                         incrementCounterMethod2.getParameterTypes().length);
+            assertTrue("incrementCounterMethod2 public",
+                       Modifier.isPublic(incrementCounterMethod2.getModifiers()));
+            assertTrue("incrementCounterMethod2 static",
+                       Modifier.isStatic(incrementCounterMethod2.getModifiers()));
+
+            // Return initial value of the counter
+            value = currentCounterMethod.invoke(null, new Object[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+            // Increment via no-arguments version
+            incrementCounterMethod1.invoke(null, new Object[0]);
+
+            // Validate updated value
+            current++;
+            value = currentCounterMethod.invoke(null, new Object[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+            // Increment via specified-argument version
+            incrementCounterMethod2.invoke(null,
+                                           new Object[] { new Integer(5) });
+
+            // Validate updated value
+            current += 5;
+            value = currentCounterMethod.invoke(null, new Object[0]);
+            assertNotNull("currentCounter exists", value);
+            assertTrue("currentCounter type",
+                       value instanceof Integer);
+            assertEquals("currentCounter value",
+                         current,
+                         ((Integer) value).intValue());
+
+        } catch (Exception e) {
+            fail("Threw exception" + e);
+        }
+
+    }
+
+    public void testPublicSub() throws Exception {
+        // make sure that bean does what it should
+        PublicSubBean bean = new PublicSubBean();
+        assertEquals("Start value (foo)", bean.getFoo(), "This is foo");
+        assertEquals("Start value (bar)", bean.getBar(), "This is bar");
+        bean.setFoo("new foo");
+        bean.setBar("new bar");
+        assertEquals("Set value (foo)", bean.getFoo(), "new foo");
+        assertEquals("Set value (bar)", bean.getBar(), "new bar");
+        
+        // see if we can access public methods in a default access superclass
+        // from a public access subclass instance
+        MethodUtils.invokeMethod(bean, "setFoo", "alpha");
+        assertEquals("Set value (foo:2)", bean.getFoo(), "alpha");
+        MethodUtils.invokeMethod(bean, "setBar", "beta");
+        assertEquals("Set value (bar:2)", bean.getFoo(), "alpha");
+    }
+    
+    public void testParentMethod() throws Exception {
+        OutputStream os = new PrintStream(System.out);
+        PrintStream ps = new PrintStream(System.out);
+        
+        A a = new A();
+        MethodUtils.invokeMethod(a, "foo", os);
+        assertTrue("Method Invoked(1)", a.called);
+        
+        a = new A();
+        MethodUtils.invokeMethod(a, "foo", ps);
+        assertTrue("Method Invoked(2)", a.called);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/NestedTestBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/NestedTestBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/NestedTestBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Specialist test bean for complex nested properties.
+ *
+ * @author Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class NestedTestBean {
+    
+    
+    // ------------------------------------------------------------- Constructors
+    public NestedTestBean(String name) {
+        setName(name);
+    }
+    
+    
+    // ------------------------------------------------------------- Properties
+    
+    private String name;
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    
+    private String testString = "NOT SET";
+    
+    public String getTestString() {
+        return testString;
+    }
+    
+    public void setTestString(String testString) {
+        this.testString = testString;
+    }
+    
+    
+    private boolean testBoolean = false;
+    
+    public boolean getTestBoolean() {
+        return testBoolean;
+    }
+    
+    public void setTestBoolean(boolean testBoolean) {
+        this.testBoolean = testBoolean;
+    }    
+    
+    
+    private NestedTestBean indexedBeans[];
+    
+    public void init() {
+        indexedBeans = new NestedTestBean[5];
+        indexedBeans[0] = new NestedTestBean("Bean at 0");
+        indexedBeans[1] = new NestedTestBean("Bean at 1"); 
+        indexedBeans[2] = new NestedTestBean("Bean at 2"); 
+        indexedBeans[3] = new NestedTestBean("Bean at 3"); 
+        indexedBeans[4] = new NestedTestBean("Bean at 4");
+        
+        simpleBean = new NestedTestBean("Simple Property Bean");
+    };
+    
+    public NestedTestBean getIndexedProperty(int index) {
+        return (this.indexedBeans[index]);
+    }
+
+    public void setIndexedProperty(int index, NestedTestBean value) {
+        this.indexedBeans[index] = value;
+    }
+    
+    private NestedTestBean simpleBean;
+    
+    public NestedTestBean getSimpleBeanProperty() {
+        return simpleBean;
+    }
+    
+    // ------------------------------------------------------- Static Variables
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PassTestException.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PassTestException.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PassTestException.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * Just a runtime exception. Useful for check that a method is called.
+ * 
+ * @author Robert Burrell Donkin
+ */
+
+public class PassTestException extends RuntimeException {
+}
\ No newline at end of file

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PrimitiveBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PrimitiveBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PrimitiveBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+/**
+ * Bean that has primitive properties
+ */
+public class PrimitiveBean {
+
+    private float _float;
+    private double _double;
+    private boolean _boolean;
+    private long _long;
+    private int _int;
+    
+    public float getFloat() {
+        return _float;
+    }
+    
+    public void setFloat(float _float) {
+        this._float = _float;
+    }
+    
+    public double getDouble() {
+        return _double;
+    }
+    
+    public void setDouble(double _double) {
+        this._double = _double;
+    }
+    
+    public boolean getBoolean() {
+        return _boolean;
+    }
+    
+    public void setBoolean(boolean _boolean) {
+        this._boolean = _boolean;
+    }
+    
+    public long getLong() {
+        return _long;
+    }
+    
+    public void setLong(long _long) {
+        this._long = _long;
+    }
+    
+    public int getInt() {
+        return _int;
+    }
+    
+    public void setInt(int _int) {
+        this._int = _int;
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsBenchCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsBenchCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsBenchCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * JUnit Test Case containing microbenchmarks for PropertyUtils.
+ */
+
+public class PropertyUtilsBenchCase extends TestCase {
+
+
+    // ------------------------------------------------------------ Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public PropertyUtilsBenchCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // ------------------------------------------------------ Instance Variables
+
+
+    // Basic loop counter
+    private long counter = 100000;
+
+    // DynaClass for inDyna and outDyna
+    private DynaClass dynaClass = null;
+
+    // Input objects that have identical sets of properties and values.
+    private BenchBean inBean = null;
+    private DynaBean inDyna = null;
+    private Map inMap = null;
+
+    // Output objects that have identical sets of properties.
+    private BenchBean outBean = null;
+    private DynaBean outDyna = null;
+
+    // PropertyUtilsBean instance to be used
+    private PropertyUtilsBean pu = null;
+
+
+    // ---------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        // Set up loop counter (if property specified)
+        String prop = System.getProperty("counter");
+        if (prop != null) {
+            counter = Long.parseLong(prop);
+        }
+
+        // Set up DynaClass for our DynaBean instances
+        dynaClass = new BasicDynaClass
+            ("BenchDynaClass", null,
+             new DynaProperty[]{
+                 new DynaProperty("booleanProperty", Boolean.TYPE),
+                 new DynaProperty("byteProperty", Byte.TYPE),
+                 new DynaProperty("doubleProperty", Double.TYPE),
+                 new DynaProperty("floatProperty", Float.TYPE),
+                 new DynaProperty("intProperty", Integer.TYPE),
+                 new DynaProperty("longProperty", Long.TYPE),
+                 new DynaProperty("shortProperty", Short.TYPE),
+                 new DynaProperty("stringProperty", String.class),
+             });
+
+        // Create input instances
+        inBean = new BenchBean();
+        inMap = new HashMap();
+        inMap.put("booleanProperty", new Boolean(inBean.getBooleanProperty()));
+        inMap.put("byteProperty", new Byte(inBean.getByteProperty()));
+        inMap.put("doubleProperty", new Double(inBean.getDoubleProperty()));
+        inMap.put("floatProperty", new Float(inBean.getFloatProperty()));
+        inMap.put("intProperty", new Integer(inBean.getIntProperty()));
+        inMap.put("longProperty", new Long(inBean.getLongProperty()));
+        inMap.put("shortProperty", new Short(inBean.getShortProperty()));
+        inMap.put("stringProperty", inBean.getStringProperty());
+        inDyna = dynaClass.newInstance();
+        Iterator inKeys = inMap.keySet().iterator();
+        while (inKeys.hasNext()) {
+            String inKey = (String) inKeys.next();
+            inDyna.set(inKey, inMap.get(inKey));
+        }
+
+        // Create output instances
+        outBean = new BenchBean();
+        outDyna = dynaClass.newInstance();
+        Iterator outKeys = inMap.keySet().iterator();
+        while (outKeys.hasNext()) {
+            String outKey = (String) outKeys.next();
+            outDyna.set(outKey, inMap.get(outKey));
+        }
+
+        // Set up PropertyUtilsBean instance we will use
+        pu = PropertyUtilsBean.getInstance();
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(PropertyUtilsBenchCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        dynaClass = null;
+        inBean = null;
+        inDyna = null;
+        inMap = null;
+        outBean = null;
+        outDyna = null;
+        pu = null;
+
+    }
+
+
+
+    // ------------------------------------------------- Individual Test Methods
+
+
+    // Time copyProperties() from a bean
+    public void testCopyPropertiesBean() throws Exception {
+
+        long start;
+        long stop;
+
+        // Bean->Bean
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outBean, inBean);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outBean, inBean);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("PU.copyProperties(bean,bean), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Bean->Dyna
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outDyna, inBean);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outDyna, inBean);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("PU.copyProperties(dyna,bean), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time copyProperties() from a DynaBean
+    public void testCopyPropertiesDyna() throws Exception {
+
+        long start;
+        long stop;
+
+        // Dyna->Bean
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outBean, inDyna);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outBean, inDyna);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("PU.copyProperties(bean,dyna), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Dyna->Dyna
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outDyna, inDyna);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outDyna, inDyna);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("PU.copyProperties(dyna,dyna), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // Time copyProperties() from a Map
+    public void testCopyPropertiesMap() throws Exception {
+
+        long start;
+        long stop;
+
+        // Dyna->Bean
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outBean, inMap);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outBean, inMap);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("PU.copyProperties(bean, map), count=" + counter +
+                           ", time=" + (stop - start));
+
+        // Dyna->Dyna
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outDyna, inMap);
+        }
+        start = System.currentTimeMillis();
+        for (long i = 0; i < counter; i++) {
+            pu.copyProperties(outDyna, inMap);
+        }
+        stop = System.currentTimeMillis();
+        System.err.println("PU.copyProperties(dyna, map), count=" + counter +
+                           ", time=" + (stop - start));
+
+    }
+
+
+    // --------------------------------------------------------- Support Methods
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,3665 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.beanutils.priv.PrivateBeanFactory;
+import org.apache.commons.beanutils.priv.PrivateDirect;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>Test Case for the PropertyUtils class.  The majority of these tests use
+ * instances of the TestBean class, so be sure to update the tests if you
+ * change the characteristics of that class.</p>
+ *
+ * <p>So far, this test case has tests for the following methods of the
+ * <code>PropertyUtils</code> class:</p>
+ * <ul>
+ * <li>getIndexedProperty(Object,String)</li>
+ * <li>getIndexedProperty(Object,String,int)</li>
+ * <li>getMappedProperty(Object,String)</li>
+ * <li>getMappedProperty(Object,String,String</li>
+ * <li>getNestedProperty(Object,String)</li>
+ * <li>getPropertyDescriptor(Object,String)</li>
+ * <li>getPropertyDescriptors(Object)</li>
+ * <li>getPropertyType(Object,String)</li>
+ * <li>getSimpleProperty(Object,String)</li>
+ * <li>setIndexedProperty(Object,String,Object)</li>
+ * <li>setIndexedProperty(Object,String,String,Object)</li>
+ * <li>setMappedProperty(Object,String,Object)</li>
+ * <li>setMappedProperty(Object,String,String,Object)</li>
+ * <li>setNestedProperty(Object,String,Object)</li>
+ * <li>setSimpleProperty(Object,String,Object)</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author Jan Sorensen
+ * @version $Revision: 1.34 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class PropertyUtilsTestCase extends TestCase {
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    /**
+     * The fully qualified class name of our private directly
+     * implemented interface.
+     */
+    private static final String PRIVATE_DIRECT_CLASS =
+            "org.apache.commons.beanutils.priv.PrivateDirect";
+
+
+    /**
+     * The fully qualified class name of our private indirectly
+     * implemented interface.
+     */
+    private static final String PRIVATE_INDIRECT_CLASS =
+            "org.apache.commons.beanutils.priv.PrivateIndirect";
+
+
+    /**
+     * The fully qualified class name of our test bean class.
+     */
+    private static final String TEST_BEAN_CLASS =
+            "org.apache.commons.beanutils.TestBean";
+
+
+    /**
+     * The basic test bean for each test.
+     */
+    protected TestBean bean = null;
+
+
+    /**
+     * The "package private subclass" test bean for each test.
+     */
+    protected TestBeanPackageSubclass beanPackageSubclass = null;
+
+
+    /**
+     * The test bean for private access tests.
+     */
+    protected PrivateDirect beanPrivate = null;
+
+
+    /**
+     * The test bean for private access tests of subclasses.
+     */
+    protected PrivateDirect beanPrivateSubclass = null;
+
+
+    /**
+     * The "public subclass" test bean for each test.
+     */
+    protected TestBeanPublicSubclass beanPublicSubclass = null;
+
+
+    /**
+     * The set of properties that should be described.
+     */
+    protected String describes[] =
+    { "booleanProperty",
+      "booleanSecond",
+      "doubleProperty",
+      "floatProperty",
+      "intArray",
+      //      "intIndexed",
+      "intProperty",
+      "listIndexed",
+      "longProperty",
+      //      "mappedObjects",
+      //      "mappedProperty",
+      //      "mappedIntProperty",
+      "nested",
+      "nullProperty",
+      //      "readOnlyProperty",
+      "shortProperty",
+      "stringArray",
+      //      "stringIndexed",
+      "stringProperty"
+    };
+
+
+    /**
+     * The set of property names we expect to have returned when calling
+     * <code>getPropertyDescriptors()</code>.  You should update this list
+     * when new properties are added to TestBean.
+     */
+    protected final static String[] properties = {
+        "booleanProperty",
+        "booleanSecond",
+        "doubleProperty",
+        "dupProperty",
+        "floatProperty",
+        "intArray",
+        "intIndexed",
+        "intProperty",
+        "listIndexed",
+        "longProperty",
+        "nested",
+        "nullProperty",
+        "readOnlyProperty",
+        "shortProperty",
+        "stringArray",
+        "stringIndexed",
+        "stringProperty",
+        "writeOnlyProperty",
+    };
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public PropertyUtilsTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        bean = new TestBean();
+        beanPackageSubclass = new TestBeanPackageSubclass();
+        beanPrivate = PrivateBeanFactory.create();
+        beanPrivateSubclass = PrivateBeanFactory.createSubclass();
+        beanPublicSubclass = new TestBeanPublicSubclass();
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(PropertyUtilsTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        bean = null;
+        beanPackageSubclass = null;
+        beanPrivate = null;
+        beanPrivateSubclass = null;
+        beanPublicSubclass = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Test copyProperties() when the origin is a a <code>Map</code>.
+     */
+    public void testCopyPropertiesMap() {
+
+        Map map = new HashMap();
+        map.put("booleanProperty", Boolean.FALSE);
+        map.put("doubleProperty", new Double(333.0));
+        map.put("dupProperty", new String[] { "New 0", "New 1", "New 2" });
+        map.put("floatProperty", new Float((float) 222.0));
+        map.put("intArray", new int[] { 0, 100, 200 });
+        map.put("intProperty", new Integer(111));
+        map.put("longProperty", new Long(444));
+        map.put("shortProperty", new Short((short) 555));
+        map.put("stringProperty", "New String Property");
+
+        try {
+            PropertyUtils.copyProperties(bean, map);
+        } catch (Throwable t) {
+            fail("Threw " + t.toString());
+        }
+
+        // Scalar properties
+        assertEquals("booleanProperty", false,
+                     bean.getBooleanProperty());
+        assertEquals("doubleProperty", 333.0,
+                     bean.getDoubleProperty(), 0.005);
+        assertEquals("floatProperty", (float) 222.0,
+                     bean.getFloatProperty(), (float) 0.005);
+        assertEquals("intProperty", 111,
+                     bean.getIntProperty());
+        assertEquals("longProperty", (long) 444,
+                     bean.getLongProperty());
+        assertEquals("shortProperty", (short) 555,
+                     bean.getShortProperty());
+        assertEquals("stringProperty", "New String Property",
+                     bean.getStringProperty());
+                     
+        // Indexed Properties
+        String dupProperty[] = bean.getDupProperty();
+        assertNotNull("dupProperty present", dupProperty);
+        assertEquals("dupProperty length", 3, dupProperty.length);
+        assertEquals("dupProperty[0]", "New 0", dupProperty[0]);
+        assertEquals("dupProperty[1]", "New 1", dupProperty[1]);
+        assertEquals("dupProperty[2]", "New 2", dupProperty[2]);
+        int intArray[] = bean.getIntArray();
+        assertNotNull("intArray present", intArray);
+        assertEquals("intArray length", 3, intArray.length);
+        assertEquals("intArray[0]", 0, intArray[0]);
+        assertEquals("intArray[1]", 100, intArray[1]);
+        assertEquals("intArray[2]", 200, intArray[2]);
+
+    }
+
+
+    /**
+     * Test the describe() method.
+     */
+    public void testDescribe() {
+
+        Map map = null;
+        try {
+            map = PropertyUtils.describe(bean);
+        } catch (Exception e) {
+            fail("Threw exception " + e);
+        }
+
+        // Verify existence of all the properties that should be present
+        for (int i = 0; i < describes.length; i++) {
+            assertTrue("Property '" + describes[i] + "' is present",
+                       map.containsKey(describes[i]));
+        }
+        assertTrue("Property 'writeOnlyProperty' is not present",
+                   !map.containsKey("writeOnlyProperty"));
+
+        // Verify the values of scalar properties
+        assertEquals("Value of 'booleanProperty'",
+                     Boolean.TRUE,
+                     (Boolean) map.get("booleanProperty"));
+        assertEquals("Value of 'doubleProperty'",
+                     new Double(321.0),
+                     (Double) map.get("doubleProperty"));
+        assertEquals("Value of 'floatProperty'",
+                     new Float((float) 123.0),
+                     (Float) map.get("floatProperty"));
+        assertEquals("Value of 'intProperty'",
+                     new Integer(123),
+                     (Integer) map.get("intProperty"));
+        assertEquals("Value of 'longProperty'",
+                     new Long(321),
+                     (Long) map.get("longProperty"));
+        assertEquals("Value of 'shortProperty'",
+                     new Short((short) 987),
+                     (Short) map.get("shortProperty"));
+        assertEquals("Value of 'stringProperty'",
+                     "This is a string",
+                     (String) map.get("stringProperty"));
+
+    }
+
+
+    /**
+     * Corner cases on getPropertyDescriptor invalid arguments.
+     */
+    public void testGetDescriptorArguments() {
+
+        try {
+            PropertyUtils.getPropertyDescriptor(null, "stringProperty");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getPropertyDescriptor(bean, null);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>booleanProperty</code>.
+     */
+    public void testGetDescriptorBoolean() {
+
+        testGetDescriptorBase("booleanProperty", "getBooleanProperty",
+                "setBooleanProperty");
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>doubleProperty</code>.
+     */
+    public void testGetDescriptorDouble() {
+
+        testGetDescriptorBase("doubleProperty", "getDoubleProperty",
+                "setDoubleProperty");
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>floatProperty</code>.
+     */
+    public void testGetDescriptorFloat() {
+
+        testGetDescriptorBase("floatProperty", "getFloatProperty",
+                "setFloatProperty");
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>intProperty</code>.
+     */
+    public void testGetDescriptorInt() {
+
+        testGetDescriptorBase("intProperty", "getIntProperty",
+                "setIntProperty");
+
+    }
+
+
+    /**
+     * <p>Negative tests on an invalid property with two different boolean
+     * getters (which is fine, according to the JavaBeans spec) but a
+     * String setter instead of a boolean setter.</p>
+     *
+     * <p>Although one could logically argue that this combination of method
+     * signatures should not identify a property at all, there is a sentence
+     * in Section 8.3.1 making it clear that the behavior tested for here
+     * is correct:  "If we find only one of these methods, then we regard
+     * it as defining either a read-only or write-only property called
+     * <em>&lt;property-name&gt;</em>.</p>
+     */
+    public void testGetDescriptorInvalidBoolean() throws Exception {
+
+	PropertyDescriptor pd =
+	    PropertyUtils.getPropertyDescriptor(bean, "invalidBoolean");
+	assertNotNull("invalidBoolean is a property", pd);
+	assertNotNull("invalidBoolean has a getter method",
+		      pd.getReadMethod());
+	assertNull("invalidBoolean has no write method",
+		   pd.getWriteMethod());
+	assertTrue("invalidBoolean getter method is isInvalidBoolean",
+		   "isInvalidBoolean".equals(pd.getReadMethod().getName()));
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>longProperty</code>.
+     */
+    public void testGetDescriptorLong() {
+
+        testGetDescriptorBase("longProperty", "getLongProperty",
+                "setLongProperty");
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property
+     * <code>readOnlyProperty</code>.
+     */
+    public void testGetDescriptorReadOnly() {
+
+        testGetDescriptorBase("readOnlyProperty", "getReadOnlyProperty",
+                null);
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>booleanSecond</code>
+     * that uses an "is" method as the getter.
+     */
+    public void testGetDescriptorSecond() {
+
+        testGetDescriptorBase("booleanSecond", "isBooleanSecond",
+                "setBooleanSecond");
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>shortProperty</code>.
+     */
+    public void testGetDescriptorShort() {
+
+        testGetDescriptorBase("shortProperty", "getShortProperty",
+                "setShortProperty");
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property <code>stringProperty</code>.
+     */
+    public void testGetDescriptorString() {
+
+        testGetDescriptorBase("stringProperty", "getStringProperty",
+                "setStringProperty");
+
+    }
+
+
+    /**
+     * Negative getPropertyDescriptor on property <code>unknown</code>.
+     */
+    public void testGetDescriptorUnknown() {
+
+        testGetDescriptorBase("unknown", null, null);
+
+    }
+
+
+    /**
+     * Positive getPropertyDescriptor on property
+     * <code>writeOnlyProperty</code>.
+     */
+    public void testGetDescriptorWriteOnly() {
+
+        testGetDescriptorBase("writeOnlyProperty", null,
+                "setWriteOnlyProperty");
+
+    }
+
+
+    /**
+     * Positive test for getPropertyDescriptors().  Each property name
+     * listed in <code>properties</code> should be returned exactly once.
+     */
+    public void testGetDescriptors() {
+
+        PropertyDescriptor pd[] =
+                PropertyUtils.getPropertyDescriptors(bean);
+        assertNotNull("Got descriptors", pd);
+        int count[] = new int[properties.length];
+        for (int i = 0; i < pd.length; i++) {
+            String name = pd[i].getName();
+            for (int j = 0; j < properties.length; j++) {
+                if (name.equals(properties[j]))
+                    count[j]++;
+            }
+        }
+        for (int j = 0; j < properties.length; j++) {
+            if (count[j] < 0)
+                fail("Missing property " + properties[j]);
+            else if (count[j] > 1)
+                fail("Duplicate property " + properties[j]);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getPropertyDescriptors invalid arguments.
+     */
+    public void testGetDescriptorsArguments() {
+
+        try {
+            PropertyUtils.getPropertyDescriptors(null);
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getIndexedProperty invalid arguments.
+     */
+    public void testGetIndexedArguments() {
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.getIndexedProperty(null, "intArray", 0);
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, null, 0);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.getIndexedProperty(null,
+                    "intArray[0]");
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "[0]");
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "intArray");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.getIndexedProperty(null, "intIndexed", 0);
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, null, 0);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.getIndexedProperty(null,
+                    "intIndexed[0]");
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "[0]");
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.getIndexedProperty(bean, "intIndexed");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on getIndexedProperty valid arguments.
+     */
+    public void testGetIndexedValues() {
+
+        Object value = null;
+
+        // Use explicit key argument
+
+        for (int i = 0; i < 5; i++) {
+
+            try {
+                value = PropertyUtils.getIndexedProperty
+                    (bean, "dupProperty", i);
+                assertNotNull("dupProperty returned value " + i, value);
+                assertTrue("dupProperty returned String " + i,
+                        value instanceof String);
+                assertEquals("dupProperty returned correct " + i,
+                             "Dup " + i,
+                             (String) value);
+            } catch (Throwable t) {
+                fail("dupProperty " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "intArray", i);
+                assertNotNull("intArray returned value " + i, value);
+                assertTrue("intArray returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intArray returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "intIndexed", i);
+                assertNotNull("intIndexed returned value " + i, value);
+                assertTrue("intIndexed returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intIndexed returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "listIndexed", i);
+                assertNotNull("listIndexed returned value " + i, value);
+                assertTrue("list returned String " + i,
+                        value instanceof String);
+                assertEquals("listIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("listIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "stringArray", i);
+                assertNotNull("stringArray returned value " + i, value);
+                assertTrue("stringArray returned String " + i,
+                        value instanceof String);
+                assertEquals("stringArray returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean, "stringIndexed", i);
+                assertNotNull("stringIndexed returned value " + i, value);
+                assertTrue("stringIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("stringIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringIndexed " + i + " threw " + t);
+            }
+
+        }
+
+        // Use key expression
+
+        for (int i = 0; i < 5; i++) {
+
+            try {
+                value = PropertyUtils.getIndexedProperty
+                    (bean, "dupProperty[" + i + "]");
+                assertNotNull("dupProperty returned value " + i, value);
+                assertTrue("dupProperty returned String " + i,
+                        value instanceof String);
+                assertEquals("dupProperty returned correct " + i,
+                             "Dup " + i,
+                             (String) value);
+            } catch (Throwable t) {
+                fail("dupProperty " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "intArray[" + i + "]");
+                assertNotNull("intArray returned value " + i, value);
+                assertTrue("intArray returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intArray returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "intIndexed[" + i + "]");
+                assertNotNull("intIndexed returned value " + i, value);
+                assertTrue("intIndexed returned Integer " + i,
+                        value instanceof Integer);
+                assertEquals("intIndexed returned correct " + i, i * 10,
+                        ((Integer) value).intValue());
+            } catch (Throwable t) {
+                fail("intIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "listIndexed[" + i + "]");
+                assertNotNull("listIndexed returned value " + i, value);
+                assertTrue("listIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("listIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("listIndexed " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "stringArray[" + i + "]");
+                assertNotNull("stringArray returned value " + i, value);
+                assertTrue("stringArray returned String " + i,
+                        value instanceof String);
+                assertEquals("stringArray returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringArray " + i + " threw " + t);
+            }
+
+            try {
+                value =
+                        PropertyUtils.getIndexedProperty(bean,
+                                "stringIndexed[" + i + "]");
+                assertNotNull("stringIndexed returned value " + i, value);
+                assertTrue("stringIndexed returned String " + i,
+                        value instanceof String);
+                assertEquals("stringIndexed returned correct " + i,
+                        "String " + i, (String) value);
+            } catch (Throwable t) {
+                fail("stringIndexed " + i + " threw " + t);
+            }
+
+        }
+
+        // Index out of bounds tests
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "dupProperty", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "dupProperty", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed", -1);
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed", 5);
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringIndexed", -1);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringIndexed", 5);
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getMappedProperty invalid arguments.
+     */
+    public void testGetMappedArguments() {
+
+        // Use explicit key argument
+
+        try {
+            PropertyUtils.getMappedProperty(null, "mappedProperty",
+                    "First Key");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, null, "First Key");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, "mappedProperty", null);
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        // Use key expression
+
+        try {
+            PropertyUtils.getMappedProperty(null,
+                    "mappedProperty(First Key)");
+            fail("Should throw IllegalArgumentException 4");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 4");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, "(Second Key)");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 5");
+        }
+
+        try {
+            PropertyUtils.getMappedProperty(bean, "mappedProperty");
+            fail("Should throw IllegalArgumentException 6");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 6");
+        }
+
+    }
+
+
+    /**
+     * Test getting mapped values with periods in the key.
+     */
+    public void testGetMappedPeriods() {
+
+        bean.setMappedProperty("key.with.a.dot", "Special Value");
+        assertEquals("Can retrieve directly",
+                     "Special Value",
+                     bean.getMappedProperty("key.with.a.dot"));
+        try {
+            assertEquals("Can retrieve via getMappedProperty",
+                         "Special Value",
+                         PropertyUtils.getMappedProperty
+                         (bean, "mappedProperty", "key.with.a.dot"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+        try {
+            assertEquals("Can retrieve via getNestedProperty",
+                         "Special Value",
+                         PropertyUtils.getNestedProperty
+                         (bean, "mappedProperty(key.with.a.dot)"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+        bean.setMappedObjects("nested.property", new TestBean());
+        assertNotNull("Can retrieve directly",
+                      bean.getMappedObjects("nested.property"));
+        try {
+            assertEquals("Can retrieve nested",
+                         "This is a string",
+                         PropertyUtils.getNestedProperty
+                         (bean,
+                          "mappedObjects(nested.property).stringProperty"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+        try 
+        {
+            assertEquals("Can't retrieved nested with mapped property",
+                         "Mapped Value",
+                         PropertyUtils.getNestedProperty(
+                             bean,"mappedNested.value(Mapped Key)"));
+        } catch (Exception e) 
+        {
+            fail("Thew exception: " + e);
+        } 
+    }
+
+
+    /**
+     * Test getting mapped values with slashes in the key.  This is different
+     * from periods because slashes are not syntactically significant.
+     */
+    public void testGetMappedSlashes() {
+
+        bean.setMappedProperty("key/with/a/slash", "Special Value");
+        assertEquals("Can retrieve directly",
+                     "Special Value",
+                     bean.getMappedProperty("key/with/a/slash"));
+        try {
+            assertEquals("Can retrieve via getMappedProperty",
+                         "Special Value",
+                         PropertyUtils.getMappedProperty
+                         (bean, "mappedProperty", "key/with/a/slash"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+        try {
+            assertEquals("Can retrieve via getNestedProperty",
+                         "Special Value",
+                         PropertyUtils.getNestedProperty
+                         (bean, "mappedProperty(key/with/a/slash)"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+        bean.setMappedObjects("nested/property", new TestBean());
+        assertNotNull("Can retrieve directly",
+                      bean.getMappedObjects("nested/property"));
+        try {
+            assertEquals("Can retrieve nested",
+                         "This is a string",
+                         PropertyUtils.getNestedProperty
+                         (bean,
+                          "mappedObjects(nested/property).stringProperty"));
+        } catch (Exception e) {
+            fail("Thew exception: " + e);
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on getMappedProperty valid arguments.
+     */
+    public void testGetMappedValues() {
+
+        Object value = null;
+
+        // Use explicit key argument
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "First Key");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Second Key");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Third Key");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+        // Use key expression with parentheses
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(First Key)");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Second Key)");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Third Key)");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+        // Use key expression with dotted syntax
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.First Key");
+            assertEquals("Can find first value", "First Value", value);
+        } catch (Throwable t) {
+            fail("Finding first value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Second Key");
+            assertEquals("Can find second value", "Second Value", value);
+        } catch (Throwable t) {
+            fail("Finding second value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Third Key");
+            assertNull("Can not find third value", value);
+        } catch (Throwable t) {
+            fail("Finding third value threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getNestedProperty invalid arguments.
+     */
+    public void testGetNestedArguments() {
+
+        try {
+            PropertyUtils.getNestedProperty(null, "stringProperty");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getNestedProperty(bean, null);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a boolean property.
+     */
+    public void testGetNestedBoolean() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.booleanProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Boolean));
+            assertTrue("Got correct value",
+                    ((Boolean) value).booleanValue() ==
+                    bean.getNested().getBooleanProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a double property.
+     */
+    public void testGetNestedDouble() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.doubleProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Double));
+            assertEquals("Got correct value",
+                    ((Double) value).doubleValue(),
+                    bean.getNested().getDoubleProperty(),
+                    0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a float property.
+     */
+    public void testGetNestedFloat() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.floatProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Float));
+            assertEquals("Got correct value",
+                    ((Float) value).floatValue(),
+                    bean.getNested().getFloatProperty(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on an int property.
+     */
+    public void testGetNestedInt() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.intProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Integer));
+            assertEquals("Got correct value",
+                    ((Integer) value).intValue(),
+                    bean.getNested().getIntProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a long property.
+     */
+    public void testGetNestedLong() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.longProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Long));
+            assertEquals("Got correct value",
+                    ((Long) value).longValue(),
+                    bean.getNested().getLongProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a read-only String property.
+     */
+    public void testGetNestedReadOnly() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.readOnlyProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            assertEquals("Got correct value",
+                    (String) value,
+                    bean.getReadOnlyProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a short property.
+     */
+    public void testGetNestedShort() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.shortProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Short));
+            assertEquals("Got correct value",
+                    ((Short) value).shortValue(),
+                    bean.getNested().getShortProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getNestedProperty on a String property.
+     */
+    public void testGetNestedString() {
+
+        try {
+            Object value =
+                    PropertyUtils.getNestedProperty
+                    (bean, "nested.stringProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            assertEquals("Got correct value",
+                    ((String) value),
+                    bean.getNested().getStringProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getNestedProperty on an unknown property.
+     */
+    public void testGetNestedUnknown() {
+
+        try {
+            PropertyUtils.getNestedProperty(bean, "nested.unknown");
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+    /** 
+     * When a bean has a null property which is reference by the standard access language,
+     * this should throw a NestedNullException.
+     */
+    public void testThrowNestedNull() throws Exception {
+        NestedTestBean nestedBean = new NestedTestBean("base");
+        // don't init!
+        
+        try {
+            NestedTestBean value = (NestedTestBean) PropertyUtils.getProperty(
+                                nestedBean,
+                                "simpleBeanProperty.indexedProperty[0]");
+            fail("NestedNullException not thrown");
+        } catch (NestedNullException e) {
+            // that's what we wanted!
+        }
+    }
+
+    /**
+     * Test getNestedProperty on a write-only String property.
+     */
+    public void testGetNestedWriteOnly() {
+
+        try {
+            PropertyUtils.getNestedProperty(bean, "writeOnlyProperty");
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test getPropertyType() on all kinds of properties.
+     */
+    public void testGetPropertyType() {
+
+        Class clazz = null;
+        int intArray[] = new int[0];
+        String stringArray[] = new String[0];
+
+        try {
+
+            // Scalar and Indexed Properties
+            clazz = PropertyUtils.getPropertyType(bean, "booleanProperty");
+            assertEquals("booleanProperty type", Boolean.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "booleanSecond");
+            assertEquals("booleanSecond type", Boolean.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "doubleProperty");
+            assertEquals("doubleProperty type", Double.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "dupProperty");
+            assertEquals("dupProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "floatProperty");
+            assertEquals("floatProperty type", Float.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "intArray");
+            assertEquals("intArray type", intArray.getClass(), clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "intIndexed");
+            assertEquals("intIndexed type", Integer.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "intProperty");
+            assertEquals("intProperty type", Integer.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "listIndexed");
+            assertEquals("listIndexed type", List.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "longProperty");
+            assertEquals("longProperty type", Long.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "mappedProperty");
+            assertEquals("mappedProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "mappedIntProperty");
+            assertEquals("mappedIntProperty type", Integer.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "readOnlyProperty");
+            assertEquals("readOnlyProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "shortProperty");
+            assertEquals("shortProperty type", Short.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "stringArray");
+            assertEquals("stringArray type", stringArray.getClass(), clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "stringIndexed");
+            assertEquals("stringIndexed type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "stringProperty");
+            assertEquals("stringProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "writeOnlyProperty");
+            assertEquals("writeOnlyProperty type", String.class, clazz);
+
+            // Nested Properties
+            clazz = PropertyUtils.getPropertyType(bean, "nested.booleanProperty");
+            assertEquals("booleanProperty type", Boolean.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.booleanSecond");
+            assertEquals("booleanSecond type", Boolean.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.doubleProperty");
+            assertEquals("doubleProperty type", Double.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.dupProperty");
+            assertEquals("dupProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.floatProperty");
+            assertEquals("floatProperty type", Float.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.intArray");
+            assertEquals("intArray type", intArray.getClass(), clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.intIndexed");
+            assertEquals("intIndexed type", Integer.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.intProperty");
+            assertEquals("intProperty type", Integer.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.listIndexed");
+            assertEquals("listIndexed type", List.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.longProperty");
+            assertEquals("longProperty type", Long.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.mappedProperty");
+            assertEquals("mappedProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.mappedIntProperty");
+            assertEquals("mappedIntProperty type", Integer.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.readOnlyProperty");
+            assertEquals("readOnlyProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.shortProperty");
+            assertEquals("shortProperty type", Short.TYPE, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.stringArray");
+            assertEquals("stringArray type", stringArray.getClass(), clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.stringIndexed");
+            assertEquals("stringIndexed type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.stringProperty");
+            assertEquals("stringProperty type", String.class, clazz);
+            clazz = PropertyUtils.getPropertyType(bean, "nested.writeOnlyProperty");
+            assertEquals("writeOnlyProperty type", String.class, clazz);
+
+        } catch (Exception e) {
+            fail("Exception: " + e.getMessage());
+        }
+
+    }
+
+
+    /**
+     * Test getting accessible property reader methods for a specified
+     * list of properties of our standard test bean.
+     */
+    public void testGetReadMethodBasic() {
+
+        testGetReadMethod(bean, properties, TEST_BEAN_CLASS);
+
+    }
+
+
+    /**
+     * Test getting accessible property reader methods for a specified
+     * list of properties of a package private subclass of our standard
+     * test bean.
+     */
+    public void testGetReadMethodPackageSubclass() {
+
+        testGetReadMethod(beanPackageSubclass, properties, TEST_BEAN_CLASS);
+
+    }
+
+
+    /**
+     * Test getting accessible property reader methods for a specified
+     * list of properties that are declared either directly or via
+     * implemented interfaces.
+     */
+    public void testGetReadMethodPublicInterface() {
+
+        // Properties "bar" and "baz" are visible via implemented interfaces
+        // (one direct and one indirect)
+        testGetReadMethod(beanPrivate,
+                new String[]{ "bar" },
+                PRIVATE_DIRECT_CLASS);
+        testGetReadMethod(beanPrivate,
+                new String[]{ "baz" },
+                PRIVATE_INDIRECT_CLASS);
+
+        // Properties "bar" and "baz" are visible via implemented interfaces
+        // (one direct and one indirect).  The interface is implemented in
+        // a superclass
+        testGetReadMethod(beanPrivateSubclass,
+                new String[]{ "bar" },
+                PRIVATE_DIRECT_CLASS);
+        testGetReadMethod(beanPrivateSubclass,
+                new String[]{ "baz" },
+                PRIVATE_INDIRECT_CLASS);
+
+        // Property "foo" is not accessible because the underlying
+        // class has package scope
+        PropertyDescriptor pd[] =
+                PropertyUtils.getPropertyDescriptors(beanPrivate);
+        int n = -1;
+        for (int i = 0; i < pd.length; i++) {
+            if ("foo".equals(pd[i].getName())) {
+                n = i;
+                break;
+            }
+        }
+        assertTrue("Found foo descriptor", n >= 0);
+        Method reader = pd[n].getReadMethod();
+        assertNotNull("Found foo read method", reader);
+        Object value = null;
+        try {
+            value = reader.invoke(beanPrivate, new Class[0]);
+            fail("Foo reader did throw IllegalAccessException");
+        } catch (IllegalAccessException e) {
+            ; // Expected result for this test
+        } catch (Throwable t) {
+            fail("Invoke foo reader: " + t);
+        }
+
+    }
+
+
+    /**
+     * Test getting accessible property reader methods for a specified
+     * list of properties of a public subclass of our standard test bean.
+     */
+    public void testGetReadMethodPublicSubclass() {
+
+        testGetReadMethod(beanPublicSubclass, properties, TEST_BEAN_CLASS);
+
+    }
+
+
+    /**
+     * Corner cases on getSimpleProperty invalid arguments.
+     */
+    public void testGetSimpleArguments() {
+
+        try {
+            PropertyUtils.getSimpleProperty(null, "stringProperty");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.getSimpleProperty(bean, null);
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a boolean property.
+     */
+    public void testGetSimpleBoolean() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "booleanProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Boolean));
+            assertTrue("Got correct value",
+                    ((Boolean) value).booleanValue() ==
+                    bean.getBooleanProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a double property.
+     */
+    public void testGetSimpleDouble() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "doubleProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Double));
+            assertEquals("Got correct value",
+                    ((Double) value).doubleValue(),
+                    bean.getDoubleProperty(),
+                    (double) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a float property.
+     */
+    public void testGetSimpleFloat() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "floatProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Float));
+            assertEquals("Got correct value",
+                    ((Float) value).floatValue(),
+                    bean.getFloatProperty(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getSimpleProperty on an indexed property.
+     */
+    public void testGetSimpleIndexed() {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getSimpleProperty(bean,
+                    "intIndexed[0]");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on an int property.
+     */
+    public void testGetSimpleInt() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "intProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Integer));
+            assertEquals("Got correct value",
+                    ((Integer) value).intValue(),
+                    bean.getIntProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a long property.
+     */
+    public void testGetSimpleLong() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "longProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Long));
+            assertEquals("Got correct value",
+                    ((Long) value).longValue(),
+                    bean.getLongProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getSimpleProperty on a nested property.
+     */
+    public void testGetSimpleNested() {
+
+        Object value = null;
+        try {
+            value = PropertyUtils.getSimpleProperty(bean,
+                    "nested.stringProperty");
+            fail("Should have thrown IllegaArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a read-only String property.
+     */
+    public void testGetSimpleReadOnly() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "readOnlyProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            assertEquals("Got correct value",
+                    (String) value,
+                    bean.getReadOnlyProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a short property.
+     */
+    public void testGetSimpleShort() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "shortProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof Short));
+            assertEquals("Got correct value",
+                    ((Short) value).shortValue(),
+                    bean.getShortProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a String property.
+     */
+    public void testGetSimpleString() {
+
+        try {
+            Object value =
+                    PropertyUtils.getSimpleProperty(bean,
+                            "stringProperty");
+            assertNotNull("Got a value", value);
+            assertTrue("Got correct type", (value instanceof String));
+            assertEquals("Got correct value",
+                    (String) value,
+                    bean.getStringProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test getSimpleProperty on an unknown property.
+     */
+    public void testGetSimpleUnknown() {
+
+        try {
+            PropertyUtils.getSimpleProperty(bean, "unknown");
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test getSimpleProperty on a write-only String property.
+     */
+    public void testGetSimpleWriteOnly() {
+
+        try {
+            PropertyUtils.getSimpleProperty(bean, "writeOnlyProperty");
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test getting accessible property writer methods for a specified
+     * list of properties of our standard test bean.
+     */
+    public void testGetWriteMethodBasic() {
+
+        testGetWriteMethod(bean, properties, TEST_BEAN_CLASS);
+
+    }
+
+
+    /**
+     * Test getting accessible property writer methods for a specified
+     * list of properties of a package private subclass of our standard
+     * test bean.
+     */
+    public void testGetWriteMethodPackageSubclass() {
+
+        testGetWriteMethod(beanPackageSubclass, properties, TEST_BEAN_CLASS);
+
+    }
+
+
+    /**
+     * Test getting accessible property writer methods for a specified
+     * list of properties of a public subclass of our standard test bean.
+     */
+    public void testGetWriteMethodPublicSubclass() {
+
+        testGetWriteMethod(beanPublicSubclass, properties, TEST_BEAN_CLASS);
+
+    }
+
+
+    /**
+     * Test the mappedPropertyType of MappedPropertyDescriptor.
+     */
+    public void testMappedPropertyType() throws Exception {
+
+        MappedPropertyDescriptor desc;
+
+        // Check a String property
+        desc = (MappedPropertyDescriptor)
+                PropertyUtils.getPropertyDescriptor(bean,
+                        "mappedProperty");
+        assertEquals(String.class, desc.getMappedPropertyType());
+
+        // Check an int property
+        desc = (MappedPropertyDescriptor)
+                PropertyUtils.getPropertyDescriptor(bean,
+                        "mappedIntProperty");
+        assertEquals(Integer.TYPE, desc.getMappedPropertyType());
+
+    }
+
+
+    /**
+     * Corner cases on setIndexedProperty invalid arguments.
+     */
+    public void testSetIndexedArguments() {
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.setIndexedProperty(null, "intArray", 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, null, 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.setIndexedProperty(null,
+                    "intArray[0]",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "[0]",
+                    new Integer(1));
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "intArray",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.setIndexedProperty(null, "intIndexed", 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, null, 0,
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.setIndexedProperty(null,
+                    "intIndexed[0]",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "[0]",
+                    new Integer(1));
+            fail("Should throw NoSuchMethodException 4");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 4");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean, "intIndexed",
+                    new Integer(1));
+            fail("Should throw IllegalArgumentException 5");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 5");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on setIndexedProperty valid arguments.
+     */
+    public void testSetIndexedValues() {
+
+        Object value = null;
+
+        // Use explicit index argument
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "dupProperty", 0,
+                    "New 0");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "dupProperty", 0);
+            assertNotNull("Returned new value 0", value);
+            assertTrue("Returned String new value 0",
+                    value instanceof String);
+            assertEquals("Returned correct new value 0", "New 0",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray", 0,
+                    new Integer(1));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray", 0);
+            assertNotNull("Returned new value 0", value);
+            assertTrue("Returned Integer new value 0",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 0", 1,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed", 1,
+                    new Integer(11));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed", 1);
+            assertNotNull("Returned new value 1", value);
+            assertTrue("Returned Integer new value 1",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 1", 11,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed", 2,
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed", 2);
+            assertNotNull("Returned new value 2", value);
+            assertTrue("Returned String new value 2",
+                    value instanceof String);
+            assertEquals("Returned correct new value 2", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", 2,
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", 2);
+            assertNotNull("Returned new value 2", value);
+            assertTrue("Returned String new value 2",
+                    value instanceof String);
+            assertEquals("Returned correct new value 2", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", 3,
+                    "New Value 3");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray", 3);
+            assertNotNull("Returned new value 3", value);
+            assertTrue("Returned String new value 3",
+                    value instanceof String);
+            assertEquals("Returned correct new value 3", "New Value 3",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        // Use index expression
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "dupProperty[4]",
+                    "New 4");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "dupProperty[4]");
+            assertNotNull("Returned new value 4", value);
+            assertTrue("Returned String new value 4",
+                    value instanceof String);
+            assertEquals("Returned correct new value 4", "New 4",
+                         (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray[4]",
+                    new Integer(1));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intArray[4]");
+            assertNotNull("Returned new value 4", value);
+            assertTrue("Returned Integer new value 4",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 4", 1,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed[3]",
+                    new Integer(11));
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "intIndexed[3]");
+            assertNotNull("Returned new value 5", value);
+            assertTrue("Returned Integer new value 5",
+                    value instanceof Integer);
+            assertEquals("Returned correct new value 5", 11,
+                    ((Integer) value).intValue());
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed[1]",
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "listIndexed[1]");
+            assertNotNull("Returned new value 6", value);
+            assertTrue("Returned String new value 6",
+                    value instanceof String);
+            assertEquals("Returned correct new value 6", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray[1]",
+                    "New Value 2");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray[2]");
+            assertNotNull("Returned new value 6", value);
+            assertTrue("Returned String new value 6",
+                    value instanceof String);
+            assertEquals("Returned correct new value 6", "New Value 2",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray[0]",
+                    "New Value 3");
+            value =
+                    PropertyUtils.getIndexedProperty(bean,
+                            "stringArray[0]");
+            assertNotNull("Returned new value 7", value);
+            assertTrue("Returned String new value 7",
+                    value instanceof String);
+            assertEquals("Returned correct new value 7", "New Value 3",
+                    (String) value);
+        } catch (Throwable t) {
+            fail("Threw " + t);
+        }
+
+        // Index out of bounds tests
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "dupProperty", -1,
+                    "New -1");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "dupProperty", 5,
+                    "New 5");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray", -1,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intArray", 5,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed", -1,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "intIndexed", 5,
+                    new Integer(0));
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed", 5,
+                    "New String");
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "listIndexed", -1,
+                    "New String");
+            fail("Should have thrown IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", -1,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringArray", 5,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringIndexed", -1,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+        try {
+            PropertyUtils.setIndexedProperty(bean,
+                    "stringIndexed", 5,
+                    "New String");
+            fail("Should have thrown ArrayIndexOutOfBoundsException");
+        } catch (ArrayIndexOutOfBoundsException t) {
+            ; // Expected results
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of ArrayIndexOutOfBoundsException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on getMappedProperty invalid arguments.
+     */
+    public void testSetMappedArguments() {
+
+        // Use explicit key argument
+
+        try {
+            PropertyUtils.setMappedProperty(null, "mappedProperty",
+                    "First Key", "First Value");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, null, "First Key",
+                    "First Value");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "mappedProperty", null,
+                    "First Value");
+            fail("Should throw IllegalArgumentException 3");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 3");
+        }
+
+        // Use key expression
+
+        try {
+            PropertyUtils.setMappedProperty(null,
+                    "mappedProperty(First Key)",
+                    "First Value");
+            fail("Should throw IllegalArgumentException 4");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 4");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "(Second Key)",
+                    "Second Value");
+            fail("Should throw IllegalArgumentException 5");
+        } catch (NoSuchMethodException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of NoSuchMethodException 5");
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "mappedProperty",
+                    "Third Value");
+            fail("Should throw IllegalArgumentException 6");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 6");
+        }
+
+    }
+
+
+    /**
+     * Positive and negative tests on setMappedProperty valid arguments.
+     */
+    public void testSetMappedValues() {
+
+        Object value = null;
+
+        // Use explicit key argument
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Fourth Key");
+            assertNull("Can not find fourth value", value);
+        } catch (Throwable t) {
+            fail("Finding fourth value threw " + t);
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean, "mappedProperty",
+                    "Fourth Key", "Fourth Value");
+        } catch (Throwable t) {
+            fail("Setting fourth value threw " + t);
+        }
+
+        try {
+            value = PropertyUtils.getMappedProperty(bean, "mappedProperty",
+                    "Fourth Key");
+            assertEquals("Can find fourth value", "Fourth Value", value);
+        } catch (Throwable t) {
+            fail("Finding fourth value threw " + t);
+        }
+
+        // Use key expression with parentheses
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Fifth Key)");
+            assertNull("Can not find fifth value", value);
+        } catch (Throwable t) {
+            fail("Finding fifth value threw " + t);
+        }
+
+        try {
+            PropertyUtils.setMappedProperty(bean,
+                    "mappedProperty(Fifth Key)",
+                    "Fifth Value");
+        } catch (Throwable t) {
+            fail("Setting fifth value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getMappedProperty(bean,
+                            "mappedProperty(Fifth Key)");
+            assertEquals("Can find fifth value", "Fifth Value", value);
+        } catch (Throwable t) {
+            fail("Finding fifth value threw " + t);
+        }
+
+        // Use key expression with dotted expression
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Sixth Key");
+            assertNull("Can not find sixth value", value);
+        } catch (Throwable t) {
+            fail("Finding fifth value threw " + t);
+        }
+
+        try {
+            PropertyUtils.setNestedProperty(bean,
+                    "mapProperty.Sixth Key",
+                    "Sixth Value");
+        } catch (Throwable t) {
+            fail("Setting sixth value threw " + t);
+        }
+
+        try {
+            value =
+                    PropertyUtils.getNestedProperty(bean,
+                            "mapProperty.Sixth Key");
+            assertEquals("Can find sixth value", "Sixth Value", value);
+        } catch (Throwable t) {
+            fail("Finding sixth value threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Corner cases on setNestedProperty invalid arguments.
+     */
+    public void testSetNestedArguments() {
+
+        try {
+            PropertyUtils.setNestedProperty(null, "stringProperty", "");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setNestedProperty(bean, null, "");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test setNextedProperty on a boolean property.
+     */
+    public void testSetNestedBoolean() {
+
+        try {
+            boolean oldValue = bean.getNested().getBooleanProperty();
+            boolean newValue = !oldValue;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.booleanProperty",
+                    new Boolean(newValue));
+            assertTrue("Matched new value",
+                    newValue ==
+                    bean.getNested().getBooleanProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a double property.
+     */
+    public void testSetNestedDouble() {
+
+        try {
+            double oldValue = bean.getNested().getDoubleProperty();
+            double newValue = oldValue + 1.0;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.doubleProperty",
+                    new Double(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getDoubleProperty(),
+                    0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a float property.
+     */
+    public void testSetNestedFloat() {
+
+        try {
+            float oldValue = bean.getNested().getFloatProperty();
+            float newValue = oldValue + (float) 1.0;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.floatProperty",
+                    new Float(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getFloatProperty(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a int property.
+     */
+    public void testSetNestedInt() {
+
+        try {
+            int oldValue = bean.getNested().getIntProperty();
+            int newValue = oldValue + 1;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.intProperty",
+                    new Integer(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getIntProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a long property.
+     */
+    public void testSetNestedLong() {
+
+        try {
+            long oldValue = bean.getNested().getLongProperty();
+            long newValue = oldValue + 1;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.longProperty",
+                    new Long(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getLongProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a read-only String property.
+     */
+    public void testSetNestedReadOnly() {
+
+        try {
+            String oldValue = bean.getNested().getWriteOnlyPropertyValue();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.readOnlyProperty",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a short property.
+     */
+    public void testSetNestedShort() {
+
+        try {
+            short oldValue = bean.getNested().getShortProperty();
+            short newValue = oldValue;
+            newValue++;
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.shortProperty",
+                    new Short(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getShortProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a String property.
+     */
+    public void testSetNestedString() {
+
+        try {
+            String oldValue = bean.getNested().getStringProperty();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.stringProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getStringProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on an unknown property name.
+     */
+    public void testSetNestedUnknown() {
+
+        try {
+            String newValue = "New String Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.unknown",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test setNestedProperty on a write-only String property.
+     */
+    public void testSetNestedWriteOnly() {
+
+        try {
+            String oldValue = bean.getNested().getWriteOnlyPropertyValue();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setNestedProperty(bean,
+                    "nested.writeOnlyProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getNested().getWriteOnlyPropertyValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Corner cases on setSimpleProperty invalid arguments.
+     */
+    public void testSetSimpleArguments() {
+
+        try {
+            PropertyUtils.setSimpleProperty(null, "stringProperty", "");
+            fail("Should throw IllegalArgumentException 1");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 1");
+        }
+
+        try {
+            PropertyUtils.setSimpleProperty(bean, null, "");
+            fail("Should throw IllegalArgumentException 2");
+        } catch (IllegalArgumentException e) {
+            ; // Expected response
+        } catch (Throwable t) {
+            fail("Threw " + t + " instead of IllegalArgumentException 2");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a boolean property.
+     */
+    public void testSetSimpleBoolean() {
+
+        try {
+            boolean oldValue = bean.getBooleanProperty();
+            boolean newValue = !oldValue;
+            PropertyUtils.setSimpleProperty(bean,
+                    "booleanProperty",
+                    new Boolean(newValue));
+            assertTrue("Matched new value",
+                    newValue ==
+                    bean.getBooleanProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a double property.
+     */
+    public void testSetSimpleDouble() {
+
+        try {
+            double oldValue = bean.getDoubleProperty();
+            double newValue = oldValue + 1.0;
+            PropertyUtils.setSimpleProperty(bean,
+                    "doubleProperty",
+                    new Double(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getDoubleProperty(),
+                    0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a float property.
+     */
+    public void testSetSimpleFloat() {
+
+        try {
+            float oldValue = bean.getFloatProperty();
+            float newValue = oldValue + (float) 1.0;
+            PropertyUtils.setSimpleProperty(bean,
+                    "floatProperty",
+                    new Float(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getFloatProperty(),
+                    (float) 0.005);
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test setSimpleProperty on an indexed property.
+     */
+    public void testSetSimpleIndexed() {
+
+        try {
+            PropertyUtils.setSimpleProperty(bean,
+                    "stringIndexed[0]",
+                    "New String Value");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a int property.
+     */
+    public void testSetSimpleInt() {
+
+        try {
+            int oldValue = bean.getIntProperty();
+            int newValue = oldValue + 1;
+            PropertyUtils.setSimpleProperty(bean,
+                    "intProperty",
+                    new Integer(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getIntProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a long property.
+     */
+    public void testSetSimpleLong() {
+
+        try {
+            long oldValue = bean.getLongProperty();
+            long newValue = oldValue + 1;
+            PropertyUtils.setSimpleProperty(bean,
+                    "longProperty",
+                    new Long(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getLongProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Negative test setSimpleProperty on a nested property.
+     */
+    public void testSetSimpleNested() {
+
+        try {
+            PropertyUtils.setSimpleProperty(bean,
+                    "nested.stringProperty",
+                    "New String Value");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            ; // Correct result for this test
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a read-only String property.
+     */
+    public void testSetSimpleReadOnly() {
+
+        try {
+            String oldValue = bean.getWriteOnlyPropertyValue();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setSimpleProperty(bean,
+                    "readOnlyProperty",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a short property.
+     */
+    public void testSetSimpleShort() {
+
+        try {
+            short oldValue = bean.getShortProperty();
+            short newValue = oldValue;
+            newValue++;
+            PropertyUtils.setSimpleProperty(bean,
+                    "shortProperty",
+                    new Short(newValue));
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getShortProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a String property.
+     */
+    public void testSetSimpleString() {
+
+        try {
+            String oldValue = bean.getStringProperty();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setSimpleProperty(bean,
+                    "stringProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getStringProperty());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on an unknown property name.
+     */
+    public void testSetSimpleUnknown() {
+
+        try {
+            String newValue = "New String Value";
+            PropertyUtils.setSimpleProperty(bean,
+                    "unknown",
+                    newValue);
+            fail("Should have thrown NoSuchMethodException");
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            ; // Correct result for this test
+        }
+
+    }
+
+
+    /**
+     * Test setSimpleProperty on a write-only String property.
+     */
+    public void testSetSimpleWriteOnly() {
+
+        try {
+            String oldValue = bean.getWriteOnlyPropertyValue();
+            String newValue = oldValue + " Extra Value";
+            PropertyUtils.setSimpleProperty(bean,
+                    "writeOnlyProperty",
+                    newValue);
+            assertEquals("Matched new value",
+                    newValue,
+                    bean.getWriteOnlyPropertyValue());
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (IllegalArgumentException e) {
+            fail("IllegalArgumentException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Base for testGetDescriptorXxxxx() series of tests.
+     *
+     * @param name Name of the property to be retrieved
+     * @param read Expected name of the read method (or null)
+     * @param write Expected name of the write method (or null)
+     */
+    protected void testGetDescriptorBase(String name, String read,
+                                         String write) {
+
+        try {
+            PropertyDescriptor pd =
+                    PropertyUtils.getPropertyDescriptor(bean, name);
+            if ((read != null) || (write != null)) {
+                assertNotNull("Got descriptor", pd);
+            } else {
+                assertNull("Got descriptor", pd);
+                return;
+            }
+            Method rm = pd.getReadMethod();
+            if (read != null) {
+                assertNotNull("Got read method", rm);
+                assertEquals("Got correct read method",
+                        rm.getName(), read);
+            } else {
+                assertNull("Got read method", rm);
+            }
+            Method wm = pd.getWriteMethod();
+            if (write != null) {
+                assertNotNull("Got write method", wm);
+                assertEquals("Got correct write method",
+                        wm.getName(), write);
+            } else {
+                assertNull("Got write method", wm);
+            }
+        } catch (IllegalAccessException e) {
+            fail("IllegalAccessException");
+        } catch (InvocationTargetException e) {
+            fail("InvocationTargetException");
+        } catch (NoSuchMethodException e) {
+            fail("NoSuchMethodException");
+        }
+
+    }
+
+
+    /**
+     * Base for testGetReadMethod() series of tests.
+     *
+     * @param bean Bean for which to retrieve read methods.
+     * @param properties Property names to search for
+     * @param className Class name where this method should be defined
+     */
+    protected void testGetReadMethod(Object bean, String properties[],
+                                     String className) {
+
+        PropertyDescriptor pd[] =
+                PropertyUtils.getPropertyDescriptors(bean);
+        for (int i = 0; i < properties.length; i++) {
+
+            // Identify the property descriptor for this property
+            if (properties[i].equals("intIndexed"))
+                continue;
+            if (properties[i].equals("stringIndexed"))
+                continue;
+            if (properties[i].equals("writeOnlyProperty"))
+                continue;
+            int n = -1;
+            for (int j = 0; j < pd.length; j++) {
+                if (properties[i].equals(pd[j].getName())) {
+                    n = j;
+                    break;
+                }
+            }
+            assertTrue("PropertyDescriptor for " + properties[i],
+                    n >= 0);
+
+            // Locate an accessible property reader method for it
+            Method reader = PropertyUtils.getReadMethod(pd[n]);
+            assertNotNull("Reader for " + properties[i],
+                    reader);
+            Class clazz = reader.getDeclaringClass();
+            assertNotNull("Declaring class for " + properties[i],
+                    clazz);
+            assertEquals("Correct declaring class for " + properties[i],
+                    clazz.getName(),
+                    className);
+
+            // Actually call the reader method we received
+            try {
+                reader.invoke(bean, new Class[0]);
+            } catch (Throwable t) {
+                fail("Call for " + properties[i] + ": " + t);
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Base for testGetWriteMethod() series of tests.
+     *
+     * @param bean Bean for which to retrieve write methods.
+     * @param properties Property names to search for
+     * @param className Class name where this method should be defined
+     */
+    protected void testGetWriteMethod(Object bean, String properties[],
+                                      String className) {
+
+
+        PropertyDescriptor pd[] =
+                PropertyUtils.getPropertyDescriptors(bean);
+        for (int i = 0; i < properties.length; i++) {
+
+            // Identify the property descriptor for this property
+            if (properties[i].equals("intIndexed"))
+                continue;
+            if (properties[i].equals("listIndexed"))
+                continue;
+            if (properties[i].equals("nested"))
+                continue; // This property is read only
+            if (properties[i].equals("readOnlyProperty"))
+                continue;
+            if (properties[i].equals("stringIndexed"))
+                continue;
+            int n = -1;
+            for (int j = 0; j < pd.length; j++) {
+                if (properties[i].equals(pd[j].getName())) {
+                    n = j;
+                    break;
+                }
+            }
+            assertTrue("PropertyDescriptor for " + properties[i],
+                    n >= 0);
+
+            // Locate an accessible property reader method for it
+            Method writer = PropertyUtils.getWriteMethod(pd[n]);
+            assertNotNull("Writer for " + properties[i],
+                    writer);
+            Class clazz = writer.getDeclaringClass();
+            assertNotNull("Declaring class for " + properties[i],
+                    clazz);
+            assertEquals("Correct declaring class for " + properties[i],
+                    clazz.getName(),
+                    className);
+
+        }
+
+    }
+
+    public void testNestedWithIndex() throws Exception
+    {
+        NestedTestBean nestedBean = new NestedTestBean("base");
+        nestedBean.init();
+        nestedBean.getSimpleBeanProperty().init();
+        
+        NestedTestBean 
+        
+        // test first calling properties on indexed beans
+        
+        value = (NestedTestBean) PropertyUtils.getProperty(
+                                nestedBean,
+                                "indexedProperty[0]");
+        assertEquals("Cannot get simple index(1)", "Bean at 0", value.getName());
+        assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
+        
+        value = (NestedTestBean) PropertyUtils.getProperty(
+                                nestedBean,
+                                "indexedProperty[1]");  
+        assertEquals("Cannot get simple index(1)", "Bean at 1", value.getName());
+        assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
+        
+        String
+        prop = (String) PropertyUtils.getProperty(
+                                nestedBean,
+                                "indexedProperty[0].testString");
+        assertEquals("Get property on indexes failed (1)", "NOT SET", prop);
+        
+        prop = (String) PropertyUtils.getProperty(
+                                nestedBean,
+                                "indexedProperty[1].testString");  
+        assertEquals("Get property on indexes failed (2)", "NOT SET", prop);  
+
+        PropertyUtils.setProperty(
+                                nestedBean,
+                                "indexedProperty[0].testString",
+                                "Test#1");
+        assertEquals(
+                "Cannot set property on indexed bean (1)", 
+                "Test#1", 
+                nestedBean.getIndexedProperty(0).getTestString());
+        
+        PropertyUtils.setProperty(
+                                nestedBean,
+                                "indexedProperty[1].testString",
+                                "Test#2");  
+        assertEquals(
+                "Cannot set property on indexed bean (2)", 
+                "Test#2", 
+                nestedBean.getIndexedProperty(1).getTestString());  
+        
+        
+        // test first calling indexed properties on a simple property
+        
+        value = (NestedTestBean) PropertyUtils.getProperty(
+                                nestedBean,
+                                "simpleBeanProperty");
+        assertEquals("Cannot get simple bean", "Simple Property Bean", value.getName());
+        assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
+        
+        value = (NestedTestBean) PropertyUtils.getProperty(
+                                nestedBean,
+                                "simpleBeanProperty.indexedProperty[3]");
+        assertEquals("Cannot get index property on property", "Bean at 3", value.getName());
+        assertEquals("Bug in NestedTestBean", "NOT SET", value.getTestString());
+   
+        PropertyUtils.setProperty(
+                                nestedBean,
+                                "simpleBeanProperty.indexedProperty[3].testString",
+                                "Test#3");  
+        assertEquals(
+            "Cannot set property on indexed property on property", 
+            "Test#3", 
+            nestedBean.getSimpleBeanProperty().getIndexedProperty(3).getTestString());  
+    }
+    
+    /** Text case for setting properties on inner classes */
+    public void testGetSetInnerBean() throws Exception {
+        BeanWithInnerBean bean = new BeanWithInnerBean();
+        
+        PropertyUtils.setProperty(bean, "innerBean.fish(loiterTimer)", "5");
+        String out = (String) PropertyUtils.getProperty(bean.getInnerBean(), "fish(loiterTimer)");
+        assertEquals(
+                "(1) Inner class property set/get property failed.", 
+                "5", 
+                out);  
+    
+        out = (String) PropertyUtils.getProperty(bean, "innerBean.fish(loiterTimer)");
+    
+        assertEquals(
+                "(2) Inner class property set/get property failed.", 
+                "5", 
+                out); 
+    }
+    
+    /** Text case for setting properties on parent */
+    public void testGetSetParentBean() throws Exception {
+
+        SonOfAlphaBean bean = new SonOfAlphaBean("Roger");
+        
+        String out = (String) PropertyUtils.getProperty(bean, "name");
+        assertEquals(
+                "(1) Get/Set On Parent.", 
+                "Roger", 
+                out); 
+        
+        PropertyUtils.setProperty(bean, "name", "abcd");
+        assertEquals(
+                "(2) Get/Set On Parent.", 
+                "abcd", 
+                bean.getName()); 
+    }
+    
+    public void testSetNoGetter() throws Exception
+    {
+        BetaBean bean = new BetaBean("Cedric");
+        
+        // test standard no getter
+        bean.setNoGetterProperty("Sigma");
+        assertEquals("BetaBean test failed", "Sigma", bean.getSecret());
+        
+        assertNotNull("Descriptor is null", PropertyUtils.getPropertyDescriptor(bean, "noGetterProperty"));
+        
+        BeanUtils.setProperty(bean, "noGetterProperty",  "Omega");
+        assertEquals("Cannot set no-getter property", "Omega", bean.getSecret());
+        
+        // test mapped no getter descriptor
+        MappedPropertyDescriptor descriptor 
+            = new MappedPropertyDescriptor("noGetterMappedProperty", BetaBean.class);
+        
+        assertNotNull("Map Descriptor is null", PropertyUtils.getPropertyDescriptor(bean, "noGetterMappedProperty"));
+        
+        PropertyUtils.setMappedProperty(bean, "noGetterMappedProperty",  "Epsilon", "Epsilon");
+        assertEquals("Cannot set mapped no-getter property", "MAP:Epsilon", bean.getSecret());
+    }
+    
+    /** 
+     * This tests to see that classes that implement Map can have 
+     * their standard properties set.
+     */
+    public void testSetMapExtension() throws Exception {
+        ExtendMapBean bean = new ExtendMapBean();
+        
+        bean.setUnusuallyNamedProperty("bean value");
+        assertEquals("Set property direct failed", "bean value", bean.getUnusuallyNamedProperty());
+        
+        PropertyUtils.setSimpleProperty(bean, "unusuallyNamedProperty", "new value");
+        assertEquals("Set property on map failed (1)", "new value", bean.getUnusuallyNamedProperty());
+        
+        PropertyUtils.setProperty(bean, "unusuallyNamedProperty", "next value");
+        assertEquals("Set property on map failed (2)", "next value", bean.getUnusuallyNamedProperty());
+    }
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/PropertyUtilsTestCase.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/SonOfAlphaBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/SonOfAlphaBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/SonOfAlphaBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils;
+
+/** @author Robert Burrell Donkin */
+public class SonOfAlphaBean extends AlphaBean {
+    
+    public SonOfAlphaBean(String name) {
+        super(name);
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * General purpose test bean for JUnit tests for the "beanutils" component.
+ *
+ * @author Craig R. McClanahan
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.20 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class TestBean {
+
+    // ----------------------------------------------------------- Constructors
+
+    public TestBean() {
+    }
+
+    public TestBean(String stringProperty) {
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(float floatProperty) {
+        setFloatProperty(floatProperty);
+    }
+
+    public TestBean(boolean booleanProperty) {
+        setBooleanProperty(booleanProperty);
+    }
+
+    public TestBean(Boolean booleanSecond) {
+        setBooleanSecond(booleanSecond.booleanValue());
+    }
+
+    public TestBean(float floatProperty, String stringProperty) {
+        setFloatProperty(floatProperty);
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(boolean booleanProperty, String stringProperty) {
+        setBooleanProperty(booleanProperty);
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(Boolean booleanSecond, String stringProperty) {
+        setBooleanSecond(booleanSecond.booleanValue());
+        setStringProperty(stringProperty);
+    }
+
+    public TestBean(Integer intProperty) {
+        setIntProperty(intProperty.intValue());
+    }
+
+   public TestBean(double doubleProperty) {
+       setDoubleProperty(doubleProperty);
+   }
+   
+    TestBean(int intProperty) {
+        setIntProperty(intProperty);
+    }
+
+    protected TestBean(boolean booleanProperty, boolean booleanSecond, String stringProperty) {
+        setBooleanProperty(booleanProperty);
+        setBooleanSecond(booleanSecond);
+        setStringProperty(stringProperty);
+    }
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A boolean property.
+     */
+    private boolean booleanProperty = true;
+
+    public boolean getBooleanProperty() {
+        return (booleanProperty);
+    }
+
+    public void setBooleanProperty(boolean booleanProperty) {
+        this.booleanProperty = booleanProperty;
+    }
+
+
+    /**
+     * A boolean property that uses an "is" method for the getter.
+     */
+    private boolean booleanSecond = true;
+
+    public boolean isBooleanSecond() {
+        return (booleanSecond);
+    }
+
+    public void setBooleanSecond(boolean booleanSecond) {
+        this.booleanSecond = booleanSecond;
+    }
+
+
+    /**
+     * A byte property.
+     */
+    private byte byteProperty = (byte) 121;
+
+    public byte getByteProperty() {
+        return (this.byteProperty);
+    }
+
+    public void setByteProperty(byte byteProperty) {
+        this.byteProperty = byteProperty;
+    }
+
+
+    /**
+     * A double property.
+     */
+    private double doubleProperty = 321.0;
+
+    public double getDoubleProperty() {
+        return (this.doubleProperty);
+    }
+
+    public void setDoubleProperty(double doubleProperty) {
+        this.doubleProperty = doubleProperty;
+    }
+
+
+    /**
+     * An "indexed property" accessible via both array and subscript
+     * based getters and setters.
+     */
+    private String dupProperty[] =
+    { "Dup 0", "Dup 1", "Dup 2", "Dup 3", "Dup 4" };
+
+    public String[] getDupProperty() {
+        return (this.dupProperty);
+    }
+
+    public String getDupProperty(int index) {
+        return (this.dupProperty[index]);
+    }
+
+    public void setDupProperty(int index, String value) {
+        this.dupProperty[index] = value;
+    }
+
+    public void setDupProperty(String dupProperty[]) {
+        this.dupProperty = dupProperty;
+    }
+
+
+    /**
+     * A float property.
+     */
+    private float floatProperty = (float) 123.0;
+
+    public float getFloatProperty() {
+        return (this.floatProperty);
+    }
+
+    public void setFloatProperty(float floatProperty) {
+        this.floatProperty = floatProperty;
+    }
+
+
+    /**
+     * An integer array property accessed as an array.
+     */
+    private int intArray[] = { 0, 10, 20, 30, 40 };
+
+    public int[] getIntArray() {
+        return (this.intArray);
+    }
+
+    public void setIntArray(int intArray[]) {
+        this.intArray = intArray;
+    }
+
+
+    /**
+     * An integer array property accessed as an indexed property.
+     */
+    private int intIndexed[] = { 0, 10, 20, 30, 40 };
+
+    public int getIntIndexed(int index) {
+        return (intIndexed[index]);
+    }
+
+    public void setIntIndexed(int index, int value) {
+        intIndexed[index] = value;
+    }
+
+
+    /**
+     * An integer property.
+     */
+    private int intProperty = 123;
+
+    public int getIntProperty() {
+        return (this.intProperty);
+    }
+
+    public void setIntProperty(int intProperty) {
+        this.intProperty = intProperty;
+    }
+
+
+    /**
+     * A List property accessed as an indexed property.
+     */
+    private static List listIndexed = new ArrayList();
+
+    static {
+        listIndexed.add("String 0");
+        listIndexed.add("String 1");
+        listIndexed.add("String 2");
+        listIndexed.add("String 3");
+        listIndexed.add("String 4");
+    }
+
+    public List getListIndexed() {
+        return (listIndexed);
+    }
+
+
+    /**
+     * A long property.
+     */
+    private long longProperty = 321;
+
+    public long getLongProperty() {
+        return (this.longProperty);
+    }
+
+    public void setLongProperty(long longProperty) {
+        this.longProperty = longProperty;
+    }
+
+
+    /**
+     * A mapped property with only a getter and setter for a Map.
+     */
+    private Map mapProperty = null;
+
+    public Map getMapProperty() {
+        // Create the map the very first time
+        if (mapProperty == null) {
+            mapProperty = new HashMap();
+            mapProperty.put("First Key", "First Value");
+            mapProperty.put("Second Key", "Second Value");
+        }
+        return (mapProperty);
+    }
+
+    public void setMapProperty(Map mapProperty) {
+        // Create the map the very first time
+        if (mapProperty == null) {
+            mapProperty = new HashMap();
+            mapProperty.put("First Key", "First Value");
+            mapProperty.put("Second Key", "Second Value");
+        }
+        this.mapProperty = mapProperty;
+    }
+
+
+    /**
+     * A mapped property that has String keys and Object values.
+     */
+    private HashMap mappedObjects = null;
+
+    public Object getMappedObjects(String key) {
+        // Create the map the very first time
+        if (mappedObjects == null) {
+            mappedObjects = new HashMap();
+            mappedObjects.put("First Key", "First Value");
+            mappedObjects.put("Second Key", "Second Value");
+        }
+        return (mappedObjects.get(key));
+    }
+
+    public void setMappedObjects(String key, Object value) {
+        // Create the map the very first time
+        if (mappedObjects == null) {
+            mappedObjects = new HashMap();
+            mappedObjects.put("First Key", "First Value");
+            mappedObjects.put("Second Key", "Second Value");
+        }
+        mappedObjects.put(key, value);
+    }
+
+
+    /**
+     * A mapped property that has String keys and String values.
+     */
+    private HashMap mappedProperty = null;
+
+    public String getMappedProperty(String key) {
+        // Create the map the very first time
+        if (mappedProperty == null) {
+            mappedProperty = new HashMap();
+            mappedProperty.put("First Key", "First Value");
+            mappedProperty.put("Second Key", "Second Value");
+        }
+        return ((String) mappedProperty.get(key));
+    }
+
+    public void setMappedProperty(String key, String value) {
+        // Create the map the very first time
+        if (mappedProperty == null) {
+            mappedProperty = new HashMap();
+            mappedProperty.put("First Key", "First Value");
+            mappedProperty.put("Second Key", "Second Value");
+        }
+        mappedProperty.put(key, value);
+    }
+
+
+    /**
+     * A mapped property that has String keys and int values.
+     */
+    private HashMap mappedIntProperty = null;
+
+    public int getMappedIntProperty(String key) {
+        // Create the map the very first time
+        if (mappedProperty == null) {
+            mappedProperty = new HashMap();
+            mappedProperty.put("One", new Integer(1));
+            mappedProperty.put("Two", new Integer(2));
+        }
+        Integer x = (Integer) mappedIntProperty.get(key);
+        return ((x == null) ? 0 : x.intValue());
+    }
+
+    public void setMappedIntProperty(String key, int value) {
+        mappedIntProperty.put(key, new Integer(value));
+    }
+
+
+    /**
+     * A nested reference to another test bean (populated as needed).
+     */
+    private TestBean nested = null;
+
+    public TestBean getNested() {
+        if (nested == null)
+            nested = new TestBean();
+        return (nested);
+    }
+
+   /**
+    * Another nested reference to another test bean,
+    */
+   private TestBean anotherNested = null;
+    
+   public TestBean getAnotherNested() {
+      return anotherNested;
+   }
+    
+   public void setAnotherNested( TestBean anotherNested ) {
+      this.anotherNested = anotherNested;
+   }
+   
+    /*
+     * Another nested reference to a bean containing mapp properties
+     */
+    class MappedTestBean {
+        public void setValue(String key,String val) { }
+        public String getValue(String key) { return "Mapped Value"; }
+    }
+
+    private MappedTestBean mappedNested = null;
+
+    public MappedTestBean getMappedNested() {
+        if (mappedNested == null)
+        {
+            mappedNested = new MappedTestBean();
+        }
+        return mappedNested;
+    }
+
+    /**
+     * A String property with an initial value of null.
+     */
+    private String nullProperty = null;
+
+    public String getNullProperty() {
+        return (this.nullProperty);
+    }
+
+    public void setNullProperty(String nullProperty) {
+        this.nullProperty = nullProperty;
+    }
+
+
+    /**
+     * A read-only String property.
+     */
+    private String readOnlyProperty = "Read Only String Property";
+
+    public String getReadOnlyProperty() {
+        return (this.readOnlyProperty);
+    }
+
+
+    /**
+     * A short property.
+     */
+    private short shortProperty = (short) 987;
+
+    public short getShortProperty() {
+        return (this.shortProperty);
+    }
+
+    public void setShortProperty(short shortProperty) {
+        this.shortProperty = shortProperty;
+    }
+
+
+    /**
+     * A String array property accessed as a String.
+     */
+    private String stringArray[] =
+            { "String 0", "String 1", "String 2", "String 3", "String 4" };
+
+    public String[] getStringArray() {
+        return (this.stringArray);
+    }
+
+    public void setStringArray(String stringArray[]) {
+        this.stringArray = stringArray;
+    }
+
+
+    /**
+     * A String array property accessed as an indexed property.
+     */
+    private String stringIndexed[] =
+            { "String 0", "String 1", "String 2", "String 3", "String 4" };
+
+    public String getStringIndexed(int index) {
+        return (stringIndexed[index]);
+    }
+
+    public void setStringIndexed(int index, String value) {
+        stringIndexed[index] = value;
+    }
+
+
+    /**
+     * A String property.
+     */
+    private String stringProperty = "This is a string";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+    /**
+     * A write-only String property.
+     */
+    private String writeOnlyProperty = "Write Only String Property";
+
+    public String getWriteOnlyPropertyValue() {
+        return (this.writeOnlyProperty);
+    }
+
+    public void setWriteOnlyProperty(String writeOnlyProperty) {
+        this.writeOnlyProperty = writeOnlyProperty;
+    }
+
+
+    // ------------------------------------------------------ Invalid Properties
+
+
+    /**
+     * <p>An invalid property that has two boolean getters (getInvalidBoolean
+     * and isInvalidBoolean) plus a String setter (setInvalidBoolean).  By the
+     * rules described in the JavaBeans Specification, this will be considered
+     * a read-only boolean property, using isInvalidBoolean() as the getter.</p>
+     */
+    private boolean invalidBoolean = false;
+
+    public boolean getInvalidBoolean() {
+	return (this.invalidBoolean);
+    }
+
+    public boolean isInvalidBoolean() {
+	return (this.invalidBoolean);
+    }
+
+    public void setInvalidBoolean(String invalidBoolean) {
+	if ("true".equalsIgnoreCase(invalidBoolean) ||
+	    "yes".equalsIgnoreCase(invalidBoolean) ||
+	    "1".equalsIgnoreCase(invalidBoolean)) {
+	    this.invalidBoolean = true;
+	} else {
+	    this.invalidBoolean = false;
+	}
+    }
+
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * A static variable that is accessed and updated via static methods
+     * for MethodUtils testing.
+     */
+    private static int counter = 0;
+
+
+    /**
+     * Return the current value of the counter.
+     */
+    public static int currentCounter() {
+
+        return (counter);
+
+    }
+
+
+    /**
+     * Increment the current value of the counter by 1.
+     */
+    public static void incrementCounter() {
+
+        incrementCounter(1);
+
+    }
+
+
+    /**
+     * Increment the current value of the counter by the specified amount.
+     *
+     * @param amount Amount to be added to the current counter
+     */
+    public static void incrementCounter(int amount) {
+
+        counter += amount;
+
+    }
+
+
+}


Property changes on: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBean.java
___________________________________________________________________
Name: svn:executable
   + 

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPackageSubclass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPackageSubclass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPackageSubclass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * This is a package private subclass of TestBean.  All of our properties
+ * should still be accessible via reflection.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+class TestBeanPackageSubclass extends TestBean {
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPublicSubclass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPublicSubclass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestBeanPublicSubclass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * This is a public subclass of TestBean.  All of our properties should still
+ * be accessible via reflection.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class TestBeanPublicSubclass extends TestBean {
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSet.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSet.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSet.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,864 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Map;
+
+
+/**
+ * <p>Mock object that implements enough of <code>java.sql.ResultSet</code>
+ * to exercise the {@link ResultSetDyaClass} functionality.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class TestResultSet implements ResultSet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Current row number (0 means "before the first one").
+     */
+    protected int row = 0;
+
+
+    /**
+     * The constant (per run) value used to initialize date/time/timestamp.
+     */
+    protected long timestamp = System.currentTimeMillis();
+
+
+    // ---------------------------------------------------- Implemented Methods
+
+
+    public void close() throws SQLException {
+        ; // No action required
+    }
+
+
+    public ResultSetMetaData getMetaData() throws SQLException {
+        return (new TestResultSetMetaData());
+    }
+
+
+    public Object getObject(String columnName) throws SQLException {
+        if (row > 5) {
+            throw new SQLException("No current row");
+        }
+        if ("bigdecimalproperty".equals(columnName)) {
+            return (new BigDecimal(123.45));
+        } else if ("booleanproperty".equals(columnName)) {
+            if ((row % 2) == 0) {
+                return (Boolean.TRUE);
+            } else {
+                return (Boolean.FALSE);
+            }
+        } else if ("byteproperty".equals(columnName)) {
+            return (new Byte((byte) row));
+        } else if ("dateproperty".equals(columnName)) {
+            return (new Date(timestamp));
+        } else if ("doubleproperty".equals(columnName)) {
+            return (new Double(321.0));
+        } else if ("floatproperty".equals(columnName)) {
+            return (new Float((float) 123.0));
+        } else if ("intproperty".equals(columnName)) {
+            return (new Integer(100 + row));
+        } else if ("longproperty".equals(columnName)) {
+            return (new Long(200 + row));
+        } else if ("nullproperty".equals(columnName)) {
+            return (null);
+        } else if ("shortproperty".equals(columnName)) {
+            return (new Short((short) (300 + row)));
+        } else if ("stringproperty".equals(columnName)) {
+            return ("This is a string");
+        } else if ("timeproperty".equals(columnName)) {
+            return (new Time(timestamp));
+        } else if ("timestampproperty".equals(columnName)) {
+            return (new Timestamp(timestamp));
+        } else {
+            throw new SQLException("Unknown column name " + columnName);
+        }
+    }
+
+
+    public boolean next() throws SQLException {
+        if (row++ < 5) {
+            return (true);
+        } else {
+            return (false);
+        }
+    }
+
+
+    public void updateObject(String columnName, Object x)
+        throws SQLException {
+        if (row > 5) {
+            throw new SQLException("No current row");
+        }
+        ; // FIXME - updateObject()
+    }
+
+
+    // -------------------------------------------------- Unimplemented Methods
+
+
+    public boolean absolute(int row) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void afterLast() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void beforeFirst() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void cancelRowUpdates() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void clearWarnings() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void deleteRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int findColumn(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean first() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Array getArray(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Array getArray(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public InputStream getAsciiStream(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public InputStream getAsciiStream(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @deprecated */
+    public BigDecimal getBigDecimal(int columnIndex, int scale)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public BigDecimal getBigDecimal(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /** @deprecated */
+    public BigDecimal getBigDecimal(String columnName, int scale)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public InputStream getBinaryStream(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public InputStream getBinaryStream(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Blob getBlob(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Blob getBlob(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean getBoolean(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean getBoolean(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public byte getByte(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public byte getByte(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public byte[] getBytes(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public byte[] getBytes(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Reader getCharacterStream(int columnIndex)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Reader getCharacterStream(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Clob getClob(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Clob getClob(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getConcurrency() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getCursorName() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Date getDate(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Date getDate(int columnIndex, Calendar cal) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Date getDate(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Date getDate(String columnName, Calendar cal) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public double getDouble(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public double getDouble(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getFetchDirection() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getFetchSize() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public float getFloat(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public float getFloat(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getInt(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getInt(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public long getLong(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public long getLong(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Object getObject(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Object getObject(int columnIndex, Map map) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Object getObject(String columnName, Map map) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Ref getRef(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Ref getRef(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public short getShort(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public short getShort(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Statement getStatement() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getString(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getString(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Time getTime(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Time getTime(int columnIndex, Calendar cal) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Time getTime(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Time getTime(String columnName, Calendar cal) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Timestamp getTimestamp(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Timestamp getTimestamp(int columnIndex, Calendar cal)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Timestamp getTimestamp(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public Timestamp getTimestamp(String columnName, Calendar cal)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getType() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /** @deprecated */
+    public InputStream getUnicodeStream(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /** @deprecated */
+    public InputStream getUnicodeStream(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public URL getURL(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public URL getURL(String columnName) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public SQLWarning getWarnings() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void insertRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isAfterLast() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isBeforeFirst() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isFirst() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isLast() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean last() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void moveToCurrentRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void moveToInsertRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean previous() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void refreshRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean relative(int rows) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean rowDeleted() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean rowInserted() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean rowUpdated() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void setFetchDirection(int direction) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void setFetchSize(int size) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateArray(int columnPosition, Array x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateArray(String columnName, Array x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateAsciiStream(int columnPosition, InputStream x, int len)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateAsciiStream(String columnName, InputStream x, int len)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBigDecimal(int columnPosition, BigDecimal x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBigDecimal(String columnName, BigDecimal x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBinaryStream(int columnPosition, InputStream x, int len)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBinaryStream(String columnName, InputStream x, int len)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBlob(int columnPosition, Blob x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBlob(String columnName, Blob x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBoolean(int columnPosition, boolean x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBoolean(String columnName, boolean x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateByte(int columnPosition, byte x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateByte(String columnName, byte x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBytes(int columnPosition, byte x[])
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateBytes(String columnName, byte x[])
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateCharacterStream(int columnPosition, Reader x, int len)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateCharacterStream(String columnName, Reader x, int len)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateClob(int columnPosition, Clob x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateClob(String columnName, Clob x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateDate(int columnPosition, Date x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateDate(String columnName, Date x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateDouble(int columnPosition, double x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateDouble(String columnName, double x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateFloat(int columnPosition, float x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateFloat(String columnName, float x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateInt(int columnPosition, int x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateInt(String columnName, int x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateLong(int columnPosition, long x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateLong(String columnName, long x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateNull(int columnPosition)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateNull(String columnName)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateObject(int columnPosition, Object x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateObject(int columnPosition, Object x, int scale)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateObject(String columnName, Object x, int scale)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateRef(int columnPosition, Ref x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateRef(String columnName, Ref x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateRow() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateShort(int columnPosition, short x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateShort(String columnName, short x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateString(int columnPosition, String x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateString(String columnName, String x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateTime(int columnPosition, Time x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateTime(String columnName, Time x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateTimestamp(int columnPosition, Timestamp x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public void updateTimestamp(String columnName, Timestamp x)
+        throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean wasNull() throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSetMetaData.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSetMetaData.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/TestResultSetMetaData.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+
+
+/**
+ * <p>Mock object that implements enough of
+ * <code>java.sql.ResultSetMetaData</code>
+ * to exercise the {@link ResultSetDyaClass} functionality.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class TestResultSetMetaData implements ResultSetMetaData {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * <p>Array of column names and class names for metadata.</p>
+     */
+    protected String metadata[][] = {
+        { "bigDecimalProperty", "java.math.BigDecimal" },
+        { "booleanProperty", Boolean.class.getName() },
+        { "byteProperty", Byte.class.getName() },
+        { "dateProperty", "java.sql.Date" },
+        { "doubleProperty", Double.class.getName() },
+        { "floatProperty", Float.class.getName() },
+        { "intProperty", Integer.class.getName() },
+        { "longProperty", Long.class.getName() },
+        { "nullProperty", "java.lang.String" },
+        { "shortProperty", Short.class.getName() },
+        { "stringProperty", "java.lang.String" },
+        { "timeProperty", "java.sql.Time" },
+        { "timestampProperty", "java.sql.Timestamp" },
+    };
+
+
+    // ---------------------------------------------------- Implemented Methods
+
+
+    public String getColumnClassName(int columnIndex) throws SQLException {
+        return (metadata[columnIndex - 1][1]);
+    }
+
+
+    public int getColumnCount() throws SQLException {
+        return (metadata.length);
+    }
+
+    public String getColumnName(int columnIndex) throws SQLException {
+        return (metadata[columnIndex - 1][0]);
+    }
+
+
+    // -------------------------------------------------- Unimplemented Methods
+
+
+    public String getCatalogName(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getColumnDisplaySize(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getColumnLabel(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getColumnType(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getColumnTypeName(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getPrecision(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int getScale(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getSchemaName(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public String getTableName(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isAutoIncrement(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isCaseSensitive(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isCurrency(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isDefinitelyWritable(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public int isNullable(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isReadOnly(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isSearchable(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isSigned(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+    public boolean isWritable(int columnIndex) throws SQLException {
+        throw new UnsupportedOperationException();
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ThrowExceptionConverter.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ThrowExceptionConverter.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/ThrowExceptionConverter.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+/**
+ * Converter implementation that throws a <code>PassTestException</code> 
+ * when convert is called.
+ * The idea is that catching this exception is a clear signal that this method
+ * has been called.
+ *
+ * @author Robert Burrell Donkin
+ */
+
+public class ThrowExceptionConverter implements Converter {
+    
+    public Object convert(Class type, Object value) {
+        throw new PassTestException();
+    }	
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/WrapDynaBeanTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/WrapDynaBeanTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/WrapDynaBeanTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils;
+
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>Test Case for the <code>WrapDynaBean</code> implementation class.
+ * These tests were based on the ones in <code>PropertyUtilsTestCase</code>
+ * because the two classes provide similar levels of functionality.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.9 $ $Date: 2004/02/28 13:18:36 $
+ */
+
+public class WrapDynaBeanTestCase extends BasicDynaBeanTestCase {
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public WrapDynaBeanTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() throws Exception {
+
+        bean = new WrapDynaBean(new TestBean());
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(WrapDynaBeanTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        bean = null;
+
+    }
+
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * The <code>contains()</code> method is not supported by the
+     * <code>WrapDynaBean</code> implementation class.
+     */
+    public void testMappedContains() {
+
+        try {
+            assertTrue("Can see first key",
+                    bean.contains("mappedProperty", "First Key"));
+            fail("Should have thrown UnsupportedOperationException");
+        } catch (UnsupportedOperationException t) {
+            ; // Expected result
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+
+        try {
+            assertTrue("Can not see unknown key",
+                    !bean.contains("mappedProperty", "Unknown Key"));
+            fail("Should have thrown UnsupportedOperationException");
+        } catch (UnsupportedOperationException t) {
+            ; // Expected result
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * The <code>remove()</code> method is not supported by the
+     * <code>WrapDynaBean</code> implementation class.
+     */
+    public void testMappedRemove() {
+
+        try {
+            assertTrue("Can see first key",
+                    bean.contains("mappedProperty", "First Key"));
+            bean.remove("mappedProperty", "First Key");
+            fail("Should have thrown UnsupportedOperationException");
+            //            assertTrue("Can not see first key",
+            //         !bean.contains("mappedProperty", "First Key"));
+        } catch (UnsupportedOperationException t) {
+            ; // Expected result
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+        try {
+            assertTrue("Can not see unknown key",
+                    !bean.contains("mappedProperty", "Unknown Key"));
+            bean.remove("mappedProperty", "Unknown Key");
+            fail("Should have thrown UnsupportedOperationException");
+            //            assertTrue("Can not see unknown key",
+            //         !bean.contains("mappedProperty", "Unknown Key"));
+        } catch (UnsupportedOperationException t) {
+            ; // Expected result
+        } catch (Throwable t) {
+            fail("Exception: " + t);
+        }
+
+    }
+
+
+    /**
+     * Suppress serialization and deserialization tests.  WrapDynaClass
+     * is not serializable.
+     */
+    public void testSerialization() { }
+    
+    /** Tests getInstance method */
+    public void testGetInstance() {
+        AlphaBean alphaBean = new AlphaBean("Now On Air... John Peel");
+        WrapDynaBean dynaBean = new WrapDynaBean(alphaBean);
+        Object wrappedInstance = dynaBean.getInstance();
+        assertTrue("Object type is AlphaBean", wrappedInstance instanceof AlphaBean);
+        AlphaBean wrappedAlphaBean = (AlphaBean) wrappedInstance;
+        assertTrue("Same Object", wrappedAlphaBean == alphaBean);
+    }
+
+    /** Tests the newInstance implementation for WrapDynaClass */
+    public void testNewInstance() throws Exception {
+        WrapDynaClass dynaClass = WrapDynaClass.createDynaClass(AlphaBean.class);
+        Object createdInstance = dynaClass.newInstance();
+        assertTrue("Object type is WrapDynaBean", createdInstance instanceof WrapDynaBean);
+        WrapDynaBean dynaBean = (WrapDynaBean) createdInstance;
+        assertTrue("Object type is AlphaBean", dynaBean.getInstance() instanceof AlphaBean);
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ByteConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ByteConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ByteConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the ByteConverter class.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class ByteConverterTestCase extends NumberConverterTestBase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public ByteConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(ByteConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new ByteConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return Byte.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+        
+        Object[] input = { 
+            String.valueOf(Byte.MIN_VALUE),
+            "-17",
+            "-1",
+            "0",
+            "1",
+            "17",
+            String.valueOf(Byte.MAX_VALUE),
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+        
+        Byte[] expected = { 
+            new Byte(Byte.MIN_VALUE),
+            new Byte((byte)-17),
+            new Byte((byte)-1),
+            new Byte((byte)0),
+            new Byte((byte)1),
+            new Byte((byte)17),
+            new Byte(Byte.MAX_VALUE),
+            new Byte((byte)7),
+            new Byte((byte)8),
+            new Byte((byte)9),
+            new Byte((byte)10),
+            new Byte((byte)11),
+            new Byte((byte)12)
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(message[i] + " to Byte",expected[i],converter.convert(Byte.class,input[i]));
+            assertEquals(message[i] + " to byte",expected[i],converter.convert(Byte.TYPE,input[i]));
+            assertEquals(message[i] + " to null type",expected[i],converter.convert(null,input[i]));
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ConverterTestSuite.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ConverterTestSuite.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ConverterTestSuite.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * <p>
+ * Created a test suite so that new test cases can be added here without having to
+ * edit the build.xml.
+ * </p>
+ *
+ * @author  Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class ConverterTestSuite {
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        TestSuite testSuite = new TestSuite();
+        testSuite.addTestSuite(ByteConverterTestCase.class);
+        testSuite.addTestSuite(DoubleConverterTestCase.class);
+        testSuite.addTestSuite(FloatConverterTestCase.class);
+        testSuite.addTestSuite(IntegerConverterTestCase.class);
+        testSuite.addTestSuite(LongConverterTestCase.class);
+        testSuite.addTestSuite(ShortConverterTestCase.class);
+        testSuite.addTestSuite(StringArrayConverterTestCase.class);
+        return testSuite;
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/DoubleConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/DoubleConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/DoubleConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the DoubleConverter class.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class DoubleConverterTestCase extends NumberConverterTestBase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public DoubleConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(DoubleConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new DoubleConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return Double.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+        
+        Object[] input = { 
+            String.valueOf(Double.MIN_VALUE),
+            "-17.2",
+            "-1.1",
+            "0.0",
+            "1.1",
+            "17.2",
+            String.valueOf(Double.MAX_VALUE),
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+        
+        Double[] expected = { 
+            new Double(Double.MIN_VALUE),
+            new Double(-17.2),
+            new Double(-1.1),
+            new Double(0.0),
+            new Double(1.1),
+            new Double(17.2),
+            new Double(Double.MAX_VALUE),
+            new Double(7),
+            new Double(8),
+            new Double(9),
+            new Double(10),
+            new Double(11.1),
+            new Double(12.2)
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(
+                message[i] + " to Double",
+                expected[i].doubleValue(),
+                ((Double)(converter.convert(Double.class,input[i]))).doubleValue(),
+                0.00001D);
+            assertEquals(
+                message[i] + " to double",
+                expected[i].doubleValue(),
+                ((Double)(converter.convert(Double.TYPE,input[i]))).doubleValue(),
+                0.00001D);
+            assertEquals(
+                message[i] + " to null type",
+                expected[i].doubleValue(),
+                ((Double)(converter.convert(null,input[i]))).doubleValue(),
+                0.00001D);
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FileConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FileConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FileConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the FileConverter class.
+ *
+ * @author James Strachan
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class FileConverterTestCase extends TestCase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public FileConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(FileConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new FileConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return File.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String"
+        };
+        
+        Object[] input = { 
+            "/tmp",
+            "/tmp/foo.txt",
+            "/tmp/does/not/exist.foo"
+        };
+        
+        File[] expected = { 
+            new File("/tmp"),
+            new File("/tmp/foo.txt"),
+            new File("/tmp/does/not/exist.foo")
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(message[i] + " to File",expected[i],converter.convert(File.class,input[i]));
+            assertEquals(message[i] + " to null type",expected[i],converter.convert(null,input[i]));
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FloatConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FloatConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/FloatConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the FloatConverter class.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class FloatConverterTestCase extends NumberConverterTestBase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public FloatConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(FloatConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new FloatConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return Float.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+        
+        Object[] input = { 
+            String.valueOf(Float.MIN_VALUE),
+            "-17.2",
+            "-1.1",
+            "0.0",
+            "1.1",
+            "17.2",
+            String.valueOf(Float.MAX_VALUE),
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+        
+        Float[] expected = { 
+            new Float(Float.MIN_VALUE),
+            new Float(-17.2),
+            new Float(-1.1),
+            new Float(0.0),
+            new Float(1.1),
+            new Float(17.2),
+            new Float(Float.MAX_VALUE),
+            new Float(7),
+            new Float(8),
+            new Float(9),
+            new Float(10),
+            new Float(11.1),
+            new Float(12.2)
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(
+                message[i] + " to Float",
+                expected[i].floatValue(),
+                ((Float)(converter.convert(Float.class,input[i]))).floatValue(),
+                0.00001);
+            assertEquals(
+                message[i] + " to float",
+                expected[i].floatValue(),
+                ((Float)(converter.convert(Float.TYPE,input[i]))).floatValue(),
+                0.00001);
+            assertEquals(
+                message[i] + " to null type",
+                expected[i].floatValue(),
+                ((Float)(converter.convert(null,input[i]))).floatValue(),
+                0.00001);
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/IntegerConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/IntegerConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/IntegerConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the IntegerConverter class.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class IntegerConverterTestCase extends NumberConverterTestBase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public IntegerConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(IntegerConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new IntegerConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return Integer.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+        
+        Object[] input = { 
+            String.valueOf(Integer.MIN_VALUE),
+            "-17",
+            "-1",
+            "0",
+            "1",
+            "17",
+            String.valueOf(Integer.MAX_VALUE),
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+        
+        Integer[] expected = { 
+            new Integer(Integer.MIN_VALUE),
+            new Integer(-17),
+            new Integer(-1),
+            new Integer(0),
+            new Integer(1),
+            new Integer(17),
+            new Integer(Integer.MAX_VALUE),
+            new Integer(7),
+            new Integer(8),
+            new Integer(9),
+            new Integer(10),
+            new Integer(11),
+            new Integer(12)
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(message[i] + " to Integer",expected[i],converter.convert(Integer.class,input[i]));
+            assertEquals(message[i] + " to int",expected[i],converter.convert(Integer.TYPE,input[i]));
+            assertEquals(message[i] + " to null type",expected[i],converter.convert(null,input[i]));
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/LongConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/LongConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/LongConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the LongConverter class.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class LongConverterTestCase extends NumberConverterTestBase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public LongConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(LongConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new LongConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return Long.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+        
+        Object[] input = { 
+            String.valueOf(Long.MIN_VALUE),
+            "-17",
+            "-1",
+            "0",
+            "1",
+            "17",
+            String.valueOf(Long.MAX_VALUE),
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+        
+        Long[] expected = { 
+            new Long(Long.MIN_VALUE),
+            new Long(-17),
+            new Long(-1),
+            new Long(0),
+            new Long(1),
+            new Long(17),
+            new Long(Long.MAX_VALUE),
+            new Long(7),
+            new Long(8),
+            new Long(9),
+            new Long(10),
+            new Long(11),
+            new Long(12)
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(message[i] + " to Long",expected[i],converter.convert(Long.class,input[i]));
+            assertEquals(message[i] + " to long",expected[i],converter.convert(Long.TYPE,input[i]));
+            assertEquals(message[i] + " to null type",expected[i],converter.convert(null,input[i]));
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/NumberConverterTestBase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/NumberConverterTestBase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/NumberConverterTestBase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.beanutils.ConversionException;
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Abstract base for &lt;Number&gt;Converter classes.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public abstract class NumberConverterTestBase extends TestCase {
+
+    // ------------------------------------------------------------------------
+
+    public NumberConverterTestBase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+    
+    protected abstract Converter makeConverter();
+    protected abstract Class getExpectedType();
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Assumes ConversionException in response to covert(getExpectedType(),null).
+     */
+    public void testConvertNull() throws Exception {
+        try {
+            makeConverter().convert(getExpectedType(),null);
+            fail("Expected ConversionException");
+        } catch(ConversionException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Assumes convert(getExpectedType(),Number) returns some non-null
+     * instance of getExpectedType().
+     */
+    public void testConvertNumber() throws Exception {
+        String[] message= { 
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+
+        Object[] number = {
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+
+        for(int i=0;i<number.length;i++) {
+            Object val = makeConverter().convert(getExpectedType(),number[i]);
+            assertNotNull("Convert " + message[i] + " should not be null",val);
+            assertTrue(
+                "Convert " + message[i] + " should return a " + getExpectedType().getName(), 
+                getExpectedType().isInstance(val));
+        }
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ShortConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ShortConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/ShortConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.Converter;
+
+
+/**
+ * Test Case for the ShortConverter class.
+ *
+ * @author Rodney Waldhoff
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class ShortConverterTestCase extends NumberConverterTestBase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public ShortConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(ShortConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new ShortConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return Short.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from Byte",
+            "from Short",
+            "from Integer",
+            "from Long",
+            "from Float",
+            "from Double"
+        };
+        
+        Object[] input = { 
+            String.valueOf(Short.MIN_VALUE),
+            "-17",
+            "-1",
+            "0",
+            "1",
+            "17",
+            String.valueOf(Short.MAX_VALUE),
+            new Byte((byte)7),
+            new Short((short)8),
+            new Integer(9),
+            new Long(10),
+            new Float(11.1),
+            new Double(12.2)
+        };
+        
+        Short[] expected = { 
+            new Short(Short.MIN_VALUE),
+            new Short((short)-17),
+            new Short((short)-1),
+            new Short((short)0),
+            new Short((short)1),
+            new Short((short)17),
+            new Short(Short.MAX_VALUE),
+            new Short((short)7),
+            new Short((short)8),
+            new Short((short)9),
+            new Short((short)10),
+            new Short((short)11),
+            new Short((short)12)
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(message[i] + " to Short",expected[i],converter.convert(Short.class,input[i]));
+            assertEquals(message[i] + " to short",expected[i],converter.convert(Short.TYPE,input[i]));
+            assertEquals(message[i] + " to null type",expected[i],converter.convert(null,input[i]));
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/StringArrayConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/StringArrayConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/StringArrayConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestCase;
+import junit.framework.TestCase;
+
+/**
+ * Test Case for StringArrayConverter
+ *
+ * @author Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class StringArrayConverterTestCase extends TestCase {
+    
+    public StringArrayConverterTestCase(String name) {
+        super(name);
+    }
+    
+    public void testIntToString() {
+        
+        int[] testArray = {1, 2, 3, 4, 5};
+        String[] results = (String []) new StringArrayConverter().convert(String.class, testArray);
+        
+        assertEquals("Incorrect results size", 5, results.length);
+        assertEquals("Entry one is wrong", "1", results[0]); 
+        assertEquals("Entry two is wrong", "2", results[1]); 
+        assertEquals("Entry three is wrong", "3", results[2]); 
+        assertEquals("Entry four is wrong", "4", results[3]); 
+        assertEquals("Entry five is wrong", "5", results[4]); 
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/URLConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/URLConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/converters/URLConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.converters;
+
+import junit.framework.TestSuite;
+import junit.framework.TestCase;
+
+import org.apache.commons.beanutils.Converter;
+
+import java.net.URL;
+
+
+/**
+ * Test Case for the URLConverter class.
+ *
+ * @author Henri Yandell
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class URLConverterTestCase extends TestCase {
+
+    private Converter converter = null;
+
+    // ------------------------------------------------------------------------
+
+    public URLConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public void setUp() throws Exception {
+        converter = makeConverter();
+    }
+
+    public static TestSuite suite() {
+        return new TestSuite(URLConverterTestCase.class);        
+    }
+
+    public void tearDown() throws Exception {
+        converter = null;
+    }
+
+    // ------------------------------------------------------------------------
+    
+    protected Converter makeConverter() {
+        return new URLConverter();
+    }
+    
+    protected Class getExpectedType() {
+        return URL.class;
+    }
+
+    // ------------------------------------------------------------------------
+
+    public void testSimpleConversion() throws Exception {
+        String[] message= { 
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+            "from String",
+        };
+        
+        Object[] input = { 
+            "http://www.apache.org",
+            "http://www.apache.org/",
+            "ftp://cvs.apache.org",
+            "file://project.xml",
+            "http://208.185.179.12",
+            "http://www.apache.org:9999/test/thing",
+            "http://user:admin@www.apache.org:50/one/two.three",
+            "http://notreal.apache.org",
+        };
+        
+        URL[] expected = { 
+            new URL("http://www.apache.org"),
+            new URL("http://www.apache.org/"),
+            new URL("ftp://cvs.apache.org"),
+            new URL("file://project.xml"),
+            new URL("http://208.185.179.12"),
+            new URL("http://www.apache.org:9999/test/thing"),
+            new URL("http://user:admin@www.apache.org:50/one/two.three"),
+            new URL("http://notreal.apache.org")
+        };
+        
+        for(int i=0;i<expected.length;i++) {
+            assertEquals(message[i] + " to URL",expected[i],converter.convert(URL.class,input[i]));
+            assertEquals(message[i] + " to null type",expected[i],converter.convert(null,input[i]));
+        }
+    }
+    
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleBeanificationTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleBeanificationTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleBeanificationTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale;
+
+import java.util.*;
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.commons.collections.ReferenceMap;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.beanutils.ContextClassLoaderLocal;
+import org.apache.commons.beanutils.PrimitiveBean;
+
+/**
+ * <p>
+ * Test Case for changes made during LocaleBeanutils Beanification.
+ * This is basically a cut-and-correct version of the beanutils beanifications tests.
+ * </p>
+ *
+ * @author Robert Burrell Donkin
+ * @author Juozas Baliuka
+ * @version $Revision: 1.2 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class LocaleBeanificationTestCase extends TestCase {
+    
+    // ---------------------------------------------------- Constants
+    
+    /** Maximum number of iterations before our test fails */
+    public static final int MAX_GC_ITERATIONS = 50;
+    
+    // ---------------------------------------------------- Instance Variables
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public LocaleBeanificationTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        LocaleConvertUtils.deregister();
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(LocaleBeanificationTestCase.class));
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        ;    // No action required
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+    
+    /** Test of the methodology we'll use for some of the later tests */
+    public void testMemoryTestMethodology() throws Exception {
+        // test methodology
+        // many thanks to Juozas Baliuka for suggesting this method
+        ClassLoader loader = new ClassLoader() {};
+        WeakReference reference = new  WeakReference(loader);
+        Class myClass = loader.loadClass("org.apache.commons.beanutils.BetaBean");
+        
+        assertNotNull("Weak reference released early", reference.get());
+        
+        // dereference class loader and class:
+        loader = null;
+        myClass = null;
+        
+        int iterations = 0;
+        int bytz = 2;
+        while(true) {
+            System.gc();
+            if(iterations++ > MAX_GC_ITERATIONS){
+                fail("Max iterations reached before resource released.");
+            }
+            if( reference.get() == null ) {
+                break;
+                
+            } else {
+                // create garbage:
+                byte[] b =  new byte[bytz];
+                bytz = bytz * 2;
+            }
+        }
+    }
+    
+    /** Tests whether classloaders and beans are released from memory by the map used by beanutils */
+    public void testMemoryLeak2() throws Exception {
+        // tests when the map used by beanutils has the right behaviour
+        
+        if (isPre14JVM()) {
+            System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
+            return;
+        }
+        
+        // many thanks to Juozas Baliuka for suggesting this methodology
+        TestClassLoader loader = new TestClassLoader();
+        ReferenceQueue queue = new ReferenceQueue();
+        WeakReference loaderReference = new WeakReference(loader, queue);
+        Integer test = new Integer(1);
+        
+        WeakReference testReference = new WeakReference(test, queue);
+        //Map map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD, true);
+        Map map = new WeakHashMap();
+        map.put(loader, test);
+        
+        assertEquals("In map", test, map.get(loader));
+        assertNotNull("Weak reference released early (1)", loaderReference.get());
+        assertNotNull("Weak reference released early (2)", testReference.get());
+        
+        // dereference strong references
+        loader = null;
+        test = null;
+        
+        int iterations = 0;
+        int bytz = 2;
+        while(true) {
+            System.gc();
+            if(iterations++ > MAX_GC_ITERATIONS){
+                fail("Max iterations reached before resource released.");
+            }
+            map.isEmpty();
+            
+            if( 
+                loaderReference.get() == null &&
+                testReference.get() == null) {
+                break;
+                
+            } else {
+                // create garbage:
+                byte[] b =  new byte[bytz];
+                bytz = bytz * 2;
+            }
+        }
+    }
+	
+    /** Tests whether classloaders and beans are released from memory */
+    public void testMemoryLeak() throws Exception {
+        if (isPre14JVM()) {
+            System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
+            return;
+        }
+        
+        // many thanks to Juozas Baliuka for suggesting this methodology
+        TestClassLoader loader = new TestClassLoader();
+        WeakReference loaderReference = new  WeakReference(loader);
+        LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
+
+        class GetBeanUtilsBeanThread extends Thread {
+            
+            LocaleBeanUtilsBean beanUtils;
+            LocaleConvertUtilsBean convertUtils;
+        
+            GetBeanUtilsBeanThread() {}
+            
+            public void run() {
+                beanUtils = LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
+                convertUtils = LocaleConvertUtilsBean.getInstance();
+                // XXX Log keeps a reference around!
+                LogFactory.releaseAll();
+            }
+            
+            public String toString() {
+                return "GetBeanUtilsBeanThread";
+            }
+        }
+        
+    
+        GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread();
+        WeakReference threadWeakReference = new WeakReference(thread);
+        thread.setContextClassLoader(loader);
+
+        thread.start();
+        thread.join();
+        
+        WeakReference beanUtilsReference = new WeakReference(thread.beanUtils);
+        WeakReference convertUtilsReference = new WeakReference(thread.convertUtils);
+        
+        assertNotNull("Weak reference released early (1)", loaderReference.get());
+        assertNotNull("Weak reference released early (2)", beanUtilsReference.get());
+        assertNotNull("Weak reference released early (4)", convertUtilsReference.get());
+        
+        // dereference strong references
+        loader = null;
+        thread.setContextClassLoader(null);
+        thread = null;
+        
+        int iterations = 0;
+        int bytz = 2;
+        while(true) {
+            LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
+            System.gc();
+            if(iterations++ > MAX_GC_ITERATIONS){
+                fail("Max iterations reached before resource released.");
+            }
+
+            if( 
+                loaderReference.get() == null &&
+                beanUtilsReference.get() == null && 
+                convertUtilsReference.get() == null) {
+                break;
+                
+            } else {
+                // create garbage:
+                byte[] b =  new byte[bytz];
+                bytz = bytz * 2;
+            }
+        }
+    }
+    
+    /** 
+     * Tests whether difference instances are loaded by different 
+     * context classloaders.
+     */
+    public void testGetByContextClassLoader() throws Exception {
+            
+        class GetBeanUtilsBeanThread extends Thread {
+            
+            private Signal signal;
+        
+            GetBeanUtilsBeanThread(Signal signal) {
+                this.signal = signal;
+            }
+            
+            public void run() {
+                signal.setSignal(2);
+                signal.setBean(LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
+                signal.setConvertUtils(LocaleConvertUtilsBean.getInstance());
+            }
+            
+            public String toString() {
+                return "GetBeanUtilsBeanThread";
+            }
+        }
+            
+        Signal signal = new Signal();
+        signal.setSignal(1);
+        
+        GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread(signal);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        thread.start();
+        thread.join();
+        
+        assertEquals("Signal not set by test thread", 2, signal.getSignal());
+        assertTrue(
+                    "Different LocaleBeanUtilsBean instances per context classloader", 
+                    LocaleBeanUtilsBean.getInstance() != signal.getBean());
+        assertTrue(
+                    "Different LocaleConvertUtilsBean instances per context classloader", 
+                    LocaleConvertUtilsBean.getInstance() != signal.getConvertUtils());
+    }
+    
+    
+    /** 
+     * Tests whether difference instances are loaded by different 
+     * context classloaders.
+     */
+    public void testContextClassLoaderLocal() throws Exception {
+            
+        class CCLLTesterThread extends Thread {
+            
+            private Signal signal;
+            private ContextClassLoaderLocal ccll;
+        
+            CCLLTesterThread(Signal signal, ContextClassLoaderLocal ccll) {
+                this.signal = signal;
+                this.ccll = ccll;
+            }
+            
+            public void run() {
+                ccll.set(new Integer(1789));
+                signal.setSignal(2);
+                signal.setMarkerObject(ccll.get());
+            }
+            
+            public String toString() {
+                return "CCLLTesterThread";
+            }
+        }
+            
+        ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
+        ccll.set(new Integer(1776));
+        assertEquals("Start thread sets value", new Integer(1776), ccll.get());  
+        
+        Signal signal = new Signal();
+        signal.setSignal(1);
+        
+        CCLLTesterThread thread = new CCLLTesterThread(signal, ccll);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        thread.start();
+        thread.join();
+        
+        assertEquals("Signal not set by test thread", 2, signal.getSignal());     
+        assertEquals("Second thread preserves value", new Integer(1776), ccll.get()); 
+        assertEquals("Second thread gets value it set", new Integer(1789), signal.getMarkerObject()); 
+    }
+    
+    /** Tests whether calls are independent for different classloaders */
+    public void testContextClassloaderIndependence() throws Exception {
+    
+        class TestIndependenceThread extends Thread {
+            private Signal signal;
+            private PrimitiveBean bean;
+        
+            TestIndependenceThread(Signal signal, PrimitiveBean bean) {
+                this.signal = signal;
+                this.bean = bean;
+            }
+            
+            public void run() {
+                try {
+                    signal.setSignal(3);
+                    LocaleConvertUtils.register(new LocaleConverter() {
+											public Object convert(Class type, Object value) {
+                                                return new Integer(9);
+                                            }
+                                            public Object convert(Class type, Object value, String pattern) {
+                                                return new Integer(9);
+                                            }
+                                                }, Integer.TYPE, Locale.getDefault());
+                    LocaleBeanUtils.setProperty(bean, "int", "1");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    signal.setException(e);
+                }
+            }
+            
+            public String toString() {
+                return "TestIndependenceThread";
+            }
+        }
+        
+        PrimitiveBean bean = new PrimitiveBean();
+        LocaleBeanUtils.setProperty(bean, "int", new Integer(1));
+        assertEquals("Wrong property value (1)", 1, bean.getInt());
+
+        LocaleConvertUtils.register(new LocaleConverter() {
+								public Object convert(Class type, Object value) {
+                                    return new Integer(5);
+                                }
+                                public Object convert(Class type, Object value, String pattern) {
+                                    return new Integer(5);
+                                }
+                                    }, Integer.TYPE, Locale.getDefault());
+        LocaleBeanUtils.setProperty(bean, "int", "1");
+        assertEquals("Wrong property value(2)", 5, bean.getInt());
+    
+        Signal signal = new Signal();
+        signal.setSignal(1);
+        TestIndependenceThread thread = new TestIndependenceThread(signal, bean);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        thread.start();
+        thread.join();
+        
+        assertNull("Exception thrown by test thread:" + signal.getException(), signal.getException());
+        assertEquals("Signal not set by test thread", 3, signal.getSignal());
+        assertEquals("Wrong property value(3)", 9, bean.getInt());
+        
+    }
+    
+    /** Tests whether different threads can set beanutils instances correctly */
+    public void testBeanUtilsBeanSetInstance() throws Exception {
+            
+        class SetInstanceTesterThread extends Thread {
+            
+            private Signal signal;
+            private LocaleBeanUtilsBean bean;
+        
+            SetInstanceTesterThread(Signal signal, LocaleBeanUtilsBean bean) {
+                this.signal = signal;
+                this.bean = bean;
+            }
+            
+            public void run() {
+                LocaleBeanUtilsBean.setInstance(bean);
+                signal.setSignal(21);
+                signal.setBean(LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
+            }
+            
+            public String toString() {
+                return "SetInstanceTesterThread";
+            }
+        }
+        
+        Signal signal = new Signal();
+        signal.setSignal(1);
+
+        LocaleBeanUtilsBean beanOne = new LocaleBeanUtilsBean();
+        LocaleBeanUtilsBean beanTwo = new LocaleBeanUtilsBean();
+        
+        SetInstanceTesterThread thread = new SetInstanceTesterThread(signal, beanTwo);
+        thread.setContextClassLoader(new TestClassLoader());
+        
+        LocaleBeanUtilsBean.setInstance(beanOne);
+        assertEquals("Start thread gets right instance", beanOne, LocaleBeanUtilsBean.getLocaleBeanUtilsInstance()); 
+        
+        thread.start();
+        thread.join();
+        
+        assertEquals("Signal not set by test thread", 21, signal.getSignal());     
+        assertEquals("Second thread preserves value", beanOne, LocaleBeanUtilsBean.getLocaleBeanUtilsInstance()); 
+        assertEquals("Second thread gets value it set", beanTwo, signal.getBean()); 
+    }
+    
+    /** Tests whether the unset method works*/
+    public void testContextClassLoaderUnset() throws Exception {
+        LocaleBeanUtilsBean beanOne = new LocaleBeanUtilsBean();
+        ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
+        ccll.set(beanOne);
+        assertEquals("Start thread gets right instance", beanOne, ccll.get()); 
+        ccll.unset();
+        assertTrue("Unset works", !beanOne.equals(ccll.get())); 
+    }
+    
+    private boolean isPre14JVM() {
+        // some pre 1.4 JVM have buggy WeakHashMap implementations 
+        // this is used to test for those JVM
+        String version = System.getProperty("java.specification.version");
+        StringTokenizer tokenizer = new StringTokenizer(version,".");
+        if (tokenizer.nextToken().equals("1")) {
+            String minorVersion = tokenizer.nextToken();
+            if (minorVersion.equals("0")) return true;
+            if (minorVersion.equals("1")) return true;
+            if (minorVersion.equals("2")) return true;
+            if (minorVersion.equals("3")) return true;
+        }
+        return false;
+    }
+    
+    // ---- Auxillary classes
+    
+    class TestClassLoader extends ClassLoader {
+        public String toString() {
+            return "TestClassLoader";
+        }
+    }
+    
+    class Signal {
+        private Exception e;
+        private int signal = 0;
+        private LocaleBeanUtilsBean bean;
+        private LocaleConvertUtilsBean convertUtils;
+        private Object marker;
+        
+        public Exception getException() {
+            return e;
+        }
+        
+        public void setException(Exception e) {
+            this.e = e;
+        }
+        
+        public int getSignal() {
+            return signal;
+        }
+        
+        public void setSignal(int signal) {
+            this.signal = signal;
+        }
+        
+        public Object getMarkerObject() {
+            return marker;
+        }
+        
+        public void setMarkerObject(Object marker) {
+            this.marker = marker;
+        }
+        
+        public LocaleBeanUtilsBean getBean() {
+            return bean;
+        }
+        
+        public void setBean(LocaleBeanUtilsBean bean) {
+            this.bean = bean;
+        }
+        
+        public LocaleConvertUtilsBean getConvertUtils() {
+            return convertUtils;
+        }
+        
+        public void setConvertUtils(LocaleConvertUtilsBean convertUtils) {
+            this.convertUtils = convertUtils;
+        }
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertTestSuite.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertTestSuite.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertTestSuite.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.commons.beanutils.locale.converters.DateLocaleConverterTestCase;
+
+/**
+ * <p>
+ * Created a test suite so that new test cases can be added here without having to
+ * edit the build.xml.
+ * </p>
+ *
+ * @author  Robert Burrell Donkin
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class LocaleConvertTestSuite {
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        TestSuite testSuite = new TestSuite();
+        testSuite.addTestSuite(LocaleConvertUtilsTestCase.class);
+        testSuite.addTestSuite(DateLocaleConverterTestCase.class);
+        testSuite.addTestSuite(LocaleBeanificationTestCase.class);
+        return testSuite;
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertUtilsTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertUtilsTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/LocaleConvertUtilsTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.HashMap;
+import java.util.Locale;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.commons.beanutils.ConvertUtils;
+import org.apache.commons.beanutils.ConversionException;
+
+
+/**
+ * <p>
+ *  Test Case for the LocaleConvertUtils class.
+ *  See unimplemented functionality of the convert utils in the method begining with fixme
+ * </p>
+ *
+ * @author  Michael Szlapa
+ * @author Paul Hamamnt & Rune Johannesen (pairing) - patches.
+ * @version $Revision: 1.7 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class LocaleConvertUtilsTestCase extends TestCase {
+
+    // ---------------------------------------------------- Instance Variables
+
+    private char m_decimalSeparator;
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public LocaleConvertUtilsTestCase(String name) {
+        super(name);
+    }
+
+
+    // -------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        LocaleConvertUtils.deregister();
+
+        NumberFormat nf = DecimalFormat.getNumberInstance();
+        String result = nf.format(1.1);
+
+        // could be commas instead of stops in Europe.
+        m_decimalSeparator = result.charAt(1);
+
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+        return (new TestSuite(LocaleConvertUtilsTestCase.class));
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+        ;    // No action required
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Negative String to primitive integer array tests.
+     */
+    public void fixmetestNegativeIntegerArray() {
+
+        fail("Array conversions not implemented yet.");
+
+        Object value = null;
+        int intArray[] = new int[0];
+
+        value = LocaleConvertUtils.convert((String) null, intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = LocaleConvertUtils.convert("a", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = LocaleConvertUtils.convert("{ a }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = LocaleConvertUtils.convert("1a3", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = LocaleConvertUtils.convert("{ 1a3 }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = LocaleConvertUtils.convert("0,1a3", intArray.getClass());
+        checkIntegerArray(value, intArray);
+        value = LocaleConvertUtils.convert("{ 0, 1a3 }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+
+    }
+
+
+    /**
+     * Negative scalar conversion tests.  These rely on the standard
+     * default value conversions in LocaleConvertUtils.
+     */
+    public void fixmetestNegativeScalar() {
+
+        Object value = null;
+
+        /*  fixme Boolean converters not implemented at this point
+        value = LocaleConvertUtils.convert("foo", Boolean.TYPE);
+        ...
+
+        value = LocaleConvertUtils.convert("foo", Boolean.class);
+        ...
+        */
+
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Byte.TYPE);
+            fail("Should have thrown conversion exception (1)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Byte.class);
+            fail("Should have thrown conversion exception (2)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        /* fixme - not implemented
+         try {
+             value = LocaleConvertUtils.convert("org.apache.commons.beanutils.Undefined", Class.class);
+             fail("Should have thrown conversion exception");
+         } catch (ConversionException e) {
+             ; // Expected result
+         }
+         */
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Double.TYPE);
+            fail("Should have thrown conversion exception (3)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Double.class);
+            fail("Should have thrown conversion exception (4)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Float.TYPE);
+            fail("Should have thrown conversion exception (5)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Float.class);
+            fail("Should have thrown conversion exception (6)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Integer.TYPE);
+            fail("Should have thrown conversion exception (7)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Integer.class);
+            fail("Should have thrown conversion exception (8)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Byte.TYPE);
+            fail("Should have thrown conversion exception (9)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Long.class);
+            fail("Should have thrown conversion exception (10)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Short.TYPE);
+            fail("Should have thrown conversion exception (11)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+        try {
+            value = LocaleConvertUtils.convert("foo", Short.class);
+            fail("Should have thrown conversion exception (12)");
+        } catch (ConversionException e) {
+            ; // Expected result
+        }
+
+    }
+
+
+    /**
+     * Negative String to String array tests.
+     */
+    public void fixmetestNegativeStringArray() {
+
+        fail("Array conversions not implemented yet.");
+
+        Object value = null;
+        String stringArray[] = new String[0];
+
+        value = LocaleConvertUtils.convert((String) null, stringArray.getClass());
+        checkStringArray(value, stringArray);
+    }
+
+
+    /**
+     * Test conversion of object to string for arrays - .
+     */
+    public void fixmetestObjectToStringArray() {
+
+        fail("Array conversions not implemented yet.");
+        int intArray0[] = new int[0];
+        int intArray1[] = {123};
+        int intArray2[] = {123, 456};
+        String stringArray0[] = new String[0];
+        String stringArray1[] = {"abc"};
+        String stringArray2[] = {"abc", "def"};
+
+        assertEquals("intArray0", null,
+                LocaleConvertUtils.convert(intArray0));
+        assertEquals("intArray1", "123",
+                LocaleConvertUtils.convert(intArray1));
+        assertEquals("intArray2", "123",
+                LocaleConvertUtils.convert(intArray2));
+
+        assertEquals("stringArray0", null,
+                LocaleConvertUtils.convert(stringArray0));
+        assertEquals("stringArray1", "abc",
+                LocaleConvertUtils.convert(stringArray1));
+        assertEquals("stringArray2", "abc",
+                LocaleConvertUtils.convert(stringArray2));
+
+    }
+
+
+    /**
+     * Test conversion of object to string for scalars.
+     */
+    public void testObjectToStringScalar() {
+
+        assertEquals("Boolean->String", "false",
+                LocaleConvertUtils.convert(Boolean.FALSE));
+        assertEquals("Boolean->String", "true",
+                LocaleConvertUtils.convert(Boolean.TRUE));
+        assertEquals("Byte->String", "123",
+                LocaleConvertUtils.convert(new Byte((byte) 123)));
+        assertEquals("Character->String", "a",
+                LocaleConvertUtils.convert(new Character('a')));
+        assertEquals("Double->String", "123" + m_decimalSeparator + "4",
+                LocaleConvertUtils.convert(new Double((double) 123.4)));
+        assertEquals("Float->String", "123" + m_decimalSeparator + "4",
+                LocaleConvertUtils.convert(new Float((float) 123.4)));
+        assertEquals("Integer->String", "123",
+                LocaleConvertUtils.convert(new Integer((int) 123)));
+        assertEquals("Long->String", "123",
+                LocaleConvertUtils.convert(new Long((long) 123)));
+        assertEquals("Short->String", "123",
+                LocaleConvertUtils.convert(new Short((short) 123)));
+        assertEquals("String->String", "abc",
+                LocaleConvertUtils.convert("abc"));
+        assertEquals("String->String null", null,
+                LocaleConvertUtils.convert(null));
+
+    }
+
+
+    /**
+     * Positive array conversion tests.
+     */
+    public void fixmetestPositiveArray() {
+
+        fail("Array conversions not implemented yet.");
+
+        String values1[] = {"10", "20", "30"};
+        Object value = LocaleConvertUtils.convert(values1, Integer.TYPE);
+        int shape[] = new int[0];
+        assertEquals(shape.getClass(), value.getClass());
+        int results1[] = (int[]) value;
+        assertEquals(results1[0], 10);
+        assertEquals(results1[1], 20);
+        assertEquals(results1[2], 30);
+
+        String values2[] = {"100", "200", "300"};
+        value = LocaleConvertUtils.convert(values2, shape.getClass());
+        assertEquals(shape.getClass(), value.getClass());
+        int results2[] = (int[]) value;
+        assertEquals(results2[0], 100);
+        assertEquals(results2[1], 200);
+        assertEquals(results2[2], 300);
+    }
+
+
+    /**
+     * Positive String to primitive integer array tests.
+     */
+    public void fixmetestPositiveIntegerArray() {
+
+        fail("Array conversions not implemented yet.");
+
+        Object value = null;
+        int intArray[] = new int[0];
+        int intArray1[] = new int[]{0};
+        int intArray2[] = new int[]{0, 10};
+
+        value = LocaleConvertUtils.convert("{  }", intArray.getClass());
+        checkIntegerArray(value, intArray);
+
+        value = LocaleConvertUtils.convert("0", intArray.getClass());
+        checkIntegerArray(value, intArray1);
+        value = LocaleConvertUtils.convert(" 0 ", intArray.getClass());
+        checkIntegerArray(value, intArray1);
+        value = LocaleConvertUtils.convert("{ 0 }", intArray.getClass());
+        checkIntegerArray(value, intArray1);
+
+        value = LocaleConvertUtils.convert("0,10", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = LocaleConvertUtils.convert("0 10", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = LocaleConvertUtils.convert("{0,10}", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = LocaleConvertUtils.convert("{0 10}", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = LocaleConvertUtils.convert("{ 0, 10 }", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+        value = LocaleConvertUtils.convert("{ 0 10 }", intArray.getClass());
+        checkIntegerArray(value, intArray2);
+    }
+
+
+    /**
+     * Positive scalar conversion tests.
+     */
+    public void testPositiveScalar() {
+        Object value = null;
+
+        /* fixme Boolean converters not implemented
+         value = LocaleConvertUtils.convert("true", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("true", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("yes", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("yes", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("y", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("y", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("on", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("on", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), true);
+
+         value = LocaleConvertUtils.convert("false", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("false", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("no", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("no", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("n", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("n", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("off", Boolean.TYPE);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+
+         value = LocaleConvertUtils.convert("off", Boolean.class);
+         assertTrue(value instanceof Boolean);
+         assertEquals(((Boolean) value).booleanValue(), false);
+         */
+
+        value = LocaleConvertUtils.convert("123", Byte.TYPE);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 123);
+
+        value = LocaleConvertUtils.convert("123", Byte.class);
+        assertTrue(value instanceof Byte);
+        assertEquals(((Byte) value).byteValue(), (byte) 123);
+
+        /*fixme Character conversion not implemented yet
+        value = LocaleConvertUtils.convert("a", Character.TYPE);
+        assertTrue(value instanceof Character);
+        assertEquals(((Character) value).charValue(), 'a');
+
+        value = LocaleConvertUtils.convert("a", Character.class);
+        assertTrue(value instanceof Character);
+        assertEquals(((Character) value).charValue(), 'a');
+        */
+        /* fixme - this is a discrepancy with standard converters ( probably not major issue )
+        value = LocaleConvertUtils.convert("java.lang.String", Class.class);
+        assertTrue(value instanceof Class);
+        assertEquals(String.class, (Class) value);
+        */
+
+        value = LocaleConvertUtils.convert("123" + m_decimalSeparator + "456", Double.TYPE);
+        assertTrue(value instanceof Double);
+        assertEquals(((Double) value).doubleValue(), (double) 123.456,
+                (double) 0.005);
+
+        value = LocaleConvertUtils.convert("123" + m_decimalSeparator + "456", Double.class);
+        assertTrue(value instanceof Double);
+        assertEquals(((Double) value).doubleValue(), (double) 123.456,
+                (double) 0.005);
+
+        value = LocaleConvertUtils.convert("123" + m_decimalSeparator + "456", Float.TYPE);
+        assertTrue(value instanceof Float);
+        assertEquals(((Float) value).floatValue(), (float) 123.456,
+                (float) 0.005);
+
+        value = LocaleConvertUtils.convert("123" + m_decimalSeparator + "456", Float.class);
+        assertTrue(value instanceof Float);
+        assertEquals(((Float) value).floatValue(), (float) 123.456,
+                (float) 0.005);
+
+        value = LocaleConvertUtils.convert("123", Integer.TYPE);
+        assertTrue(value instanceof Integer);
+        assertEquals(((Integer) value).intValue(), (int) 123);
+
+        value = LocaleConvertUtils.convert("123", Integer.class);
+        assertTrue(value instanceof Integer);
+        assertEquals(((Integer) value).intValue(), (int) 123);
+
+        value = LocaleConvertUtils.convert("123", Long.TYPE);
+        assertTrue(value instanceof Long);
+        assertEquals(((Long) value).longValue(), (long) 123);
+
+        value = LocaleConvertUtils.convert("123456", Long.class);
+        assertTrue(value instanceof Long);
+        assertEquals(((Long) value).longValue(), (long) 123456);
+
+        /* fixme - Short conversion not implemented at this point
+        value = LocaleConvertUtils.convert("123", Short.TYPE);
+        assertTrue(value instanceof Short);
+        assertEquals(((Short) value).shortValue(), (short) 123);
+
+        value = LocaleConvertUtils.convert("123", Short.class);
+        assertTrue(value instanceof Short);
+        assertEquals(((Short) value).shortValue(), (short) 123);
+        */
+
+        String input = null;
+
+        input = "2002-03-17";
+        value = LocaleConvertUtils.convert(input, Date.class);
+        assertTrue(value instanceof Date);
+        assertEquals(input, value.toString());
+
+        input = "20:30:40";
+        value = LocaleConvertUtils.convert(input, Time.class);
+        assertTrue(value instanceof Time);
+        assertEquals(input, value.toString());
+
+        input = "2002-03-17 20:30:40.0";
+        value = LocaleConvertUtils.convert(input, Timestamp.class);
+        assertTrue(value instanceof Timestamp);
+        assertEquals(input, value.toString());
+
+    }
+
+
+    /**
+     * Positive String to String array tests.
+     */
+    public void fixmetestPositiveStringArray() {
+
+        fail("Array conversions not implemented yet.");
+
+        Object value = null;
+        String stringArray[] = new String[0];
+        String stringArray1[] = new String[]
+        {"abc"};
+        String stringArray2[] = new String[]
+        {"abc", "de,f"};
+
+        value = LocaleConvertUtils.convert("", stringArray.getClass());
+        checkStringArray(value, stringArray);
+        value = LocaleConvertUtils.convert(" ", stringArray.getClass());
+        checkStringArray(value, stringArray);
+        value = LocaleConvertUtils.convert("{}", stringArray.getClass());
+        checkStringArray(value, stringArray);
+        value = LocaleConvertUtils.convert("{  }", stringArray.getClass());
+        checkStringArray(value, stringArray);
+
+        value = LocaleConvertUtils.convert("abc", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = LocaleConvertUtils.convert("{abc}", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = LocaleConvertUtils.convert("\"abc\"", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = LocaleConvertUtils.convert("{\"abc\"}", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = LocaleConvertUtils.convert("'abc'", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+        value = LocaleConvertUtils.convert("{'abc'}", stringArray.getClass());
+        checkStringArray(value, stringArray1);
+
+        value = LocaleConvertUtils.convert("abc 'de,f'",
+                stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = LocaleConvertUtils.convert("{abc, 'de,f'}",
+                stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = LocaleConvertUtils.convert("\"abc\",\"de,f\"",
+                stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = LocaleConvertUtils.convert("{\"abc\" 'de,f'}",
+                stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = LocaleConvertUtils.convert("'abc' 'de,f'",
+                stringArray.getClass());
+        checkStringArray(value, stringArray2);
+        value = LocaleConvertUtils.convert("{'abc', \"de,f\"}",
+                stringArray.getClass());
+        checkStringArray(value, stringArray2);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    private void checkIntegerArray(Object value, int intArray[]) {
+
+        assertNotNull("Returned value is not null", value);
+        assertEquals("Returned value is int[]",
+                intArray.getClass(), value.getClass());
+        int results[] = (int[]) value;
+        assertEquals("Returned array length", intArray.length, results.length);
+        for (int i = 0; i < intArray.length; i++) {
+            assertEquals("Returned array value " + i,
+                    intArray[i], results[i]);
+        }
+
+    }
+
+
+    private void checkStringArray(Object value, String stringArray[]) {
+
+        assertNotNull("Returned value is not null", value);
+        assertEquals("Returned value is String[]",
+                stringArray.getClass(), value.getClass());
+        String results[] = (String[]) value;
+        assertEquals("Returned array length",
+                stringArray.length, results.length);
+        for (int i = 0; i < stringArray.length; i++) {
+            assertEquals("Returned array value " + i,
+                    stringArray[i], results[i]);
+        }
+
+    }
+
+
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/converters/DateLocaleConverterTestCase.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/converters/DateLocaleConverterTestCase.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/locale/converters/DateLocaleConverterTestCase.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+package org.apache.commons.beanutils.locale.converters;
+
+import junit.framework.TestSuite;
+import junit.framework.TestCase;
+
+import java.text.SimpleDateFormat;
+import java.text.ParseException;
+
+import java.util.Locale;
+
+import org.apache.commons.beanutils.Converter;
+import org.apache.commons.beanutils.ConversionException;
+
+/**
+ * Test Case for the DateLocaleConverter class.
+ *
+ * @author Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class DateLocaleConverterTestCase extends TestCase {
+
+    // ------------------------------------------------------------------------
+
+    public DateLocaleConverterTestCase(String name) {
+        super(name);
+    }
+    
+    // ------------------------------------------------------------------------
+
+    public static TestSuite suite() {
+        return new TestSuite(DateLocaleConverterTestCase.class);        
+    }
+
+
+    // ------------------------------------------------------------------------
+
+    public void testSetLenient() {
+        // make sure that date format works as expected
+        SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.UK);
+        
+        // test with no leniency
+        dateFormat.setLenient(false);
+        
+        try {
+            
+            dateFormat.parse("Feb 10, 2001");
+            
+        } catch (ParseException e) {
+            fail("Could not parse date (1) - " + e.getMessage());
+        }
+        
+        try {
+        
+            dateFormat.parse("Feb 31, 2001");
+            fail("Parsed illegal date (1)");
+        
+        } catch (ParseException e) {
+            // that's what we expected
+        }	
+        
+        // test with leniency
+        dateFormat.setLenient(true);
+        
+        try {
+            
+            dateFormat.parse("Feb 10, 2001");
+            
+        } catch (ParseException e) {
+            fail("Could not parse date (2) - " + e.getMessage());
+        }
+        
+        try {
+        
+            dateFormat.parse("Feb 31, 2001");
+        
+        } catch (ParseException e) {
+            fail("Could not parse date (3) - " + e.getMessage());
+        }
+        
+        // now repeat tests for converter
+        DateLocaleConverter converter = new DateLocaleConverter(Locale.UK, "MMM dd, yyyy");
+        
+        // test with no leniency
+        converter.setLenient(false);
+        assertEquals("Set lenient failed", converter.isLenient(), false);
+        
+        try {
+            
+            converter.convert("Feb 10, 2001");
+            
+        } catch (ConversionException e) {
+            fail("Could not parse date (4) - " + e.getMessage());
+        }
+        
+        try {
+        
+            converter.convert("Feb 31, 2001");
+            assertEquals("Set lenient failed", converter.isLenient(), false);
+            fail("Parsed illegal date (2)");
+        
+        } catch (ConversionException e) {
+            // that's what we expected
+        }	
+        
+        // test with leniency
+        converter.setLenient(true);
+        assertEquals("Set lenient failed", converter.isLenient(), true);
+        
+        try {
+            
+            converter.convert("Feb 10, 2001");
+            
+        } catch (ConversionException e) {
+            fail("Could not parse date (5) - " + e.getMessage());
+        }
+        
+        try {
+        
+            converter.convert("Feb 31, 2001");
+        
+        } catch (ConversionException e) {
+            fail("Could not parse date (6) - " + e.getMessage());
+        }
+    }
+}
+

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PackageBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PackageBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PackageBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * <p>This class is designed to test the default access jvm problem workaround.
+ * The issue is that public methods of a public subclass contained in a default access
+ * superclass are returned by reflection but an IllegalAccessException is thrown 
+ * when they are invoked.</p>
+ *
+ * <p>This is the default access superclass</p>
+ * 
+ * @author Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+class PackageBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Package private constructor - can only use factory method to create
+     * beans.
+     */
+    PackageBean() {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     */
+    private String bar = "This is bar";
+
+    public String getBar() {
+
+        return (this.bar);
+
+    }
+    
+    public void setBar(String bar) {
+
+        this.bar = bar;
+
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * Bean that has a private constructor that exposes properties via
+ * various mechanisms (based on property name):
+ * <ul>
+ * <li><strong>foo</strong> - Via direct public method
+ * <li><strong>bar</strong> - Via directly implemented interface
+ * <li><strong>baz</strong> - Via indirectly implemented interface
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+class PrivateBean implements PrivateDirect {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Package private constructor - can only use factory method to create
+     * beans.
+     */
+    PrivateBean() {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A directly implemented property.
+     */
+    private String foo = "This is foo";
+
+    public String getFoo() {
+
+        return (this.foo);
+
+    }
+
+
+    /**
+     * A property accessible via a directly implemented interface.
+     */
+    private String bar = "This is bar";
+
+    public String getBar() {
+
+        return (this.bar);
+
+    }
+
+
+    /**
+     * A method accessible via a directly implemented interface.
+     */
+    public String methodBar(String in) {
+
+        return (in);
+
+    }
+
+
+    /**
+     * A property accessible via an indirectly implemented interface.
+     */
+    private String baz = "This is baz";
+
+    public String getBaz() {
+
+        return (this.baz);
+
+    }
+
+
+    /**
+     * A method accessible via an indirectly implemented interface.
+     */
+    public String methodBaz(String in) {
+
+        return (in);
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanFactory.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanFactory.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanFactory.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * Factory class for PrivateBean instances.
+ *
+ * @author Craig R. McClanahan
+ * @author Jan Sorensen
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class PrivateBeanFactory {
+
+
+    /**
+     * Factory method to create new beans.
+     */
+    public static PrivateDirect create() {
+
+        return (new PrivateBean());
+
+    }
+
+
+    /**
+     * Factory method to create new beans.
+     */
+    public static PrivateDirect createSubclass() {
+
+        return (new PrivateBeanSubclass());
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanSubclass.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanSubclass.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateBeanSubclass.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * Bean that exposes methods defined by an interface that is implemented
+ * in the superclass.
+ *
+ * @author Jan Sorensen
+ * @version $Revision: 1.5 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+class PrivateBeanSubclass extends PrivateBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new PrivateBeanSubclass instance.
+     */
+    PrivateBeanSubclass() {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A property accessible via the superclass.
+     */
+    public String getBar() {
+
+        return (super.getBar());
+
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateDirect.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateDirect.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateDirect.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * Interface that is directly implemented by PrivateBean.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public interface PrivateDirect extends PrivateIndirect {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A property accessible via a directly implemented interface.
+     */
+    String getBar();
+
+
+    /**
+     * A method accessible via a directly implemented interface.
+     */
+    String methodBar(String in);
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateIndirect.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateIndirect.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PrivateIndirect.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * Interface that is indirectly implemented by PrivateBean.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 1.6 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public interface PrivateIndirect {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A property accessible via an indirectly implemented interface.
+     */
+    public String getBaz();
+
+
+    /**
+     * A method accessible via an indirectly implemented interface.
+     */
+    public String methodBaz(String in);
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PublicSubBean.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PublicSubBean.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/beanutils/priv/PublicSubBean.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+
+
+package org.apache.commons.beanutils.priv;
+
+
+/**
+ * <p>This class is designed to test the default access jvm problem workaround.
+ * The issue is that public methods of a public subclass contained in a default access
+ * superclass are returned by reflection but an IllegalAccessException is thrown 
+ * when they are invoked.</p>
+ *
+ * <p>This is the default access superclass</p>
+ *
+ * @author Robert Burrell Donkin
+ * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:37 $
+ */
+
+public class PublicSubBean extends PackageBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Package private constructor - can only use factory method to create
+     * beans.
+     */
+    public PublicSubBean() {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A directly implemented property.
+     */
+    private String foo = "This is foo";
+
+    public String getFoo() {
+
+        return (this.foo);
+
+    }
+    
+    public void setFoo(String foo) {
+
+        this.foo = foo;
+
+    }
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/ReferenceMap.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/ReferenceMap.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/ReferenceMap.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,957 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.commons.collections.keyvalue.DefaultMapEntry;
+
+/**
+ *  Hash-based {@link Map} implementation that allows
+ *  mappings to be removed by the garbage collector.<p>
+ *
+ *  When you construct a <code>ReferenceMap</code>, you can 
+ *  specify what kind of references are used to store the
+ *  map's keys and values.  If non-hard references are 
+ *  used, then the garbage collector can remove mappings
+ *  if a key or value becomes unreachable, or if the 
+ *  JVM's memory is running low.  For information on how
+ *  the different reference types behave, see
+ *  {@link Reference}.<p>
+ *
+ *  Different types of references can be specified for keys
+ *  and values.  The keys can be configured to be weak but
+ *  the values hard, in which case this class will behave
+ *  like a <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/WeakHashMap.html">
+ *  <code>WeakHashMap</code></a>.  However, you
+ *  can also specify hard keys and weak values, or any other
+ *  combination.  The default constructor uses hard keys
+ *  and soft values, providing a memory-sensitive cache.<p>
+ *
+ *  The algorithms used are basically the same as those
+ *  in {@link java.util.HashMap}.  In particular, you 
+ *  can specify a load factor and capacity to suit your
+ *  needs.  All optional {@link Map} operations are 
+ *  supported.<p>
+ *
+ *  However, this {@link Map} implementation does <I>not</I>
+ *  allow null elements.  Attempting to add a null key or
+ *  or a null value to the map will raise a 
+ *  <code>NullPointerException</code>.<p>
+ *
+ *  As usual, this implementation is not synchronized.  You
+ *  can use {@link java.util.Collections#synchronizedMap} to 
+ *  provide synchronized access to a <code>ReferenceMap</code>.
+ *
+ * @see java.lang.ref.Reference
+ * 
+ * @deprecated Moved to map subpackage. Due to be removed in v4.0.
+ * @since Commons Collections 2.1
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:52:42 $
+ * 
+ * @author Paul Jack
+ */
+public class ReferenceMap extends AbstractMap {
+
+    /**
+     *  For serialization.
+     */
+    final private static long serialVersionUID = -3370601314380922368L;
+
+
+    /**
+     *  Constant indicating that hard references should be used.
+     */
+    final public static int HARD = 0;
+
+
+    /**
+     *  Constant indicating that soft references should be used.
+     */
+    final public static int SOFT = 1;
+
+
+    /**
+     *  Constant indicating that weak references should be used.
+     */
+    final public static int WEAK = 2;
+
+
+    // --- serialized instance variables:
+
+
+    /**
+     *  The reference type for keys.  Must be HARD, SOFT, WEAK.
+     *  Note: I originally marked this field as final, but then this class
+     *   didn't compile under JDK1.2.2.
+     *  @serial
+     */
+    private int keyType;
+
+
+    /**
+     *  The reference type for values.  Must be HARD, SOFT, WEAK.
+     *  Note: I originally marked this field as final, but then this class
+     *   didn't compile under JDK1.2.2.
+     *  @serial
+     */
+    private int valueType;
+
+
+    /**
+     *  The threshold variable is calculated by multiplying
+     *  table.length and loadFactor.  
+     *  Note: I originally marked this field as final, but then this class
+     *   didn't compile under JDK1.2.2.
+     *  @serial
+     */
+    private float loadFactor;
+    
+    /**
+     * Should the value be automatically purged when the associated key has been collected?
+     */
+    private boolean purgeValues = false;
+
+
+    // -- Non-serialized instance variables
+
+    /**
+     *  ReferenceQueue used to eliminate stale mappings.
+     *  See purge.
+     */
+    private transient ReferenceQueue queue = new ReferenceQueue();
+
+
+    /**
+     *  The hash table.  Its length is always a power of two.  
+     */
+    private transient Entry[] table;
+
+
+    /**
+     *  Number of mappings in this map.
+     */
+    private transient int size;
+
+
+    /**
+     *  When size reaches threshold, the map is resized.  
+     *  See resize().
+     */
+    private transient int threshold;
+
+
+    /**
+     *  Number of times this map has been modified.
+     */
+    private transient volatile int modCount;
+
+
+    /**
+     *  Cached key set.  May be null if key set is never accessed.
+     */
+    private transient Set keySet;
+
+
+    /**
+     *  Cached entry set.  May be null if entry set is never accessed.
+     */
+    private transient Set entrySet;
+
+
+    /**
+     *  Cached values.  May be null if values() is never accessed.
+     */
+    private transient Collection values;
+
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> that will
+     *  use hard references to keys and soft references to values.
+     */
+    public ReferenceMap() {
+        this(HARD, SOFT);
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> that will
+     *  use the specified types of references.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param purgeValues should the value be automatically purged when the 
+     *   key is garbage collected 
+     */
+    public ReferenceMap(int keyType, int valueType, boolean purgeValues) {
+        this(keyType, valueType);
+        this.purgeValues = purgeValues;
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> that will
+     *  use the specified types of references.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     */
+    public ReferenceMap(int keyType, int valueType) {
+        this(keyType, valueType, 16, 0.75f);
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> with the
+     *  specified reference types, load factor and initial
+     *  capacity.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param capacity  the initial capacity for the map
+     *  @param loadFactor  the load factor for the map
+     *  @param purgeValues should the value be automatically purged when the 
+     *   key is garbage collected 
+     */
+    public ReferenceMap(
+                        int keyType, 
+                        int valueType, 
+                        int capacity, 
+                        float loadFactor, 
+                        boolean purgeValues) {
+        this(keyType, valueType, capacity, loadFactor);
+        this.purgeValues = purgeValues;
+    }
+
+    /**
+     *  Constructs a new <code>ReferenceMap</code> with the
+     *  specified reference types, load factor and initial
+     *  capacity.
+     *
+     *  @param keyType  the type of reference to use for keys;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param valueType  the type of reference to use for values;
+     *   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
+     *  @param capacity  the initial capacity for the map
+     *  @param loadFactor  the load factor for the map
+     */
+    public ReferenceMap(int keyType, int valueType, int capacity, float loadFactor) {
+        super();
+
+        verify("keyType", keyType);
+        verify("valueType", valueType);
+
+        if (capacity <= 0) {
+            throw new IllegalArgumentException("capacity must be positive");
+        }
+        if ((loadFactor <= 0.0f) || (loadFactor >= 1.0f)) {
+            throw new IllegalArgumentException("Load factor must be greater than 0 and less than 1.");
+        }
+
+        this.keyType = keyType;
+        this.valueType = valueType;
+
+        int v = 1;
+        while (v < capacity) v *= 2;
+
+        this.table = new Entry[v];
+        this.loadFactor = loadFactor;
+        this.threshold = (int)(v * loadFactor);
+    }
+
+
+    // used by constructor
+    private static void verify(String name, int type) {
+        if ((type < HARD) || (type > WEAK)) {
+            throw new IllegalArgumentException(name + 
+               " must be HARD, SOFT, WEAK.");
+        }
+    }
+
+
+    /**
+     *  Writes this object to the given output stream.
+     *
+     *  @param out  the output stream to write to
+     *  @throws IOException  if the stream raises it
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        out.writeInt(table.length);
+
+        // Have to use null-terminated list because size might shrink
+        // during iteration
+
+        for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            out.writeObject(entry.getKey());
+            out.writeObject(entry.getValue());
+        }
+        out.writeObject(null);
+    }
+
+
+    /**
+     *  Reads the contents of this object from the given input stream.
+     *
+     *  @param inp  the input stream to read from
+     *  @throws IOException  if the stream raises it
+     *  @throws ClassNotFoundException  if the stream raises it
+     */
+    private void readObject(ObjectInputStream inp) throws IOException, ClassNotFoundException {
+        inp.defaultReadObject();
+        table = new Entry[inp.readInt()];
+        threshold = (int)(table.length * loadFactor);
+        queue = new ReferenceQueue();
+        Object key = inp.readObject();
+        while (key != null) {
+            Object value = inp.readObject();
+            put(key, value);
+            key = inp.readObject();
+        }
+    }
+
+
+    /**
+     *  Constructs a reference of the given type to the given 
+     *  referent.  The reference is registered with the queue
+     *  for later purging.
+     *
+     *  @param type  HARD, SOFT or WEAK
+     *  @param referent  the object to refer to
+     *  @param hash  the hash code of the <I>key</I> of the mapping;
+     *    this number might be different from referent.hashCode() if
+     *    the referent represents a value and not a key
+     */
+    private Object toReference(int type, Object referent, int hash) {
+        switch (type) {
+            case HARD: return referent;
+            case SOFT: return new SoftRef(hash, referent, queue);
+            case WEAK: return new WeakRef(hash, referent, queue);
+            default: throw new Error();
+        }
+    }
+
+
+    /**
+     *  Returns the entry associated with the given key.
+     *
+     *  @param key  the key of the entry to look up
+     *  @return  the entry associated with that key, or null
+     *    if the key is not in this map
+     */
+    private Entry getEntry(Object key) {
+        if (key == null) return null;
+        int hash = key.hashCode();
+        int index = indexFor(hash);
+        for (Entry entry = table[index]; entry != null; entry = entry.next) {
+            if ((entry.hash == hash) && key.equals(entry.getKey())) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     *  Converts the given hash code into an index into the
+     *  hash table.
+     */
+    private int indexFor(int hash) {
+        // mix the bits to avoid bucket collisions...
+        hash += ~(hash << 15);
+        hash ^= (hash >>> 10);
+        hash += (hash << 3);
+        hash ^= (hash >>> 6);
+        hash += ~(hash << 11);
+        hash ^= (hash >>> 16);
+        return hash & (table.length - 1);
+    }
+
+
+
+    /**
+     *  Resizes this hash table by doubling its capacity.
+     *  This is an expensive operation, as entries must
+     *  be copied from the old smaller table to the new 
+     *  bigger table.
+     */
+    private void resize() {
+        Entry[] old = table;
+        table = new Entry[old.length * 2];
+
+        for (int i = 0; i < old.length; i++) {
+            Entry next = old[i];
+            while (next != null) {
+                Entry entry = next;
+                next = next.next;
+                int index = indexFor(entry.hash);
+                entry.next = table[index];
+                table[index] = entry;
+            }
+            old[i] = null;
+        }
+        threshold = (int)(table.length * loadFactor);
+    }
+
+
+
+    /**
+     * Purges stale mappings from this map.
+     * <p>
+     * Ordinarily, stale mappings are only removed during
+     * a write operation, although this method is called for both
+     * read and write operations to maintain a consistent state.
+     * <p>
+     * Note that this method is not synchronized!  Special
+     * care must be taken if, for instance, you want stale
+     * mappings to be removed on a periodic basis by some
+     * background thread.
+     */
+    private void purge() {
+        Reference ref = queue.poll();
+        while (ref != null) {
+            purge(ref);
+            ref = queue.poll();
+        }
+    }
+
+
+    private void purge(Reference ref) {
+        // The hashCode of the reference is the hashCode of the
+        // mapping key, even if the reference refers to the 
+        // mapping value...
+        int hash = ref.hashCode();
+        int index = indexFor(hash);
+        Entry previous = null;
+        Entry entry = table[index];
+        while (entry != null) {
+            if (entry.purge(ref)) {
+                if (previous == null) table[index] = entry.next;
+                else previous.next = entry.next;
+                this.size--;
+                return;
+            }
+            previous = entry;
+            entry = entry.next;
+        }
+
+    }
+
+
+    /**
+     *  Returns the size of this map.
+     *
+     *  @return  the size of this map
+     */
+    public int size() {
+        purge();
+        return size;
+    }
+
+
+    /**
+     *  Returns <code>true</code> if this map is empty.
+     *
+     *  @return <code>true</code> if this map is empty
+     */
+    public boolean isEmpty() {
+        purge();
+        return size == 0;
+    }
+
+
+    /**
+     *  Returns <code>true</code> if this map contains the given key.
+     *
+     *  @return true if the given key is in this map
+     */
+    public boolean containsKey(Object key) {
+        purge();
+        Entry entry = getEntry(key);
+        if (entry == null) return false;
+        return entry.getValue() != null;
+    }
+
+
+    /**
+     *  Returns the value associated with the given key, if any.
+     *
+     *  @return the value associated with the given key, or <code>null</code>
+     *   if the key maps to no value
+     */
+    public Object get(Object key) {
+        purge();
+        Entry entry = getEntry(key);
+        if (entry == null) return null;
+        return entry.getValue();
+    }
+
+
+    /**
+     *  Associates the given key with the given value.<p>
+     *  Neither the key nor the value may be null.
+     *
+     *  @param key  the key of the mapping
+     *  @param value  the value of the mapping
+     *  @return  the last value associated with that key, or 
+     *   null if no value was associated with the key
+     *  @throws NullPointerException if either the key or value
+     *   is null
+     */
+    public Object put(Object key, Object value) {
+        if (key == null) throw new NullPointerException("null keys not allowed");
+        if (value == null) throw new NullPointerException("null values not allowed");
+
+        purge();
+        if (size + 1 > threshold) resize();
+
+        int hash = key.hashCode();
+        int index = indexFor(hash);
+        Entry entry = table[index];
+        while (entry != null) {
+            if ((hash == entry.hash) && key.equals(entry.getKey())) {
+                Object result = entry.getValue();
+                entry.setValue(value);
+                return result;
+            }
+            entry = entry.next;
+        }
+        this.size++; 
+        modCount++;
+        key = toReference(keyType, key, hash);
+        value = toReference(valueType, value, hash);
+        table[index] = new Entry(key, hash, value, table[index]);
+        return null;
+    }
+
+
+    /**
+     *  Removes the key and its associated value from this map.
+     *
+     *  @param key  the key to remove
+     *  @return the value associated with that key, or null if
+     *   the key was not in the map
+     */
+    public Object remove(Object key) {
+        if (key == null) return null;
+        purge();
+        int hash = key.hashCode();
+        int index = indexFor(hash);
+        Entry previous = null;
+        Entry entry = table[index];
+        while (entry != null) {
+            if ((hash == entry.hash) && key.equals(entry.getKey())) {
+                if (previous == null) table[index] = entry.next;
+                else previous.next = entry.next;
+                this.size--;
+                modCount++;
+                return entry.getValue();
+            }
+            previous = entry;
+            entry = entry.next;
+        }
+        return null;
+    }
+
+
+    /**
+     *  Clears this map.
+     */
+    public void clear() {
+        Arrays.fill(table, null);
+        size = 0;
+        while (queue.poll() != null); // drain the queue
+    }
+
+
+    /**
+     *  Returns a set view of this map's entries.
+     *
+     *  @return a set view of this map's entries
+     */
+    public Set entrySet() {
+        if (entrySet != null) {
+            return entrySet;
+        } 
+        entrySet = new AbstractSet() {
+            public int size() {
+                return ReferenceMap.this.size();
+            }
+
+            public void clear() {
+                ReferenceMap.this.clear();
+            }
+
+            public boolean contains(Object o) {
+                if (o == null) return false;
+                if (!(o instanceof Map.Entry)) return false;
+                Map.Entry e = (Map.Entry)o;
+                Entry e2 = getEntry(e.getKey());
+                return (e2 != null) && e.equals(e2);
+            }
+
+            public boolean remove(Object o) {
+                boolean r = contains(o);
+                if (r) {
+                    Map.Entry e = (Map.Entry)o;
+                    ReferenceMap.this.remove(e.getKey());
+                }
+                return r;
+            }
+
+            public Iterator iterator() {
+                return new EntryIterator();
+            }
+
+            public Object[] toArray() {
+                return toArray(new Object[0]);
+            }
+
+            public Object[] toArray(Object[] arr) {
+                ArrayList list = new ArrayList();
+                Iterator iterator = iterator();
+                while (iterator.hasNext()) {
+                    Entry e = (Entry)iterator.next();
+                    list.add(new DefaultMapEntry(e.getKey(), e.getValue()));
+                }
+                return list.toArray(arr);
+            }
+        };
+        return entrySet;
+    }
+
+
+    /**
+     *  Returns a set view of this map's keys.
+     *
+     *  @return a set view of this map's keys
+     */
+    public Set keySet() {
+        if (keySet != null) return keySet;
+        keySet = new AbstractSet() {
+            public int size() {
+                return ReferenceMap.this.size();
+            }
+
+            public Iterator iterator() {
+                return new KeyIterator();
+            }
+
+            public boolean contains(Object o) {
+                return containsKey(o);
+            }
+
+
+            public boolean remove(Object o) {
+                Object r = ReferenceMap.this.remove(o);
+                return r != null;
+            }
+
+            public void clear() {
+                ReferenceMap.this.clear();
+            }
+
+            public Object[] toArray() {
+                return toArray(new Object[0]);
+            }
+
+            public Object[] toArray(Object[] array) {
+                Collection c = new ArrayList(size());
+                for (Iterator it = iterator(); it.hasNext(); ) {
+                    c.add(it.next());
+                }
+                return c.toArray(array);
+            }
+        };
+        return keySet;
+    }
+
+
+    /**
+     *  Returns a collection view of this map's values.
+     *
+     *  @return a collection view of this map's values.
+     */
+    public Collection values() {
+        if (values != null) return values;
+        values = new AbstractCollection()  {
+            public int size() {
+                return ReferenceMap.this.size();
+            }
+
+            public void clear() {
+                ReferenceMap.this.clear();
+            }
+
+            public Iterator iterator() {
+                return new ValueIterator();
+            }
+
+            public Object[] toArray() {
+                return toArray(new Object[0]);
+            }
+
+            public Object[] toArray(Object[] array) {
+                Collection c = new ArrayList(size());
+                for (Iterator it = iterator(); it.hasNext(); ) {
+                    c.add(it.next());
+                }
+                return c.toArray(array);
+            }
+        };
+        return values;
+    }
+
+
+    // If getKey() or getValue() returns null, it means
+    // the mapping is stale and should be removed.
+    private class Entry implements Map.Entry, KeyValue {
+
+        Object key;
+        Object value;
+        int hash;
+        Entry next;
+
+
+        public Entry(Object key, int hash, Object value, Entry next) {
+            this.key = key;
+            this.hash = hash;
+            this.value = value;
+            this.next = next;
+        }
+
+
+        public Object getKey() {
+            return (keyType > HARD) ? ((Reference)key).get() : key;
+        }
+
+
+        public Object getValue() {
+            return (valueType > HARD) ? ((Reference)value).get() : value;
+        }
+
+
+        public Object setValue(Object object) {
+            Object old = getValue();
+            if (valueType > HARD) ((Reference)value).clear();
+            value = toReference(valueType, object, hash);
+            return old;
+        }
+
+
+        public boolean equals(Object o) {
+            if (o == null) return false;
+            if (o == this) return true;
+            if (!(o instanceof Map.Entry)) return false;
+            
+            Map.Entry entry = (Map.Entry)o;
+            Object key = entry.getKey();
+            Object value = entry.getValue();
+            if ((key == null) || (value == null)) return false;
+            return key.equals(getKey()) && value.equals(getValue());
+        }
+
+
+        public int hashCode() {
+            Object v = getValue();
+            return hash ^ ((v == null) ? 0 : v.hashCode());
+        }
+
+
+        public String toString() {
+            return getKey() + "=" + getValue();
+        }
+
+
+        boolean purge(Reference ref) {
+            boolean r = (keyType > HARD) && (key == ref);
+            r = r || ((valueType > HARD) && (value == ref));
+            if (r) {
+                if (keyType > HARD) ((Reference)key).clear();
+                if (valueType > HARD) {
+                    ((Reference)value).clear();
+                } else if (purgeValues) {
+                    value = null;
+                }
+            }
+            return r;
+        }
+    }
+
+
+    private class EntryIterator implements Iterator {
+        // These fields keep track of where we are in the table.
+        int index;
+        Entry entry;
+        Entry previous;
+
+        // These Object fields provide hard references to the
+        // current and next entry; this assures that if hasNext()
+        // returns true, next() will actually return a valid element.
+        Object nextKey, nextValue;
+        Object currentKey, currentValue;
+
+        int expectedModCount;
+
+
+        public EntryIterator() {
+            index = (size() != 0 ? table.length : 0);
+            // have to do this here!  size() invocation above
+            // may have altered the modCount.
+            expectedModCount = modCount;
+        }
+
+
+        public boolean hasNext() {
+            checkMod();
+            while (nextNull()) {
+                Entry e = entry;
+                int i = index;
+                while ((e == null) && (i > 0)) {
+                    i--;
+                    e = table[i];
+                }
+                entry = e;
+                index = i;
+                if (e == null) {
+                    currentKey = null;
+                    currentValue = null;
+                    return false;
+                }
+                nextKey = e.getKey();
+                nextValue = e.getValue();
+                if (nextNull()) entry = entry.next;
+            }
+            return true;
+        }
+
+
+        private void checkMod() {
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+
+        private boolean nextNull() {
+            return (nextKey == null) || (nextValue == null);
+        }
+
+        protected Entry nextEntry() {    
+            checkMod();
+            if (nextNull() && !hasNext()) throw new NoSuchElementException();
+            previous = entry;
+            entry = entry.next;
+            currentKey = nextKey;
+            currentValue = nextValue;
+            nextKey = null;
+            nextValue = null;
+            return previous;
+        }
+
+
+        public Object next() {
+            return nextEntry();
+        }
+
+
+        public void remove() {
+            checkMod();
+            if (previous == null) throw new IllegalStateException();
+            ReferenceMap.this.remove(currentKey);
+            previous = null;
+            currentKey = null;
+            currentValue = null;
+            expectedModCount = modCount;
+        }
+
+    }
+
+
+    private class ValueIterator extends EntryIterator {
+        public Object next() {
+            return nextEntry().getValue();
+        }
+    }
+
+
+    private class KeyIterator extends EntryIterator {
+        public Object next() {
+            return nextEntry().getKey();
+        }
+    }
+
+
+
+    // These two classes store the hashCode of the key of
+    // of the mapping, so that after they're dequeued a quick
+    // lookup of the bucket in the table can occur.
+
+
+    private static class SoftRef extends SoftReference {
+        private int hash;
+
+
+        public SoftRef(int hash, Object r, ReferenceQueue q) {
+            super(r, q);
+            this.hash = hash;
+        }
+
+
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+
+    private static class WeakRef extends WeakReference {
+        private int hash;
+
+
+        public WeakRef(int hash, Object r, ReferenceQueue q) {
+            super(r, q);
+            this.hash = hash;
+        }
+
+
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractKeyValue.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractKeyValue.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractKeyValue.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,81 @@
+/*
+ *  Copyright 2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections.keyvalue;
+
+import org.apache.commons.collections.KeyValue;
+
+/**
+ * Abstract pair class to assist with creating KeyValue and MapEntry implementations.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:53:54 $
+ * 
+ * @author James Strachan
+ * @author Michael A. Smith
+ * @author Neil O'Toole
+ * @author Stephen Colebourne
+ */
+public abstract class AbstractKeyValue implements KeyValue {
+    
+    /** The key */
+    protected Object key;
+    /** The value */
+    protected Object value;
+    
+    /**
+     * Constructs a new pair with the specified key and given value.
+     *
+     * @param key  the key for the entry, may be null
+     * @param value  the value for the entry, may be null
+     */
+    protected AbstractKeyValue(Object key, Object value) {
+        super();
+        this.key = key;
+        this.value = value;
+    }
+
+    /**
+     * Gets the key from the pair.
+     *
+     * @return the key 
+     */
+    public Object getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from the pair.
+     *
+     * @return the value
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Gets a debugging String view of the pair.
+     * 
+     * @return a String view of the entry
+     */
+    public String toString() {
+        return new StringBuffer()
+            .append(getKey())
+            .append('=')
+            .append(getValue())
+            .toString();
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractMapEntry.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractMapEntry.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/AbstractMapEntry.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,92 @@
+/*
+ *  Copyright 2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections.keyvalue;
+
+import java.util.Map;
+
+/**
+ * Abstract Pair class to assist with creating correct Map Entry implementations.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:53:36 $
+ * 
+ * @author James Strachan
+ * @author Michael A. Smith
+ * @author Neil O'Toole
+ * @author Stephen Colebourne
+ */
+public abstract class AbstractMapEntry extends AbstractKeyValue implements Map.Entry {
+    
+    /**
+     * Constructs a new entry with the given key and given value.
+     *
+     * @param key  the key for the entry, may be null
+     * @param value  the value for the entry, may be null
+     */
+    protected AbstractMapEntry(Object key, Object value) {
+        super(key, value);
+    }
+
+    // Map.Entry interface
+    //-------------------------------------------------------------------------
+    /** 
+     * Sets the value stored in this Map Entry.
+     * <p>
+     * This Map Entry is not connected to a Map, so only the local data is changed.
+     *
+     * @param value  the new value
+     * @return the previous value
+     */
+    public Object setValue(Object value) {
+        Object answer = this.value;
+        this.value = value;
+        return answer;
+    }
+
+    /**
+     * Compares this Map Entry with another Map Entry.
+     * <p>
+     * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
+     * 
+     * @param obj  the object to compare to
+     * @return true if equal key and value
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Map.Entry == false) {
+            return false;
+        }
+        Map.Entry other = (Map.Entry) obj;
+        return
+            (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) &&
+            (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
+    }
+     
+    /**
+     * Gets a hashCode compatible with the equals method.
+     * <p>
+     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
+     * 
+     * @return a suitable hash code
+     */
+    public int hashCode() {
+        return (getKey() == null ? 0 : getKey().hashCode()) ^
+               (getValue() == null ? 0 : getValue().hashCode()); 
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/DefaultMapEntry.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/DefaultMapEntry.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/DefaultMapEntry.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 2001-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections.keyvalue;
+
+import java.util.Map;
+
+import org.apache.commons.collections.KeyValue;
+
+/**
+ * A restricted implementation of {@link java.util.Map.Entry} that prevents
+ * the MapEntry contract from being broken.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:53:16 $
+ * 
+ * @author James Strachan
+ * @author Michael A. Smith
+ * @author Neil O'Toole
+ * @author Stephen Colebourne
+ */
+public final class DefaultMapEntry extends AbstractMapEntry {
+    
+    /**
+     * Constructs a new entry with the specified key and given value.
+     *
+     * @param key  the key for the entry, may be null
+     * @param value  the value for the entry, may be null
+     */
+    public DefaultMapEntry(final Object key, final Object value) {
+        super(key, value);
+    }
+
+    /**
+     * Constructs a new entry from the specified KeyValue.
+     *
+     * @param pair  the pair to copy, must not be null
+     * @throws NullPointerException if the entry is null
+     */
+    public DefaultMapEntry(final KeyValue pair) {
+        super(pair.getKey(), pair.getValue());
+    }
+
+    /**
+     * Constructs a new entry from the specified MapEntry.
+     *
+     * @param entry  the entry to copy, must not be null
+     * @throws NullPointerException if the entry is null
+     */
+    public DefaultMapEntry(final Map.Entry entry) {
+        super(entry.getKey(), entry.getValue());
+    }
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/KeyValue.java
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/KeyValue.java	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/src/test/org/apache/commons/collections/keyvalue/KeyValue.java	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 2003-2004 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.commons.collections;
+
+/**
+ * Defines a simple key value pair.
+ * <p>
+ * A Map Entry has considerable additional semantics over and above a simple
+ * key-value pair. This interface defines the minimum key value, with just the
+ * two get methods.
+ *
+ * @since Commons Collections 3.0
+ * @version $Revision: 1.1 $ $Date: 2004/05/10 19:52:59 $
+ * 
+ * @author Stephen Colebourne
+ */
+public interface KeyValue {
+
+    /**
+     * Gets the key from the pair.
+     *
+     * @return the key 
+     */
+    Object getKey();
+
+    /**
+     * Gets the value from the pair.
+     *
+     * @return the value
+     */
+    Object getValue();
+
+}

Added: trunk/commons-beanutils/branches/upstream/current/xdocs/.cvsignore
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/xdocs/.cvsignore	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/xdocs/.cvsignore	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1 @@
+stylesheets

Added: trunk/commons-beanutils/branches/upstream/current/xdocs/images/logo.png
===================================================================
(Binary files differ)


Property changes on: trunk/commons-beanutils/branches/upstream/current/xdocs/images/logo.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/commons-beanutils/branches/upstream/current/xdocs/index.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/xdocs/index.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/xdocs/index.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,153 @@
+<?xml version="1.0"?>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<document>
+
+ <properties>
+  <title>Commons</title>
+  <author email="commons-dev at jakarta.apache.org">Commons Documentation Team</author>
+ </properties>
+
+ <body>
+
+<section name="Commons BeanUtils">
+
+<p>
+Most Java developers are used to creating Java classes that conform to the
+JavaBeans naming patterns for property getters and setters.  It is natural to
+then access these methods directly, using calls to the corresponding
+<code>getXxx</code> and <code>setXxx</code> methods.  However, there are some
+occasions where dynamic access to Java object properties (without compiled-in
+knowledge of the property getter and setter methods to be called) is needed.
+Example use cases include:</p>
+<ul>
+<li>Building scripting languages that interact with the Java object model
+    (such as the Bean Scripting Framework).</li>
+<li>Building template language processors for web presentation and similar
+    uses (such as JSP or Velocity).</li>
+<li>Building custom tag libraries for JSP and XSP environments (such as Jakarta
+    Taglibs, Struts, Cocoon).</li>
+<li>Consuming XML-based configuration resources (such as Ant build scripts, web
+    application deployment descriptors, Tomcat's <code>server.xml</code>
+    file).</li>
+</ul>
+
+<p>
+The Java language provides <em>Reflection</em> and <em>Introspection</em>
+APIs (see the <code>java.lang.reflect</code> and <code>java.beans</code>
+packages in the JDK Javadocs).  However, these APIs can be quite complex to
+understand and utilize.  The  <em>BeanUtils</em> component provides
+easy-to-use wrappers around these capabilities.
+</p>
+    <subsection name='BeanUtils Core And Modules'>
+        <p>
+The next release will see a departure from the usual packaging strategy. 
+Rather than just a single jar, BeanUtils will distribute a 
+<code>commons-beanutils-core.jar</code> containing the essential parts of BeanUtils
+with minimal dependencies (for this release just 
+<a href='http://jakarta.apache.org/commons/logging'>Commons Logging</a>).
+Other parts of BeanUtils (typically specialized modules) will be distributed as separate,
+modular jars with additional dependencies. Hopefully this will allow library and framework 
+creators more finely grained control over their dependencies. It should also help with
+compatibility issues.
+        </p>
+        <p>
+For everyone else, don't worry :) There will be a single commons-beanutils-all.jar 
+containing everything. Drop it in and add any dependencies your application needs.
+        </p>
+    </subsection>
+    <subsection name='Bean Collections'>
+        <p>
+Bean collections is a library combining BeanUtils with 
+<a href='http://jakarta.apache.org/commons/collections'>Commons Collections</a>
+to provide services for collections of beans. Once class (<code>BeanComparator</code>)
+was previously released, the rest are new. This new distribution strategy should allow
+this sub-component to evolve naturally without the concerns about size and scope
+that might otherwise happen.
+        </p>
+        <p>
+Bean Collections has an additional dependency on 
+<a href='http://jakarta.apache.org/commons/collections'>Commons Collections</a>.
+        </p>
+    </subsection>
+</section>
+
+
+<section name="Documentation">
+
+<p>The <a href="http://jakarta.apache.org/commons/beanutils/RELEASE-NOTES.txt">
+Release Notes</a> document the new features and bug fixes that have been
+included in this release.</p>
+
+<p>The <a href="http://jakarta.apache.org/commons/beanutils/api/index.html">
+JavaDoc API documents</a> are available online.  In particular, you should
+note the property reference syntax options described in the
+<code>PropertyUtils</code> class description.</p>
+
+</section>
+
+
+<section name="Releases">
+    <subsection name='Mirrored Releases'>
+<p>
+Releases after 1.5 should be downloaded from a mirror. Please remember to verify the 
+sigature of the release from the 
+<a href='http://www.apache.org/dist/jakarta/commons/beanutils/'>main apache site</a>
+when downloading from a mirror.
+</p>
+<p>
+    Binary releases are available 
+       <a href="http://jakarta.apache.org/site/binindex.cgi">here</a>.
+    Source releases are available
+       <a href="http://jakarta.apache.org/site/sourceindex.cgi">here</a>
+</p>
+</subsection>
+<subsection name='1.7.x Releases (Mirrored)'>
+    <p>
+<strong>BeanUtils 1.7.0</strong> is a service release which removes the dependency
+upon a specific commons-collection library version. It may be safely used together
+with either the 2.x or 3.x series of commons-collections releases.
+It also introduces a number of important enhancements. It is backward compatible
+with the 1.6 release.
+    </p>
+</subsection>
+<subsection name='1.6.x Releases (Mirrored)'>
+<ul>
+       <li>Version 1.6.1 (latest) - 18 Feb 2003</li>
+       <li>Version 1.6 - 21 Jan 2003</li>
+</ul>
+    </subsection>
+    <subsection name='Older Releases (Not Mirrored)'>
+    <p>
+    <ul>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.5/">Version 1.5 </a> - 23 Oct 2002</li>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.4.1/">Version 1.4.1</a> - 28 Aug 2002</li>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.4/">Version 1.4</a> - 13 Aug 2002
+</li>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.3/">Version 1.3</a> - 29 Apr 2002</li>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.2/">Version 1.2</a> - 24 Dec 2001</li>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.1/">Version 1.1</a> - 22 Sep 2001</li>
+    <li><a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils/v1.0/">Version 1.0</a> - 14 July 2001</li>
+    </ul>
+    </p>
+    </subsection>
+</section>
+
+
+
+</body>
+</document>

Added: trunk/commons-beanutils/branches/upstream/current/xdocs/navigation.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/xdocs/navigation.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/xdocs/navigation.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE org.apache.commons.menus SYSTEM '../../commons-build/menus/menus.dtd'>
+<project name="BeanUtils">
+
+  <title>BeanUtils</title>
+  <organizationLogo href="/images/jakarta-logo-blue.gif">
+   Jakarta
+  </organizationLogo>
+
+  <body>
+    <links>
+      <item name="Jakarta Commons"                   
+            href="http://jakarta.apache.org/commons/"/>
+    </links>
+
+    <menu name="Commons BeanUtils">
+      <item name="Overview" href="/index.html"/>
+      <item name="Javadoc (Release)" href="api/index.html"/>
+      <item name="Mailing lists" href="/mail-lists.html"/>
+      <item name="Team" href="/team-list.html"/>
+      <!--item name="Tasks" href="/tasks.html"/-->
+      <item name="CVS" href="http://cvs.apache.org/viewcvs/jakarta-commons/beanutils/"/>
+      <item name="Javadoc (CVS latest)" href="apidocs/index.html"/>
+    </menu>
+    
+    <menu name='Modules'>
+        <item name="Bean Collections" href="bean-collections/index.html"/>
+    </menu>
+    
+    &common-menus;
+
+  </body>
+</project>

Added: trunk/commons-beanutils/branches/upstream/current/xdocs/proposal.xml
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/xdocs/proposal.xml	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/xdocs/proposal.xml	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,136 @@
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+<properties>
+<title>Proposal for BeanUtils Package</title>
+</properties>
+<body>
+
+
+<section name="Proposal for BeanUtils Package">
+
+
+
+<subsection name="(0) Rationale">
+
+<p>Most Java developers are used to creating Java classes that conform to the
+JavaBeans naming patterns for property getters and setters.  It is natural to
+then access these methods directly, using calls to the corresponding
+<code>getXxx</code> and <code>setXxx</code> methods.  However, there are some
+occasions where dynamic access to Java object properties (without compiled-in
+knowledge of the property getter and setter methods to be called) is needed.
+Example use cases include:</p>
+<ul>
+<li>Building scripting languages that interact with the Java object model
+    (such as the Bean Scripting Framework).</li>
+<li>Building template language processors for web presentation and similar
+    uses (such as JSP or Velocity).</li>
+<li>Building custom tag libraries for JSP and XSP environments (such as Jakarta
+    Taglibs, Struts, Cocoon).</li>
+<li>Consuming XML-based configuration resources (such as Ant build scripts, web
+    application deployment descriptors, Tomcat's <code>server.xml</code>
+    file).</li>
+</ul>
+
+<p>The Java language provides <em>Reflection</em> and <em>Introspection</em>
+APIs (see the <code>java.lang.reflect</code> and <code>java.beans</code>
+packages in the JDK Javadocs).  However, these APIs can be quite complex to
+understand and utilize.  The proposed <em>BeanUtils</em> component provides
+easy-to-use wrappers around these capabilities.</p>
+
+
+</subsection>
+<subsection name="(1) Scope of the Package">
+
+<p>This proposal is to create a package of Java utility methods for accessing
+and modifying the properties of arbitrary JavaBeans.  No dependencies outside
+of the JDK are required, so the use of this package is very lightweight.</p>
+
+<p>In addition to wrapping the reflection and introspection APIs of the
+standard JDK, <em>BeanUtils</em> components shall support a syntax for directly
+accessing <strong>nested</strong> and <strong>indexed</strong> properties, in a
+manner that will be familar to users of scripting languages like JavaScript.
+For example, the following property accessor expressions are supported:</p>
+<ul>
+<li><strong>customer</strong> - Equivalent to <code>getCustomer()</code>.</li>
+<li><strong>customer.address</strong> - Equivalent to
+    <code>getCustomer().getAddress()</code>.</li>
+<li><strong>customer.address[2].street</strong> - Equivalent to
+    <code>getCustomer().getAddress(2).getStreet()</code> (access to indexed
+    properties also works if the underlying property is an array rather than
+    providing indexed getter and setter methods).</li>
+</ul>
+
+
+</subsection>
+<subsection name="(1.5) Interaction With Other Packages">
+
+<p><em>BeanUtils</em> relies only on standard JDK 1.2 (or later) APIs for
+production deployment.  It utilizes the JUnit unit testing framework for
+developing and executing unit tests, but this is of interest only to
+developers of the component.  BeanUtils will also be a dependency for
+several future proposed components for the Jakarta Commons subproject.</p>
+
+<p>No external configuration files are utilized.</p>
+
+
+</subsection>
+<subsection name="(2) Initial Source of the Package">
+
+<p>The three original Java classes (<code>BeanUtils</code>,
+<code>ConvertUtils</code>, and <code>PropertyUtils</code>) are an integral
+part of the <a href="http://jakarta.apache.org/struts">Struts Framework</a>.
+However, they have very few dependencies on other aspects of Struts, and
+those dependencies have been removed in the proposed code base.
+Once accepted and released as a Jakarta Commons component, Struts will
+be modified to use the Commons version of these classes, and its internal
+versions will be deprecated.</p>
+
+<p>The proposed package name for the new component is
+<code>org.apache.commons.beanutils</code>.</p>
+
+
+</subsection>
+<subsection name="(3)  Required Jakarta-Commons Resources">
+
+<ul>
+<li>CVS Repository - New directory <code>beanutils</code> in the
+    <code>jakarta-commons</code> CVS repository.  All initial committers
+    are already committers on <code>jakarta-commons</code>, so no
+    additional user setups are required.</li>
+<li>Mailing List - Discussions will take place on the general
+    <em>jakarta-commons at jakarta.apache.org</em> mailing list.  To help
+    list subscribers identify messages of interest, it is suggested that
+    the message subject of messages about this component be prefixed with
+    [BeanUtils].</li>
+<li>Bugzilla - New component "BeanUtils" under the "Commons" product
+    category, with appropriate version identifiers as needed.</li>
+<li>Jyve FAQ - New category "commons-beanutils" (when available). </li>
+</ul>
+
+
+</subsection>
+<subsection name="(4) Initial Committers">
+
+<p>The initial committers on the BeanUtils component shall be Craig
+McClanahan and Geir Magnusson Jr.</p>
+
+
+
+</subsection>
+</section>
+</body>
+</document>

Added: trunk/commons-beanutils/branches/upstream/current/xdocs/style/project.css
===================================================================
--- trunk/commons-beanutils/branches/upstream/current/xdocs/style/project.css	2006-03-09 22:01:25 UTC (rev 1957)
+++ trunk/commons-beanutils/branches/upstream/current/xdocs/style/project.css	2006-03-09 22:04:21 UTC (rev 1958)
@@ -0,0 +1,5 @@
+#banner, #banner td { 
+ background: #fff;
+ color: #000;
+}
+




More information about the pkg-java-commits mailing list