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 0c09176d..7eae35dd 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 @@ -41,8 +41,7 @@ import java.util.Arrays; /** * A utility class with some useful bean-related functions. *

- * NOTE: This class is not considered part of the public API and may be - * changed without notice + * NOTE: This class is not considered part of the public API and may be changed without notice * * @author Harald Kuhr * @author last modified by $Author: haku $ @@ -60,10 +59,10 @@ public final class BeanUtil { * Now supports getting values from properties of properties * (recursive). * - * @param pObject The object to get the property from + * @param pObject The object to get the property from * @param pProperty The name of the property * - * @return A string containing the value of the given property, or null + * @return A string containing the value of the given property, or {@code null} * if it can not be found. * @todo Remove System.err's... Create new Exception? Hmm.. */ @@ -77,7 +76,7 @@ public final class BeanUtil { return null; } - Class objClass = pObject.getClass(); + Class objClass = pObject.getClass(); Object result = pObject; @@ -154,9 +153,8 @@ public final class BeanUtil { catch (NoSuchMethodException e) { System.err.print("No method named \"" + methodName + "()\""); // The array might be of size 0... - if (paramClass != null && paramClass.length > 0) { - System.err.print(" with the parameter " - + paramClass[0].getName()); + if (paramClass.length > 0 && paramClass[0] != null) { + System.err.print(" with the parameter " + paramClass[0].getName()); } System.err.println(" in class " + objClass.getName() + "!"); @@ -177,8 +175,7 @@ public final class BeanUtil { result = method.invoke(result, param); } catch (InvocationTargetException e) { - System.err.println("property=" + pProperty + " & result=" - + result + " & param=" + Arrays.toString(param)); + System.err.println("property=" + pProperty + " & result=" + result + " & param=" + Arrays.toString(param)); e.getTargetException().printStackTrace(); e.printStackTrace(); return null; @@ -188,8 +185,7 @@ public final class BeanUtil { return null; } catch (NullPointerException e) { - System.err.println(objClass.getName() + "." + method.getName() - + "(" + ((paramClass != null && paramClass.length > 0) ? paramClass[0].getName() : "") + ")"); + System.err.println(objClass.getName() + "." + method.getName() + "(" + ((paramClass.length > 0 && paramClass[0] != null) ? paramClass[0].getName() : "") + ")"); e.printStackTrace(); return null; } @@ -221,10 +217,8 @@ public final class BeanUtil { * @throws IllegalAccessException if the caller class has no access to the * write method */ - public static void setPropertyValue(Object pObject, String pProperty, - Object pValue) - throws NoSuchMethodException, InvocationTargetException, - IllegalAccessException { + public static void setPropertyValue(Object pObject, String pProperty, Object pValue) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // // TODO: Support set(Object, Object)/put(Object, Object) methods @@ -255,7 +249,8 @@ public final class BeanUtil { method.invoke(obj, params); } - private static Method getMethodMayModifyParams(Object pObject, String pName, Class[] pParams, Object[] pValues) throws NoSuchMethodException { + private static Method getMethodMayModifyParams(Object pObject, String pName, Class[] pParams, Object[] pValues) + throws NoSuchMethodException { // NOTE: This method assumes pParams.length == 1 && pValues.length == 1 Method method = null; @@ -307,10 +302,8 @@ public final class BeanUtil { if (method == null) { Method[] methods = pObject.getClass().getMethods(); for (Method candidate : methods) { - if (Modifier.isPublic(candidate.getModifiers()) - && candidate.getName().equals(pName) - && candidate.getReturnType() == Void.TYPE - && candidate.getParameterTypes().length == 1) { + if (Modifier.isPublic(candidate.getModifiers()) && candidate.getName().equals(pName) + && candidate.getReturnType() == Void.TYPE && candidate.getParameterTypes().length == 1) { // NOTE: Assumes paramTypes.length == 1 Class type = candidate.getParameterTypes()[0]; @@ -337,7 +330,7 @@ public final class BeanUtil { return method; } - private static Object convertValueToType(Object pValue, Class pType) throws ConversionException { + private static Object convertValueToType(Object pValue, Class pType) throws ConversionException { if (pType.isPrimitive()) { if (pType == Boolean.TYPE && pValue instanceof Boolean) { return pValue; @@ -395,7 +388,7 @@ public final class BeanUtil { * @throws InvocationTargetException if the constructor failed */ // TODO: Move to ReflectUtil - public static Object createInstance(Class pClass, Object pParam) + public static T createInstance(Class pClass, Object pParam) throws InvocationTargetException { return createInstance(pClass, new Object[] {pParam}); } @@ -414,9 +407,9 @@ public final class BeanUtil { * @throws InvocationTargetException if the constructor failed */ // TODO: Move to ReflectUtil - public static Object createInstance(Class pClass, Object... pParams) + public static T createInstance(Class pClass, Object... pParams) throws InvocationTargetException { - Object value; + T value; try { // Create param and argument arrays @@ -429,8 +422,7 @@ public final class BeanUtil { } // Get constructor - //Constructor constructor = pClass.getDeclaredConstructor(paramTypes); - Constructor constructor = pClass.getConstructor(paramTypes); + Constructor constructor = pClass.getConstructor(paramTypes); // Invoke and create instance value = constructor.newInstance(pParams); @@ -468,12 +460,11 @@ public final class BeanUtil { * If the return type of the method is void, null is returned. * If the method could not be invoked for any reason, null is returned. * - * @throws InvocationTargetException if the invocaton failed + * @throws InvocationTargetException if the invocation failed */ // TODO: Move to ReflectUtil // TODO: Rename to invokeStatic? - public static Object invokeStaticMethod(Class pClass, String pMethod, - Object pParam) + public static Object invokeStaticMethod(Class pClass, String pMethod, Object pParam) throws InvocationTargetException { return invokeStaticMethod(pClass, pMethod, new Object[] {pParam}); @@ -492,12 +483,11 @@ public final class BeanUtil { * If the return type of the method is void, null is returned. * If the method could not be invoked for any reason, null is returned. * - * @throws InvocationTargetException if the invocaton failed + * @throws InvocationTargetException if the invocation failed */ // TODO: Move to ReflectUtil // TODO: Rename to invokeStatic? - public static Object invokeStaticMethod(Class pClass, String pMethod, - Object[] pParams) + public static Object invokeStaticMethod(Class pClass, String pMethod, Object... pParams) throws InvocationTargetException { Object value = null; @@ -518,8 +508,7 @@ public final class BeanUtil { Method method = pClass.getMethod(pMethod, paramTypes); // Invoke public static method - if (Modifier.isPublic(method.getModifiers()) - && Modifier.isStatic(method.getModifiers())) { + if (Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) { value = method.invoke(null, pParams); } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/Converter.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/Converter.java index aa4015ef..106b6164 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/Converter.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/Converter.java @@ -36,7 +36,7 @@ import java.util.Map; /** * The converter (singleton). Converts strings to objects and back. - * This is the entrypoint to the converter framework. + * This is the entry point to the converter framework. *

* By default, converters for {@link com.twelvemonkeys.util.Time}, {@link Date} * and {@link Object} @@ -53,17 +53,17 @@ import java.util.Map; */ // TODO: Get rid of singleton stuff // Can probably be a pure static class, but is that a good idea? -// Maybe have BeanUtil act as a "proxy", and hide this class alltogheter? +// Maybe have BeanUtil act as a "proxy", and hide this class all together? // 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 + protected static final Converter sInstance = new ConverterImpl(); // Thread safe & EASY - /** The conveters Map */ - protected Map converters = new Hashtable(); + /** The converters Map */ + protected final Map converters = new Hashtable(); // Register our predefined converters static { @@ -115,20 +115,21 @@ public abstract class Converter implements PropertyConverter { * * @see #unregisterConverter(Class) */ - public static void registerConverter(Class pType, PropertyConverter pConverter) { + public static void registerConverter(final Class pType, final PropertyConverter pConverter) { getInstance().converters.put(pType, pConverter); } /** - * Unregisters a converter for a given type. That is, making it unavailable + * Un-registers a converter for a given type. That is, making it unavailable * for the converter framework, and making it (potentially) available for - * garbabe collection. + * garbage collection. * * @param pType the (super) type to remove converter for * * @see #registerConverter(Class,PropertyConverter) */ - public static void unregisterConverter(Class pType) { + @SuppressWarnings("UnusedDeclaration") + public static void unregisterConverter(final Class pType) { getInstance().converters.remove(pType); } @@ -143,8 +144,7 @@ public abstract class Converter implements PropertyConverter { * @throws ConversionException if the string cannot be converted for any * reason. */ - public Object toObject(String pString, Class pType) - throws ConversionException { + public Object toObject(final String pString, final Class pType) throws ConversionException { return toObject(pString, pType, null); } @@ -174,7 +174,7 @@ public abstract class Converter implements PropertyConverter { * @throws ConversionException if the object cannot be converted to a * string for any reason. */ - public String toString(Object pObject) throws ConversionException { + public String toString(final Object pObject) throws ConversionException { return toString(pObject, null); } diff --git a/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/DefaultConverter.java b/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/DefaultConverter.java index 81e4d589..59236d7c 100755 --- a/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/DefaultConverter.java +++ b/common/common-lang/src/main/java/com/twelvemonkeys/util/convert/DefaultConverter.java @@ -67,9 +67,9 @@ public final class DefaultConverter implements PropertyConverter { * * @throws ConversionException if the type is null, or if the string cannot * be converted into the given type, using a string constructor or static - * {@code valueof} method. + * {@code valueOf} method. */ - public Object toObject(String pString, final Class pType, String pFormat) throws ConversionException { + public Object toObject(final String pString, final Class pType, final String pFormat) throws ConversionException { if (pString == null) { return null; } @@ -87,13 +87,7 @@ public final class DefaultConverter implements PropertyConverter { // But what about generic type?! It's erased... // Primitive -> wrapper - Class type; - if (pType == Boolean.TYPE) { - type = Boolean.class; - } - else { - type = pType; - } + Class type = unBoxType(pType); try { // Try to create instance from (String) @@ -101,13 +95,15 @@ public final class DefaultConverter implements PropertyConverter { if (value == null) { // createInstance failed for some reason - - // Try to invoke the static method valueof(String) + // Try to invoke the static method valueOf(String) value = BeanUtil.invokeStaticMethod(type, "valueOf", pString); if (value == null) { // If the value is still null, well, then I cannot help... - throw new ConversionException("Could not convert String to " + pType.getName() + ": No constructor " + type.getName() + "(String) or static " + type.getName() + ".valueof(String) method found!"); + throw new ConversionException(String.format( + "Could not convert String to %1$s: No constructor %1$s(String) or static %1$s.valueOf(String) method found!", + type.getName() + )); } } @@ -116,12 +112,15 @@ public final class DefaultConverter implements PropertyConverter { catch (InvocationTargetException ite) { throw new ConversionException(ite.getTargetException()); } + catch (ConversionException ce) { + throw ce; + } catch (RuntimeException rte) { throw new ConversionException(rte); } } - private Object toArray(String pString, Class pType, String pFormat) { + private Object toArray(final String pString, final Class pType, final String pFormat) { String[] strings = StringUtil.toStringArray(pString, pFormat != null ? pFormat : StringUtil.DELIMITER_STRING); Class type = pType.getComponentType(); if (type == String.class) { @@ -152,10 +151,9 @@ public final class DefaultConverter implements PropertyConverter { * @param pObject the object to convert. * @param pFormat ignored. * - * @return the string representation of the object, or {@code null} if - * {@code pObject == null} + * @return the string representation of the object, or {@code null} if {@code pObject == null} */ - public String toString(Object pObject, String pFormat) + public String toString(final Object pObject, final String pFormat) throws ConversionException { try { @@ -170,7 +168,7 @@ public final class DefaultConverter implements PropertyConverter { return pFormat == null ? StringUtil.toCSVString(pArray) : StringUtil.toCSVString(pArray, pFormat); } - private Object[] toObjectArray(Object pObject) { + private Object[] toObjectArray(final Object pObject) { // TODO: Extract util method for wrapping/unwrapping native arrays? Object[] array; Class componentType = pObject.getClass().getComponentType(); @@ -232,4 +230,37 @@ public final class DefaultConverter implements PropertyConverter { } return array; } + + private Class unBoxType(final Class pType) { + if (pType.isPrimitive()) { + if (pType == boolean.class) { + return Boolean.class; + } + if (pType == byte.class) { + return Byte.class; + } + if (pType == char.class) { + return Character.class; + } + if (pType == short.class) { + return Short.class; + } + if (pType == int.class) { + return Integer.class; + } + if (pType == float.class) { + return Float.class; + } + if (pType == long.class) { + return Long.class; + } + if (pType == double.class) { + return Double.class; + } + + throw new IllegalArgumentException("Unknown type: " + pType); + } + + return pType; + } } diff --git a/common/common-lang/src/test/java/com/twelvemonkeys/lang/BeanUtilTestCase.java b/common/common-lang/src/test/java/com/twelvemonkeys/lang/BeanUtilTestCase.java index 2b567ed6..59e69b97 100755 --- a/common/common-lang/src/test/java/com/twelvemonkeys/lang/BeanUtilTestCase.java +++ b/common/common-lang/src/test/java/com/twelvemonkeys/lang/BeanUtilTestCase.java @@ -108,13 +108,13 @@ public class BeanUtilTestCase extends TestCase { assertEquals(0.3, bean.getDoubleValue()); } - public void testConfigureAmbigious1() { + public void testConfigureAmbiguous1() { TestBean bean = new TestBean(); Map map = new HashMap(); String value = "one"; - map.put("ambigious", value); + map.put("ambiguous", value); try { BeanUtil.configure(bean, map); @@ -123,20 +123,20 @@ public class BeanUtilTestCase extends TestCase { fail(e.getMessage()); } - assertNotNull(bean.getAmbigious()); - assertEquals("String converted rather than invoking setAmbigiouos(String), ordering not predictable", - "one", bean.getAmbigious()); - assertSame("String converted rather than invoking setAmbigiouos(String), ordering not predictable", - value, bean.getAmbigious()); + assertNotNull(bean.getAmbiguous()); + assertEquals("String converted rather than invoking setAmbiguous(String), ordering not predictable", + "one", bean.getAmbiguous()); + assertSame("String converted rather than invoking setAmbiguous(String), ordering not predictable", + value, bean.getAmbiguous()); } - public void testConfigureAmbigious2() { + public void testConfigureAmbiguous2() { TestBean bean = new TestBean(); Map map = new HashMap(); Integer value = 2; - map.put("ambigious", value); + map.put("ambiguous", value); try { BeanUtil.configure(bean, map); @@ -145,20 +145,20 @@ public class BeanUtilTestCase extends TestCase { fail(e.getMessage()); } - assertNotNull(bean.getAmbigious()); - assertEquals("Integer converted rather than invoking setAmbigiouos(Integer), ordering not predictable", - 2, bean.getAmbigious()); - assertSame("Integer converted rather than invoking setAmbigiouos(Integer), ordering not predictable", - value, bean.getAmbigious()); + assertNotNull(bean.getAmbiguous()); + assertEquals("Integer converted rather than invoking setAmbiguous(Integer), ordering not predictable", + 2, bean.getAmbiguous()); + assertSame("Integer converted rather than invoking setAmbiguous(Integer), ordering not predictable", + value, bean.getAmbiguous()); } - public void testConfigureAmbigious3() { + public void testConfigureAmbiguous3() { TestBean bean = new TestBean(); Map map = new HashMap(); Double value = .3; - map.put("ambigious", value); + map.put("ambiguous", value); try { BeanUtil.configure(bean, map); @@ -167,11 +167,11 @@ public class BeanUtilTestCase extends TestCase { fail(e.getMessage()); } - assertNotNull(bean.getAmbigious()); - assertEquals("Object converted rather than invoking setAmbigious(Object), ordering not predictable", - value.getClass(), bean.getAmbigious().getClass()); - assertSame("Object converted rather than invoking setAmbigious(Object), ordering not predictable", - value, bean.getAmbigious()); + assertNotNull(bean.getAmbiguous()); + assertEquals("Object converted rather than invoking setAmbiguous(Object), ordering not predictable", + value.getClass(), bean.getAmbiguous().getClass()); + assertSame("Object converted rather than invoking setAmbiguous(Object), ordering not predictable", + value, bean.getAmbiguous()); } static class TestBean { @@ -179,7 +179,7 @@ public class BeanUtilTestCase extends TestCase { private int intVal; private Double doubleVal; - private Object ambigious; + private Object ambiguous; public Double getDoubleValue() { return doubleVal; @@ -193,36 +193,43 @@ public class BeanUtilTestCase extends TestCase { return stringVal; } + @SuppressWarnings("UnusedDeclaration") public void setStringValue(String pString) { stringVal = pString; } + @SuppressWarnings("UnusedDeclaration") public void setIntValue(int pInt) { intVal = pInt; } + @SuppressWarnings("UnusedDeclaration") public void setDoubleValue(Double pDouble) { doubleVal = pDouble; } - public void setAmbigious(String pString) { - ambigious = pString; + @SuppressWarnings("UnusedDeclaration") + public void setAmbiguous(String pString) { + ambiguous = pString; } - public void setAmbigious(Object pObject) { - ambigious = pObject; + @SuppressWarnings("UnusedDeclaration") + public void setAmbiguous(Object pObject) { + ambiguous = pObject; } - public void setAmbigious(Integer pInteger) { - ambigious = pInteger; + @SuppressWarnings("UnusedDeclaration") + public void setAmbiguous(Integer pInteger) { + ambiguous = pInteger; } - public void setAmbigious(int pInt) { - ambigious = (long) pInt; // Just to differentiate... + @SuppressWarnings("UnusedDeclaration") + public void setAmbiguous(int pInt) { + ambiguous = (long) pInt; // Just to differentiate... } - public Object getAmbigious() { - return ambigious; + public Object getAmbiguous() { + return ambiguous; } } } 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 bbced569..6f1f19e7 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,10 +1,14 @@ package com.twelvemonkeys.util.convert; import com.twelvemonkeys.lang.Validate; +import org.junit.Ignore; +import org.junit.Test; import java.io.File; import java.net.URI; +import static org.junit.Assert.*; + /** * DefaultConverterTestCase *

@@ -56,7 +60,61 @@ public class DefaultConverterTestCase extends PropertyConverterAbstractTestCase }; } - // TODO: Test boolean -> Boolean conversion + @Test + public void testConvertBooleanPrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertTrue((Boolean) converter.toObject("true", boolean.class, null)); + assertFalse((Boolean) converter.toObject("FalsE", Boolean.TYPE, null)); + } + + @Test + public void testConvertShortPrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals(1, (short) (Short) converter.toObject("1", short.class, null)); + assertEquals(-2, (short) (Short) converter.toObject("-2", Short.TYPE, null)); + } + @Test + public void testConvertIntPrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals(1, (int) (Integer) converter.toObject("1", int.class, null)); + assertEquals(-2, (int) (Integer) converter.toObject("-2", Integer.TYPE, null)); + } + + @Test + public void testConvertLongPrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals(Long.MAX_VALUE, (long) (Long) converter.toObject("9223372036854775807", long.class, null)); + assertEquals(-2, (long) (Long) converter.toObject("-2", Long.TYPE, null)); + } + + @Test + public void testConvertBytePrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals(1, (byte) (Byte) converter.toObject("1", byte.class, null)); + assertEquals(-2, (byte) (Byte) converter.toObject("-2", Byte.TYPE, null)); + } + + @Test + public void testConvertFloatPrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals(1f, (Float) converter.toObject("1.0", float.class, null), 0); + assertEquals(-2.3456f, (Float) converter.toObject("-2.3456", Float.TYPE, null), 0); + } + + @Test + public void testConvertDoublePrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals(1d, (Double) converter.toObject("1.0", double.class, null), 0); + assertEquals(-2.3456, (Double) converter.toObject("-2.3456", Double.TYPE, null), 0); + } + + @Ignore("Known issue. Why would anyone do something like this?") + @Test + public void testConvertCharPrimitive() { + PropertyConverter converter = makePropertyConverter(); + assertEquals('A', (char) (Character) converter.toObject("A", char.class, null)); + assertEquals('Z', (char) (Character) converter.toObject("Z", Character.TYPE, null)); + } public static class FooBar { private final String bar;