diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/lang/BeanUtil.java b/common/common-lang/src/main/java/com/twelvemonkeys/lang/BeanUtil.java index e35aca9f..0c09176d 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/lang/BeanUtil.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/lang/BeanUtil.java @@ -276,19 +276,19 @@ public final class BeanUtil { } try { - // If this does not throw an excption, it works + // If this does not throw an exception, it works method = pObject.getClass().getMethod(pName, pParams); } catch (Throwable t) { // Ignore } - // 2: Try any supertypes of paramType, to see if we have a match + // 2: Try any super-types of paramType, to see if we have a match if (method == null) { while ((paramType = paramType.getSuperclass()) != null) { pParams[0] = paramType; try { - // If this does not throw an excption, it works + // If this does not throw an exception, it works method = pObject.getClass().getMethod(pName, pParams); } catch (Throwable t) { @@ -365,6 +365,9 @@ public final class BeanUtil { } } + // TODO: Convert value to single-value array if needed + // TODO: Convert CSV String to string array (or potentially any type of array) + // TODO: Convert other types if (pValue instanceof String) { Converter converter = Converter.getInstance(); @@ -596,8 +599,7 @@ public final class BeanUtil { catch (NoSuchMethodException ignore) { // If invocation failed, convert lisp-style and try again if (pLispToCamel && property.indexOf('-') > 0) { - setPropertyValue(pBean, StringUtil.lispToCamel(property, false), - entry.getValue()); + setPropertyValue(pBean, StringUtil.lispToCamel(property, false), entry.getValue()); } } } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/lang/ExceptionUtil.java b/common/common-lang/src/main/java/com/twelvemonkeys/lang/ExceptionUtil.java index fe9cd78c..32a8ffc9 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/lang/ExceptionUtil.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/lang/ExceptionUtil.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.sql.SQLException; +import static com.twelvemonkeys.lang.Validate.notNull; + /** * ExceptionUtil * @@ -14,6 +16,15 @@ import java.sql.SQLException; */ public final class ExceptionUtil { + /** + * Re-throws an exception, either as-is if the exception was already unchecked, otherwise wrapped in + * a {@link RuntimeException}. + * "Expected" exception types are wrapped in {@link RuntimeException}s, while + * "unexpected" exception types are wrapped in {@link java.lang.reflect.UndeclaredThrowableException}s. + * + * @param pThrowable the exception to launder + * @param pExpectedTypes the types of exception the code is expected to throw + */ /*public*/ static void launder(final Throwable pThrowable, Class... pExpectedTypes) { if (pThrowable instanceof Error) { throw (Error) pThrowable; @@ -40,36 +51,38 @@ public final class ExceptionUtil { throwAs(RuntimeException.class, pThrowable); } - /*public*/ static void handle(final Throwable pThrowable, final ThrowableHandler... pHandler) { - handleImpl(pThrowable, pHandler); + @SuppressWarnings({"unchecked"}) + /*public*/ static void handle(final Throwable pThrowable, final ThrowableHandler... pHandlers) { + handleImpl(pThrowable, (ThrowableHandler[]) pHandlers); } - @SuppressWarnings({"unchecked"}) - private static void handleImpl(final Throwable pThrowable, final ThrowableHandler... pHandler) { + private static void handleImpl(final Throwable pThrowable, final ThrowableHandler... pHandlers) { // TODO: Sort more specific throwable handlers before less specific? - for (ThrowableHandler handler : pHandler) { + for (ThrowableHandler handler : pHandlers) { if (handler.handles(pThrowable)) { - handler.handle((T) pThrowable); + handler.handle(pThrowable); return; } } + + // Not handled, re-throw throwUnchecked(pThrowable); } public static abstract class ThrowableHandler { - private Class[] mThrowables; + private final Class[] throwables; protected ThrowableHandler(final Class... pThrowables) { - // TODO: Assert not null - mThrowables = pThrowables.clone(); + throwables = notNull(pThrowables).clone(); } final public boolean handles(final Throwable pThrowable) { - for (Class throwable : mThrowables) { + for (Class throwable : throwables) { if (throwable.isAssignableFrom(pThrowable.getClass())) { return true; } } + return false; } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/lang/Platform.java b/common/common-lang/src/main/java/com/twelvemonkeys/lang/Platform.java index 76c85eab..90b5b22f 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/lang/Platform.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/lang/Platform.java @@ -39,24 +39,24 @@ public final class Platform { /** * Normalized operating system constant */ - final OperatingSystem mOS; + final OperatingSystem os; /** * Unormalized operating system version constant (for completeness) */ - final String mVersion; + final String version; /** * Normalized system architecture constant */ - final Architecture mArchitecture; + final Architecture architecture; static final private Platform INSTANCE = new Platform(); private Platform() { - mOS = normalizeOperatingSystem(); - mVersion = System.getProperty("os.version"); - mArchitecture = normalizeArchitecture(mOS); + os = normalizeOperatingSystem(); + version = System.getProperty("os.version"); + architecture = normalizeArchitecture(os); } private static OperatingSystem normalizeOperatingSystem() { @@ -138,21 +138,21 @@ public final class Platform { * @return this platform's OS. */ public OperatingSystem getOS() { - return mOS; + return os; } /** * @return this platform's OS version. */ public String getVersion() { - return mVersion; + return version; } /** * @return this platform's architecture. */ public Architecture getArchitecture() { - return mArchitecture; + return architecture; } /** @@ -160,7 +160,7 @@ public final class Platform { * @return the current {@code OperatingSystem}. */ public static OperatingSystem os() { - return INSTANCE.mOS; + return INSTANCE.os; } /** @@ -168,7 +168,7 @@ public final class Platform { * @return the current OS version. */ public static String version() { - return INSTANCE.mVersion; + return INSTANCE.version; } /** @@ -176,7 +176,7 @@ public final class Platform { * @return the current {@code Architecture}. */ public static Architecture arch() { - return INSTANCE.mArchitecture; + return INSTANCE.architecture; } /** @@ -197,14 +197,14 @@ public final class Platform { Unknown(System.getProperty("os.arch")); - final String mName;// for debug only + final String name;// for debug only private Architecture(String pName) { - mName = pName; + name = pName; } public String toString() { - return mName; + return name; } } @@ -225,20 +225,20 @@ public final class Platform { Unknown(System.getProperty("os.name"), ""); - final String mId; - final String mName;// for debug only + final String id; + final String name;// for debug only private OperatingSystem(String pName, String pId) { - mName = pName; - mId = pId; + name = pName; + id = pId; } public String getName() { - return mName; + return name; } public String toString() { - return mId; + return id; } } } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/lang/StringUtil.java b/common/common-lang/src/main/java/com/twelvemonkeys/lang/StringUtil.java index b7dc34e1..1d244b72 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/lang/StringUtil.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/lang/StringUtil.java @@ -77,7 +77,7 @@ public final class StringUtil { } /** - * Constructs a new {@link String} by decoding the specified subarray of bytes using the specified charset. + * Constructs a new {@link String} by decoding the specified sub array of bytes using the specified charset. * Replacement for {@link String#String(byte[], int, int, String) new String(byte[], int, int, String)}, that does * not throw the checked {@link UnsupportedEncodingException}, * but instead the unchecked {@link UnsupportedCharsetException} if the character set is not supported. @@ -1580,7 +1580,7 @@ public final class StringUtil { * Converts a string array to a string separated by the given delimiter. * * @param pStringArray the string array - * @param pDelimiterString the delimter string + * @param pDelimiterString the delimiter string * @return string of delimiter separated values * @throws IllegalArgumentException if {@code pDelimiterString == null} */ diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/lang/Validate.java b/common/common-lang/src/main/java/com/twelvemonkeys/lang/Validate.java index 1fe91775..c6f308ea 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/lang/Validate.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/lang/Validate.java @@ -16,6 +16,8 @@ import java.util.Map; * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/lang/Validate.java#1 $ */ public final class Validate { + // TODO: Make it possible to throw IllegalStateException instead of IllegalArgumentException? + private static final String UNSPECIFIED_PARAM_NAME = "method parameter"; private Validate() {} @@ -121,4 +123,16 @@ public final class Validate { return pParameter; } + + public static boolean isTrue(final boolean pExpression, final String pMessage) { + return isTrue(pExpression, pExpression, pMessage); + } + + public static T isTrue(final boolean condition, final T value, final String message) { + if (!condition) { + throw new IllegalArgumentException(String.format(message, value)); + } + + return value; + } } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/BeanMap.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/BeanMap.java index 75d40df2..a67c2f21 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/BeanMap.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/BeanMap.java @@ -40,7 +40,7 @@ import java.io.Serializable; /** * A {@code Map} adapter for a Java Bean. *

- * Ruhtlessly stolen from + * Ruthlessly stolen from * wrapper Class type; if (pType == Boolean.TYPE) { @@ -113,6 +121,31 @@ public final class DefaultConverter implements PropertyConverter { } } + private Object toArray(String pString, Class pType, String pFormat) { + String[] strings = StringUtil.toStringArray(pString, pFormat != null ? pFormat : StringUtil.DELIMITER_STRING); + Class type = pType.getComponentType(); + if (type == String.class) { + return strings; + } + + Object array = Array.newInstance(type, strings.length); + try { + for (int i = 0; i < strings.length; i++) { + Array.set(array, i, Converter.getInstance().toObject(strings[i], type)); + } + } + catch (ConversionException e) { + if (pFormat != null) { + throw new ConversionException(String.format("%s for string \"%s\" with format \"%s\"", e.getMessage(), pString, pFormat), e); + } + else { + throw new ConversionException(String.format("%s for string \"%s\"", e.getMessage(), pString), e); + } + } + + return array; + } + /** * Converts the object to a string, using {@code pObject.toString()}. * @@ -126,10 +159,77 @@ public final class DefaultConverter implements PropertyConverter { throws ConversionException { try { - return (pObject != null ? pObject.toString() : null); + return pObject == null ? null : pObject.getClass().isArray() ? arrayToString(toObjectArray(pObject), pFormat) : pObject.toString(); } catch (RuntimeException rte) { throw new ConversionException(rte); } } + + private String arrayToString(final Object[] pArray, final String pFormat) { + return pFormat == null ? StringUtil.toCSVString(pArray) : StringUtil.toCSVString(pArray, pFormat); + } + + private Object[] toObjectArray(Object pObject) { + // TODO: Extract util method for wrapping/unwrapping native arrays? + Object[] array; + Class componentType = pObject.getClass().getComponentType(); + if (componentType.isPrimitive()) { + if (int.class == componentType) { + array = new Integer[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (short.class == componentType) { + array = new Short[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (long.class == componentType) { + array = new Long[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (float.class == componentType) { + array = new Float[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (double.class == componentType) { + array = new Double[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (boolean.class == componentType) { + array = new Boolean[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (byte.class == componentType) { + array = new Byte[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else if (char.class == componentType) { + array = new Character[Array.getLength(pObject)]; + for (int i = 0; i < array.length; i++) { + Array.set(array, i, Array.get(pObject, i)); + } + } + else { + throw new IllegalArgumentException("Unknown type " + componentType); + } + } + else { + array = (Object[]) pObject; + } + return array; + } } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/NumberConverter.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/NumberConverter.java index 8a3b586b..f84c3477 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/NumberConverter.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/NumberConverter.java @@ -39,14 +39,14 @@ import java.text.*; * Converts strings to numbers and back. *

* This class has a static cache of {@code NumberFormats}, to avoid - * creation and parsing of numberformats every time one is used. + * creation and parsing of number formats every time one is used. * * @author Harald Kuhr * @author last modified by $Author: haku $ * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/convert/NumberConverter.java#2 $ */ public class NumberConverter implements PropertyConverter { - // TODO: Need to either make this non-local aware, or document that it is... + // TODO: Need to either make this non-locale aware, or document that it is... private static final DecimalFormatSymbols SYMBOLS = new DecimalFormatSymbols(Locale.US); private static final NumberFormat sDefaultFormat = new DecimalFormat("#0.#", SYMBOLS); diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/RegExTokenIterator.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/RegExTokenIterator.java index 0dbfa61b..ce1219f9 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/RegExTokenIterator.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/RegExTokenIterator.java @@ -45,8 +45,8 @@ import java.util.regex.PatternSyntaxException; * @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/regex/RegExTokenIterator.java#1 $ */ public class RegExTokenIterator extends AbstractTokenIterator { - private final Matcher mMatcher; - private boolean mNext = false; + private final Matcher matcher; + private boolean next = false; /** * Creates a {@code RegExTokenIterator}. @@ -80,7 +80,7 @@ public class RegExTokenIterator extends AbstractTokenIterator { throw new IllegalArgumentException("pattern == null"); } - mMatcher = Pattern.compile(pPattern).matcher(pString); + matcher = Pattern.compile(pPattern).matcher(pString); } /** @@ -88,18 +88,18 @@ public class RegExTokenIterator extends AbstractTokenIterator { * */ public void reset() { - mMatcher.reset(); + matcher.reset(); } public boolean hasNext() { - return mNext || (mNext = mMatcher.find()); + return next || (next = matcher.find()); } public String next() { if (!hasNext()) { throw new NoSuchElementException(); } - mNext = false; - return mMatcher.group(); + next = false; + return matcher.group(); } } \ No newline at end of file diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/WildcardStringParser.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/WildcardStringParser.java index 62dbeb5f..0d1ce190 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/WildcardStringParser.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/regex/WildcardStringParser.java @@ -114,6 +114,7 @@ import java.io.PrintStream; * @deprecated Will probably be removed in the near future */ public class WildcardStringParser { + // TODO: Get rid of this class // Constants diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/service/ServiceRegistry.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/service/ServiceRegistry.java index e6ce626d..b271336b 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/service/ServiceRegistry.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/service/ServiceRegistry.java @@ -65,7 +65,7 @@ import java.util.*; */ public class ServiceRegistry { // TODO: Security issues? - // TODO: Application contexts? + // TODO: Application contexts? Probably use instance per thread group.. /** * "META-INF/services/" @@ -73,7 +73,7 @@ public class ServiceRegistry { public static final String SERVICES = "META-INF/services/"; // Class to CategoryRegistry mapping - private final Map, CategoryRegistry> mCategoryMap; + private final Map, CategoryRegistry> categoryMap; /** * Creates a {@code ServiceRegistry} instance with a set of categories @@ -98,7 +98,7 @@ public class ServiceRegistry { } // NOTE: Categories are constant for the lifetime of a registry - mCategoryMap = Collections.unmodifiableMap(map); + categoryMap = Collections.unmodifiableMap(map); } private void putCategory(Map, CategoryRegistry> pMap, Class pCategory) { @@ -154,7 +154,7 @@ public class ServiceRegistry { if (!classNames.isEmpty()) { @SuppressWarnings({"unchecked"}) - CategoryRegistry registry = mCategoryMap.get(pCategory); + CategoryRegistry registry = categoryMap.get(pCategory); Set providerClassNames = classNames.keySet(); @@ -213,7 +213,7 @@ public class ServiceRegistry { * @return an {@code Iterator} containing all categories in this registry. */ protected Iterator> categories() { - return mCategoryMap.keySet().iterator(); + return categoryMap.keySet().iterator(); } /** @@ -260,18 +260,19 @@ public class ServiceRegistry { return getRegistry(pElement).contatins(pProvider); } }) { - Class mCurrent; + Class current; public Class next() { - return (mCurrent = super.next()); + return (current = super.next()); } public void remove() { - if (mCurrent == null) { + if (current == null) { throw new IllegalStateException("No current element"); } - getRegistry(mCurrent).deregister(pProvider); - mCurrent = null; + + getRegistry(current).deregister(pProvider); + current = null; } }; } @@ -284,7 +285,7 @@ public class ServiceRegistry { */ private CategoryRegistry getRegistry(final Class pCategory) { @SuppressWarnings({"unchecked"}) - CategoryRegistry registry = mCategoryMap.get(pCategory); + CategoryRegistry registry = categoryMap.get(pCategory); if (registry == null) { throw new IllegalArgumentException("No such category: " + pCategory.getName()); } @@ -366,17 +367,17 @@ public class ServiceRegistry { * Keeps track of each individual category. */ class CategoryRegistry { - private final Class mCategory; - private final Map mProviders = new LinkedHashMap(); + private final Class category; + private final Map providers = new LinkedHashMap(); CategoryRegistry(Class pCategory) { Validate.notNull(pCategory, "category"); - mCategory = pCategory; + category = pCategory; } private void checkCategory(final Object pProvider) { - if (!mCategory.isInstance(pProvider)) { - throw new IllegalArgumentException(pProvider + " not instance of category " + mCategory.getName()); + if (!category.isInstance(pProvider)) { + throw new IllegalArgumentException(pProvider + " not instance of category " + category.getName()); } } @@ -386,7 +387,7 @@ public class ServiceRegistry { // NOTE: We only register the new instance, if we don't allready // have an instance of pProvider's class. if (!contatins(pProvider)) { - mProviders.put(pProvider.getClass(), pProvider); + providers.put(pProvider.getClass(), pProvider); processRegistration(pProvider); return true; } @@ -397,7 +398,7 @@ public class ServiceRegistry { void processRegistration(final T pProvider) { if (pProvider instanceof RegisterableService) { RegisterableService service = (RegisterableService) pProvider; - service.onRegistration(ServiceRegistry.this, mCategory); + service.onRegistration(ServiceRegistry.this, category); } } @@ -406,7 +407,7 @@ public class ServiceRegistry { // NOTE: We remove any provider of the same class, this may or may // not be the same instance as pProvider. - T oldProvider = mProviders.remove(pProvider.getClass()); + T oldProvider = providers.remove(pProvider.getClass()); if (oldProvider != null) { processDeregistration(oldProvider); @@ -419,12 +420,12 @@ public class ServiceRegistry { void processDeregistration(final T pOldProvider) { if (pOldProvider instanceof RegisterableService) { RegisterableService service = (RegisterableService) pOldProvider; - service.onDeregistration(ServiceRegistry.this, mCategory); + service.onDeregistration(ServiceRegistry.this, category); } } public boolean contatins(final Object pProvider) { - return mProviders.containsKey(pProvider.getClass()); + return providers.containsKey(pProvider.getClass()); } public Iterator providers() { @@ -432,9 +433,9 @@ public class ServiceRegistry { // using the deregister method will result in // ConcurrentModificationException in the iterator.. // We wrap the iterator to track deregistration right. - final Iterator iterator = mProviders.values().iterator(); + final Iterator iterator = providers.values().iterator(); return new Iterator() { - T mCurrent; + T current; public boolean hasNext() { return iterator.hasNext(); @@ -442,12 +443,12 @@ public class ServiceRegistry { } public T next() { - return (mCurrent = iterator.next()); + return (current = iterator.next()); } public void remove() { iterator.remove(); - processDeregistration(mCurrent); + processDeregistration(current); } }; } diff --git a/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/DefaultConverterTestCase.java b/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/DefaultConverterTestCase.java index e5ff4226..65c879bd 100755 --- a/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/DefaultConverterTestCase.java +++ b/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/DefaultConverterTestCase.java @@ -1,5 +1,8 @@ package com.twelvemonkeys.util.convert; +import java.io.File; +import java.net.URI; + /** * DefaultConverterTestCase *

@@ -20,7 +23,9 @@ public class DefaultConverterTestCase extends PropertyConverterAbstractTestCase new Conversion("true", Boolean.TRUE), new Conversion("TRUE", Boolean.TRUE, null, "true"), new Conversion("false", Boolean.FALSE), - new Conversion("FALSE", new Boolean(false), null, "false"), + new Conversion("FALSE", false, null, "false"), + + new Conversion("2", 2), // Stupid but valid new Conversion("fooBar", "fooBar"), @@ -29,6 +34,22 @@ public class DefaultConverterTestCase extends PropertyConverterAbstractTestCase // Stupid test class that reveres chars new Conversion("fooBar", new FooBar("fooBar")), + // String array tests + new Conversion("foo, bar, baz", new String[] {"foo", "bar", "baz"}), + new Conversion("foo", new String[] {"foo"}), + new Conversion("foo;bar; baz", new String[] {"foo", "bar", "baz"}, "; ", "foo; bar; baz"), + + // Native array tests + new Conversion("1, 2, 3", new int[] {1, 2, 3}), + new Conversion("-1, 42, 0", new long[] {-1, 42, 0}), + new Conversion("true, true, false", new boolean[] {true, true, false}), + new Conversion(".3, 4E7, .97", new float[] {.3f, 4e7f, .97f}, ", ", "0.3, 4.0E7, 0.97"), + + // Object array test + new Conversion("foo, bar", new FooBar[] {new FooBar("foo"), new FooBar("bar")}), + new Conversion("/temp, /usr/local/bin", new File[] {new File("/temp"), new File("/usr/local/bin")}), + new Conversion("file:/temp, http://java.net/", new URI[] {URI.create("file:/temp"), URI.create("http://java.net/")}), + // TODO: More tests }; } diff --git a/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/PropertyConverterAbstractTestCase.java b/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/PropertyConverterAbstractTestCase.java index 2f557027..28987aa6 100755 --- a/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/PropertyConverterAbstractTestCase.java +++ b/common/common-lang/src/test/java/com/twelvemonkeys/util/convert/PropertyConverterAbstractTestCase.java @@ -2,6 +2,8 @@ package com.twelvemonkeys.util.convert; import com.twelvemonkeys.lang.ObjectAbstractTestCase; +import java.util.Arrays; + /** * PropertyConverterAbstractTestCase *

@@ -30,16 +32,28 @@ public abstract class PropertyConverterAbstractTestCase extends ObjectAbstractTe Object obj; try { obj = converter.toObject(test.original(), test.type(), test.format()); - assertEquals("'" + test.original() + "' convtered to incorrect type", test.type(), obj.getClass()); - assertEquals("'" + test.original() + "' not converted", test.value(), obj); + + assertEquals("'" + test.original() + "' converted to incorrect type", test.type(), obj.getClass()); + if (test.type().isArray()) { + assertTrue("'" + test.original() + "' not converted", arrayEquals(test.value(), obj)); + } + else { + assertEquals("'" + test.original() + "' not converted", test.value(), obj); + } String result = converter.toString(test.value(), test.format()); - assertEquals("'" + test.converted() + "' does not macth", test.converted(), result); + assertEquals("'" + test.converted() + "' does not match", test.converted(), result); obj = converter.toObject(result, test.type(), test.format()); - assertEquals("'" + test.original() + "' convtered to incorrect type", test.type(), obj.getClass()); - assertEquals("'" + test.original() + "' did not survive roundrip conversion", test.value(), obj); + assertEquals("'" + test.original() + "' converted to incorrect type", test.type(), obj.getClass()); + + if (test.type().isArray()) { + assertTrue("'" + test.original() + "' did not survive round trip conversion", arrayEquals(test.value(), obj)); + } + else { + assertEquals("'" + test.original() + "' did not survive round trip conversion", test.value(), obj); + } } catch (ConversionException e) { e.printStackTrace(); @@ -48,6 +62,39 @@ public abstract class PropertyConverterAbstractTestCase extends ObjectAbstractTe } } + // TODO: Util method? + private boolean arrayEquals(final Object left, final Object right) { + if (left.getClass().getComponentType().isPrimitive()) { + if (int.class == left.getClass().getComponentType()) { + return Arrays.equals((int[]) left, (int[]) right); + } + if (short.class == left.getClass().getComponentType()) { + return Arrays.equals((short[]) left, (short[]) right); + } + if (long.class == left.getClass().getComponentType()) { + return Arrays.equals((long[]) left, (long[]) right); + } + if (float.class == left.getClass().getComponentType()) { + return Arrays.equals((float[]) left, (float[]) right); + } + if (double.class == left.getClass().getComponentType()) { + return Arrays.equals((double[]) left, (double[]) right); + } + if (boolean.class == left.getClass().getComponentType()) { + return Arrays.equals((boolean[]) left, (boolean[]) right); + } + if (byte.class == left.getClass().getComponentType()) { + return Arrays.equals((byte[]) left, (byte[]) right); + } + if (char.class == left.getClass().getComponentType()) { + return Arrays.equals((char[]) left, (char[]) right); + } + // Else blow up below... + } + + return Arrays.equals((Object[]) left, (Object[]) right); + } + public static final class Conversion { private final String mStrVal; private final Object mObjVal;