[joda-convert] 04/05: Imported Upstream version 1.5

Tony Mancill tmancill at moszumanska.debian.org
Sat Sep 5 21:38:39 UTC 2015


This is an automated email from the git hooks/post-receive script.

tmancill pushed a commit to branch master
in repository joda-convert.

commit 0ee426bd04843093d73c04ecba23955f2666d5db
Author: tony mancill <tmancill at debian.org>
Date:   Sat Sep 5 14:37:37 2015 -0700

    Imported Upstream version 1.5
---
 pom.xml                                            |  10 +-
 src/changes/changes.xml                            |  26 ++
 src/main/checkstyle/checkstyle.xml                 |   2 +-
 .../convert/AnnotationStringConverterFactory.java  | 222 +++++++++++++
 src/main/java/org/joda/convert/FromString.java     |   2 +-
 .../java/org/joda/convert/FromStringConverter.java |   2 +-
 .../java/org/joda/convert/FromStringFactory.java   |   2 +-
 .../java/org/joda/convert/JDKStringConverter.java  |  28 +-
 .../convert/MethodConstructorStringConverter.java  |   2 +-
 .../org/joda/convert/MethodsStringConverter.java   |   6 +-
 .../joda/convert/ReflectionStringConverter.java    |   2 +-
 src/main/java/org/joda/convert/StringConvert.java  | 344 +++++++++++----------
 .../java/org/joda/convert/StringConverter.java     |   2 +-
 ...gConverter.java => StringConverterFactory.java} |  20 +-
 src/main/java/org/joda/convert/ToString.java       |   2 +-
 .../java/org/joda/convert/ToStringConverter.java   |   2 +-
 .../BooleanArrayStringConverterFactory.java        | 103 ++++++
 .../BooleanObjectArrayStringConverterFactory.java  | 105 +++++++
 .../ByteObjectArrayStringConverterFactory.java     | 110 +++++++
 .../CharObjectArrayStringConverterFactory.java     | 128 ++++++++
 .../NumericArrayStringConverterFactory.java        | 240 ++++++++++++++
 .../NumericObjectArrayStringConverterFactory.java  | 250 +++++++++++++++
 src/site/xdoc/index.xml                            |   4 +-
 src/site/xdoc/userguide.xml                        |  23 +-
 ...tanceFromStringConstructorInvalidParameter.java |   2 +-
 ...FromStringConstructorInvalidParameterCount.java |   2 +-
 .../joda/convert/DistanceFromStringException.java  |   2 +-
 .../DistanceFromStringInvalidParameter.java        |   2 +-
 .../DistanceFromStringInvalidParameterCount.java   |   2 +-
 .../DistanceFromStringInvalidReturnType.java       |   2 +-
 .../joda/convert/DistanceFromStringNoToString.java |   2 +-
 .../DistanceMethodAndConstructorAnnotations.java   |   2 +-
 .../joda/convert/DistanceMethodConstructor.java    |   2 +-
 .../DistanceMethodConstructorCharSequence.java     |   2 +-
 .../org/joda/convert/DistanceMethodMethod.java     |   2 +-
 .../convert/DistanceMethodMethodCharSequence.java  |   2 +-
 .../org/joda/convert/DistanceNoAnnotations.java    |   2 +-
 .../convert/DistanceNoAnnotationsCharSequence.java |   2 +-
 .../joda/convert/DistanceToStringException.java    |   2 +-
 .../convert/DistanceToStringInvalidParameters.java |   2 +-
 .../convert/DistanceToStringInvalidReturnType.java |   2 +-
 .../joda/convert/DistanceToStringNoFromString.java |   2 +-
 .../DistanceTwoFromStringMethodAnnotations.java    |   2 +-
 .../convert/DistanceTwoToStringAnnotations.java    |   2 +-
 .../java/org/joda/convert/DistanceWithFactory.java |   2 +-
 .../joda/convert/DistanceWithFactoryFactory.java   |   2 +-
 .../joda/convert/MockDistanceStringConverter.java  |   2 +-
 .../joda/convert/MockIntegerStringConverter.java   |   2 +-
 .../org/joda/convert/SubMethodConstructor.java     |   2 +-
 .../java/org/joda/convert/SubMethodMethod.java     |   2 +-
 .../java/org/joda/convert/SubNoAnnotations.java    |   2 +-
 .../java/org/joda/convert/SuperFactorySub.java     |   2 +-
 .../java/org/joda/convert/SuperFactorySuper.java   |   2 +-
 .../TestBooleanArrayStringConverterFactory.java    |  46 +++
 ...stBooleanObjectArrayStringConverterFactory.java |  47 +++
 .../TestByteObjectArrayStringConverterFactory.java |  46 +++
 .../TestCharObjectArrayStringConverterFactory.java |  49 +++
 .../org/joda/convert/TestJDKStringConverters.java  |  34 +-
 .../TestNumericArrayStringConverterFactory.java    | 112 +++++++
 ...stNumericObjectArrayStringConverterFactory.java | 117 +++++++
 .../java/org/joda/convert/TestStringConvert.java   |  46 ++-
 .../joda/convert/TestStringConverterFactory.java   |  61 ++++
 .../java/org/joda/convert/test1/Test1Class.java    |   2 +-
 .../org/joda/convert/test1/Test1Interface.java     |   2 +-
 .../java/org/joda/convert/test2/Test2Class.java    |   2 +-
 .../java/org/joda/convert/test2/Test2Factory.java  |   2 +-
 .../org/joda/convert/test2/Test2Interface.java     |   2 +-
 .../java/org/joda/convert/test3/Test3Class.java    |   2 +-
 .../java/org/joda/convert/test3/Test3Factory.java  |   2 +-
 .../org/joda/convert/test3/Test3Interface.java     |   2 +-
 .../org/joda/convert/test3/Test3SuperClass.java    |   2 +-
 .../java/org/joda/convert/test4/Test4Class.java    |   2 +-
 .../java/org/joda/convert/test4/Test4Factory.java  |   2 +-
 .../org/joda/convert/test4/Test4Interface.java     |   2 +-
 74 files changed, 2035 insertions(+), 242 deletions(-)

diff --git a/pom.xml b/pom.xml
index 96ebadf..800f379 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
   <artifactId>joda-convert</artifactId>
   <packaging>jar</packaging>
   <name>Joda-Convert</name>
-  <version>1.4</version>
+  <version>1.5</version>
   <description>Library to convert Objects to and from String</description>
   <url>http://www.joda.org/joda-convert/</url>
 
@@ -177,7 +177,7 @@
           <skipDeploy>true</skipDeploy>
         </configuration>
       </plugin>
-      <plugin>
+      <plugin><!-- invoke with mvn site-deploy -->
         <groupId>com.github.github</groupId>
         <artifactId>site-maven-plugin</artifactId>
         <version>0.8</version>
@@ -509,7 +509,7 @@
     <maven-deploy-plugin.version>2.7</maven-deploy-plugin.version>
     <maven-dependency-plugin.version>2.8</maven-dependency-plugin.version>
     <maven-gpg-plugin.version>1.4</maven-gpg-plugin.version>
-    <maven-install-plugin.version>2.4</maven-install-plugin.version>
+    <maven-install-plugin.version>2.5</maven-install-plugin.version>
     <maven-jar-plugin.version>2.4</maven-jar-plugin.version>
     <maven-javadoc-plugin.version>2.9.1</maven-javadoc-plugin.version>
     <maven-jxr-plugin.version>2.3</maven-jxr-plugin.version>
@@ -520,8 +520,8 @@
     <maven-resources-plugin.version>2.6</maven-resources-plugin.version>
     <maven-site-plugin.version>3.3</maven-site-plugin.version>
     <maven-source-plugin.version>2.2.1</maven-source-plugin.version>
-    <maven-surefire-plugin.version>2.15</maven-surefire-plugin.version>
-    <maven-surefire-report-plugin.version>2.15</maven-surefire-report-plugin.version>
+    <maven-surefire-plugin.version>2.16</maven-surefire-plugin.version>
+    <maven-surefire-report-plugin.version>2.16</maven-surefire-report-plugin.version>
     <maven-toolchains-plugin.version>1.0</maven-toolchains-plugin.version>
     <!-- Properties for maven-compiler-plugin -->
     <maven.compiler.compilerVersion>1.6</maven.compiler.compilerVersion>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5fc48d1..08a9b09 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -7,6 +7,32 @@
 
   <body>
     <!-- types are add, fix, remove, update -->
+    <release version="1.5" date="2013-09-17" description="Version 1.5">
+      <action dev="scolebourne" type="add" >
+        Add support for all primitive object arrays.
+      </action>
+      <action dev="scolebourne" type="add" >
+        Add support for boolean[].
+      </action>
+      <action dev="scolebourne" type="add" >
+        Add support for numeric primitive arrays.
+      </action>
+      <action dev="scolebourne" type="add" >
+        Add support for char[] and byte[].
+      </action>
+      <action dev="scolebourne" type="add" >
+        Add StringConverterFactory for more flexible initialization.
+      </action>
+      <action dev="scolebourne" type="add" >
+        Weaken generics to better support framework-level access.
+      </action>
+      <action dev="scolebourne" type="add" >
+        Add isConvertible() method.
+      </action>
+      <action dev="scolebourne" type="update" >
+        Validate the @FromString is a static method.
+      </action>
+    </release>
     <release version="1.4" date="2013-08-15" description="Version 1.4">
       <action dev="scolebourne" type="update" >
         Change to use Maven plugin for OSGi, changing some published info.
diff --git a/src/main/checkstyle/checkstyle.xml b/src/main/checkstyle/checkstyle.xml
index 63ea58c..bb0c77a 100644
--- a/src/main/checkstyle/checkstyle.xml
+++ b/src/main/checkstyle/checkstyle.xml
@@ -122,7 +122,7 @@
   </module>
   <!-- Header inlined due to m2e -->
   <module name="RegexpHeader">
-    <property name="header" value="^/\*[*]?\n^ \*  Copyright 2010([-](20[01][0-9]))? Stephen Colebourne"/>
+    <property name="header" value="^/\*[*]?\n^ \*  Copyright 2010[-]present Stephen Colebourne"/>
     <property name="fileExtensions" value="java"/>
   </module>
   <module name="SuppressionCommentFilter">
diff --git a/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java b/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java
new file mode 100644
index 0000000..c22cfb3
--- /dev/null
+++ b/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java
@@ -0,0 +1,222 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Factory for {@code StringConverter} looking up annotations.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+final class AnnotationStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    static final StringConverterFactory INSTANCE = new AnnotationStringConverterFactory();
+
+    /**
+     * Restricted constructor.
+     */
+    private AnnotationStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        return findAnnotatedConverter(cls);  // capture generics
+    }
+
+    /**
+     * Finds a converter searching annotated.
+     * 
+     * @param <T>  the type of the converter
+     * @param cls  the class to find a method for, not null
+     * @return the converter, not null
+     * @throws RuntimeException if none found
+     */
+    private <T> StringConverter<T> findAnnotatedConverter(final Class<T> cls) {
+        Method toString = findToStringMethod(cls);  // checks superclasses
+        if (toString == null) {
+            return null;
+        }
+        Constructor<T> con = findFromStringConstructor(cls);
+        Method fromString = findFromStringMethod(cls, con == null);  // optionally checks superclasses
+        if (con == null && fromString == null) {
+            throw new IllegalStateException("Class annotated with @ToString but not with @FromString: " + cls.getName());
+        }
+        if (con != null && fromString != null) {
+            throw new IllegalStateException("Both method and constructor are annotated with @FromString: " + cls.getName());
+        }
+        if (con != null) {
+            return new MethodConstructorStringConverter<T>(cls, toString, con);
+        } else {
+            return new MethodsStringConverter<T>(cls, toString, fromString);
+        }
+    }
+
+    /**
+     * Finds the conversion method.
+     * 
+     * @param cls  the class to find a method for, not null
+     * @return the method to call, null means use {@code toString}
+     * @throws RuntimeException if invalid
+     */
+    private Method findToStringMethod(Class<?> cls) {
+        Method matched = null;
+        // find in superclass hierarchy
+        Class<?> loopCls = cls;
+        while (loopCls != null && matched == null) {
+            Method[] methods = loopCls.getDeclaredMethods();
+            for (Method method : methods) {
+                ToString toString = method.getAnnotation(ToString.class);
+                if (toString != null) {
+                    if (matched != null) {
+                        throw new IllegalStateException("Two methods are annotated with @ToString: " + cls.getName());
+                    }
+                    matched = method;
+                }
+            }
+            loopCls = loopCls.getSuperclass();
+        }
+        // find in immediate parent interfaces
+        if (matched == null) {
+            for (Class<?> loopIfc : cls.getInterfaces()) {
+                Method[] methods = loopIfc.getDeclaredMethods();
+                for (Method method : methods) {
+                    ToString toString = method.getAnnotation(ToString.class);
+                    if (toString != null) {
+                        if (matched != null) {
+                            throw new IllegalStateException("Two methods are annotated with @ToString on interfaces: " + cls.getName());
+                        }
+                        matched = method;
+                    }
+                }
+            }
+        }
+        return matched;
+    }
+
+    /**
+     * Finds the conversion method.
+     * 
+     * @param <T>  the type of the converter
+     * @param cls  the class to find a method for, not null
+     * @return the method to call, null means use {@code toString}
+     * @throws RuntimeException if invalid
+     */
+    private <T> Constructor<T> findFromStringConstructor(Class<T> cls) {
+        Constructor<T> con;
+        try {
+            con = cls.getDeclaredConstructor(String.class);
+        } catch (NoSuchMethodException ex) {
+            try {
+                con = cls.getDeclaredConstructor(CharSequence.class);
+            } catch (NoSuchMethodException ex2) {
+                return null;
+            }
+        }
+        FromString fromString = con.getAnnotation(FromString.class);
+        return fromString != null ? con : null;
+    }
+
+    /**
+     * Finds the conversion method.
+     * 
+     * @param cls  the class to find a method for, not null
+     * @return the method to call, null means not found
+     * @throws RuntimeException if invalid
+     */
+    private Method findFromStringMethod(Class<?> cls, boolean searchSuperclasses) {
+        Method matched = null;
+        // find in superclass hierarchy
+        Class<?> loopCls = cls;
+        while (loopCls != null && matched == null) {
+            matched = findFromString(loopCls, matched);
+            if (searchSuperclasses == false) {
+                break;
+            }
+            loopCls = loopCls.getSuperclass();
+        }
+        // find in immediate parent interfaces
+        if (searchSuperclasses && matched == null) {
+            for (Class<?> loopIfc : cls.getInterfaces()) {
+                matched = findFromString(loopIfc, matched);
+            }
+        }
+        return matched;
+    }
+
+    /**
+     * Finds the conversion method.
+     * 
+     * @param cls  the class to find a method for, not null
+     * @param matched  the matched method, may be null
+     * @return the method to call, null means not found
+     * @throws RuntimeException if invalid
+     */
+    private Method findFromString(Class<?> cls, Method matched) {
+        // find in declared methods
+        Method[] methods = cls.getDeclaredMethods();
+        for (Method method : methods) {
+            FromString fromString = method.getAnnotation(FromString.class);
+            if (fromString != null) {
+                if (matched != null) {
+                    throw new IllegalStateException("Two methods are annotated with @FromString: " + cls.getName());
+                }
+                matched = method;
+            }
+        }
+        // check for factory
+        FromStringFactory factory = cls.getAnnotation(FromStringFactory.class);
+        if (factory != null) {
+            if (matched != null) {
+                throw new IllegalStateException("Class annotated with @FromString and @FromStringFactory: " + cls.getName());
+            }
+            Method[] factoryMethods = factory.factory().getDeclaredMethods();
+            for (Method method : factoryMethods) {
+                // handle factory containing multiple FromString for different types
+                if (cls.isAssignableFrom(method.getReturnType())) {
+                    FromString fromString = method.getAnnotation(FromString.class);
+                    if (fromString != null) {
+                        if (matched != null) {
+                            throw new IllegalStateException("Two methods are annotated with @FromString on the factory: " + factory.factory().getName());
+                        }
+                        matched = method;
+                    }
+                }
+            }
+        }
+        return matched;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/FromString.java b/src/main/java/org/joda/convert/FromString.java
index f3432a6..bf4290d 100644
--- a/src/main/java/org/joda/convert/FromString.java
+++ b/src/main/java/org/joda/convert/FromString.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/FromStringConverter.java b/src/main/java/org/joda/convert/FromStringConverter.java
index e5bace9..fc4e4e4 100644
--- a/src/main/java/org/joda/convert/FromStringConverter.java
+++ b/src/main/java/org/joda/convert/FromStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/FromStringFactory.java b/src/main/java/org/joda/convert/FromStringFactory.java
index 6517e06..3e970df 100644
--- a/src/main/java/org/joda/convert/FromStringFactory.java
+++ b/src/main/java/org/joda/convert/FromStringFactory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/JDKStringConverter.java b/src/main/java/org/joda/convert/JDKStringConverter.java
index c90448d..b74f0a8 100644
--- a/src/main/java/org/joda/convert/JDKStringConverter.java
+++ b/src/main/java/org/joda/convert/JDKStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -36,6 +36,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
+import javax.xml.bind.DatatypeConverter;
+
 /**
  * Conversion between JDK classes and a {@code String}.
  */
@@ -109,6 +111,18 @@ enum JDKStringConverter implements StringConverter<Object> {
         }
     },
     /**
+     * String converter.
+     */
+    BYTE_ARRAY(byte[].class) {
+        @Override
+        public String convertToString(Object object) {
+            return DatatypeConverter.printBase64Binary((byte[]) object);
+        }
+        public Object convertFromString(Class<?> cls, String str) {
+            return DatatypeConverter.parseBase64Binary(str);
+        }
+    },
+    /**
      * Character converter.
      */
     CHARACTER(Character.class) {
@@ -120,6 +134,18 @@ enum JDKStringConverter implements StringConverter<Object> {
         }
     },
     /**
+     * String converter.
+     */
+    CHAR_ARRAY(char[].class) {
+        @Override
+        public String convertToString(Object object) {
+            return new String((char[]) object);
+        }
+        public Object convertFromString(Class<?> cls, String str) {
+            return str.toCharArray();
+        }
+    },
+    /**
      * Boolean converter.
      */
     BOOLEAN(Boolean.class) {
diff --git a/src/main/java/org/joda/convert/MethodConstructorStringConverter.java b/src/main/java/org/joda/convert/MethodConstructorStringConverter.java
index f6ed6a3..9cf0c53 100644
--- a/src/main/java/org/joda/convert/MethodConstructorStringConverter.java
+++ b/src/main/java/org/joda/convert/MethodConstructorStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/MethodsStringConverter.java b/src/main/java/org/joda/convert/MethodsStringConverter.java
index 7f5dd39..65aa5d4 100644
--- a/src/main/java/org/joda/convert/MethodsStringConverter.java
+++ b/src/main/java/org/joda/convert/MethodsStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package org.joda.convert;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 
 /**
  * Conversion to and from a string using two methods.
@@ -45,6 +46,9 @@ final class MethodsStringConverter<T> extends ReflectionStringConverter<T> {
      */
     MethodsStringConverter(Class<T> cls, Method toString, Method fromString) {
         super(cls, toString);
+        if (Modifier.isStatic(fromString.getModifiers()) == false) {
+            throw new IllegalStateException("FromString method must be static: " + fromString);
+        }
         if (fromString.getParameterTypes().length != 1) {
             throw new IllegalStateException("FromString method must have one parameter: " + fromString);
         }
diff --git a/src/main/java/org/joda/convert/ReflectionStringConverter.java b/src/main/java/org/joda/convert/ReflectionStringConverter.java
index c3593d4..1cc8e30 100644
--- a/src/main/java/org/joda/convert/ReflectionStringConverter.java
+++ b/src/main/java/org/joda/convert/ReflectionStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/StringConvert.java b/src/main/java/org/joda/convert/StringConvert.java
index 778bfdc..56e99d7 100644
--- a/src/main/java/org/joda/convert/StringConvert.java
+++ b/src/main/java/org/joda/convert/StringConvert.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -18,8 +18,17 @@ package org.joda.convert;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.Arrays;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.joda.convert.factory.BooleanArrayStringConverterFactory;
+import org.joda.convert.factory.BooleanObjectArrayStringConverterFactory;
+import org.joda.convert.factory.ByteObjectArrayStringConverterFactory;
+import org.joda.convert.factory.CharObjectArrayStringConverterFactory;
+import org.joda.convert.factory.NumericArrayStringConverterFactory;
+import org.joda.convert.factory.NumericObjectArrayStringConverterFactory;
 
 /**
  * Manager for conversion to and from a {@code String}, acting as the main client interface.
@@ -53,10 +62,48 @@ public final class StringConvert {
     };
 
     /**
+     * The list of factories.
+     */
+    private final CopyOnWriteArrayList<StringConverterFactory> factories = new CopyOnWriteArrayList<StringConverterFactory>();
+    /**
      * The cache of converters.
      */
     private final ConcurrentMap<Class<?>, StringConverter<?>> registered = new ConcurrentHashMap<Class<?>, StringConverter<?>>();
 
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a new conversion manager including the extended standard set of converters.
+     * <p>
+     * The returned converter is a new instance that includes additional converters:
+     * <ul>
+     * <li>JDK converters
+     * <li>{@link NumericArrayStringConverterFactory}
+     * <li>{@link NumericObjectArrayStringConverterFactory}
+     * <li>{@link CharObjectArrayStringConverterFactory}
+     * <li>{@link ByteObjectArrayStringConverterFactory}
+     * <li>{@link BooleanArrayStringConverterFactory}
+     * <li>{@link BooleanObjectArrayStringConverterFactory}
+     * </ul>
+     * <p>
+     * The convert instance is mutable in a thread-safe manner.
+     * Converters may be altered at any time, including the JDK converters.
+     * It is strongly recommended to only alter the converters before performing
+     * actual conversions.
+     * 
+     * @return the new converter, not null
+     * @since 1.5
+     */
+    public static StringConvert create() {
+        return new StringConvert(true, 
+                        NumericArrayStringConverterFactory.INSTANCE,
+                        NumericObjectArrayStringConverterFactory.INSTANCE,
+                        CharObjectArrayStringConverterFactory.INSTANCE,
+                        ByteObjectArrayStringConverterFactory.INSTANCE,
+                        BooleanArrayStringConverterFactory.INSTANCE,
+                        BooleanObjectArrayStringConverterFactory.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
     /**
      * Creates a new conversion manager including the JDK converters.
      * <p>
@@ -76,10 +123,21 @@ public final class StringConvert {
      * Converters may be altered at any time, including the JDK converters.
      * It is strongly recommended to only alter the converters before performing
      * actual conversions.
+     * <p>
+     * If specified, the factories will be queried in the order specified.
      * 
      * @param includeJdkConverters  true to include the JDK converters
+     * @param factories  optional array of factories to use, not null
      */
-    public StringConvert(boolean includeJdkConverters) {
+    public StringConvert(boolean includeJdkConverters, StringConverterFactory... factories) {
+        if (factories == null) {
+            throw new IllegalArgumentException("StringConverterFactory array must not be null");
+        }
+        for (int i = 0; i < factories.length; i++) {
+            if (factories[i] == null) {
+                throw new IllegalArgumentException("StringConverterFactory array must not contain a null element");
+            }
+        }
         if (includeJdkConverters) {
             for (JDKStringConverter conv : JDKStringConverter.values()) {
                 registered.put(conv.getType(), conv);
@@ -140,6 +198,10 @@ public final class StringConvert {
             tryRegister("javax.time.calendar.ZoneId", "of");
             tryRegister("javax.time.calendar.TimeZone", "of");
         }
+        if (factories.length > 0) {
+            this.factories.addAll(Arrays.asList(factories));
+        }
+        this.factories.add(AnnotationStringConverterFactory.INSTANCE);
     }
 
     /**
@@ -162,18 +224,16 @@ public final class StringConvert {
      * <p>
      * This uses {@link #findConverter} to provide the converter.
      * 
-     * @param <T>  the type to convert from
      * @param object  the object to convert, null returns null
      * @return the converted string, may be null
      * @throws RuntimeException (or subclass) if unable to convert
      */
-    @SuppressWarnings("unchecked")
-    public <T> String convertToString(T object) {
+    public String convertToString(Object object) {
         if (object == null) {
             return null;
         }
-        Class<T> cls = (Class<T>) object.getClass();
-        StringConverter<T> conv = findConverter(cls);
+        Class<?> cls = object.getClass();
+        StringConverter<Object> conv = findConverterNoGenerics(cls);
         return conv.convertToString(object);
     }
 
@@ -183,17 +243,16 @@ public final class StringConvert {
      * This uses {@link #findConverter} to provide the converter.
      * The class can be provided to select a more specific converter.
      * 
-     * @param <T>  the type to convert from
      * @param cls  the class to convert from, not null
      * @param object  the object to convert, null returns null
      * @return the converted string, may be null
      * @throws RuntimeException (or subclass) if unable to convert
      */
-    public <T> String convertToString(Class<T> cls, T object) {
+    public String convertToString(Class<?> cls, Object object) {
         if (object == null) {
             return null;
         }
-        StringConverter<T> conv = findConverter(cls);
+        StringConverter<Object> conv = findConverterNoGenerics(cls);
         return conv.convertToString(object);
     }
 
@@ -216,11 +275,32 @@ public final class StringConvert {
         return conv.convertFromString(cls, str);
     }
 
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if a suitable converter exists for the type.
+     * <p>
+     * This performs the same checks as the {@code findConverter} methods.
+     * Calling this before {@code findConverter} will cache the converter.
+     * <p>
+     * Note that all exceptions, including developer errors are caught and hidden.
+     * 
+     * @param cls  the class to find a converter for, null returns false
+     * @return true if convertible
+     * @since 1.5
+     */
+    public boolean isConvertible(final Class<?> cls) {
+        try {
+            return cls != null && findConverterQuiet(cls) != null;
+        } catch (RuntimeException ex) {
+            return false;
+        }
+    }
+
     /**
      * Finds a suitable converter for the type.
      * <p>
      * This returns an instance of {@code StringConverter} for the specified class.
-     * This could be useful in other frameworks.
+     * This is designed for user code where the {@code Class} object generics is known.
      * <p>
      * The search algorithm first searches the registered converters in the
      * class hierarchy and immediate parent interfaces.
@@ -232,28 +312,84 @@ public final class StringConvert {
      * @return the converter, not null
      * @throws RuntimeException (or subclass) if no converter found
      */
-    @SuppressWarnings("unchecked")
     public <T> StringConverter<T> findConverter(final Class<T> cls) {
+        StringConverter<T> conv = findConverterQuiet(cls);
+        if (conv == null) {
+            throw new IllegalStateException("No registered converter found: " + cls);
+        }
+        return conv;
+    }
+
+    /**
+     * Finds a suitable converter for the type with open generics.
+     * <p>
+     * This returns an instance of {@code StringConverter} for the specified class.
+     * This is designed for framework usage where the {@code Class} object generics are unknown'?'.
+     * The returned type is declared with {@code Object} instead of '?' to
+     * allow the {@link ToStringConverter} to be invoked.
+     * <p>
+     * The search algorithm first searches the registered converters in the
+     * class hierarchy and immediate parent interfaces.
+     * It then searches for {@code ToString} and {@code FromString} annotations on the
+     * specified class, class hierarchy or immediate parent interfaces.
+     * 
+     * @param cls  the class to find a converter for, not null
+     * @return the converter, using {@code Object} to avoid generics, not null
+     * @throws RuntimeException (or subclass) if no converter found
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public StringConverter<Object> findConverterNoGenerics(final Class<?> cls) {
+        StringConverter<Object> conv = (StringConverter<Object>) findConverterQuiet(cls);
+        if (conv == null) {
+            throw new IllegalStateException("No registered converter found: " + cls);
+        }
+        return conv;
+    }
+
+    /**
+     * Finds a converter searching registered and annotated.
+     * 
+     * @param <T>  the type of the converter
+     * @param cls  the class to find a method for, not null
+     * @return the converter, null if no converter
+     * @throws RuntimeException if invalid
+     */
+    @SuppressWarnings("unchecked")
+    private <T> StringConverter<T> findConverterQuiet(final Class<T> cls) {
         if (cls == null) {
             throw new IllegalArgumentException("Class must not be null");
         }
         StringConverter<T> conv = (StringConverter<T>) registered.get(cls);
         if (conv == CACHED_NULL) {
-            throw new IllegalStateException("No registered converter found: " + cls);
+            return null;
         }
         if (conv == null) {
-            conv = findAnnotationConverter(cls);
+            try {
+                conv = findAnyConverter(cls);
+            } catch (RuntimeException ex) {
+                registered.putIfAbsent(cls, CACHED_NULL);
+                throw ex;
+            }
             if (conv == null) {
                 registered.putIfAbsent(cls, CACHED_NULL);
-                throw new IllegalStateException("No registered converter found: " + cls);
+                return null;
             }
             registered.putIfAbsent(cls, conv);
         }
         return conv;
     }
 
+    /**
+     * Finds a converter searching registered and annotated.
+     * 
+     * @param <T>  the type of the converter
+     * @param cls  the class to find a method for, not null
+     * @return the converter, not null
+     * @throws RuntimeException if invalid
+     */
     @SuppressWarnings("unchecked")
-    private <T> StringConverter<T> findAnnotationConverter(final Class<T> cls) {
+    private <T> StringConverter<T> findAnyConverter(final Class<T> cls) {
         StringConverter<T> conv = null;
         // check for registered on superclass
         Class<?> loopCls = cls.getSuperclass();
@@ -271,170 +407,36 @@ public final class StringConvert {
                 return conv;
             }
         }
-        // check for annotations
-        conv = findAnnotatedConverter(cls);
-        if (conv != null) {
-            return conv;
-        }
-        return null;
-    }
-
-    /**
-     * Finds the conversion method.
-     * 
-     * @param <T>  the type of the converter
-     * @param cls  the class to find a method for, not null
-     * @return the method to call, null means use {@code toString}
-     */
-    private <T> StringConverter<T> findAnnotatedConverter(final Class<T> cls) {
-        Method toString = findToStringMethod(cls);  // checks superclasses
-        if (toString == null) {
-            return null;
-        }
-        Constructor<T> con = findFromStringConstructor(cls);
-        Method fromString = findFromStringMethod(cls, con == null);  // optionally checks superclasses
-        if (con == null && fromString == null) {
-            throw new IllegalStateException("Class annotated with @ToString but not with @FromString: " + cls.getName());
-        }
-        if (con != null && fromString != null) {
-            throw new IllegalStateException("Both method and constructor are annotated with @FromString: " + cls.getName());
-        }
-        if (con != null) {
-            return new MethodConstructorStringConverter<T>(cls, toString, con);
-        } else {
-            return new MethodsStringConverter<T>(cls, toString, fromString);
-        }
-    }
-
-    /**
-     * Finds the conversion method.
-     * 
-     * @param cls  the class to find a method for, not null
-     * @return the method to call, null means use {@code toString}
-     */
-    private Method findToStringMethod(Class<?> cls) {
-        Method matched = null;
-        // find in superclass hierarchy
-        Class<?> loopCls = cls;
-        while (loopCls != null && matched == null) {
-            Method[] methods = loopCls.getDeclaredMethods();
-            for (Method method : methods) {
-                ToString toString = method.getAnnotation(ToString.class);
-                if (toString != null) {
-                    if (matched != null) {
-                        throw new IllegalStateException("Two methods are annotated with @ToString: " + cls.getName());
-                    }
-                    matched = method;
-                }
-            }
-            loopCls = loopCls.getSuperclass();
-        }
-        // find in immediate parent interfaces
-        if (matched == null) {
-            for (Class<?> loopIfc : cls.getInterfaces()) {
-                Method[] methods = loopIfc.getDeclaredMethods();
-                for (Method method : methods) {
-                    ToString toString = method.getAnnotation(ToString.class);
-                    if (toString != null) {
-                        if (matched != null) {
-                            throw new IllegalStateException("Two methods are annotated with @ToString on interfaces: " + cls.getName());
-                        }
-                        matched = method;
-                    }
-                }
-            }
-        }
-        return matched;
-    }
-
-    /**
-     * Finds the conversion method.
-     * 
-     * @param <T>  the type of the converter
-     * @param cls  the class to find a method for, not null
-     * @return the method to call, null means use {@code toString}
-     */
-    private <T> Constructor<T> findFromStringConstructor(Class<T> cls) {
-        Constructor<T> con;
-        try {
-            con = cls.getDeclaredConstructor(String.class);
-        } catch (NoSuchMethodException ex) {
-            try {
-                con = cls.getDeclaredConstructor(CharSequence.class);
-            } catch (NoSuchMethodException ex2) {
-                return null;
-            }
-        }
-        FromString fromString = con.getAnnotation(FromString.class);
-        return fromString != null ? con : null;
-    }
-
-    /**
-     * Finds the conversion method.
-     * 
-     * @param cls  the class to find a method for, not null
-     * @return the method to call, null means not found
-     */
-    private Method findFromStringMethod(Class<?> cls, boolean searchSuperclasses) {
-        Method matched = null;
-        // find in superclass hierarchy
-        Class<?> loopCls = cls;
-        while (loopCls != null && matched == null) {
-            matched = findFromString(loopCls, matched);
-            if (searchSuperclasses == false) {
-                break;
-            }
-            loopCls = loopCls.getSuperclass();
-        }
-        // find in immediate parent interfaces
-        if (searchSuperclasses && matched == null) {
-            for (Class<?> loopIfc : cls.getInterfaces()) {
-                matched = findFromString(loopIfc, matched);
+        // check factories
+        for (StringConverterFactory factory : factories) {
+            conv = (StringConverter<T>) factory.findConverter(cls);
+            if (conv != null) {
+                return conv;
             }
         }
-        return matched;
+        return null;
     }
 
+    //-----------------------------------------------------------------------
     /**
-     * Finds the conversion method.
+     * Registers a converter factory.
+     * <p>
+     * This will be registered ahead of all existing factories.
+     * <p>
+     * No new factories may be registered for the global singleton.
      * 
-     * @param cls  the class to find a method for, not null
-     * @param matched  the matched method, may be null
-     * @return the method to call, null means not found
+     * @param factory  the converter factory, not null
+     * @throws IllegalStateException if trying to alter the global singleton
+     * @since 1.5
      */
-    private Method findFromString(Class<?> cls, Method matched) {
-        // find in declared methods
-        Method[] methods = cls.getDeclaredMethods();
-        for (Method method : methods) {
-            FromString fromString = method.getAnnotation(FromString.class);
-            if (fromString != null) {
-                if (matched != null) {
-                    throw new IllegalStateException("Two methods are annotated with @FromString: " + cls.getName());
-                }
-                matched = method;
-            }
+    public void registerFactory(final StringConverterFactory factory) {
+        if (factory == null) {
+            throw new IllegalArgumentException("Factory must not be null");
         }
-        // check for factory
-        FromStringFactory factory = cls.getAnnotation(FromStringFactory.class);
-        if (factory != null) {
-            if (matched != null) {
-                throw new IllegalStateException("Class annotated with @FromString and @FromStringFactory: " + cls.getName());
-            }
-            Method[] factoryMethods = factory.factory().getDeclaredMethods();
-            for (Method method : factoryMethods) {
-                // handle factory containing multiple FromString for different types
-                if (cls.isAssignableFrom(method.getReturnType())) {
-                    FromString fromString = method.getAnnotation(FromString.class);
-                    if (fromString != null) {
-                        if (matched != null) {
-                            throw new IllegalStateException("Two methods are annotated with @FromString on the factory: " + factory.factory().getName());
-                        }
-                        matched = method;
-                    }
-                }
-            }
+        if (this == INSTANCE) {
+            throw new IllegalStateException("Global singleton cannot be extended");
         }
-        return matched;
+        factories.add(0, factory);
     }
 
     //-----------------------------------------------------------------------
diff --git a/src/main/java/org/joda/convert/StringConverter.java b/src/main/java/org/joda/convert/StringConverter.java
index e90f51b..f09335b 100644
--- a/src/main/java/org/joda/convert/StringConverter.java
+++ b/src/main/java/org/joda/convert/StringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/ToStringConverter.java b/src/main/java/org/joda/convert/StringConverterFactory.java
similarity index 57%
copy from src/main/java/org/joda/convert/ToStringConverter.java
copy to src/main/java/org/joda/convert/StringConverterFactory.java
index 39b32af..067c575 100644
--- a/src/main/java/org/joda/convert/ToStringConverter.java
+++ b/src/main/java/org/joda/convert/StringConverterFactory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,20 +16,22 @@
 package org.joda.convert;
 
 /**
- * Interface defining conversion to a {@code String}.
+ * Factory for {@code StringConverter} that allows converters to be
+ * created dynamically or easily initialised.
  * <p>
- * ToStringConverter is an interface and must be implemented with care.
  * Implementations must be immutable and thread-safe.
  * 
- * @param <T>  the type of the converter
+ * @since 1.5
  */
-public interface ToStringConverter<T> {
+public interface StringConverterFactory {
 
     /**
-     * Converts the specified object to a {@code String}.
-     * @param object  the object to convert, not null
-     * @return the converted string, may be null but generally not
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
      */
-    String convertToString(T object);
+    StringConverter<?> findConverter(Class<?> cls);
 
 }
diff --git a/src/main/java/org/joda/convert/ToString.java b/src/main/java/org/joda/convert/ToString.java
index da248e1..c44e30e 100644
--- a/src/main/java/org/joda/convert/ToString.java
+++ b/src/main/java/org/joda/convert/ToString.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/ToStringConverter.java b/src/main/java/org/joda/convert/ToStringConverter.java
index 39b32af..3b50658 100644
--- a/src/main/java/org/joda/convert/ToStringConverter.java
+++ b/src/main/java/org/joda/convert/ToStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java
new file mode 100644
index 0000000..ac1421c
--- /dev/null
+++ b/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java
@@ -0,0 +1,103 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert.factory;
+
+import org.joda.convert.StringConverter;
+import org.joda.convert.StringConverterFactory;
+
+/**
+ * Factory for {@code StringConverter} providing support for primitive boolean array
+ * as a sequence of 'T' and 'F'.
+ * <p>
+ * This is intended as a human readable format, not a compact format.
+ * <p>
+ * To use, simply register the instance with a {@code StringConvert} instance.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public final class BooleanArrayStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    public static final StringConverterFactory INSTANCE = new BooleanArrayStringConverterFactory();
+
+    /**
+     * Restricted constructor.
+     */
+    private BooleanArrayStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == boolean[].class) {
+            return BooleanArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum BooleanArrayStringConverter implements StringConverter<boolean[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(boolean[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length);
+                for (int i = 0; i < array.length; i++) {
+                    buf.append(array[i] ? 'T' : 'F');
+                }
+                return buf.toString();
+            }
+            @Override
+            public boolean[] convertFromString(Class<? extends boolean[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                boolean[] array = new boolean[str.length()];
+                for (int i = 0; i < array.length; i++) {
+                    char ch = str.charAt(i);
+                    if (ch == 'T') {
+                        array[i] = true;
+                    } else if (ch == 'F') {
+                        array[i] = false;
+                    } else {
+                        throw new IllegalArgumentException("Invalid boolean[] string, must consist only of 'T' and 'F'");
+                    }
+                }
+                return array;
+            }
+        };
+        private static final boolean[] EMPTY = new boolean[0];
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/factory/BooleanObjectArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/BooleanObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..99a2caa
--- /dev/null
+++ b/src/main/java/org/joda/convert/factory/BooleanObjectArrayStringConverterFactory.java
@@ -0,0 +1,105 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert.factory;
+
+import org.joda.convert.StringConverter;
+import org.joda.convert.StringConverterFactory;
+
+/**
+ * Factory for {@code StringConverter} providing support for Boolean object array
+ * as a sequence of 'T', 'F' and '-' for null.
+ * <p>
+ * This is intended as a human readable format, not a compact format.
+ * <p>
+ * To use, simply register the instance with a {@code StringConvert} instance.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public final class BooleanObjectArrayStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    public static final StringConverterFactory INSTANCE = new BooleanObjectArrayStringConverterFactory();
+
+    /**
+     * Restricted constructor.
+     */
+    private BooleanObjectArrayStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == Boolean[].class) {
+            return BooleanArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum BooleanArrayStringConverter implements StringConverter<Boolean[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Boolean[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length);
+                for (int i = 0; i < array.length; i++) {
+                    buf.append(array[i] == null ? '-' : (array[i].booleanValue() ? 'T' : 'F'));
+                }
+                return buf.toString();
+            }
+            @Override
+            public Boolean[] convertFromString(Class<? extends Boolean[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                Boolean[] array = new Boolean[str.length()];
+                for (int i = 0; i < array.length; i++) {
+                    char ch = str.charAt(i);
+                    if (ch == 'T') {
+                        array[i] = Boolean.TRUE;
+                    } else if (ch == 'F') {
+                        array[i] = Boolean.FALSE;
+                    } else if (ch == '-') {
+                        array[i] = null;
+                    } else {
+                        throw new IllegalArgumentException("Invalid Boolean[] string, must consist only of 'T', 'F' and '-'");
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Boolean[] EMPTY = new Boolean[0];
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/factory/ByteObjectArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/ByteObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..b1cfbd8
--- /dev/null
+++ b/src/main/java/org/joda/convert/factory/ByteObjectArrayStringConverterFactory.java
@@ -0,0 +1,110 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert.factory;
+
+import org.joda.convert.StringConverter;
+import org.joda.convert.StringConverterFactory;
+
+/**
+ * Factory for {@code StringConverter} providing support for Byte object array
+ * as a sequence of two letter hex codes for each byte plus '--' for null.
+ * <p>
+ * This is intended as a human readable format, not a compact format.
+ * <p>
+ * To use, simply register the instance with a {@code StringConvert} instance.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public final class ByteObjectArrayStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    public static final StringConverterFactory INSTANCE = new ByteObjectArrayStringConverterFactory();
+
+    /**
+     * Restricted constructor.
+     */
+    private ByteObjectArrayStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == Byte[].class) {
+            return ByteArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum ByteArrayStringConverter implements StringConverter<Byte[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Byte[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length);
+                for (int i = 0; i < array.length; i++) {
+                    if (array[i] == null) {
+                        buf.append('-').append('-');
+                    } else {
+                        int b = array[i].byteValue();
+                        buf.append(HEX.charAt((b & 0xF0) >>> 4)).append(HEX.charAt(b & 0x0F));
+                    }
+                }
+                return buf.toString();
+            }
+            @Override
+            public Byte[] convertFromString(Class<? extends Byte[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                if (str.length() % 2 == 1) {
+                    throw new IllegalArgumentException("Invalid Byte[] string");
+                }
+                Byte[] array = new Byte[str.length() / 2];
+                for (int i = 0; i < array.length; i++) {
+                    String in = str.substring(i * 2, i * 2 + 2);
+                    if (in.equals("--")) {
+                        array[i] = null;
+                    } else {
+                        array[i] = (byte) Integer.parseInt(in, 16);
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Byte[] EMPTY = new Byte[0];
+        private static final String HEX = "0123456789ABCDEF";
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/factory/CharObjectArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/CharObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..2f17fc1
--- /dev/null
+++ b/src/main/java/org/joda/convert/factory/CharObjectArrayStringConverterFactory.java
@@ -0,0 +1,128 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert.factory;
+
+import java.util.Arrays;
+import java.util.regex.Pattern;
+
+import org.joda.convert.StringConverter;
+import org.joda.convert.StringConverterFactory;
+
+/**
+ * Factory for {@code StringConverter} providing support for Character object arrays
+ * as a string, using backslash as an escape.
+ * <p>
+ * Double backslash is a backslash.
+ * One backslash followed by a dash is null.
+ * <p>
+ * To use, simply register the instance with a {@code StringConvert} instance.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public final class CharObjectArrayStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    public static final StringConverterFactory INSTANCE = new CharObjectArrayStringConverterFactory();
+    /**
+     * Delimiter to find.
+     */
+    static final Pattern DELIMITER = Pattern.compile("[,]");
+
+    /**
+     * Restricted constructor.
+     */
+    private CharObjectArrayStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == Character[].class) {
+            return CharecterArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum CharecterArrayStringConverter implements StringConverter<Character[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Character[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                for (int i = 0; i < array.length; i++) {
+                    if (array[i] == null) {
+                        buf.append("\\-");
+                    } else {
+                        char ch = array[i].charValue();
+                        if (ch == '\\') {
+                            buf.append("\\\\");
+                        } else {
+                            buf.append(ch);
+                        }
+                    }
+                }
+                return buf.toString();
+            }
+            @Override
+            public Character[] convertFromString(Class<? extends Character[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                Character[] array = new Character[str.length()];
+                int arrayPos = 0;
+                int pos;
+                while ((pos = str.indexOf('\\')) >= 0) {
+                    for (int i = 0; i < pos; i++) {
+                        array[arrayPos++] = str.charAt(i);
+                    }
+                    if (str.charAt(pos + 1) == '\\') {
+                        array[arrayPos++] = '\\';
+                    } else if (str.charAt(pos + 1) == '-') {
+                        array[arrayPos++] = null;
+                    } else {
+                        throw new IllegalArgumentException("Invalid Character[] string, incorrect escape");
+                    }
+                    str = str.substring(pos + 2);
+                }
+                for (int i = 0; i < str.length(); i++) {
+                    array[arrayPos++] = str.charAt(i);
+                }
+                return Arrays.copyOf(array, arrayPos);
+            }
+        };
+        private static final Character[] EMPTY = new Character[0];
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/factory/NumericArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/NumericArrayStringConverterFactory.java
new file mode 100644
index 0000000..5144697
--- /dev/null
+++ b/src/main/java/org/joda/convert/factory/NumericArrayStringConverterFactory.java
@@ -0,0 +1,240 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert.factory;
+
+import java.util.regex.Pattern;
+
+import org.joda.convert.StringConverter;
+import org.joda.convert.StringConverterFactory;
+
+/**
+ * Factory for {@code StringConverter} providing support for primitive arrays
+ * as a comma separated list.
+ * <p>
+ * To use, simply register the instance with a {@code StringConvert} instance.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public final class NumericArrayStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    public static final StringConverterFactory INSTANCE = new NumericArrayStringConverterFactory();
+    /**
+     * Delimiter to find.
+     */
+    static final Pattern DELIMITER = Pattern.compile("[,]");
+
+    /**
+     * Restricted constructor.
+     */
+    private NumericArrayStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls.isArray() && cls.getComponentType().isPrimitive()) {
+            if (cls == long[].class) {
+                return LongArrayStringConverter.INSTANCE;
+            }
+            if (cls == int[].class) {
+                return IntArrayStringConverter.INSTANCE;
+            }
+            if (cls == short[].class) {
+                return ShortArrayStringConverter.INSTANCE;
+            }
+            if (cls == double[].class) {
+                return DoubleArrayStringConverter.INSTANCE;
+            }
+            if (cls == float[].class) {
+                return FloatArrayStringConverter.INSTANCE;
+            }
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum LongArrayStringConverter implements StringConverter<long[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(long[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                buf.append(array[0]);
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i]);
+                }
+                return buf.toString();
+            }
+            @Override
+            public long[] convertFromString(Class<? extends long[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                long[] array = new long[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    array[i] = Long.parseLong(split[i]);
+                }
+                return array;
+            }
+        };
+        private static final long[] EMPTY = new long[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum IntArrayStringConverter implements StringConverter<int[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(int[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 6);
+                buf.append(array[0]);
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i]);
+                }
+                return buf.toString();
+            }
+            @Override
+            public int[] convertFromString(Class<? extends int[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                int[] array = new int[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    array[i] = Integer.parseInt(split[i]);
+                }
+                return array;
+            }
+        };
+        private static final int[] EMPTY = new int[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum ShortArrayStringConverter implements StringConverter<short[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(short[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 3);
+                buf.append(array[0]);
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i]);
+                }
+                return buf.toString();
+            }
+            @Override
+            public short[] convertFromString(Class<? extends short[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                short[] array = new short[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    array[i] = Short.parseShort(split[i]);
+                }
+                return array;
+            }
+        };
+        private static final short[] EMPTY = new short[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum DoubleArrayStringConverter implements StringConverter<double[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(double[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                buf.append(array[0]);
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i]);
+                }
+                return buf.toString();
+            }
+            @Override
+            public double[] convertFromString(Class<? extends double[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                double[] array = new double[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    array[i] = Double.parseDouble(split[i]);
+                }
+                return array;
+            }
+        };
+        private static final double[] EMPTY = new double[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum FloatArrayStringConverter implements StringConverter<float[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(float[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                buf.append(array[0]);
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i]);
+                }
+                return buf.toString();
+            }
+            @Override
+            public float[] convertFromString(Class<? extends float[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                float[] array = new float[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    array[i] = Float.parseFloat(split[i]);
+                }
+                return array;
+            }
+        };
+        private static final float[] EMPTY = new float[0];
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/factory/NumericObjectArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/NumericObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..5514d94
--- /dev/null
+++ b/src/main/java/org/joda/convert/factory/NumericObjectArrayStringConverterFactory.java
@@ -0,0 +1,250 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert.factory;
+
+import java.util.regex.Pattern;
+
+import org.joda.convert.StringConverter;
+import org.joda.convert.StringConverterFactory;
+
+/**
+ * Factory for {@code StringConverter} providing support for numeric object arrays
+ * as a comma separated list, using '-' for null.
+ * <p>
+ * To use, simply register the instance with a {@code StringConvert} instance.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public final class NumericObjectArrayStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    public static final StringConverterFactory INSTANCE = new NumericObjectArrayStringConverterFactory();
+    /**
+     * Delimiter to find.
+     */
+    static final Pattern DELIMITER = Pattern.compile("[,]");
+
+    /**
+     * Restricted constructor.
+     */
+    private NumericObjectArrayStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Finds a converter by type.
+     * 
+     * @param cls  the type to lookup, not null
+     * @return the converter, null if not found
+     * @throws RuntimeException (or subclass) if source code is invalid
+     */
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls.isArray()) {
+            if (cls == Long[].class) {
+                return LongArrayStringConverter.INSTANCE;
+            }
+            if (cls == Integer[].class) {
+                return IntArrayStringConverter.INSTANCE;
+            }
+            if (cls == Short[].class) {
+                return ShortArrayStringConverter.INSTANCE;
+            }
+            if (cls == Double[].class) {
+                return DoubleArrayStringConverter.INSTANCE;
+            }
+            if (cls == Float[].class) {
+                return FloatArrayStringConverter.INSTANCE;
+            }
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum LongArrayStringConverter implements StringConverter<Long[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Long[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                buf.append(array[0] != null ? array[0] : "-");
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i] != null ? array[i] : "-");
+                }
+                return buf.toString();
+            }
+            @Override
+            public Long[] convertFromString(Class<? extends Long[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                Long[] array = new Long[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    if (split[i].equals("-") == false) {
+                        array[i] = Long.parseLong(split[i]);
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Long[] EMPTY = new Long[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum IntArrayStringConverter implements StringConverter<Integer[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Integer[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 6);
+                buf.append(array[0] != null ? array[0] : "-");
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i] != null ? array[i] : "-");
+                }
+                return buf.toString();
+            }
+            @Override
+            public Integer[] convertFromString(Class<? extends Integer[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                Integer[] array = new Integer[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    if (split[i].equals("-") == false) {
+                        array[i] = Integer.parseInt(split[i]);
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Integer[] EMPTY = new Integer[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum ShortArrayStringConverter implements StringConverter<Short[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Short[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 3);
+                buf.append(array[0] != null ? array[0] : "-");
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i] != null ? array[i] : "-");
+                }
+                return buf.toString();
+            }
+            @Override
+            public Short[] convertFromString(Class<? extends Short[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                Short[] array = new Short[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    if (split[i].equals("-") == false) {
+                        array[i] = Short.parseShort(split[i]);
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Short[] EMPTY = new Short[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum DoubleArrayStringConverter implements StringConverter<Double[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Double[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                buf.append(array[0] != null ? array[0] : "-");
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i] != null ? array[i] : "-");
+                }
+                return buf.toString();
+            }
+            @Override
+            public Double[] convertFromString(Class<? extends Double[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                Double[] array = new Double[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    if (split[i].equals("-") == false) {
+                        array[i] = Double.parseDouble(split[i]);
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Double[] EMPTY = new Double[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum FloatArrayStringConverter implements StringConverter<Float[]> {
+        INSTANCE {
+            @Override
+            public String convertToString(Float[] array) {
+                if (array.length == 0) {
+                    return "";
+                }
+                StringBuilder buf = new StringBuilder(array.length * 8);
+                buf.append(array[0] != null ? array[0] : "-");
+                for (int i = 1; i < array.length; i++) {
+                    buf.append(',').append(array[i] != null ? array[i] : "-");
+                }
+                return buf.toString();
+            }
+            @Override
+            public Float[] convertFromString(Class<? extends Float[]> cls, String str) {
+                if (str.length() == 0) {
+                    return EMPTY;
+                }
+                String[] split = DELIMITER.split(str);
+                Float[] array = new Float[split.length];
+                for (int i = 0; i < split.length; i++) {
+                    if (split[i].equals("-") == false) {
+                        array[i] = Float.parseFloat(split[i]);
+                    }
+                }
+                return array;
+            }
+        };
+        private static final Float[] EMPTY = new Float[0];
+    }
+
+}
diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml
index c1b2154..a71e6d2 100644
--- a/src/site/xdoc/index.xml
+++ b/src/site/xdoc/index.xml
@@ -72,12 +72,12 @@ Various documentation is available:
 
 <section name="Releases">
 <p>
-<a href="download.html">Release 1.4</a> is the current latest release.
+<a href="download.html">Release 1.5</a> is the current latest release.
 This release is considered stable and worthy of the 1.x tag.
 It depends on JDK 1.6 or later.
 </p>
 <p>
-Available in the <a href="http://search.maven.org/#artifactdetails|org.joda|joda-convert|1.4|jar">Maven Central repository</a>.
+Available in the <a href="http://search.maven.org/#artifactdetails|org.joda|joda-convert|1.5|jar">Maven Central repository</a>.
 </p>
 </section>
 
diff --git a/src/site/xdoc/userguide.xml b/src/site/xdoc/userguide.xml
index 2c089e4..a32bd2a 100644
--- a/src/site/xdoc/userguide.xml
+++ b/src/site/xdoc/userguide.xml
@@ -54,6 +54,10 @@ These cover all the standard JDK types for which conversion to and from a string
 The set also includes JSR-310 types, but these are optional and loaded by reflection. The system will run without any dependency.
 </p>
 <p>
+Arrays of <code>byte</code> are handled as a standard JDK type using Base64.
+Arrays of <code>char</code> are handled by a standard JDK type by conversion to a string.
+</p>
+<p>
 Each <code>StringConvert</code> instance, other than the global singleton, may have additional converters registered manually.
 Each converter implements the <code>StringConverter</code> interface, which is self explanatory.
 </p>
@@ -62,8 +66,25 @@ Converters may also be manually added by method name.
 This is equivalent to using annotations, but suitable when you don't own the code to add them.
 See <code>StringConvert.registerMethods</code> and <code>StringConvert.registerMethodConstructor</code>.
 </p>
+</subsection>
+
+<subsection name="Factories">
+<p>
+In addition to manual registration of individual converters, each instance of <code>StringConvert</code>
+has a list of factories to use. The <code>StringConverterFactory</code> interface defines the factory.
+This allows either bulk registration or dynamic lookup of converters.
+</p>
+<p>
+A factory is provided to allow numeric arrays to be converted to/from a comma separated list.
+A separate factory handles numeric object arrays.
+Another factory is provided to allow boolean arrays to be converted to/from a string such as 'TTFFT'.
+Again, a separate factory handles boolean object arrays.
+Primitive byte and char arrays are handled by default, but the primitive object arrays are
+handled  via their own factories.
+</p>
 <p>
-A converter can only be registered if one is not already registered for that type.
+These extra factories must be manually registered, unless the <code>StringConvert.create()</code>
+static method is used, which defines an "extended" converter with the factories included.
 </p>
 </subsection>
 
diff --git a/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameter.java b/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameter.java
index c250fbc..2e39bfe 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameter.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameterCount.java b/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameterCount.java
index 91a8730..d720775 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameterCount.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringConstructorInvalidParameterCount.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceFromStringException.java b/src/test/java/org/joda/convert/DistanceFromStringException.java
index b8dd645..9e322c5 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringException.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringException.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceFromStringInvalidParameter.java b/src/test/java/org/joda/convert/DistanceFromStringInvalidParameter.java
index c1dee91..a845796 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringInvalidParameter.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringInvalidParameter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceFromStringInvalidParameterCount.java b/src/test/java/org/joda/convert/DistanceFromStringInvalidParameterCount.java
index 352cac0..583d4a9 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringInvalidParameterCount.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringInvalidParameterCount.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceFromStringInvalidReturnType.java b/src/test/java/org/joda/convert/DistanceFromStringInvalidReturnType.java
index d0a5a55..6ec25bd 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringInvalidReturnType.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringInvalidReturnType.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceFromStringNoToString.java b/src/test/java/org/joda/convert/DistanceFromStringNoToString.java
index 1749fcf..db05528 100644
--- a/src/test/java/org/joda/convert/DistanceFromStringNoToString.java
+++ b/src/test/java/org/joda/convert/DistanceFromStringNoToString.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceMethodAndConstructorAnnotations.java b/src/test/java/org/joda/convert/DistanceMethodAndConstructorAnnotations.java
index d1529f0..81c94e3 100644
--- a/src/test/java/org/joda/convert/DistanceMethodAndConstructorAnnotations.java
+++ b/src/test/java/org/joda/convert/DistanceMethodAndConstructorAnnotations.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceMethodConstructor.java b/src/test/java/org/joda/convert/DistanceMethodConstructor.java
index d559dab..b6674ce 100644
--- a/src/test/java/org/joda/convert/DistanceMethodConstructor.java
+++ b/src/test/java/org/joda/convert/DistanceMethodConstructor.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java b/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java
index a7ad0ad..ce53587 100644
--- a/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java
+++ b/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceMethodMethod.java b/src/test/java/org/joda/convert/DistanceMethodMethod.java
index e8ba0fc..a995e44 100644
--- a/src/test/java/org/joda/convert/DistanceMethodMethod.java
+++ b/src/test/java/org/joda/convert/DistanceMethodMethod.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java b/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java
index b0b2e65..57aa2b4 100644
--- a/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java
+++ b/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceNoAnnotations.java b/src/test/java/org/joda/convert/DistanceNoAnnotations.java
index 58b3b59..29159cb 100644
--- a/src/test/java/org/joda/convert/DistanceNoAnnotations.java
+++ b/src/test/java/org/joda/convert/DistanceNoAnnotations.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java b/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java
index a9413bc..1349fe3 100644
--- a/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java
+++ b/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceToStringException.java b/src/test/java/org/joda/convert/DistanceToStringException.java
index e29c7ab..99934df 100644
--- a/src/test/java/org/joda/convert/DistanceToStringException.java
+++ b/src/test/java/org/joda/convert/DistanceToStringException.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceToStringInvalidParameters.java b/src/test/java/org/joda/convert/DistanceToStringInvalidParameters.java
index 91d36ee..12af26f 100644
--- a/src/test/java/org/joda/convert/DistanceToStringInvalidParameters.java
+++ b/src/test/java/org/joda/convert/DistanceToStringInvalidParameters.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceToStringInvalidReturnType.java b/src/test/java/org/joda/convert/DistanceToStringInvalidReturnType.java
index 7cabbab..bfd2628 100644
--- a/src/test/java/org/joda/convert/DistanceToStringInvalidReturnType.java
+++ b/src/test/java/org/joda/convert/DistanceToStringInvalidReturnType.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceToStringNoFromString.java b/src/test/java/org/joda/convert/DistanceToStringNoFromString.java
index f87b7d0..cfb3a0e 100644
--- a/src/test/java/org/joda/convert/DistanceToStringNoFromString.java
+++ b/src/test/java/org/joda/convert/DistanceToStringNoFromString.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceTwoFromStringMethodAnnotations.java b/src/test/java/org/joda/convert/DistanceTwoFromStringMethodAnnotations.java
index 4a11f27..f1f4423 100644
--- a/src/test/java/org/joda/convert/DistanceTwoFromStringMethodAnnotations.java
+++ b/src/test/java/org/joda/convert/DistanceTwoFromStringMethodAnnotations.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceTwoToStringAnnotations.java b/src/test/java/org/joda/convert/DistanceTwoToStringAnnotations.java
index 1f3a465..b2d1144 100644
--- a/src/test/java/org/joda/convert/DistanceTwoToStringAnnotations.java
+++ b/src/test/java/org/joda/convert/DistanceTwoToStringAnnotations.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceWithFactory.java b/src/test/java/org/joda/convert/DistanceWithFactory.java
index 8627929..9c73a04 100644
--- a/src/test/java/org/joda/convert/DistanceWithFactory.java
+++ b/src/test/java/org/joda/convert/DistanceWithFactory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java b/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java
index 88fa2e9..3631531 100644
--- a/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java
+++ b/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/MockDistanceStringConverter.java b/src/test/java/org/joda/convert/MockDistanceStringConverter.java
index 1e75ea3..a98fdaa 100644
--- a/src/test/java/org/joda/convert/MockDistanceStringConverter.java
+++ b/src/test/java/org/joda/convert/MockDistanceStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/MockIntegerStringConverter.java b/src/test/java/org/joda/convert/MockIntegerStringConverter.java
index 79de32f..47b4cb2 100644
--- a/src/test/java/org/joda/convert/MockIntegerStringConverter.java
+++ b/src/test/java/org/joda/convert/MockIntegerStringConverter.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/SubMethodConstructor.java b/src/test/java/org/joda/convert/SubMethodConstructor.java
index ce6df54..2eb5184 100644
--- a/src/test/java/org/joda/convert/SubMethodConstructor.java
+++ b/src/test/java/org/joda/convert/SubMethodConstructor.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/SubMethodMethod.java b/src/test/java/org/joda/convert/SubMethodMethod.java
index d3bae48..5dc9013 100644
--- a/src/test/java/org/joda/convert/SubMethodMethod.java
+++ b/src/test/java/org/joda/convert/SubMethodMethod.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/SubNoAnnotations.java b/src/test/java/org/joda/convert/SubNoAnnotations.java
index af58042..098aaf3 100644
--- a/src/test/java/org/joda/convert/SubNoAnnotations.java
+++ b/src/test/java/org/joda/convert/SubNoAnnotations.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/SuperFactorySub.java b/src/test/java/org/joda/convert/SuperFactorySub.java
index 6525382..2262e9d 100644
--- a/src/test/java/org/joda/convert/SuperFactorySub.java
+++ b/src/test/java/org/joda/convert/SuperFactorySub.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/SuperFactorySuper.java b/src/test/java/org/joda/convert/SuperFactorySuper.java
index 3e9be17..8a0dd89 100644
--- a/src/test/java/org/joda/convert/SuperFactorySuper.java
+++ b/src/test/java/org/joda/convert/SuperFactorySuper.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java
new file mode 100644
index 0000000..c6f84e3
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.joda.convert.factory.BooleanArrayStringConverterFactory;
+import org.junit.Test;
+
+/**
+ * Test BooleanArrayStringConverterFactory.
+ */
+public class TestBooleanArrayStringConverterFactory {
+
+    @Test
+    public void test_longArray() {
+        doTest(new boolean[0], "");
+        doTest(new boolean[] {true}, "T");
+        doTest(new boolean[] {false}, "F");
+        doTest(new boolean[] {true, true, false, true, false, false}, "TTFTFF");
+    }
+
+    private void doTest(boolean[] array, String str) {
+        StringConvert test = new StringConvert(true, BooleanArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(boolean[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(boolean[].class, str)));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/TestBooleanObjectArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestBooleanObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..0d73041
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestBooleanObjectArrayStringConverterFactory.java
@@ -0,0 +1,47 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.joda.convert.factory.BooleanObjectArrayStringConverterFactory;
+import org.junit.Test;
+
+/**
+ * Test BooleanObjectArrayStringConverterFactory.
+ */
+public class TestBooleanObjectArrayStringConverterFactory {
+
+    @Test
+    public void test_longArray() {
+        doTest(new Boolean[0], "");
+        doTest(new Boolean[] {true}, "T");
+        doTest(new Boolean[] {false}, "F");
+        doTest(new Boolean[] {null}, "-");
+        doTest(new Boolean[] {true, true, false, null, true, false, null, null, false}, "TTF-TF--F");
+    }
+
+    private void doTest(Boolean[] array, String str) {
+        StringConvert test = new StringConvert(true, BooleanObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Boolean[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Boolean[].class, str)));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/TestByteObjectArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestByteObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..dcfc92e
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestByteObjectArrayStringConverterFactory.java
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.joda.convert.factory.ByteObjectArrayStringConverterFactory;
+import org.junit.Test;
+
+/**
+ * Test ByteObjectArrayStringConverterFactory.
+ */
+public class TestByteObjectArrayStringConverterFactory {
+
+    @Test
+    public void test_ByteArray() {
+        doTest(new Byte[0], "");
+        doTest(new Byte[] {(byte) 0}, "00");
+        doTest(new Byte[] {null}, "--");
+        doTest(new Byte[] {(byte) 0, (byte) 1, null, null, (byte) 15, (byte) 16, (byte) 127, (byte) -128, (byte) -1}, "0001----0F107F80FF");
+    }
+
+    private void doTest(Byte[] array, String str) {
+        StringConvert test = new StringConvert(true, ByteObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Byte[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Byte[].class, str)));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/TestCharObjectArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestCharObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..8e6bc67
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestCharObjectArrayStringConverterFactory.java
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.joda.convert.factory.CharObjectArrayStringConverterFactory;
+import org.junit.Test;
+
+/**
+ * Test CharObjectArrayStringConverterFactory.
+ */
+public class TestCharObjectArrayStringConverterFactory {
+
+    @Test
+    public void test_CharacterArray() {
+        doTest(new Character[0], "");
+        doTest(new Character[] {'T'}, "T");
+        doTest(new Character[] {'-'}, "-");
+        doTest(new Character[] {null}, "\\-");
+        doTest(new Character[] {'J', '-', 'T'}, "J-T");
+        doTest(new Character[] {'\\', '\\', null}, "\\\\\\\\\\-");
+        doTest(new Character[] {'-', 'H', 'e', null, null, 'o'}, "-He\\-\\-o");
+    }
+
+    private void doTest(Character[] array, String str) {
+        StringConvert test = new StringConvert(true, CharObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Character[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Character[].class, str)));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/TestJDKStringConverters.java b/src/test/java/org/joda/convert/TestJDKStringConverters.java
index 540bd0d..427dfbe 100644
--- a/src/test/java/org/joda/convert/TestJDKStringConverters.java
+++ b/src/test/java/org/joda/convert/TestJDKStringConverters.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
 package org.joda.convert;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.io.File;
 import java.math.BigDecimal;
@@ -24,6 +25,7 @@ import java.math.RoundingMode;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Currency;
 import java.util.Date;
@@ -107,12 +109,42 @@ public class TestJDKStringConverters {
     }
 
     @Test
+    public void test_charArray() {
+        JDKStringConverter test = JDKStringConverter.CHAR_ARRAY;
+        char[] array = new char[] {'M', 'a', 'p'};
+        String str = "Map";
+        assertEquals(char[].class, test.getType());
+        assertEquals(str, test.convertToString(array));
+        assertTrue(Arrays.equals(array, (char[]) test.convertFromString(char[].class, str)));
+    }
+
+    @Test
     public void test_Byte() {
         JDKStringConverter test = JDKStringConverter.BYTE;
         doTest(test, Byte.class, Byte.valueOf((byte) 12), "12");
     }
 
     @Test
+    public void test_byteArray1() {
+        JDKStringConverter test = JDKStringConverter.BYTE_ARRAY;
+        byte[] array = new byte[] {77, 97, 112};
+        String str = "TWFw";
+        assertEquals(byte[].class, test.getType());
+        assertEquals(str, test.convertToString(array));
+        assertTrue(Arrays.equals(array, (byte[]) test.convertFromString(byte[].class, str)));
+    }
+
+    @Test
+    public void test_byteArray2() {
+        JDKStringConverter test = JDKStringConverter.BYTE_ARRAY;
+        byte[] array = new byte[] {77, 97};
+        String str = "TWE=";
+        assertEquals(byte[].class, test.getType());
+        assertEquals(str, test.convertToString(array));
+        assertTrue(Arrays.equals(array, (byte[]) test.convertFromString(byte[].class, str)));
+    }
+
+    @Test
     public void test_Boolean() {
         JDKStringConverter test = JDKStringConverter.BOOLEAN;
         doTest(test, Boolean.class, Boolean.TRUE, "true");
diff --git a/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java
new file mode 100644
index 0000000..bbc4c66
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java
@@ -0,0 +1,112 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.joda.convert.factory.NumericArrayStringConverterFactory;
+import org.junit.Test;
+
+/**
+ * Test NumericArrayStringConverterFactory.
+ */
+public class TestNumericArrayStringConverterFactory {
+
+    @Test
+    public void test_longArray() {
+        doTest(new long[0], "");
+        doTest(new long[] {5}, "5");
+        doTest(new long[] {-1234, 56789}, "-1234,56789");
+        doTest(new long[] {12345678912345L, 12345678912345L}, "12345678912345,12345678912345");
+    }
+
+    private void doTest(long[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(long[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(long[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_intArray() {
+        doTest(new int[0], "");
+        doTest(new int[] {5}, "5");
+        doTest(new int[] {-1234, 56789}, "-1234,56789");
+    }
+
+    private void doTest(int[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(int[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(int[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_shortArray() {
+        doTest(new short[0], "");
+        doTest(new short[] {5}, "5");
+        doTest(new short[] {-1234, 5678}, "-1234,5678");
+    }
+
+    private void doTest(short[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(short[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(short[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_doubleArray() {
+        doTest(new double[0], "");
+        doTest(new double[] {5d}, "5.0");
+        doTest(new double[] {5.123456789d}, "5.123456789");
+        doTest(new double[] {-1234d, 5678d}, "-1234.0,5678.0");
+        doTest(new double[] {Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, -0.0d, +0.0d, 0d}, "NaN,-Infinity,Infinity,-0.0,0.0,0.0");
+        doTest(new double[] {0.0000006d, 6000000000d}, "6.0E-7,6.0E9");
+    }
+
+    private void doTest(double[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(double[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(double[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_floatArray() {
+        doTest(new float[0], "");
+        doTest(new float[] {5f}, "5.0");
+        doTest(new float[] {5.1234f}, "5.1234");
+        doTest(new float[] {-1234f, 5678f}, "-1234.0,5678.0");
+        doTest(new float[] {Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, -0.0f, +0.0f, 0f}, "NaN,-Infinity,Infinity,-0.0,0.0,0.0");
+        doTest(new float[] {0.0000006f, 6000000000f}, "6.0E-7,6.0E9");
+    }
+
+    private void doTest(float[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(float[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(float[].class, str)));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/TestNumericObjectArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestNumericObjectArrayStringConverterFactory.java
new file mode 100644
index 0000000..3fde3f1
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestNumericObjectArrayStringConverterFactory.java
@@ -0,0 +1,117 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.joda.convert.factory.NumericObjectArrayStringConverterFactory;
+import org.junit.Test;
+
+/**
+ * Test NumericObjectArrayStringConverterFactory.
+ */
+public class TestNumericObjectArrayStringConverterFactory {
+
+    @Test
+    public void test_LongArray() {
+        doTest(new Long[0], "");
+        doTest(new Long[] {5L}, "5");
+        doTest(new Long[] {null}, "-");
+        doTest(new Long[] {-1234L, null, 56789L, null, null, 5L}, "-1234,-,56789,-,-,5");
+        doTest(new Long[] {12345678912345L, 12345678912345L}, "12345678912345,12345678912345");
+    }
+
+    private void doTest(Long[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Long[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Long[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_IntegerArray() {
+        doTest(new Integer[0], "");
+        doTest(new Integer[] {5}, "5");
+        doTest(new Integer[] {null}, "-");
+        doTest(new Integer[] {-1234, null, 56789, null, null, 5}, "-1234,-,56789,-,-,5");
+    }
+
+    private void doTest(Integer[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Integer[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Integer[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_ShortArray() {
+        doTest(new Short[0], "");
+        doTest(new Short[] {5}, "5");
+        doTest(new Short[] {null}, "-");
+        doTest(new Short[] {-1234, null, 5678, null, null, 5}, "-1234,-,5678,-,-,5");
+    }
+
+    private void doTest(Short[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Short[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Short[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_DoubleArray() {
+        doTest(new Double[0], "");
+        doTest(new Double[] {5d}, "5.0");
+        doTest(new Double[] {null}, "-");
+        doTest(new Double[] {5.123456789d}, "5.123456789");
+        doTest(new Double[] {-1234d, null, 5678d, null, null, 5d}, "-1234.0,-,5678.0,-,-,5.0");
+        doTest(new Double[] {Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, -0.0d, +0.0d, 0d}, "NaN,-Infinity,Infinity,-0.0,0.0,0.0");
+        doTest(new Double[] {0.0000006d, 6000000000d}, "6.0E-7,6.0E9");
+    }
+
+    private void doTest(Double[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Double[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Double[].class, str)));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void test_FloatArray() {
+        doTest(new Float[0], "");
+        doTest(new Float[] {5f}, "5.0");
+        doTest(new Float[] {null}, "-");
+        doTest(new Float[] {5.1234f}, "5.1234");
+        doTest(new Float[] {-1234f, null, 5678f, null, null, 5f}, "-1234.0,-,5678.0,-,-,5.0");
+        doTest(new Float[] {Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, -0.0f, +0.0f, 0f}, "NaN,-Infinity,Infinity,-0.0,0.0,0.0");
+        doTest(new Float[] {0.0000006f, 6000000000f}, "6.0E-7,6.0E9");
+    }
+
+    private void doTest(Float[] array, String str) {
+        StringConvert test = new StringConvert(true, NumericObjectArrayStringConverterFactory.INSTANCE);
+        assertEquals(str, test.convertToString(array));
+        assertEquals(str, test.convertToString(Float[].class, array));
+        assertTrue(Arrays.equals(array, test.convertFromString(Float[].class, str)));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/TestStringConvert.java b/src/test/java/org/joda/convert/TestStringConvert.java
index ddca01d..f3a6580 100644
--- a/src/test/java/org/joda/convert/TestStringConvert.java
+++ b/src/test/java/org/joda/convert/TestStringConvert.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2011 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
 package org.joda.convert;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
@@ -58,6 +60,14 @@ public class TestStringConvert {
 
     //-----------------------------------------------------------------------
     @Test
+    public void test_isConvertible() {
+        assertTrue(StringConvert.INSTANCE.isConvertible(Integer.class));
+        assertTrue(StringConvert.INSTANCE.isConvertible(String.class));
+        assertFalse(StringConvert.INSTANCE.isConvertible(Object.class));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
     public void test_convertToString() {
         Integer i = 6;
         assertEquals("6", StringConvert.INSTANCE.convertToString(i));
@@ -87,6 +97,13 @@ public class TestStringConvert {
     }
 
     @Test
+    public void test_convertToString_withType_noGenerics() {
+        Integer i = 6;
+        Class<?> cls = Integer.class;
+        assertEquals("6", StringConvert.INSTANCE.convertToString(cls, i));
+    }
+
+    @Test
     public void test_convertToString_withType_primitive1() {
         int i = 6;
         assertEquals("6", StringConvert.INSTANCE.convertToString(Integer.class, i));
@@ -150,6 +167,14 @@ public class TestStringConvert {
     }
 
     //-----------------------------------------------------------------------
+    @Test
+    public void test_findConverter() {
+        Class<Integer> cls = Integer.class;
+        StringConverter<Integer> conv = StringConvert.INSTANCE.findConverter(cls);
+        assertEquals(Integer.valueOf(12), conv.convertFromString(cls, "12"));
+        assertEquals("12", conv.convertToString(12));
+    }
+
     @Test(expected=IllegalArgumentException.class)
     public void test_findConverter_null() {
         StringConvert.INSTANCE.findConverter(null);
@@ -162,6 +187,25 @@ public class TestStringConvert {
 
     //-----------------------------------------------------------------------
     @Test
+    public void test_findConverterNoGenerics() {
+        Class<?> cls = Integer.class;
+        StringConverter<Object> conv = StringConvert.INSTANCE.findConverterNoGenerics(cls);
+        assertEquals(Integer.valueOf(12), conv.convertFromString(cls, "12"));
+        assertEquals("12", conv.convertToString(12));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void test_findConverterNoGenerics_null() {
+        StringConvert.INSTANCE.findConverterNoGenerics(null);
+    }
+
+    @Test(expected=IllegalStateException.class)
+    public void test_findConverterNoGenerics_Object() {
+        StringConvert.INSTANCE.findConverterNoGenerics(Object.class);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
     public void test_convert_annotationMethodMethod() {
         StringConvert test = new StringConvert();
         DistanceMethodMethod d = new DistanceMethodMethod(25);
diff --git a/src/test/java/org/joda/convert/TestStringConverterFactory.java b/src/test/java/org/joda/convert/TestStringConverterFactory.java
new file mode 100644
index 0000000..884926a
--- /dev/null
+++ b/src/test/java/org/joda/convert/TestStringConverterFactory.java
@@ -0,0 +1,61 @@
+/*
+ *  Copyright 2010-present Stephen Colebourne
+ *
+ *  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.joda.convert;
+
+import static org.junit.Assert.assertSame;
+
+import org.junit.Test;
+
+/**
+ * Test StringConvert factory.
+ */
+public class TestStringConverterFactory {
+
+    @Test
+    public void test_constructor() {
+        StringConvert test = new StringConvert(true, new Factory1());
+        assertSame(MockDistanceStringConverter.INSTANCE, test.findConverter(DistanceMethodMethod.class));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void test_constructor_null() {
+        new StringConvert(true, (StringConverterFactory[]) null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void test_constructor_nullInArray() {
+        new StringConvert(true, new StringConverterFactory[] {null});
+    }
+
+    @Test
+    public void test_registerFactory() {
+        StringConvert test = new StringConvert();
+        test.registerFactory(new Factory1());
+        assertSame(MockDistanceStringConverter.INSTANCE, test.findConverter(DistanceMethodMethod.class));
+    }
+
+    static class Factory1 implements StringConverterFactory {
+        @Override
+        public StringConverter<?> findConverter(Class<?> cls) {
+            if (cls == DistanceMethodMethod.class) {
+                return MockDistanceStringConverter.INSTANCE;
+            }
+            return null;
+        }
+        
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test1/Test1Class.java b/src/test/java/org/joda/convert/test1/Test1Class.java
index 46e29e1..964dc70 100644
--- a/src/test/java/org/joda/convert/test1/Test1Class.java
+++ b/src/test/java/org/joda/convert/test1/Test1Class.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test1/Test1Interface.java b/src/test/java/org/joda/convert/test1/Test1Interface.java
index 34624aa..a20f12e 100644
--- a/src/test/java/org/joda/convert/test1/Test1Interface.java
+++ b/src/test/java/org/joda/convert/test1/Test1Interface.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test2/Test2Class.java b/src/test/java/org/joda/convert/test2/Test2Class.java
index 2cfe734..df90aac 100644
--- a/src/test/java/org/joda/convert/test2/Test2Class.java
+++ b/src/test/java/org/joda/convert/test2/Test2Class.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test2/Test2Factory.java b/src/test/java/org/joda/convert/test2/Test2Factory.java
index 8e83ca4..c5fe8e9 100644
--- a/src/test/java/org/joda/convert/test2/Test2Factory.java
+++ b/src/test/java/org/joda/convert/test2/Test2Factory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test2/Test2Interface.java b/src/test/java/org/joda/convert/test2/Test2Interface.java
index f8937f5..d68189a 100644
--- a/src/test/java/org/joda/convert/test2/Test2Interface.java
+++ b/src/test/java/org/joda/convert/test2/Test2Interface.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test3/Test3Class.java b/src/test/java/org/joda/convert/test3/Test3Class.java
index 3c4ed74..45d2627 100644
--- a/src/test/java/org/joda/convert/test3/Test3Class.java
+++ b/src/test/java/org/joda/convert/test3/Test3Class.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test3/Test3Factory.java b/src/test/java/org/joda/convert/test3/Test3Factory.java
index bd364c6..d3e2719 100644
--- a/src/test/java/org/joda/convert/test3/Test3Factory.java
+++ b/src/test/java/org/joda/convert/test3/Test3Factory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test3/Test3Interface.java b/src/test/java/org/joda/convert/test3/Test3Interface.java
index ac69dc1..06aab3f 100644
--- a/src/test/java/org/joda/convert/test3/Test3Interface.java
+++ b/src/test/java/org/joda/convert/test3/Test3Interface.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test3/Test3SuperClass.java b/src/test/java/org/joda/convert/test3/Test3SuperClass.java
index b0225ee..83ff91b 100644
--- a/src/test/java/org/joda/convert/test3/Test3SuperClass.java
+++ b/src/test/java/org/joda/convert/test3/Test3SuperClass.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test4/Test4Class.java b/src/test/java/org/joda/convert/test4/Test4Class.java
index c026a2f..a386ce0 100644
--- a/src/test/java/org/joda/convert/test4/Test4Class.java
+++ b/src/test/java/org/joda/convert/test4/Test4Class.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test4/Test4Factory.java b/src/test/java/org/joda/convert/test4/Test4Factory.java
index dd5de49..dff11fd 100644
--- a/src/test/java/org/joda/convert/test4/Test4Factory.java
+++ b/src/test/java/org/joda/convert/test4/Test4Factory.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
diff --git a/src/test/java/org/joda/convert/test4/Test4Interface.java b/src/test/java/org/joda/convert/test4/Test4Interface.java
index fd8d64f..8602f5a 100644
--- a/src/test/java/org/joda/convert/test4/Test4Interface.java
+++ b/src/test/java/org/joda/convert/test4/Test4Interface.java
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2010-2013 Stephen Colebourne
+ *  Copyright 2010-present Stephen Colebourne
  *
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/joda-convert.git



More information about the pkg-java-commits mailing list