Clean-up and minor changes in core classes.

Adapted new code style.
No or few functional changes.
This commit is contained in:
Harald Kuhr 2011-02-16 22:29:23 +01:00
parent df0d3f90e8
commit 191643a36c
16 changed files with 298 additions and 127 deletions

View File

@ -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());
}
}
}

View File

@ -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<? extends Throwable>... 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<? extends Throwable>... pHandler) {
handleImpl(pThrowable, pHandler);
@SuppressWarnings({"unchecked"})
/*public*/ static void handle(final Throwable pThrowable, final ThrowableHandler<? extends Throwable>... pHandlers) {
handleImpl(pThrowable, (ThrowableHandler<Throwable>[]) pHandlers);
}
@SuppressWarnings({"unchecked"})
private static <T extends Throwable> void handleImpl(final Throwable pThrowable, final ThrowableHandler<T>... pHandler) {
private static void handleImpl(final Throwable pThrowable, final ThrowableHandler<Throwable>... pHandlers) {
// TODO: Sort more specific throwable handlers before less specific?
for (ThrowableHandler<T> handler : pHandler) {
for (ThrowableHandler<Throwable> 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<T extends Throwable> {
private Class<? extends T>[] mThrowables;
private final Class<? extends T>[] throwables;
protected ThrowableHandler(final Class<? extends T>... pThrowables) {
// TODO: Assert not null
mThrowables = pThrowables.clone();
throwables = notNull(pThrowables).clone();
}
final public boolean handles(final Throwable pThrowable) {
for (Class<? extends T> throwable : mThrowables) {
for (Class<? extends T> throwable : throwables) {
if (throwable.isAssignableFrom(pThrowable.getClass())) {
return true;
}
}
return false;
}

View File

@ -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;
}
}
}

View File

@ -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}
*/

View File

@ -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> T isTrue(final boolean condition, final T value, final String message) {
if (!condition) {
throw new IllegalArgumentException(String.format(message, value));
}
return value;
}
}

View File

@ -40,7 +40,7 @@ import java.io.Serializable;
/**
* A {@code Map} adapter for a Java Bean.
* <p/>
* Ruhtlessly stolen from
* Ruthlessly stolen from
* <a href="http://binkley.blogspot.com/2006/08/mapping-java-bean.html>Binkley's Blog</a>
*/
public final class BeanMap extends AbstractMap<String, Object> implements Serializable, Cloneable {

View File

@ -37,60 +37,31 @@ package com.twelvemonkeys.util.convert;
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/util/convert/ConversionException.java#1 $
*/
public class ConversionException extends IllegalArgumentException {
protected Throwable mCause = this;
/**
* Creates a {@code ConversionException} with the given error message.
*
* @param pMessage the error message
*/
public ConversionException(String pMessage) {
public ConversionException(final String pMessage) {
super(pMessage);
}
/**
* Creates a {@code ConversionException} with the given cause.
*
* @param pCause The Throwable that caused this exception
* @param pCause The {@link Throwable} that caused this exception
*/
public ConversionException(Throwable pCause) {
super(pCause == null ? null : pCause.getMessage());
initCause(pCause);
public ConversionException(final Throwable pCause) {
super(pCause != null ? pCause.getMessage() : null, pCause);
}
/**
* Returns the cause of this {@code Throwable} or {@code null} if the
* cause is nonexistent or unknown.
* Creates a {@code ConversionException} with the given message and cause.
*
* @return the cause of this {@code Throwable} or {@code null} if the
* cause is nonexistent or unknown (the cause is the throwable that caused
* this throwable to get thrown).
* @param pMessage the error message
* @param pCause The {@link Throwable} that caused this exception
*/
public Throwable getCause() {
if (mCause == this) {
return null;
}
return mCause;
}
/**
* Initializes this ConversionException with the given cause.
*
* @param pCause The Throwable that caused this exception
*
* @throws IllegalStateException if cause is allready set
* @throws IllegalArgumentException if {@code pCause == this}
*/
public Throwable initCause(Throwable pCause) {
if (mCause != this) {
throw new IllegalStateException("Can't overwrite cause");
}
if (pCause == this) {
throw new IllegalArgumentException("Can't be caused by self");
}
mCause = pCause;
return this;
public ConversionException(final String pMessage, final Throwable pCause) {
super(pMessage, pCause);
}
}

View File

@ -56,13 +56,14 @@ import java.util.Map;
// Maybe have BeanUtil act as a "proxy", and hide this class alltogheter?
// TODO: ServiceRegistry for registering 3rd party converters
// TODO: URI scheme, for implicit typing? Is that a good idea?
// TODO: Array converters?
public abstract class Converter implements PropertyConverter {
/** Our singleton instance */
protected static Converter sInstance = new ConverterImpl(); // Thread safe & EASY
/** The conveters Map */
protected Map mConverters = new Hashtable();
protected Map converters = new Hashtable();
// Register our predefined converters
static {
@ -115,7 +116,7 @@ public abstract class Converter implements PropertyConverter {
* @see #unregisterConverter(Class)
*/
public static void registerConverter(Class pType, PropertyConverter pConverter) {
getInstance().mConverters.put(pType, pConverter);
getInstance().converters.put(pType, pConverter);
}
/**
@ -128,7 +129,7 @@ public abstract class Converter implements PropertyConverter {
* @see #registerConverter(Class,PropertyConverter)
*/
public static void unregisterConverter(Class pType) {
getInstance().mConverters.remove(pType);
getInstance().converters.remove(pType);
}
/**

View File

@ -59,7 +59,7 @@ class ConverterImpl extends Converter {
// Loop until we find a suitable converter
do {
// Have a match, return converter
if ((converter = getInstance().mConverters.get(cl)) != null) {
if ((converter = getInstance().converters.get(cl)) != null) {
return (PropertyConverter) converter;
}

View File

@ -28,9 +28,11 @@
package com.twelvemonkeys.util.convert;
import com.twelvemonkeys.lang.*;
import com.twelvemonkeys.lang.BeanUtil;
import com.twelvemonkeys.lang.StringUtil;
import java.lang.reflect.*;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
/**
* Converts strings to objects and back.
@ -67,9 +69,7 @@ public final class DefaultConverter implements PropertyConverter {
* be converted into the given type, using a string constructor or static
* {@code valueof} method.
*/
public Object toObject(String pString, final Class pType, String pFormat)
throws ConversionException {
public Object toObject(String pString, final Class pType, String pFormat) throws ConversionException {
if (pString == null) {
return null;
}
@ -78,6 +78,14 @@ public final class DefaultConverter implements PropertyConverter {
throw new MissingTypeException();
}
if (pType.isArray()) {
return toArray(pString, pType, pFormat);
}
// TODO: Separate CollectionConverter?
// should however, be simple to wrap array using Arrays.asList
// But what about generic type?! It's erased...
// Primitive -> 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;
}
}

View File

@ -39,14 +39,14 @@ import java.text.*;
* Converts strings to numbers and back.
* <p/>
* <small>This class has a static cache of {@code NumberFormats}, to avoid
* creation and parsing of numberformats every time one is used.</small>
* creation and parsing of number formats every time one is used.</small>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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);

View File

@ -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();
}
}

View File

@ -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

View File

@ -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<Class<?>, CategoryRegistry> mCategoryMap;
private final Map<Class<?>, 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 <T> void putCategory(Map<Class<?>, CategoryRegistry> pMap, Class<T> pCategory) {
@ -154,7 +154,7 @@ public class ServiceRegistry {
if (!classNames.isEmpty()) {
@SuppressWarnings({"unchecked"})
CategoryRegistry<T> registry = mCategoryMap.get(pCategory);
CategoryRegistry<T> 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<Class<?>> 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 <T> CategoryRegistry<T> getRegistry(final Class<T> pCategory) {
@SuppressWarnings({"unchecked"})
CategoryRegistry<T> registry = mCategoryMap.get(pCategory);
CategoryRegistry<T> 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<T> {
private final Class<T> mCategory;
private final Map<Class, T> mProviders = new LinkedHashMap<Class, T>();
private final Class<T> category;
private final Map<Class, T> providers = new LinkedHashMap<Class, T>();
CategoryRegistry(Class<T> 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<T> 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<T> iterator = mProviders.values().iterator();
final Iterator<T> iterator = providers.values().iterator();
return new Iterator<T>() {
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);
}
};
}

View File

@ -1,5 +1,8 @@
package com.twelvemonkeys.util.convert;
import java.io.File;
import java.net.URI;
/**
* DefaultConverterTestCase
* <p/>
@ -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
};
}

View File

@ -2,6 +2,8 @@ package com.twelvemonkeys.util.convert;
import com.twelvemonkeys.lang.ObjectAbstractTestCase;
import java.util.Arrays;
/**
* PropertyConverterAbstractTestCase
* <p/>
@ -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;