[joda-convert] 04/07: Imported Upstream version 1.7

Tony Mancill tmancill at moszumanska.debian.org
Sat Sep 5 22:04:40 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 15443424d5b73240727fca8ab61d60bb4ab040a5
Author: tony mancill <tmancill at debian.org>
Date:   Sat Sep 5 14:46:03 2015 -0700

    Imported Upstream version 1.7
---
 .gitignore                                         |   11 +
 .travis.yml                                        |   12 +
 README.md                                          |   63 ++
 pom.xml                                            | 1084 ++++++++++----------
 src/changes/changes.xml                            |  226 ++--
 src/main/checkstyle/checkstyle.xml                 |  286 +++---
 .../convert/AnnotationStringConverterFactory.java  |  467 +++++----
 .../joda/convert/EnumStringConverterFactory.java   |   87 ++
 .../java/org/joda/convert/FromStringFactory.java   |   98 +-
 .../java/org/joda/convert/JDKStringConverter.java  |   60 +-
 .../convert/MethodConstructorStringConverter.java  |    7 +
 .../org/joda/convert/MethodsStringConverter.java   |   12 +-
 .../joda/convert/ReflectionStringConverter.java    |    3 +-
 src/main/java/org/joda/convert/RenameHandler.java  |  213 ++++
 src/main/java/org/joda/convert/StringConvert.java  |  112 +-
 .../org/joda/convert/StringConverterFactory.java   |   74 +-
 src/main/java/org/joda/convert/TypedAdapter.java   |   59 ++
 ...erterFactory.java => TypedStringConverter.java} |   77 +-
 .../BooleanArrayStringConverterFactory.java        |  212 ++--
 .../BooleanObjectArrayStringConverterFactory.java  |  216 ++--
 .../ByteObjectArrayStringConverterFactory.java     |  226 ++--
 .../CharObjectArrayStringConverterFactory.java     |  262 ++---
 .../NumericArrayStringConverterFactory.java        |  502 ++++-----
 .../NumericObjectArrayStringConverterFactory.java  |  522 +++++-----
 src/site/resources/css/site.css                    |    2 -
 src/site/resources/download.html                   |   12 +-
 src/site/site.xml                                  |    3 +-
 src/site/xdoc/index.xml                            |   38 +-
 src/site/xdoc/userguide.xml                        |  404 +++++---
 .../DistanceMethodConstructorCharSequence.java     |   92 +-
 .../convert/DistanceMethodMethodCharSequence.java  |   92 +-
 .../convert/DistanceNoAnnotationsCharSequence.java |   96 +-
 .../java/org/joda/convert/DistanceWithFactory.java |   74 +-
 .../joda/convert/DistanceWithFactoryFactory.java   |   58 +-
 .../joda/convert/MockDistanceStringConverter.java  |    2 +
 .../joda/convert/MockIntegerStringConverter.java   |    2 +
 .../{test1/Test1Interface.java => Status.java}     |   54 +-
 .../TestBooleanArrayStringConverterFactory.java    |   92 +-
 ...stBooleanObjectArrayStringConverterFactory.java |   94 +-
 .../TestByteObjectArrayStringConverterFactory.java |   92 +-
 .../TestCharObjectArrayStringConverterFactory.java |   98 +-
 .../org/joda/convert/TestJDKStringConverters.java  |   39 +-
 .../TestNumericArrayStringConverterFactory.java    |  224 ++--
 ...stNumericObjectArrayStringConverterFactory.java |  234 ++---
 .../java/org/joda/convert/TestStringConvert.java   |  106 +-
 .../joda/convert/TestStringConverterFactory.java   |  133 +--
 .../{test1/Test1Interface.java => Validity.java}   |   54 +-
 ...Converter.java => ValidityStringConverter.java} |   96 +-
 .../java/org/joda/convert/test1/Test1Class.java    |   95 +-
 .../org/joda/convert/test1/Test1Interface.java     |   56 +-
 .../java/org/joda/convert/test2/Test2Class.java    |   79 +-
 .../java/org/joda/convert/test2/Test2Factory.java  |   62 +-
 .../org/joda/convert/test2/Test2Interface.java     |   60 +-
 .../java/org/joda/convert/test3/Test3Class.java    |   80 +-
 .../java/org/joda/convert/test3/Test3Factory.java  |   60 +-
 .../org/joda/convert/test3/Test3Interface.java     |   62 +-
 .../org/joda/convert/test3/Test3SuperClass.java    |   70 +-
 .../java/org/joda/convert/test4/Test4Class.java    |   79 +-
 .../java/org/joda/convert/test4/Test4Factory.java  |   74 +-
 .../org/joda/convert/test4/Test4Interface.java     |   60 +-
 60 files changed, 4389 insertions(+), 3530 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5928e6e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+/bin/
+/target/
+*.log
+/tests/
+.checkstyle
+.classpath
+.project
+/.settings/
+/nbproject/
+.idea
+*.iml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..424ff27
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+# This file enables the Travis continuous integration system, which
+# automatically builds and tests joda-convert for each GitHub commit or 
+# pull request on three separate JDKs.
+#
+# For more information, see https://travis-ci.org
+
+language: java
+
+jdk: 
+  - oraclejdk7
+  - openjdk7
+  - openjdk6
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..944fc6e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,63 @@
+Joda-Convert
+------------
+
+Joda-Convert provides a small set of classes to aid conversion between Objects and Strings.
+It is not intended to tackle the wider problem of Object to Object transformation.
+
+```java
+// conversion to String
+String str = StringConvert.INSTANCE.convertToString(foo);
+
+// conversion from String
+Foo bar = StringConvert.INSTANCE.convertFromString(Foo.class, str);
+```
+
+Joda-Convert supports two mechanisms of extending the list of supported conversions.
+The first is to write your own converter implementing an interface.
+The second is to use annotations.
+
+The ability of Joda-Convert to use annotations to define the conversion methods is a key difference from other projects.
+For example, most value classes, like <code>Currency</code> or <code>TimeZone</code>, already have methods
+to convert to and from a standard format String.
+Consider a <code>Distance</code> class:
+
+```java
+public class Distance {
+
+  @FromString
+  public static Distance parse(String str) { ... }
+
+  @ToString
+  public String getStandardOutput() { ... }
+
+}
+```
+
+As shown, the two methods may have any name. They must simply fulfil the required method signatures for conversion.
+The <code>FromString</code> annotation may also be applied to a constructor.
+
+When Joda-Convert is asked to convert between an object and a String, if there is no registered converter
+then the annotations are checked. If they are found, then the methods are called by reflection.
+
+Joda-Convert is licensed under the business-friendly [Apache 2.0 licence](http://www.joda.org/joda-convert/license.html).
+
+
+### Documentation
+Various documentation is available:
+
+* The [home page](http://www.joda.org/joda-convert/)
+* The helpful [user guide](http://www.joda.org/joda-convert/userguide.html)
+* The [Javadoc](http://www.joda.org/joda-convert/apidocs/index.html)
+* The change notes for the [releases](http://www.joda.org/joda-convert/changes-report.html)
+
+
+### Releases
+[Release 1.7](http://www.joda.org/joda-convert/download.html) is the current latest release.
+This release is considered stable and worthy of the 1.x tag.
+It depends on Java SE 6 or later.
+
+Available in the [Maven Central repository](http://search.maven.org/#artifactdetails|org.joda|joda-convert|1.7|jar)
+
+
+### Support
+Please use GitHub issues and Pull Requests for support.
diff --git a/pom.xml b/pom.xml
index 800f379..c68f892 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,543 +1,541 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project
-    xmlns="http://maven.apache.org/POM/4.0.0"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.joda</groupId>
-  <artifactId>joda-convert</artifactId>
-  <packaging>jar</packaging>
-  <name>Joda-Convert</name>
-  <version>1.5</version>
-  <description>Library to convert Objects to and from String</description>
-  <url>http://www.joda.org/joda-convert/</url>
-
-  <!-- ==================================================================== -->
-  <issueManagement>
-    <system>GitHub</system>
-    <url>https://github.com/JodaOrg/joda-convert/issues</url>
-  </issueManagement>
-  <inceptionYear>2010</inceptionYear>
-  <mailingLists>
-    <mailingList>
-      <name>Joda Convert Interest list</name>
-      <subscribe>https://lists.sourceforge.net/lists/listinfo/joda-convert-interest</subscribe>
-      <unsubscribe>https://lists.sourceforge.net/lists/listinfo/joda-convert-interest</unsubscribe>
-      <archive>http://sourceforge.net/mailarchive/forum.php?forum_name=joda-convert-interest</archive>
-    </mailingList>
-  </mailingLists>
-
-  <!-- ==================================================================== -->
-  <developers>
-    <developer>
-      <id>scolebourne</id>
-      <name>Stephen Colebourne</name>
-      <email></email>
-      <roles>
-        <role>Project Lead</role>
-      </roles>
-      <timezone>0</timezone>
-      <url>https://github.com/jodastephen</url>
-    </developer>
-  </developers>
-  <contributors>
-    <contributor>
-      <name>Chris Kent</name>
-      <url>https://github.com/cjkent</url>
-    </contributor>
-    <contributor>
-      <name>Raman Gupta</name>
-      <url>https://github.com/rocketraman</url>
-    </contributor>
-  </contributors>
-
-  <!-- ==================================================================== -->
-  <licenses>
-    <license>
-      <name>Apache 2</name>
-      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
-      <distribution>repo</distribution>
-    </license>
-  </licenses>
-  <scm>
-    <connection>scm:git:https://github.com/JodaOrg/joda-convert.git</connection>
-    <developerConnection>scm:git:git at github.com:JodaOrg/joda-convert.git</developerConnection>
-    <url>https://github.com/JodaOrg/joda-convert</url>
-  </scm>
-  <organization>
-    <name>Joda.org</name>
-    <url>http://www.joda.org</url>
-  </organization>
-
-  <!-- ==================================================================== -->
-  <build>
-    <resources>
-      <resource>
-        <targetPath>META-INF</targetPath>
-        <directory>${project.basedir}</directory>
-        <includes>
-          <include>LICENSE.txt</include>
-          <include>NOTICE.txt</include>
-        </includes>
-      </resource>
-    </resources>
-    <!-- define build -->
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-checkstyle-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>run-checkstyle</id>
-            <phase>process-sources</phase>
-            <goals>
-              <goal>checkstyle</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <configuration>
-          <archive>
-            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
-            <manifest>
-              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
-              <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
-            </manifest>
-          </archive>
-        </configuration>
-      </plugin>
-      <plugin>   
-        <groupId>org.apache.felix</groupId>
-        <artifactId>maven-bundle-plugin</artifactId>
-        <version>2.4.0</version>
-        <executions>
-          <execution>
-            <id>bundle-manifest</id>
-            <phase>process-classes</phase>
-            <goals>    
-              <goal>manifest</goal>
-            </goals>   
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-javadoc-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>attach-javadocs</id>
-            <phase>package</phase>
-            <goals>
-              <goal>jar</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-source-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>attach-sources</id>
-            <phase>package</phase>
-            <goals>
-              <goal>jar-no-fork</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <configuration>
-          <attach>false</attach>
-          <descriptors>
-            <descriptor>src/main/assembly/dist.xml</descriptor>
-          </descriptors>
-          <tarLongFileMode>gnu</tarLongFileMode>
-        </configuration>
-        <executions>
-          <execution>
-            <id>make-assembly</id>
-            <phase>deploy</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-site-plugin</artifactId>
-        <configuration>
-          <skipDeploy>true</skipDeploy>
-        </configuration>
-      </plugin>
-      <plugin><!-- invoke with mvn site-deploy -->
-        <groupId>com.github.github</groupId>
-        <artifactId>site-maven-plugin</artifactId>
-        <version>0.8</version>
-        <executions>
-          <execution>
-            <id>github-site</id>
-            <goals>
-              <goal>site</goal>
-            </goals>
-            <phase>site-deploy</phase>
-          </execution>
-        </executions>
-        <configuration>
-          <message>Create website for ${project.artifactId} v${project.version}</message>
-          <path>joda-convert</path>
-          <merge>true</merge>
-          <server>github</server>
-          <repositoryOwner>JodaOrg</repositoryOwner>
-          <repositoryName>jodaorg.github.io</repositoryName>
-          <branch>refs/heads/master</branch>
-        </configuration>
-      </plugin>
-    </plugins>
-    <!-- Manage plugin versions -->
-    <pluginManagement>
-      <plugins>
-        <!-- Maven build and reporting plugins (alphabetical) -->
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-assembly-plugin</artifactId>
-          <version>${maven-assembly-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-checkstyle-plugin</artifactId>
-          <version>${maven-checkstyle-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-changes-plugin</artifactId>
-          <version>${maven-changes-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-clean-plugin</artifactId>
-          <version>${maven-clean-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-compiler-plugin</artifactId>
-          <version>${maven-compiler-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-deploy-plugin</artifactId>
-          <version>${maven-deploy-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-dependency-plugin</artifactId>
-          <version>${maven-dependency-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-gpg-plugin</artifactId>
-          <version>${maven-gpg-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-install-plugin</artifactId>
-          <version>${maven-install-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-jar-plugin</artifactId>
-          <version>${maven-jar-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-javadoc-plugin</artifactId>
-          <version>${maven-javadoc-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-jxr-plugin</artifactId>
-          <version>${maven-jxr-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-plugin-plugin</artifactId>
-          <version>${maven-plugin-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-pmd-plugin</artifactId>
-          <version>${maven-pmd-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-project-info-reports-plugin</artifactId>
-          <version>${maven-project-info-reports-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-repository-plugin</artifactId>
-          <version>${maven-repository-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-resources-plugin</artifactId>
-          <version>${maven-resources-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-site-plugin</artifactId>
-          <version>${maven-site-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-source-plugin</artifactId>
-          <version>${maven-source-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-surefire-plugin</artifactId>
-          <version>${maven-surefire-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-surefire-report-plugin</artifactId>
-          <version>${maven-surefire-report-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-toolchains-plugin</artifactId>
-          <version>${maven-toolchains-plugin.version}</version>
-        </plugin>
-        <plugin>
-          <groupId>org.eclipse.m2e</groupId>
-          <artifactId>lifecycle-mapping</artifactId>
-          <version>1.0.0</version>
-          <configuration>
-            <lifecycleMappingMetadata>
-              <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.apache.felix</groupId>
-                    <artifactId>maven-bundle-plugin</artifactId>
-                    <versionRange>[2.4.0,)</versionRange>
-                    <goals>
-                      <goal>manifest</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-              </pluginExecutions>
-            </lifecycleMappingMetadata>
-          </configuration>
-        </plugin>
-      </plugins>
-    </pluginManagement>
-  </build>
-
-  <!-- ==================================================================== -->
-  <prerequisites>
-    <maven>3.0.4</maven>
-  </prerequisites>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <version>4.11</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <!-- ==================================================================== -->
-  <reporting>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-project-info-reports-plugin</artifactId>
-        <version>${maven-project-info-plugin.version}</version>
-        <reportSets>
-          <reportSet>
-            <reports>
-              <report>dependencies</report>
-              <report>dependency-info</report>
-              <report>issue-tracking</report>
-              <report>license</report>
-              <report>mailing-list</report>
-              <report>project-team</report>
-              <report>scm</report>
-              <report>summary</report>
-            </reports>
-          </reportSet>
-        </reportSets>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>${maven-checkstyle-plugin.version}</version>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-javadoc-plugin</artifactId>
-        <version>${maven-javadoc-plugin.version}</version>
-        <reportSets>
-          <reportSet>
-            <reports>
-              <report>javadoc</report>
-            </reports>
-          </reportSet>
-        </reportSets>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-report-plugin</artifactId>
-        <version>${maven-surefire-report-plugin.version}</version>
-        <configuration>
-           <showSuccess>true</showSuccess>
-        </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-changes-plugin</artifactId>
-        <version>${maven-changes-plugin.version}</version>
-        <reportSets>
-          <reportSet>
-            <reports>
-              <report>changes-report</report>
-            </reports>
-          </reportSet>
-        </reportSets>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jxr-plugin</artifactId>
-        <version>${maven-jxr-plugin.version}</version>
-        <reportSets>
-          <reportSet>
-            <reports>
-              <report>jxr</report>
-            </reports>
-          </reportSet>
-        </reportSets>
-      </plugin>
-    </plugins>
-  </reporting>
-
-  <!-- ==================================================================== -->
-  <distributionManagement>
-    <repository>
-      <id>sonatype-joda-staging</id>
-      <name>Sonatype OSS staging repository</name>
-      <url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
-      <layout>default</layout>
-    </repository>
-    <snapshotRepository>
-      <uniqueVersion>false</uniqueVersion>
-      <id>sonatype-joda-snapshot</id>
-      <name>Sonatype OSS snapshot repository</name>
-      <url>http://oss.sonatype.org/content/repositories/joda-snapshots</url>
-      <layout>default</layout>
-    </snapshotRepository>
-    <downloadUrl>http://oss.sonatype.org/content/repositories/joda-releases</downloadUrl>
-  </distributionManagement>
-
-  <!-- ==================================================================== -->
-  <profiles>
-    <profile>
-      <id>repo-sign-artifacts</id>
-      <activation>
-        <property>
-          <name>oss.repo</name>
-          <value>true</value>
-        </property>
-      </activation>
-      <build>
-        <plugins>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-toolchains-plugin</artifactId>
-            <executions>
-              <execution>
-                <phase>validate</phase>
-                <goals>
-                  <goal>toolchain</goal>
-                </goals>
-              </execution>
-            </executions>
-            <configuration>
-              <toolchains>
-                <jdk>
-                  <version>1.6</version>
-                  <vendor>sun</vendor>
-                </jdk>
-              </toolchains>
-            </configuration>
-          </plugin>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-gpg-plugin</artifactId>
-            <executions>
-              <execution>
-                <id>sign-artifacts</id>
-                <phase>verify</phase>
-                <goals>
-                  <goal>sign</goal>
-                </goals>
-              </execution>
-            </executions>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-  </profiles>
-
-  <!-- ==================================================================== -->
-  <properties>
-    <!-- Plugin version numbers -->
-    <maven-assembly-plugin.version>2.4</maven-assembly-plugin.version>
-    <maven-changes-plugin.version>2.9</maven-changes-plugin.version>
-    <maven-checkstyle-plugin.version>2.10</maven-checkstyle-plugin.version>
-    <maven-clean-plugin.version>2.5</maven-clean-plugin.version>
-    <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
-    <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.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>
-    <maven-plugin-plugin.version>3.2</maven-plugin-plugin.version>
-    <maven-pmd-plugin.version>3.0.1</maven-pmd-plugin.version>
-    <maven-project-info-reports-plugin.version>2.7</maven-project-info-reports-plugin.version>
-    <maven-repository-plugin.version>2.3.1</maven-repository-plugin.version>
-    <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.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>
-    <maven.compiler.source>1.6</maven.compiler.source>
-    <maven.compiler.target>1.6</maven.compiler.target>
-    <maven.compiler.fork>true</maven.compiler.fork>
-    <maven.compiler.verbose>true</maven.compiler.verbose>
-    <maven.compiler.debug>true</maven.compiler.debug>
-    <maven.compiler.optimize>true</maven.compiler.optimize>
-    <!-- Properties for maven-javadoc-plugin -->
-    <author>false</author>
-    <notimestamp>true</notimestamp>
-    <!-- Properties for maven-checkstyle-plugin -->
-    <checkstyle.config.location>${project.basedir}/src/main/checkstyle/checkstyle.xml</checkstyle.config.location>
-    <!-- Other properties -->
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-  </properties>
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+    xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.joda</groupId>
+  <artifactId>joda-convert</artifactId>
+  <packaging>jar</packaging>
+  <name>Joda-Convert</name>
+  <version>1.7</version>
+  <description>Library to convert Objects to and from String</description>
+  <url>http://www.joda.org/joda-convert/</url>
+
+  <!-- ==================================================================== -->
+  <issueManagement>
+    <system>GitHub</system>
+    <url>https://github.com/JodaOrg/joda-convert/issues</url>
+  </issueManagement>
+  <inceptionYear>2010</inceptionYear>
+
+  <!-- ==================================================================== -->
+  <developers>
+    <developer>
+      <id>jodastephen</id>
+      <name>Stephen Colebourne</name>
+      <roles>
+        <role>Project Lead</role>
+      </roles>
+      <timezone>0</timezone>
+      <url>https://github.com/jodastephen</url>
+    </developer>
+  </developers>
+  <contributors>
+    <contributor>
+      <name>Chris Kent</name>
+      <url>https://github.com/cjkent</url>
+    </contributor>
+    <contributor>
+      <name>Raman Gupta</name>
+      <url>https://github.com/rocketraman</url>
+    </contributor>
+  </contributors>
+
+  <!-- ==================================================================== -->
+  <licenses>
+    <license>
+      <name>Apache 2</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:git:https://github.com/JodaOrg/joda-convert.git</connection>
+    <developerConnection>scm:git:git at github.com:JodaOrg/joda-convert.git</developerConnection>
+    <url>https://github.com/JodaOrg/joda-convert</url>
+  </scm>
+  <organization>
+    <name>Joda.org</name>
+    <url>http://www.joda.org</url>
+  </organization>
+
+  <!-- ==================================================================== -->
+  <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+      <resource>
+        <targetPath>META-INF</targetPath>
+        <directory>${project.basedir}</directory>
+        <includes>
+          <include>LICENSE.txt</include>
+          <include>NOTICE.txt</include>
+        </includes>
+      </resource>
+    </resources>
+    <!-- define build -->
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>run-checkstyle</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>checkstyle</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+            <manifest>
+              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+              <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+            </manifest>
+          </archive>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.4.0</version>
+        <executions>
+          <execution>
+            <id>bundle-manifest</id>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>manifest</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-javadocs</id>
+            <phase>package</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>package</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <attach>false</attach>
+          <descriptors>
+            <descriptor>src/main/assembly/dist.xml</descriptor>
+          </descriptors>
+          <tarLongFileMode>gnu</tarLongFileMode>
+        </configuration>
+        <executions>
+          <execution>
+            <id>make-assembly</id>
+            <phase>deploy</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-site-plugin</artifactId>
+        <configuration>
+          <skipDeploy>true</skipDeploy>
+        </configuration>
+      </plugin>
+      <plugin><!-- invoke with mvn site-deploy -->
+        <groupId>com.github.github</groupId>
+        <artifactId>site-maven-plugin</artifactId>
+        <version>0.9</version>
+        <executions>
+          <execution>
+            <id>github-site</id>
+            <goals>
+              <goal>site</goal>
+            </goals>
+            <phase>site-deploy</phase>
+          </execution>
+        </executions>
+        <configuration>
+          <message>Create website for ${project.artifactId} v${project.version}</message>
+          <path>${project.artifactId}</path>
+          <merge>true</merge>
+          <server>github</server>
+          <repositoryOwner>JodaOrg</repositoryOwner>
+          <repositoryName>jodaorg.github.io</repositoryName>
+          <branch>refs/heads/master</branch>
+        </configuration>
+      </plugin>
+    </plugins>
+    <!-- Manage plugin versions -->
+    <pluginManagement>
+      <plugins>
+        <!-- Maven build and reporting plugins (alphabetical) -->
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-assembly-plugin</artifactId>
+          <version>${maven-assembly-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-checkstyle-plugin</artifactId>
+          <version>${maven-checkstyle-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-changes-plugin</artifactId>
+          <version>${maven-changes-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-clean-plugin</artifactId>
+          <version>${maven-clean-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>${maven-compiler-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-deploy-plugin</artifactId>
+          <version>${maven-deploy-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-dependency-plugin</artifactId>
+          <version>${maven-dependency-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-gpg-plugin</artifactId>
+          <version>${maven-gpg-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-install-plugin</artifactId>
+          <version>${maven-install-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>${maven-jar-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-javadoc-plugin</artifactId>
+          <version>${maven-javadoc-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-jxr-plugin</artifactId>
+          <version>${maven-jxr-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-plugin-plugin</artifactId>
+          <version>${maven-plugin-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-pmd-plugin</artifactId>
+          <version>${maven-pmd-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-project-info-reports-plugin</artifactId>
+          <version>${maven-project-info-reports-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-repository-plugin</artifactId>
+          <version>${maven-repository-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-resources-plugin</artifactId>
+          <version>${maven-resources-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-site-plugin</artifactId>
+          <version>${maven-site-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-source-plugin</artifactId>
+          <version>${maven-source-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>${maven-surefire-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-report-plugin</artifactId>
+          <version>${maven-surefire-report-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-toolchains-plugin</artifactId>
+          <version>${maven-toolchains-plugin.version}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <versionRange>[2.4.0,)</versionRange>
+                    <goals>
+                      <goal>manifest</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore></ignore>
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <!-- ==================================================================== -->
+  <prerequisites>
+    <maven>3.0.4</maven>
+  </prerequisites>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <!-- ==================================================================== -->
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+        <version>${maven-project-info-plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>dependencies</report>
+              <report>dependency-info</report>
+              <report>issue-tracking</report>
+              <report>license</report>
+              <report>project-team</report>
+              <report>scm</report>
+              <report>summary</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${maven-checkstyle-plugin.version}</version>
+        <configuration>
+          <includeResources>false</includeResources>
+          <includeTestResources>false</includeTestResources>
+          <includeTestSourceDirectory>false</includeTestSourceDirectory>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>${maven-javadoc-plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>javadoc</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+        <version>${maven-surefire-report-plugin.version}</version>
+        <configuration>
+           <showSuccess>true</showSuccess>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+        <version>${maven-changes-plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+        <version>${maven-jxr-plugin.version}</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>jxr</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <!-- ==================================================================== -->
+  <distributionManagement>
+    <repository>
+      <id>sonatype-joda-staging</id>
+      <name>Sonatype OSS staging repository</name>
+      <url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+      <layout>default</layout>
+    </repository>
+    <snapshotRepository>
+      <uniqueVersion>false</uniqueVersion>
+      <id>sonatype-joda-snapshot</id>
+      <name>Sonatype OSS snapshot repository</name>
+      <url>http://oss.sonatype.org/content/repositories/joda-snapshots</url>
+      <layout>default</layout>
+    </snapshotRepository>
+    <downloadUrl>http://oss.sonatype.org/content/repositories/joda-releases</downloadUrl>
+  </distributionManagement>
+
+  <!-- ==================================================================== -->
+  <profiles>
+    <profile>
+      <id>repo-sign-artifacts</id>
+      <activation>
+        <property>
+          <name>oss.repo</name>
+          <value>true</value>
+        </property>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-toolchains-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>validate</phase>
+                <goals>
+                  <goal>toolchain</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <toolchains>
+                <jdk>
+                  <version>1.6</version>
+                  <vendor>sun</vendor>
+                </jdk>
+              </toolchains>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+  <!-- ==================================================================== -->
+  <properties>
+    <!-- Plugin version numbers -->
+    <maven-assembly-plugin.version>2.4</maven-assembly-plugin.version>
+    <maven-changes-plugin.version>2.9</maven-changes-plugin.version>
+    <maven-checkstyle-plugin.version>2.11</maven-checkstyle-plugin.version>
+    <maven-clean-plugin.version>2.5</maven-clean-plugin.version>
+    <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
+    <maven-deploy-plugin.version>2.8.1</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.5.1</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>
+    <maven-plugin-plugin.version>3.2</maven-plugin-plugin.version>
+    <maven-pmd-plugin.version>3.0.1</maven-pmd-plugin.version>
+    <maven-project-info-reports-plugin.version>2.7</maven-project-info-reports-plugin.version>
+    <maven-repository-plugin.version>2.3.1</maven-repository-plugin.version>
+    <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.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>
+    <maven.compiler.source>1.6</maven.compiler.source>
+    <maven.compiler.target>1.6</maven.compiler.target>
+    <maven.compiler.fork>true</maven.compiler.fork>
+    <maven.compiler.verbose>true</maven.compiler.verbose>
+    <maven.compiler.debug>true</maven.compiler.debug>
+    <maven.compiler.optimize>true</maven.compiler.optimize>
+    <!-- Properties for maven-javadoc-plugin -->
+    <author>false</author>
+    <notimestamp>true</notimestamp>
+    <!-- Properties for maven-checkstyle-plugin -->
+    <checkstyle.config.location>${project.basedir}/src/main/checkstyle/checkstyle.xml</checkstyle.config.location>
+    <!-- Other properties -->
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+  </properties>
+</project>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 08a9b09..5306580 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -1,106 +1,120 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<document>
-  <properties>
-    <title>Java convert - Changes</title>
-    <author>Stephen Colebourne</author>
-  </properties>
-
-  <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.
-      </action>
-      <action dev="scolebourne" type="add" >
-        Home page at GitHub.
-      </action>
-      <action dev="scolebourne" type="add" >
-        Add support for FromString using a factory. Issue #5.
-      </action>
-      <action dev="scolebourne" type="update" >
-        Change to use m2e Maven Eclipse.
-      </action>
-    </release>
-    <release version="1.3.1" date="2013-03-08" description="Version 1.3.1">
-      <action dev="rocketraman" type="fix" >
-        Fix OSGI manifest.
-      </action>
-    </release>
-    <release version="1.3" date="2013-01-25" description="Version 1.3">
-      <action dev="scolebourne" type="add" >
-        Add register method designed for JDK 1.8 method references or lambdas.
-      </action>
-      <action dev="scolebourne" type="update" >
-        Change to requiring JDK 1.6.
-      </action>
-      <action dev="scolebourne" type="add" >
-        Add alternate package locations for JSR-310 classes.
-      </action>
-    </release>
-    <release version="1.2" date="2011-10-27" description="Version 1.2">
-      <action dev="scolebourne" type="add" >
-        Add support for CharSequence based fromString methods.
-      </action>
-      <action dev="scolebourne" type="add" >
-        Add support for JSR-310 by reflection, avoiding a dependency.
-      </action>
-      <action dev="scolebourne" type="add" >
-        Allow registration of conversions by method name.
-      </action>
-      <action dev="scolebourne" type="add" >
-        Allow toString conversion to specify the desired type.
-      </action>
-    </release>
-    <release version="1.1.2" date="2011-10-21" description="Version 1.1.2">
-      <action dev="scolebourne" type="fix" >
-        Allow conversion of primitive types.
-      </action>
-    </release>
-    <release version="1.1.1" date="2011-10-24" description="Version 1.1.1">
-      <action dev="scolebourne" type="fix" >
-        Allow conversion of primitive types
-      </action>
-    </release>
-    <release version="1.1" date="2010-12-04" description="Version 1.1">
-      <action dev="scolebourne" type="fix" >
-        Enable superclass factories.
-      </action>
-    </release>
-    <release version="1.0" date="2010-09-05" description="Version 1.0">
-      <action dev="scolebourne" type="fix" >
-        Lots of tests and fixes.
-      </action>
-    </release>
-    <release version="0.5" date="unreleased" description="Version 0.5">
-      <action dev="scolebourne" type="fix" >
-        Initial checkin.
-      </action>
-    </release>
-  </body>
-</document>
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<document>
+  <properties>
+    <title>Java convert - Changes</title>
+    <author>Stephen Colebourne</author>
+  </properties>
+
+  <body>
+    <!-- types are add, fix, remove, update -->
+    <release version="1.7" date="2014-08-04" description="Version 1.7">
+      <action dev="jodastephen" type="add" >
+        Add ability to extract the effective type.
+        Useful when serializing data to avoid exposing private subclasses.
+        The effective type is the class defining the FromString.
+        Fixes #8.
+      </action>
+    </release>
+    <release version="1.6" date="2014-01-27" description="Version 1.6">
+      <action dev="jodastephen" type="add" >
+        Add support for renaming types and enum constants.
+        Fixes #6.
+      </action>
+    </release>
+    <release version="1.5" date="2013-09-17" description="Version 1.5">
+      <action dev="jodastephen" type="add" >
+        Add support for all primitive object arrays.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add support for boolean[].
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add support for numeric primitive arrays.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add support for char[] and byte[].
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add StringConverterFactory for more flexible initialization.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Weaken generics to better support framework-level access.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add isConvertible() method.
+      </action>
+      <action dev="jodastephen" 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="jodastephen" type="update" >
+        Change to use Maven plugin for OSGi, changing some published info.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Home page at GitHub.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add support for FromString using a factory. Issue #5.
+      </action>
+      <action dev="jodastephen" type="update" >
+        Change to use m2e Maven Eclipse.
+      </action>
+    </release>
+    <release version="1.3.1" date="2013-03-08" description="Version 1.3.1">
+      <action dev="rocketraman" type="fix" >
+        Fix OSGI manifest.
+      </action>
+    </release>
+    <release version="1.3" date="2013-01-25" description="Version 1.3">
+      <action dev="jodastephen" type="add" >
+        Add register method designed for JDK 1.8 method references or lambdas.
+      </action>
+      <action dev="jodastephen" type="update" >
+        Change to requiring JDK 1.6.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add alternate package locations for JSR-310 classes.
+      </action>
+    </release>
+    <release version="1.2" date="2011-10-27" description="Version 1.2">
+      <action dev="jodastephen" type="add" >
+        Add support for CharSequence based fromString methods.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Add support for JSR-310 by reflection, avoiding a dependency.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Allow registration of conversions by method name.
+      </action>
+      <action dev="jodastephen" type="add" >
+        Allow toString conversion to specify the desired type.
+      </action>
+    </release>
+    <release version="1.1.2" date="2011-10-21" description="Version 1.1.2">
+      <action dev="jodastephen" type="fix" >
+        Allow conversion of primitive types.
+      </action>
+    </release>
+    <release version="1.1.1" date="2011-10-24" description="Version 1.1.1">
+      <action dev="jodastephen" type="fix" >
+        Allow conversion of primitive types
+      </action>
+    </release>
+    <release version="1.1" date="2010-12-04" description="Version 1.1">
+      <action dev="jodastephen" type="fix" >
+        Enable superclass factories.
+      </action>
+    </release>
+    <release version="1.0" date="2010-09-05" description="Version 1.0">
+      <action dev="jodastephen" type="fix" >
+        Lots of tests and fixes.
+      </action>
+    </release>
+    <release version="0.5" date="unreleased" description="Version 0.5">
+      <action dev="jodastephen" type="fix" >
+        Initial checkin.
+      </action>
+    </release>
+  </body>
+</document>
diff --git a/src/main/checkstyle/checkstyle.xml b/src/main/checkstyle/checkstyle.xml
index bb0c77a..cea7994 100644
--- a/src/main/checkstyle/checkstyle.xml
+++ b/src/main/checkstyle/checkstyle.xml
@@ -1,143 +1,143 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
-
-<module name="Checker">
-  <property name="severity" value="warning"/>
-  <module name="TreeWalker">
-    <property name="tabWidth" value="4"/>
-    <module name="FileContentsHolder"/>
-    <module name="ConstantName">
-      <property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$|^[a-z][a-zA-Z0-9]*$"/>
-    </module>
-    <module name="AvoidStarImport">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="EmptyBlock">
-      <property name="tokens" value="LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_IF,LITERAL_FOR,LITERAL_TRY,LITERAL_WHILE,STATIC_INIT"/>
-    </module>
-    <module name="EmptyForInitializerPad">
-      <property name="option" value="space"/>
-    </module>
-    <module name="EmptyForIteratorPad">
-      <property name="option" value="space"/>
-    </module>
-    <module name="EqualsHashCode"/>
-    <module name="IllegalImport"/>
-    <module name="IllegalInstantiation">
-      <property name="classes" value="Boolean"/>
-    </module>
-    <module name="JavadocType">
-      <property name="scope" value="protected"/>
-    </module>
-    <module name="JavadocMethod">
-      <property name="scope" value="protected"/>
-      <property name="allowUndeclaredRTE" value="true"/>
-      <property name="allowMissingThrowsTags" value="true"/>
-      <property name="allowMissingJavadoc" value="true"/>
-      <property name="allowMissingPropertyJavadoc" value="true"/>
-      <property name="logLoadErrors" value="true"/>
-      <property name="suppressLoadErrors" value="true"/>
-    </module>
-    <module name="JavadocVariable">
-      <property name="scope" value="protected"/>
-    </module>
-    <module name="LeftCurly">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="LineLength">
-      <property name="ignorePattern" value="^ *\* *[^ ]+$"/>
-      <property name="max" value="200"/>
-      <property name="tabWidth" value="2"/>
-    </module>
-    <module name="LocalFinalVariableName"/>
-    <module name="LocalVariableName"/>
-    <module name="MemberName">
-      <property name="format" value="^[a-z][a-zA-Z0-9$]*$"/>
-    </module>
-    <module name="MethodLength">
-      <property name="max" value="300"/>
-    </module>
-    <module name="MethodName"/>
-    <module name="ModifierOrder">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="NeedBraces">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="NoWhitespaceAfter"/>
-    <module name="NoWhitespaceBefore">
-      <property name="allowLineBreaks" value="true"/>
-      <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
-    </module>
-    <module name="OperatorWrap">
-      <property name="option" value="eol"/>
-      <property name="tokens" value="ASSIGN, DIV_ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN, STAR_ASSIGN, MOD_ASSIGN, SR_ASSIGN, BSR_ASSIGN, SL_ASSIGN, BXOR_ASSIGN, BOR_ASSIGN, BAND_ASSIGN"/>
-    </module>
-    <module name="PackageName"/>
-    <module name="ParameterName"/>
-    <module name="ParameterNumber">
-      <property name="max" value="20"/>
-    </module>
-    <module name="ParenPad"/>
-    <module name="RedundantImport"/>
-    <module name="RedundantModifier"/>
-    <module name="RightCurly">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="StaticVariableName">
-      <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
-    </module>
-    <module name="TypeName"/>
-    <module name="TypecastParenPad"/>
-    <module name="UpperEll">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="VisibilityModifier"/>
-    <module name="WhitespaceAfter"/>
-    <module name="WhitespaceAround">
-      <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAND,LCURLY,LE,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/>
-      <property name="allowEmptyConstructors" value="true"/>
-      <property name="allowEmptyMethods" value="true"/>
-    </module>
-    <module name="MissingDeprecated"/>
-    <module name="MissingOverride"/>
-    <module name="PackageAnnotation"/>
-    <module name="CovariantEquals"/>
-    <module name="DefaultComesLast"/>
-    <module name="ExplicitInitialization"/>
-    <module name="FallThrough"/>
-    <module name="InnerAssignment"/>
-    <module name="StringLiteralEquality"/>
-    <module name="GenericWhitespace"/>
-    <module name="MethodParamPad"/>
-    <module name="FinalClass"/>
-    <module name="MutableException"/>
-    <module name="ArrayTypeStyle">
-      <property name="severity" value="error"/>
-    </module>
-    <module name="Indentation">
-      <property name="basicOffset" value="4"/>
-      <property name="caseIndent" value="4"/>
-    </module>
-  </module>
-  <!-- Header inlined due to m2e -->
-  <module name="RegexpHeader">
-    <property name="header" value="^/\*[*]?\n^ \*  Copyright 2010[-]present Stephen Colebourne"/>
-    <property name="fileExtensions" value="java"/>
-  </module>
-  <module name="SuppressionCommentFilter">
-    <property name="offCommentFormat" value="CSOFF"/>
-    <property name="onCommentFormat" value="CSON"/>
-  </module>
-  <module name="FileLength"/>
-  <module name="FileTabCharacter">
-    <property name="eachLine" value="true"/>
-    <property name="severity" value="error"/>
-  </module>
-  <module name="NewlineAtEndOfFile"/>
-  <module name="SuppressWithNearbyCommentFilter">
-    <property name="commentFormat" value="CSIGNORE"/>
-    <property name="checkFormat" value=".*"/>
-    <property name="checkC" value="false"/>
-  </module>
-</module>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<module name="Checker">
+  <property name="severity" value="warning"/>
+  <module name="TreeWalker">
+    <property name="tabWidth" value="4"/>
+    <module name="FileContentsHolder"/>
+    <module name="ConstantName">
+      <property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$|^[a-z][a-zA-Z0-9]*$"/>
+    </module>
+    <module name="AvoidStarImport">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="EmptyBlock">
+      <property name="tokens" value="LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_IF,LITERAL_FOR,LITERAL_TRY,LITERAL_WHILE,STATIC_INIT"/>
+    </module>
+    <module name="EmptyForInitializerPad">
+      <property name="option" value="space"/>
+    </module>
+    <module name="EmptyForIteratorPad">
+      <property name="option" value="space"/>
+    </module>
+    <module name="EqualsHashCode"/>
+    <module name="IllegalImport"/>
+    <module name="IllegalInstantiation">
+      <property name="classes" value="Boolean"/>
+    </module>
+    <module name="JavadocType">
+      <property name="scope" value="protected"/>
+    </module>
+    <module name="JavadocMethod">
+      <property name="scope" value="protected"/>
+      <property name="allowUndeclaredRTE" value="true"/>
+      <property name="allowMissingThrowsTags" value="true"/>
+      <property name="allowMissingJavadoc" value="true"/>
+      <property name="allowMissingPropertyJavadoc" value="true"/>
+      <property name="logLoadErrors" value="true"/>
+      <property name="suppressLoadErrors" value="true"/>
+    </module>
+    <module name="JavadocVariable">
+      <property name="scope" value="protected"/>
+    </module>
+    <module name="LeftCurly">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="LineLength">
+      <property name="ignorePattern" value="^ *\* *[^ ]+$"/>
+      <property name="max" value="200"/>
+      <property name="tabWidth" value="2"/>
+    </module>
+    <module name="LocalFinalVariableName"/>
+    <module name="LocalVariableName"/>
+    <module name="MemberName">
+      <property name="format" value="^[a-z][a-zA-Z0-9$]*$"/>
+    </module>
+    <module name="MethodLength">
+      <property name="max" value="300"/>
+    </module>
+    <module name="MethodName"/>
+    <module name="ModifierOrder">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="NeedBraces">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="NoWhitespaceAfter"/>
+    <module name="NoWhitespaceBefore">
+      <property name="allowLineBreaks" value="true"/>
+      <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
+    </module>
+    <module name="OperatorWrap">
+      <property name="option" value="eol"/>
+      <property name="tokens" value="ASSIGN, DIV_ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN, STAR_ASSIGN, MOD_ASSIGN, SR_ASSIGN, BSR_ASSIGN, SL_ASSIGN, BXOR_ASSIGN, BOR_ASSIGN, BAND_ASSIGN"/>
+    </module>
+    <module name="PackageName"/>
+    <module name="ParameterName"/>
+    <module name="ParameterNumber">
+      <property name="max" value="20"/>
+    </module>
+    <module name="ParenPad"/>
+    <module name="RedundantImport"/>
+    <module name="RedundantModifier"/>
+    <module name="RightCurly">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="StaticVariableName">
+      <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+    </module>
+    <module name="TypeName"/>
+    <module name="TypecastParenPad"/>
+    <module name="UpperEll">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="VisibilityModifier"/>
+    <module name="WhitespaceAfter"/>
+    <module name="WhitespaceAround">
+      <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAND,LCURLY,LE,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/>
+      <property name="allowEmptyConstructors" value="true"/>
+      <property name="allowEmptyMethods" value="true"/>
+    </module>
+    <module name="MissingDeprecated"/>
+    <module name="MissingOverride"/>
+    <module name="PackageAnnotation"/>
+    <module name="CovariantEquals"/>
+    <module name="DefaultComesLast"/>
+    <module name="ExplicitInitialization"/>
+    <module name="FallThrough"/>
+    <module name="InnerAssignment"/>
+    <module name="StringLiteralEquality"/>
+    <module name="GenericWhitespace"/>
+    <module name="MethodParamPad"/>
+    <module name="FinalClass"/>
+    <module name="MutableException"/>
+    <module name="ArrayTypeStyle">
+      <property name="severity" value="error"/>
+    </module>
+    <module name="Indentation">
+      <property name="basicOffset" value="4"/>
+      <property name="caseIndent" value="4"/>
+    </module>
+  </module>
+  <!-- Header inlined due to m2e -->
+  <module name="RegexpHeader">
+    <property name="header" value="^/\*[*]?\n^ \*  Copyright 2010[-]present Stephen Colebourne"/>
+    <property name="fileExtensions" value="java"/>
+  </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CSOFF"/>
+    <property name="onCommentFormat" value="CSON"/>
+  </module>
+  <module name="FileLength"/>
+  <module name="FileTabCharacter">
+    <property name="eachLine" value="true"/>
+    <property name="severity" value="error"/>
+  </module>
+  <module name="NewlineAtEndOfFile"/>
+  <module name="SuppressWithNearbyCommentFilter">
+    <property name="commentFormat" value="CSIGNORE"/>
+    <property name="checkFormat" value=".*"/>
+    <property name="checkC" value="false"/>
+  </module>
+</module>
diff --git a/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java b/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java
index c22cfb3..b5d85d2 100644
--- a/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/AnnotationStringConverterFactory.java
@@ -1,222 +1,245 @@
-/*
- *  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();
-    }
-
-}
+/*
+ *  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
+     */
+    @Override
+    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;
+        }
+        MethodConstructorStringConverter<T> con = findFromStringConstructor(cls, toString);
+        MethodsStringConverter<T> mth = findFromStringMethod(cls, toString, con == null);  // optionally checks superclasses
+        if (con == null && mth == null) {
+            throw new IllegalStateException("Class annotated with @ToString but not with @FromString: " + cls.getName());
+        }
+        if (con != null && mth != null) {
+            throw new IllegalStateException("Both method and constructor are annotated with @FromString: " + cls.getName());
+        }
+        return (con != null ? con : mth);
+    }
+
+    /**
+     * 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 : eliminateEnumSubclass(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
+     * @param toString  the toString method, not null
+     * @return the method to call, null means none found
+     * @throws RuntimeException if invalid
+     */
+    private <T> MethodConstructorStringConverter<T> findFromStringConstructor(Class<T> cls, Method toString) {
+        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);
+        if (fromString == null) {
+            return null;
+        }
+        return new MethodConstructorStringConverter<T>(cls, toString, con);
+    }
+
+    /**
+     * Finds the conversion method.
+     * 
+     * @param cls  the class to find a method for, not null
+     * @param toString  the toString method, not null
+     * @param searchSuperclasses  whether to search superclasses
+     * @return the method to call, null means not found
+     * @throws RuntimeException if invalid
+     */
+    private <T> MethodsStringConverter<T> findFromStringMethod(Class<T> cls, Method toString, boolean searchSuperclasses) {
+        // find in superclass hierarchy
+        Class<?> loopCls = cls;
+        while (loopCls != null) {
+            Method fromString = findFromString(loopCls);
+            if (fromString != null) {
+                return new MethodsStringConverter<T>(cls, toString, fromString, loopCls);
+            }
+            if (searchSuperclasses == false) {
+                break;
+            }
+            loopCls = loopCls.getSuperclass();
+        }
+        // find in immediate parent interfaces
+        MethodsStringConverter<T> matched = null;
+        if (searchSuperclasses) {
+            for (Class<?> loopIfc : eliminateEnumSubclass(cls).getInterfaces()) {
+                Method fromString = findFromString(loopIfc);
+                if (fromString != null) {
+                    if (matched != null) {
+                        throw new IllegalStateException("Two different interfaces are annotated with " +
+                            "@FromString or @FromStringFactory: " + cls.getName());
+                    }
+                    matched = new MethodsStringConverter<T>(cls, toString, fromString, loopIfc);
+                }
+            }
+        }
+        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) {
+        // find in declared methods
+        Method[] methods = cls.getDeclaredMethods();
+        Method matched = null;
+        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;
+    }
+
+    // eliminates enum subclass as they are pesky
+    private Class<?> eliminateEnumSubclass(Class<?> cls) {
+        Class<?> sup = cls.getSuperclass();
+        if (sup != null && sup.getSuperclass() == Enum.class) {
+            return sup;
+        }
+        return cls;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/EnumStringConverterFactory.java b/src/main/java/org/joda/convert/EnumStringConverterFactory.java
new file mode 100644
index 0000000..8ad2753
--- /dev/null
+++ b/src/main/java/org/joda/convert/EnumStringConverterFactory.java
@@ -0,0 +1,87 @@
+/*
+ *  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 for {@code StringConverter} looking up enums.
+ * <p>
+ * This class is immutable and thread-safe.
+ * 
+ * @since 1.7
+ */
+final class EnumStringConverterFactory implements StringConverterFactory {
+
+    /**
+     * Singleton instance.
+     */
+    static final StringConverterFactory INSTANCE = new EnumStringConverterFactory();
+
+    /**
+     * Restricted constructor.
+     */
+    private EnumStringConverterFactory() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * 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
+     */
+    @Override
+    public StringConverter<?> findConverter(Class<?> cls) {
+        Class<?> sup = cls.getSuperclass();
+        if (sup == Enum.class) {
+            return new EnumStringConverter(cls);
+        } else if (sup != null && sup.getSuperclass() == Enum.class) {
+            return new EnumStringConverter(sup);
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    final class EnumStringConverter implements TypedStringConverter<Enum<?>> {
+        
+        private final Class<?> effectiveType;
+        
+        EnumStringConverter(Class<?> effectiveType) {
+            this.effectiveType = effectiveType;
+        }
+
+        @Override
+        public String convertToString(Enum<?> en) {
+            return en.name();  // avoid toString() as that can be overridden
+        }
+        @Override
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        public Enum<?> convertFromString(Class<? extends Enum<?>> cls, String str) {
+            return RenameHandler.INSTANCE.lookupEnum((Class) cls, str);
+        }
+        @Override
+        public Class<?> getEffectiveType() {
+            return effectiveType;
+        }
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/FromStringFactory.java b/src/main/java/org/joda/convert/FromStringFactory.java
index 3e970df..7531ac0 100644
--- a/src/main/java/org/joda/convert/FromStringFactory.java
+++ b/src/main/java/org/joda/convert/FromStringFactory.java
@@ -1,49 +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 java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation used on a type to indicate that another class, the factory,
- * provides the 'from string' method.
- * <p>
- * This annotation is applied at the type level, typically to an interface.
- * It indicates the class which contains the relevant {@code FromString}
- * annotation, which follows the normal rules.
- * <p>
- * For example, the interface {@code Foo} could be annotated to define its
- * associated factory as being {@code FooFactory}. The {@code FooFactory}
- * class would then be expected to provide a method returning {@code Foo}
- * with a single {@code String} parameter, annotated with {@code FromString}.
- * 
- * @since 1.4
- */
- at Target(ElementType.TYPE)
- at Retention(RetentionPolicy.RUNTIME)
-public @interface FromStringFactory {
-
-    /**
-     * The factory class containing the static method.
-     * The static method must have a return type of the type that declares
-     * the factory annotation.
-     */
-    Class<?> factory();
-
-}
+/*
+ *  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.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used on a type to indicate that another class, the factory,
+ * provides the 'from string' method.
+ * <p>
+ * This annotation is applied at the type level, typically to an interface.
+ * It indicates the class which contains the relevant {@code FromString}
+ * annotation, which follows the normal rules.
+ * <p>
+ * For example, the interface {@code Foo} could be annotated to define its
+ * associated factory as being {@code FooFactory}. The {@code FooFactory}
+ * class would then be expected to provide a method returning {@code Foo}
+ * with a single {@code String} parameter, annotated with {@code FromString}.
+ * 
+ * @since 1.4
+ */
+ at Target(ElementType.TYPE)
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface FromStringFactory {
+
+    /**
+     * The factory class containing the static method.
+     * The static method must have a return type of the type that declares
+     * the factory annotation.
+     */
+    Class<?> factory();
+
+}
diff --git a/src/main/java/org/joda/convert/JDKStringConverter.java b/src/main/java/org/joda/convert/JDKStringConverter.java
index b74f0a8..d9e52b8 100644
--- a/src/main/java/org/joda/convert/JDKStringConverter.java
+++ b/src/main/java/org/joda/convert/JDKStringConverter.java
@@ -41,12 +41,13 @@ import javax.xml.bind.DatatypeConverter;
 /**
  * Conversion between JDK classes and a {@code String}.
  */
-enum JDKStringConverter implements StringConverter<Object> {
+enum JDKStringConverter implements TypedStringConverter<Object> {
 
     /**
      * String converter.
      */
     STRING(String.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return str;
         }
@@ -55,6 +56,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * CharSequence converter.
      */
     CHAR_SEQUENCE(CharSequence.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return str;
         }
@@ -63,6 +65,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * StringBuffer converter.
      */
     STRING_BUFFER(StringBuffer.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new StringBuffer(str);
         }
@@ -71,6 +74,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * StringBuilder converter.
      */
     STRING_BUILDER(StringBuilder.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new StringBuilder(str);
         }
@@ -79,6 +83,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Long converter.
      */
     LONG(Long.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new Long(str);
         }
@@ -88,6 +93,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Integer converter.
      */
     INTEGER(Integer.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new Integer(str);
         }
@@ -97,6 +103,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Short converter.
      */
     SHORT (Short.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new Short(str);
         }
@@ -106,6 +113,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Byte converter.
      */
     BYTE(Byte.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new Byte(str);
         }
@@ -118,6 +126,7 @@ enum JDKStringConverter implements StringConverter<Object> {
         public String convertToString(Object object) {
             return DatatypeConverter.printBase64Binary((byte[]) object);
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return DatatypeConverter.parseBase64Binary(str);
         }
@@ -126,6 +135,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Character converter.
      */
     CHARACTER(Character.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             if (str.length() != 1) {
                 throw new IllegalArgumentException("Character value must be a string length 1");
@@ -141,6 +151,7 @@ enum JDKStringConverter implements StringConverter<Object> {
         public String convertToString(Object object) {
             return new String((char[]) object);
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return str.toCharArray();
         }
@@ -149,6 +160,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Boolean converter.
      */
     BOOLEAN(Boolean.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             if ("true".equalsIgnoreCase(str)) {
                 return Boolean.TRUE;
@@ -163,6 +175,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Double converter.
      */
     DOUBLE(Double.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new Double(str);
         }
@@ -171,6 +184,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Float converter.
      */
     FLOAT(Float.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new Float(str);
         }
@@ -179,6 +193,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * BigInteger converter.
      */
     BIG_INTEGER(BigInteger.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new BigInteger(str);
         }
@@ -187,6 +202,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * BigDecimal converter.
      */
     BIG_DECIMAL(BigDecimal.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new BigDecimal(str);
         }
@@ -195,6 +211,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * AtomicLong converter.
      */
     ATOMIC_LONG(AtomicLong.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             long val = Long.parseLong(str);
             return new AtomicLong(val);
@@ -204,6 +221,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * AtomicLong converter.
      */
     ATOMIC_INTEGER(AtomicInteger.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             int val = Integer.parseInt(str);
             return new AtomicInteger(val);
@@ -213,6 +231,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * AtomicBoolean converter.
      */
     ATOMIC_BOOLEAN(AtomicBoolean.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             if ("true".equalsIgnoreCase(str)) {
                 return new AtomicBoolean(true);
@@ -227,6 +246,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Locale converter.
      */
     LOCALE(Locale.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             String[] split = str.split("_", 3);
             switch (split.length) {
@@ -248,11 +268,12 @@ enum JDKStringConverter implements StringConverter<Object> {
         public String convertToString(Object object) {
             return ((Class<?>) object).getName();
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             try {
-                return getClass().getClassLoader().loadClass(str);
+                return RenameHandler.INSTANCE.lookupType(str);
             } catch (ClassNotFoundException ex) {
-                throw new RuntimeException("Unable to create class: " + str, ex);
+                throw new RuntimeException("Unable to create type: " + str, ex);
             }
         }
     },
@@ -264,6 +285,7 @@ enum JDKStringConverter implements StringConverter<Object> {
         public String convertToString(Object object) {
             return ((Package) object).getName();
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return Package.getPackage(str);
         }
@@ -272,6 +294,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * Currency converter.
      */
     CURRENCY(Currency.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return Currency.getInstance(str);
         }
@@ -284,6 +307,7 @@ enum JDKStringConverter implements StringConverter<Object> {
         public String convertToString(Object object) {
             return ((TimeZone) object).getID();
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return TimeZone.getTimeZone(str);
         }
@@ -292,6 +316,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * UUID converter.
      */
     UUID(UUID.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return java.util.UUID.fromString(str);
         }
@@ -300,6 +325,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * URL converter.
      */
     URL(URL.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             try {
                 return new URL(str);
@@ -312,6 +338,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * URI converter.
      */
     URI(URI.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return java.net.URI.create(str);
         }
@@ -324,6 +351,7 @@ enum JDKStringConverter implements StringConverter<Object> {
         public String convertToString(Object object) {
             return ((InetAddress) object).getHostAddress();
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             try {
                 return InetAddress.getByName(str);
@@ -336,6 +364,7 @@ enum JDKStringConverter implements StringConverter<Object> {
      * File converter.
      */
     FILE(File.class) {
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             return new File(str);
         }
@@ -350,6 +379,7 @@ enum JDKStringConverter implements StringConverter<Object> {
             String str = f.format(object);
             return str.substring(0, 26) + ":" + str.substring(26);
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             if (str.length() != 29) {
                 throw new IllegalArgumentException("Unable to parse date: " + str);
@@ -378,6 +408,7 @@ enum JDKStringConverter implements StringConverter<Object> {
             String str = f.format(cal.getTime());
             return str.substring(0, 26) + ":" + str.substring(26) + "[" + cal.getTimeZone().getID() + "]";
         }
+        @Override
         public Object convertFromString(Class<?> cls, String str) {
             if (str.length() < 31 || str.charAt(26) != ':'
                     || str.charAt(29) != '[' || str.charAt(str.length() - 1) != ']') {
@@ -397,19 +428,6 @@ enum JDKStringConverter implements StringConverter<Object> {
             }
         }
     },
-    /**
-     * Enum converter.
-     */
-    ENUM(Enum.class) {
-        @SuppressWarnings("rawtypes")
-        public String convertToString(Object object) {
-            return ((Enum) object).name();  // avoid toString() as that can be overridden
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public Object convertFromString(Class cls, String str) {
-            return Enum.valueOf(cls, str);
-        }
-    },
     ;
 
     /** The type. */
@@ -431,7 +449,17 @@ enum JDKStringConverter implements StringConverter<Object> {
         return type;
     }
 
+    /**
+     * Gets the type of the converter.
+     * @return the type, not null
+     */
+    @Override
+    public Class<?> getEffectiveType() {
+        return type;
+    }
+
     //-----------------------------------------------------------------------
+    @Override
     public String convertToString(Object object) {
         return object.toString();
     }
diff --git a/src/main/java/org/joda/convert/MethodConstructorStringConverter.java b/src/main/java/org/joda/convert/MethodConstructorStringConverter.java
index 9cf0c53..c0cd2f6 100644
--- a/src/main/java/org/joda/convert/MethodConstructorStringConverter.java
+++ b/src/main/java/org/joda/convert/MethodConstructorStringConverter.java
@@ -62,6 +62,7 @@ final class MethodConstructorStringConverter<T> extends ReflectionStringConverte
      * @param str  the string to convert, not null
      * @return the converted object, may be null but generally not
      */
+    @Override
     public T convertFromString(Class<? extends T> cls, String str) {
         try {
             return fromString.newInstance(str);
@@ -77,4 +78,10 @@ final class MethodConstructorStringConverter<T> extends ReflectionStringConverte
         }
     }
 
+    //-------------------------------------------------------------------------
+    @Override
+    public Class<?> getEffectiveType() {
+        return fromString.getDeclaringClass();
+    }
+
 }
diff --git a/src/main/java/org/joda/convert/MethodsStringConverter.java b/src/main/java/org/joda/convert/MethodsStringConverter.java
index 65aa5d4..455dfd0 100644
--- a/src/main/java/org/joda/convert/MethodsStringConverter.java
+++ b/src/main/java/org/joda/convert/MethodsStringConverter.java
@@ -36,6 +36,8 @@ final class MethodsStringConverter<T> extends ReflectionStringConverter<T> {
 
     /** Conversion from a string. */
     private final Method fromString;
+    /** Effective type. */
+    private final Class<?> effectiveType;
 
     /**
      * Creates an instance using two methods.
@@ -44,7 +46,7 @@ final class MethodsStringConverter<T> extends ReflectionStringConverter<T> {
      * @param fromString  the fromString method, not null
      * @throws RuntimeException (or subclass) if the method signatures are invalid
      */
-    MethodsStringConverter(Class<T> cls, Method toString, Method fromString) {
+    MethodsStringConverter(Class<T> cls, Method toString, Method fromString, Class<?> effectiveType) {
         super(cls, toString);
         if (Modifier.isStatic(fromString.getModifiers()) == false) {
             throw new IllegalStateException("FromString method must be static: " + fromString);
@@ -60,6 +62,7 @@ final class MethodsStringConverter<T> extends ReflectionStringConverter<T> {
             throw new IllegalStateException("FromString method must return specified class or a supertype: " + fromString);
         }
         this.fromString = fromString;
+        this.effectiveType = effectiveType;
     }
 
     //-----------------------------------------------------------------------
@@ -69,6 +72,7 @@ final class MethodsStringConverter<T> extends ReflectionStringConverter<T> {
      * @param str  the string to convert, not null
      * @return the converted object, may be null but generally not
      */
+    @Override
     public T convertFromString(Class<? extends T> cls, String str) {
         try {
             return cls.cast(fromString.invoke(null, str));
@@ -82,4 +86,10 @@ final class MethodsStringConverter<T> extends ReflectionStringConverter<T> {
         }
     }
 
+    //-------------------------------------------------------------------------
+    @Override
+    public Class<?> getEffectiveType() {
+        return effectiveType;
+    }
+
 }
diff --git a/src/main/java/org/joda/convert/ReflectionStringConverter.java b/src/main/java/org/joda/convert/ReflectionStringConverter.java
index 1cc8e30..702f652 100644
--- a/src/main/java/org/joda/convert/ReflectionStringConverter.java
+++ b/src/main/java/org/joda/convert/ReflectionStringConverter.java
@@ -28,7 +28,7 @@ import java.lang.reflect.Method;
  * 
  * @param <T>  the type of the converter
  */
-abstract class ReflectionStringConverter<T> implements StringConverter<T> {
+abstract class ReflectionStringConverter<T> implements TypedStringConverter<T> {
 
     /** The converted class. */
     private final Class<T> cls;
@@ -58,6 +58,7 @@ abstract class ReflectionStringConverter<T> implements StringConverter<T> {
      * @param object  the object to convert, not null
      * @return the converted string, may be null but generally not
      */
+    @Override
     public String convertToString(T object) {
         try {
             return (String) toString.invoke(object);
diff --git a/src/main/java/org/joda/convert/RenameHandler.java b/src/main/java/org/joda/convert/RenameHandler.java
new file mode 100644
index 0000000..1389471
--- /dev/null
+++ b/src/main/java/org/joda/convert/RenameHandler.java
@@ -0,0 +1,213 @@
+/*
+ *  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.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A general purpose utility for registering renames.
+ * <p>
+ * This handles type and enum constant renames.
+ * For example, use as follows:
+ * <pre>
+ *  RenameHandler.INSTANCE.renamedType("org.joda.OldName", NewName.class);
+ *  RenameHandler.INSTANCE.renamedEnum("CORRECT", Status.VALID);
+ *  RenameHandler.INSTANCE.renamedEnum("INCORRECT", Status.INVALID);
+ * </pre>
+ * The recommended usage is to edit the static singleton before using other classes.
+ * Editing a static is acceptable because renames are driven by bytecode which is static.
+ * <p>
+ * This class is thread-safe with concurrent caches.
+ * 
+ * @since 1.6
+ */
+public final class RenameHandler {
+
+    /**
+     * A mutable global instance.
+     * This is a singleton instance which is mutated.
+     */
+    public static final RenameHandler INSTANCE = new RenameHandler();
+
+    /**
+     * The type renames.
+     */
+    private final ConcurrentHashMap<String, Class<?>> typeRenames =
+                    new ConcurrentHashMap<String, Class<?>>(16, 0.75f, 2);
+    /**
+     * The enum renames.
+     */
+    private final ConcurrentHashMap<Class<?>, Map<String, Enum<?>>> enumRenames =
+                    new ConcurrentHashMap<Class<?>, Map<String, Enum<?>>>(16, 0.75f, 2);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     * <p>
+     * This is not normally used as the preferred option is to edit the singleton.
+     * 
+     * @return a new instance, not null
+     */
+    public static RenameHandler create() {
+        return new RenameHandler();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restricted constructor.
+     */
+    private RenameHandler() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Register the fact that a type was renamed.
+     * 
+     * @param oldName  the old name of the type including the package name, not null
+     * @param currentValue  the current type, not null
+     */
+    public void renamedType(String oldName, Class<?> currentValue) {
+        if (oldName == null) {
+            throw new IllegalArgumentException("oldName must not be null");
+        }
+        if (currentValue == null) {
+            throw new IllegalArgumentException("currentValue must not be null");
+        }
+        typeRenames.put(oldName, currentValue);
+    }
+
+    /**
+     * Gets the map of renamed types.
+     * <p>
+     * An empty map is returned if there are no renames.
+     * 
+     * @return a copy of the set of enum types with renames, not null
+     */
+    public Map<String, Class<?>> getTypeRenames() {
+        return new HashMap<String, Class<?>>(typeRenames);
+    }
+
+    /**
+     * Lookup a type from a name, handling renames.
+     * 
+     * @param name  the name of the type to lookup, not null
+     * @return the type, not null
+     * @throws ClassNotFoundException if the name is not a valid type
+     */
+    public Class<?> lookupType(String name) throws ClassNotFoundException {
+        if (name == null) {
+            throw new IllegalArgumentException("name must not be null");
+        }
+        Class<?> type = typeRenames.get(name);
+        if (type == null) {
+            type = loadType(name);
+        }
+        return type;
+    }
+
+    private Class<?> loadType(String fullName) throws ClassNotFoundException {
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        return loader != null ? loader.loadClass(fullName) : Class.forName(fullName);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Register the fact that an enum constant was renamed.
+     * 
+     * @param oldName  the old name of the enum constant, not null
+     * @param currentValue  the current enum constant, not null
+     */
+    public void renamedEnum(String oldName, Enum<?> currentValue) {
+        if (oldName == null) {
+            throw new IllegalArgumentException("oldName must not be null");
+        }
+        if (currentValue == null) {
+            throw new IllegalArgumentException("currentValue must not be null");
+        }
+        Class<?> enumType = currentValue.getDeclaringClass();
+        Map<String, Enum<?>> perClass = enumRenames.get(enumType);
+        if (perClass == null) {
+            enumRenames.putIfAbsent(enumType, new ConcurrentHashMap<String, Enum<?>>(16, 0.75f, 2));
+            perClass = enumRenames.get(enumType);
+        }
+        perClass.put(oldName, currentValue);
+    }
+
+    /**
+     * Gets the set of enum types that have renames.
+     * <p>
+     * An empty set is returned if there are no renames.
+     * 
+     * @return a copy of the set of enum types with renames, not null
+     */
+    public Set<Class<?>> getEnumTypesWithRenames() {
+        return new HashSet<Class<?>>(enumRenames.keySet());
+    }
+
+    /**
+     * Gets the map of renamed for an enum type.
+     * <p>
+     * An empty map is returned if there are no renames.
+     * 
+     * @param type  the enum type, not null
+     * @return a copy of the set of enum renames, not null
+     */
+    public Map<String, Enum<?>> getEnumRenames(Class<?> type) {
+        if (type == null) {
+            throw new IllegalArgumentException("type must not be null");
+        }
+        Map<String, Enum<?>> map = enumRenames.get(type);
+        if (map == null) {
+            return new HashMap<String, Enum<?>>();
+        }
+        return new HashMap<String, Enum<?>>(map);
+    }
+
+    /**
+     * Lookup an enum from a name, handling renames.
+     * 
+     * @param <T>  the type of the desired enum
+     * @param type  the enum type, not null
+     * @param name  the name of the enum to lookup, not null
+     * @return the enum value, not null
+     * @throws IllegalArgumentException if the name is not a valid enum constant
+     */
+    public <T extends Enum<T>> T lookupEnum(Class<T> type, String name) {
+        if (type == null) {
+            throw new IllegalArgumentException("type must not be null");
+        }
+        if (name == null) {
+            throw new IllegalArgumentException("name must not be null");
+        }
+        Map<String, Enum<?>> map = getEnumRenames(type);
+        Enum<?> value = map.get(name);
+        if (value != null) {
+            return type.cast(value);
+        }
+        return Enum.valueOf(type, name);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return "RenamedTypes" + typeRenames + ",RenamedEnumConstants" + enumRenames;
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/StringConvert.java b/src/main/java/org/joda/convert/StringConvert.java
index 56e99d7..3fd4046 100644
--- a/src/main/java/org/joda/convert/StringConvert.java
+++ b/src/main/java/org/joda/convert/StringConvert.java
@@ -50,7 +50,7 @@ public final class StringConvert {
     /**
      * The cached null object.
      */
-    private static final StringConverter<?> CACHED_NULL = new StringConverter<Object>() {
+    private static final TypedStringConverter<?> CACHED_NULL = new TypedStringConverter<Object>() {
         @Override
         public String convertToString(Object object) {
             return null;
@@ -59,6 +59,10 @@ public final class StringConvert {
         public Object convertFromString(Class<? extends Object> cls, String str) {
             return null;
         }
+        @Override
+        public Class<?> getEffectiveType() {
+            return null;
+        }
     };
 
     /**
@@ -68,7 +72,7 @@ public final class StringConvert {
     /**
      * The cache of converters.
      */
-    private final ConcurrentMap<Class<?>, StringConverter<?>> registered = new ConcurrentHashMap<Class<?>, StringConverter<?>>();
+    private final ConcurrentMap<Class<?>, TypedStringConverter<?>> registered = new ConcurrentHashMap<Class<?>, TypedStringConverter<?>>();
 
     //-----------------------------------------------------------------------
     /**
@@ -202,6 +206,9 @@ public final class StringConvert {
             this.factories.addAll(Arrays.asList(factories));
         }
         this.factories.add(AnnotationStringConverterFactory.INSTANCE);
+        if (includeJdkConverters) {
+            this.factories.add(EnumStringConverterFactory.INSTANCE);
+        }
     }
 
     /**
@@ -306,6 +313,7 @@ public final class StringConvert {
      * 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.
+     * Finally, it handles {@code Enum} instances.
      * 
      * @param <T>  the type of the converter
      * @param cls  the class to find a converter for, not null
@@ -313,7 +321,59 @@ public final class StringConvert {
      * @throws RuntimeException (or subclass) if no converter found
      */
     public <T> StringConverter<T> findConverter(final Class<T> cls) {
-        StringConverter<T> conv = findConverterQuiet(cls);
+        return findTypedConverter(cls);
+    }
+
+    /**
+     * 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.
+     * Finally, it handles {@code Enum} instances.
+     * 
+     * @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
+     */
+    public StringConverter<Object> findConverterNoGenerics(final Class<?> cls) {
+        return findTypedConverterNoGenerics(cls);
+    }
+
+    /**
+     * Finds a suitable converter for the type.
+     * <p>
+     * This returns an instance of {@code TypedStringConverter} for the specified class.
+     * 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.
+     * It then searches for {@code ToString} and {@code FromString} annotations on the
+     * specified class, class hierarchy or immediate parent interfaces.
+     * Finally, it handles {@code Enum} instances.
+     * <p>
+     * The returned converter may be queried for the effective type of the conversion.
+     * This can be used to find the best type to send in a serialized form.
+     * <p>
+     * NOTE: Changing the method return type of {@link #findConverter(Class)}
+     * would be source compatible but not binary compatible. As this is a low-level
+     * library, binary compatibility is important, hence the addition of this method.
+     * 
+     * @param <T>  the type of the converter
+     * @param cls  the class to find a converter for, not null
+     * @return the converter, not null
+     * @throws RuntimeException (or subclass) if no converter found
+     * @since 1.7
+     */
+    public <T> TypedStringConverter<T> findTypedConverter(final Class<T> cls) {
+        TypedStringConverter<T> conv = findConverterQuiet(cls);
         if (conv == null) {
             throw new IllegalStateException("No registered converter found: " + cls);
         }
@@ -323,7 +383,7 @@ public final class StringConvert {
     /**
      * Finds a suitable converter for the type with open generics.
      * <p>
-     * This returns an instance of {@code StringConverter} for the specified class.
+     * This returns an instance of {@code TypedStringConverter} 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.
@@ -332,15 +392,23 @@ public final class StringConvert {
      * 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.
+     * Finally, it handles {@code Enum} instances.
+     * <p>
+     * The returned converter may be queried for the effective type of the conversion.
+     * This can be used to find the best type to send in a serialized form.
+     * <p>
+     * NOTE: Changing the method return type of {@link #findConverterNoGenerics(Class)}
+     * would be source compatible but not binary compatible. As this is a low-level
+     * library, binary compatibility is important, hence the addition of this method.
      * 
      * @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
+     * @since 1.7
      */
     @SuppressWarnings("unchecked")
-    public StringConverter<Object> findConverterNoGenerics(final Class<?> cls) {
-        StringConverter<Object> conv = (StringConverter<Object>) findConverterQuiet(cls);
+    public TypedStringConverter<Object> findTypedConverterNoGenerics(final Class<?> cls) {
+        TypedStringConverter<Object> conv = (TypedStringConverter<Object>) findConverterQuiet(cls);
         if (conv == null) {
             throw new IllegalStateException("No registered converter found: " + cls);
         }
@@ -356,11 +424,11 @@ public final class StringConvert {
      * @throws RuntimeException if invalid
      */
     @SuppressWarnings("unchecked")
-    private <T> StringConverter<T> findConverterQuiet(final Class<T> cls) {
+    private <T> TypedStringConverter<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);
+        TypedStringConverter<T> conv = (TypedStringConverter<T>) registered.get(cls);
         if (conv == CACHED_NULL) {
             return null;
         }
@@ -389,12 +457,12 @@ public final class StringConvert {
      * @throws RuntimeException if invalid
      */
     @SuppressWarnings("unchecked")
-    private <T> StringConverter<T> findAnyConverter(final Class<T> cls) {
-        StringConverter<T> conv = null;
+    private <T> TypedStringConverter<T> findAnyConverter(final Class<T> cls) {
+        TypedStringConverter<T> conv = null;
         // check for registered on superclass
         Class<?> loopCls = cls.getSuperclass();
         while (loopCls != null && conv == null) {
-            conv = (StringConverter<T>) registered.get(loopCls);
+            conv = (TypedStringConverter<T>) registered.get(loopCls);
             if (conv != null && conv != CACHED_NULL) {
                 return conv;
             }
@@ -402,16 +470,16 @@ public final class StringConvert {
         }
         // check for registered on interfaces
         for (Class<?> loopIfc : cls.getInterfaces()) {
-            conv = (StringConverter<T>) registered.get(loopIfc);
+            conv = (TypedStringConverter<T>) registered.get(loopIfc);
             if (conv != null && conv != CACHED_NULL) {
                 return conv;
             }
         }
         // check factories
         for (StringConverterFactory factory : factories) {
-            conv = (StringConverter<T>) factory.findConverter(cls);
-            if (conv != null) {
-                return conv;
+            StringConverter<T> factoryConv = (StringConverter<T>) factory.findConverter(cls);
+            if (factoryConv != null) {
+                return TypedAdapter.adapt(cls, factoryConv);
             }
         }
         return null;
@@ -463,7 +531,7 @@ public final class StringConvert {
         if (this == INSTANCE) {
             throw new IllegalStateException("Global singleton cannot be extended");
         }
-        registered.put(cls, converter);
+        registered.put(cls, TypedAdapter.adapt(cls, converter));
     }
 
     /**
@@ -490,13 +558,19 @@ public final class StringConvert {
         if (fromString == null || toString == null) {
             throw new IllegalArgumentException("Converters must not be null");
         }
-        register(cls, new StringConverter<T>() {
+        register(cls, new TypedStringConverter<T>() {
+            @Override
             public String convertToString(T object) {
                 return toString.convertToString(object);
             }
+            @Override
             public T convertFromString(Class<? extends T> cls, String str) {
                 return fromString.convertFromString(cls, str);
             }
+            @Override
+            public Class<?> getEffectiveType() {
+                return cls;
+            }
         });
     }
 
@@ -531,7 +605,7 @@ public final class StringConvert {
         }
         Method toString = findToStringMethod(cls, toStringMethodName);
         Method fromString = findFromStringMethod(cls, fromStringMethodName);
-        MethodsStringConverter<T> converter = new MethodsStringConverter<T>(cls, toString, fromString);
+        MethodsStringConverter<T> converter = new MethodsStringConverter<T>(cls, toString, fromString, cls);
         registered.putIfAbsent(cls, converter);
     }
 
diff --git a/src/main/java/org/joda/convert/StringConverterFactory.java b/src/main/java/org/joda/convert/StringConverterFactory.java
index 067c575..7bdcf6f 100644
--- a/src/main/java/org/joda/convert/StringConverterFactory.java
+++ b/src/main/java/org/joda/convert/StringConverterFactory.java
@@ -1,37 +1,37 @@
-/*
- *  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 for {@code StringConverter} that allows converters to be
- * created dynamically or easily initialised.
- * <p>
- * Implementations must be immutable and thread-safe.
- * 
- * @since 1.5
- */
-public interface StringConverterFactory {
-
-    /**
-     * 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
-     */
-    StringConverter<?> findConverter(Class<?> cls);
-
-}
+/*
+ *  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 for {@code StringConverter} that allows converters to be
+ * created dynamically or easily initialised.
+ * <p>
+ * Implementations must be immutable and thread-safe.
+ * 
+ * @since 1.5
+ */
+public interface StringConverterFactory {
+
+    /**
+     * 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
+     */
+    StringConverter<?> findConverter(Class<?> cls);
+
+}
diff --git a/src/main/java/org/joda/convert/TypedAdapter.java b/src/main/java/org/joda/convert/TypedAdapter.java
new file mode 100644
index 0000000..bb6ba49
--- /dev/null
+++ b/src/main/java/org/joda/convert/TypedAdapter.java
@@ -0,0 +1,59 @@
+/*
+ *  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;
+
+/**
+ * Adapts {@code StringConverter} to {@code TypedStringConverter}.
+ * 
+ * @param <T>  the type of the converter
+ * @since 1.7
+ */
+final class TypedAdapter<T> implements TypedStringConverter<T> {
+
+    private final StringConverter<T> conv;
+    private final Class<?> effectiveType;
+
+    static <R> TypedStringConverter<R> adapt(final Class<R> cls, StringConverter<R> converter) {
+        if (converter instanceof TypedStringConverter) {
+            return (TypedStringConverter<R>) converter;
+        } else {
+            return new TypedAdapter<R>(converter, cls);
+        }
+    }
+
+    private TypedAdapter(StringConverter<T> conv, Class<?> effectiveType) {
+        this.conv = conv;
+        this.effectiveType = effectiveType;
+    }
+
+    @Override
+    public String convertToString(T object) {
+        return conv.convertToString(object);
+    }
+    @Override
+    public T convertFromString(Class<? extends T> cls, String str) {
+        return conv.convertFromString(cls, str);
+    }
+    @Override
+    public Class<?> getEffectiveType() {
+        return effectiveType;
+    }
+    @Override
+    public String toString() {
+        return "TypedAdapter:" + conv.toString();
+    }
+
+}
diff --git a/src/main/java/org/joda/convert/StringConverterFactory.java b/src/main/java/org/joda/convert/TypedStringConverter.java
similarity index 52%
copy from src/main/java/org/joda/convert/StringConverterFactory.java
copy to src/main/java/org/joda/convert/TypedStringConverter.java
index 067c575..6e31f21 100644
--- a/src/main/java/org/joda/convert/StringConverterFactory.java
+++ b/src/main/java/org/joda/convert/TypedStringConverter.java
@@ -1,37 +1,40 @@
-/*
- *  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 for {@code StringConverter} that allows converters to be
- * created dynamically or easily initialised.
- * <p>
- * Implementations must be immutable and thread-safe.
- * 
- * @since 1.5
- */
-public interface StringConverterFactory {
-
-    /**
-     * 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
-     */
-    StringConverter<?> findConverter(Class<?> cls);
-
-}
+/*
+ *  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;
+
+/**
+ * Interface defining conversion to and from a {@code String} together with the type.
+ * <p>
+ * TypedStringConverter 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.7
+ */
+public interface TypedStringConverter<T> extends StringConverter<T> {
+
+    /**
+     * Gets the effective type that the converter works on.
+     * <p>
+     * For example, if a class declares the {@code FromString} and  {@code ToString}
+     * then the effective type of the converter is that class. If a subclass is
+     * queried for a converter, then the effective type is that of the superclass.
+     * 
+     * @return the effective type
+     */
+    Class<?> getEffectiveType();
+
+}
diff --git a/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java b/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java
index ac1421c..479ba32 100644
--- a/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/factory/BooleanArrayStringConverterFactory.java
@@ -1,103 +1,109 @@
-/*
- *  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];
-    }
-
-}
+/*
+ *  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;
+import org.joda.convert.TypedStringConverter;
+
+/**
+ * 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
+     */
+    @Override
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == boolean[].class) {
+            return BooleanArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum BooleanArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return boolean[].class;
+            }
+        };
+        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
index 99a2caa..c1b6745 100644
--- a/src/main/java/org/joda/convert/factory/BooleanObjectArrayStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/factory/BooleanObjectArrayStringConverterFactory.java
@@ -1,105 +1,111 @@
-/*
- *  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];
-    }
-
-}
+/*
+ *  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;
+import org.joda.convert.TypedStringConverter;
+
+/**
+ * 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
+     */
+    @Override
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == Boolean[].class) {
+            return BooleanArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum BooleanArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Boolean[].class;
+            }
+        };
+        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
index b1cfbd8..e2056dd 100644
--- a/src/main/java/org/joda/convert/factory/ByteObjectArrayStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/factory/ByteObjectArrayStringConverterFactory.java
@@ -1,110 +1,116 @@
-/*
- *  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";
-    }
-
-}
+/*
+ *  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;
+import org.joda.convert.TypedStringConverter;
+
+/**
+ * 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
+     */
+    @Override
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == Byte[].class) {
+            return ByteArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum ByteArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Byte[].class;
+            }
+        };
+        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
index 2f17fc1..4fde8d0 100644
--- a/src/main/java/org/joda/convert/factory/CharObjectArrayStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/factory/CharObjectArrayStringConverterFactory.java
@@ -1,128 +1,134 @@
-/*
- *  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];
-    }
-
-}
+/*
+ *  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;
+import org.joda.convert.TypedStringConverter;
+
+/**
+ * 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
+     */
+    @Override
+    public StringConverter<?> findConverter(Class<?> cls) {
+        if (cls == Character[].class) {
+            return CharecterArrayStringConverter.INSTANCE;
+        }
+        return null;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return getClass().getSimpleName();
+    }
+
+    //-----------------------------------------------------------------------
+    enum CharecterArrayStringConverter implements TypedStringConverter<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);
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Character[].class;
+            }
+        };
+        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
index 5144697..b80e540 100644
--- a/src/main/java/org/joda/convert/factory/NumericArrayStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/factory/NumericArrayStringConverterFactory.java
@@ -1,240 +1,262 @@
-/*
- *  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];
-    }
-
-}
+/*
+ *  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;
+import org.joda.convert.TypedStringConverter;
+
+/**
+ * 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
+     */
+    @Override
+    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 TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return long[].class;
+            }
+        };
+        private static final long[] EMPTY = new long[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum IntArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return int[].class;
+            }
+        };
+        private static final int[] EMPTY = new int[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum ShortArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return short[].class;
+            }
+        };
+        private static final short[] EMPTY = new short[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum DoubleArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return double[].class;
+            }
+        };
+        private static final double[] EMPTY = new double[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum FloatArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return float[].class;
+            }
+        };
+        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
index 5514d94..51d5c3f 100644
--- a/src/main/java/org/joda/convert/factory/NumericObjectArrayStringConverterFactory.java
+++ b/src/main/java/org/joda/convert/factory/NumericObjectArrayStringConverterFactory.java
@@ -1,250 +1,272 @@
-/*
- *  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];
-    }
-
-}
+/*
+ *  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;
+import org.joda.convert.TypedStringConverter;
+
+/**
+ * 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
+     */
+    @Override
+    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 TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Long[].class;
+            }
+        };
+        private static final Long[] EMPTY = new Long[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum IntArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Integer[].class;
+            }
+        };
+        private static final Integer[] EMPTY = new Integer[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum ShortArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Short[].class;
+            }
+        };
+        private static final Short[] EMPTY = new Short[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum DoubleArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Double[].class;
+            }
+        };
+        private static final Double[] EMPTY = new Double[0];
+    }
+
+    //-----------------------------------------------------------------------
+    enum FloatArrayStringConverter implements TypedStringConverter<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;
+            }
+            @Override
+            public Class<?> getEffectiveType() {
+                return Float[].class;
+            }
+        };
+        private static final Float[] EMPTY = new Float[0];
+    }
+
+}
diff --git a/src/site/resources/css/site.css b/src/site/resources/css/site.css
index 2ed8bb6..747065c 100644
--- a/src/site/resources/css/site.css
+++ b/src/site/resources/css/site.css
@@ -57,8 +57,6 @@ p, ul {
 #bannerLeft, #bannerRight {
   font-size: 30px;
   color:black;
-  background-color:white;
-  border: 1px solid #999;
   padding: 0px 5px;
 }
 #banner a:hover {
diff --git a/src/site/resources/download.html b/src/site/resources/download.html
index c8048a5..3b37290 100644
--- a/src/site/resources/download.html
+++ b/src/site/resources/download.html
@@ -1,6 +1,6 @@
-<head>
-<title>OpenGamma</title>
-<meta http-equiv="REFRESH" content="0;url=http://sourceforge.net/projects/joda-convert/files/joda-convert/">
-</head>
-<body></body>
-</html>
+<head>
+<title>OpenGamma</title>
+<meta http-equiv="REFRESH" content="0;url=https://github.com/JodaOrg/joda-convert/releases">
+</head>
+<body></body>
+</html>
diff --git a/src/site/site.xml b/src/site/site.xml
index 239f80e..15281fc 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -24,12 +24,13 @@
     <menu name="Development">
       <item name="GitHub" href="https://github.com/JodaOrg/joda-convert"/>
       <item name="Bugs/Issues" href="https://github.com/JodaOrg/joda-convert/issues"/>
-      <item name="Sourceforge" href="http://sourceforge.net/projects/joda-convert/"/>
+      <item name="Test results" href="surefire-report.html"/>
     </menu>
 
     <menu name="Joda">
       <item name="Joda home" href="http://www.joda.org"/>
       <item name="Beans" href="http://www.joda.org/joda-beans/"/>
+      <item name="Collect" href="http://www.joda.org/joda-collect/"/>
       <item name="Money" href="http://www.joda.org/joda-money/"/>
       <item name="Primitives" href="http://www.joda.org/joda-primitives/"/>
       <item name="Time" href="http://www.joda.org/joda-time/"/>
diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml
index a71e6d2..12d7395 100644
--- a/src/site/xdoc/index.xml
+++ b/src/site/xdoc/index.xml
@@ -11,16 +11,16 @@
 
 <section name="Joda Convert">
 <p>
-Joda-Convert provides a small set of classes to aid conversion between Objects and Strings.
-It is not intended to tackle the wider problem of Object to Object transformation.
+Joda-Convert provides a small set of classes to provide round-trip conversion between Objects and Strings.
+It does not tackle the wider problem of Object to Object transformation.
 </p>
-<div style="border:1px solid black; padding: 0px 6px; margin: 4px;"><pre>
-// conversion to String
-String str = StringConvert.INSTANCE.convertToString(foo);
+<pre class="source">
+  // conversion to String
+  String str = StringConvert.INSTANCE.convertToString(foo);
 
-// conversion from String
-Foo bar = StringConvert.INSTANCE.convertFromString(Foo.class, str);
-</pre></div>
+  // conversion from String
+  Foo bar = StringConvert.INSTANCE.convertFromString(Foo.class, str);
+</pre>
 <p>
 Joda-Convert supports two mechanisms of extending the list of supported conversions.
 The first is to write your own converter implementing an interface.
@@ -32,17 +32,17 @@ For example, most value classes, like <code>Currency</code> or <code>TimeZone</c
 to convert to and from a standard format String.
 Consider a <code>Distance</code> class:
 </p>
-<div style="border:1px solid black; padding: 0px 6px; margin: 4px;"><pre>
-public class Distance {
+<pre class="source">
+  public class Distance {
 
-  @FromString
-  public static Distance parse(String str) { ... }
+    @FromString
+    public static Distance parse(String str) { ... }
 
-  @ToString
-  public String getStandardOutput() { ... }
+    @ToString
+    public String getStandardOutput() { ... }
 
-}
-</pre></div>
+  }
+</pre>
 <p>
 As shown, the two methods may have any name. They must simply fulfil the required method signatures for conversion.
 The <code>FromString</code> annotation may also be applied to a constructor.
@@ -72,12 +72,12 @@ Various documentation is available:
 
 <section name="Releases">
 <p>
-<a href="download.html">Release 1.5</a> is the current latest release.
+Release 1.7 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.
+It depends on Java SE 6 or later.
 </p>
 <p>
-Available in the <a href="http://search.maven.org/#artifactdetails|org.joda|joda-convert|1.5|jar">Maven Central repository</a>.
+Available in the <a href="http://search.maven.org/#artifactdetails|org.joda|joda-convert|1.7|jar">Maven Central repository</a>.
 </p>
 </section>
 
diff --git a/src/site/xdoc/userguide.xml b/src/site/xdoc/userguide.xml
index a32bd2a..77b2883 100644
--- a/src/site/xdoc/userguide.xml
+++ b/src/site/xdoc/userguide.xml
@@ -1,166 +1,238 @@
-<?xml version="1.0"?>
-
-<document>
-
- <properties>
-  <title>Joda Convert</title>
-  <author>Stephen Colebourne</author>
- </properties>
-
- <body>
-
-<section name="User guide">
-
-<p>
-Joda-Convert is intended for one simple task -
-Converting objects to and from strings.
-This is a common problem, particularly when communicating over textual protocols like XML or JSON.
-</p>
-
-<subsection name="Basic usage">
-<p>
-Using Joda-Convert is easy at the simplest level.
-The main access is via the class <code>StringConvert</code>.
-</p>
-<p>
-The easiest way to use the conversion is via the global constant:
-</p>
-<div style="border:1px solid black; padding: 0px 6px; margin: 4px;"><pre>
-// conversion to a String
-TimeZone zone = ...
-String str = StringConvert.INSTANCE.convertToString(zone);
-
-// conversion from a String
-TimeZone zone = StringConvert.INSTANCE.convertFromString(TimeZone.class, str);
-</pre></div>
-<p>
-In both cases, if the input is <code>null</code> then the output will also be <code>null</code>.
-</p>
-<p>
-The global constant is quick and easy to use, but is shared between all users in the <code>ClassLoader</code>.
-It also cannot be extended.
-</p>
-<p>
-The alternative approach is to instantiate your own instance of <code>StringConvert</code>.
-This would normally be stored in your own static variable, or made available as needed by dependency injection.
-This may be updated by registering your own converters.
-</p>
-</subsection>
-
-<subsection name="Converters">
-<p>
-Each instance of <code>StringConvert</code>, including the global singleton, includes a standard set of JDK-based converters.
-These cover all the standard JDK types for which conversion to and from a string is sensible.
-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>
-<p>
-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>
-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>
-
-<subsection name="Annotation based conversion">
-<p>
-If there is no registered converter for a type, then a search by annotation is performed.
-This will search for the <code>ToString</code> and <code>FromString</code> annotation on the type.
-These annotations will indicate which method should be called to perform the conversion.
-</p>
-<div style="border:1px solid black; padding: 0px 6px; margin: 4px;"><pre>
-public class Distance {
-
-  @FromString
-  public static Distance parse(String str) { ... }
-
-  @ToString
-  public String getStandardOutput() { ... }
-
-}
-</pre></div>
-<p>
-To be valid, the class must contain one <code>ToString</code> annotation and one <code>FromString</code> annotation.
-The <code>ToString</code> annotation must be an instance method taking no parameters and returning a String.
-The <code>FromString</code> annotation must be either a static method or a constructor taking a String parameter and
-returning the correct type.
-If the annotations are not found on the target class, then superclasses are searched, followed by immediate parent interfaces.
-</p>
-<p>
-Sometimes, you want to provide to/from string conversions for interfaces.
-In JDK 8 this can be done using static methods on interfaces.
-However in earlier versions, a separate "factory" class is necessary.
-This can also be annotated:
-</p>
-<div style="border:1px solid black; padding: 0px 6px; margin: 4px;"><pre>
- at FromStringFactory(factory = DistanceFactory.class)
-public interface Distance {
-
-  @ToString
-  String standardFormat();
-
-}
-
-public class Metres implements Distance {
-
-  @Override
-  public String standardFormat() { ... }
-
-}
-
-public class DistanceFactory {
-
-  @FromString
-  public static Distance parseDistance(String str) { ... }
-
-}
-</pre></div>
-<p>
-The <code>FromStringFactory</code> annotation points at the factory class that will provide the factory method.
-Although intended for use with interfaces, it can also be used on the target class or any superclass.
-Note that only the immediate parent interfaces of a class will be searched.
-</p>
-</subsection>
-
-<subsection name="Rationale">
-<p>
-The concept is that other open source libraries, as well as your application code, will implement these two annotations.
-For open source projects, a key point is that adding the annotations is a compile-time only event.
-The Joda-Convert jar file is not needed by your users unless they want to use conversion.
-If they don't want to use Joda-Convert then the annotations are effectively ignored.
-</p>
-<p>
-Joda-Time v2.0 and Joda-Money will both contain the annotations.
-In both cases, the dependency is not a runtime for users of the projects.
-</p>
-</subsection>
-
-</section>
-</body>
-</document>
+<?xml version="1.0"?>
+
+<document>
+
+ <properties>
+  <title>Joda Convert</title>
+  <author>Stephen Colebourne</author>
+ </properties>
+
+ <body>
+
+<section name="User guide">
+
+<p>
+Joda-Convert is intended for one simple task -
+Converting objects to and from strings.
+This is a common problem, particularly when communicating over textual protocols like XML or JSON.
+</p>
+
+<subsection name="Basic usage">
+<p>
+Using Joda-Convert is easy at the simplest level.
+The main access is via the class <code>StringConvert</code>.
+</p>
+<p>
+The easiest way to use the conversion is via the global constant:
+</p>
+<pre class="source">
+// conversion to a String
+TimeZone zone = ...
+String str = StringConvert.INSTANCE.convertToString(zone);
+
+// conversion from a String
+TimeZone zone = StringConvert.INSTANCE.convertFromString(TimeZone.class, str);
+</pre>
+<p>
+In both cases, if the input is <code>null</code> then the output will also be <code>null</code>.
+</p>
+<p>
+The global constant is quick and easy to use, but is shared between all users in the <code>ClassLoader</code>.
+It also cannot be extended.
+</p>
+<p>
+The alternative approach is to instantiate your own instance of <code>StringConvert</code>.
+This would normally be stored in your own static variable, or made available as needed by dependency injection.
+This may be updated by registering your own converters.
+</p>
+</subsection>
+
+<subsection name="Converters">
+<p>
+Each instance of <code>StringConvert</code>, including the global singleton, includes a standard set of JDK-based converters.
+These cover all the standard JDK types for which conversion to and from a string is sensible.
+The set also includes JSR-310 types, but these are optional and loaded by reflection.
+The system will run without any dependency.
+</p>
+<p>
+The JDK conversions are generally obvious. The types are as follows:
+</p>
+<ul>
+<li>String</li>
+<li>CharSequence</li>
+<li>StringBuffer</li>
+<li>StringBuilder</li>
+<li>long and Long</li>
+<li>int and Integer</li>
+<li>short and Short</li>
+<li>char and Character</li>
+<li>byte and Byte</li>
+<li>double and Double</li>
+<li>float and Float</li>
+<li>boolean and Boolean - 'true' or 'false'</li>
+<li>byte[] - using Base-64 encoding</li>
+<li>char[]</li>
+<li>BigInteger</li>
+<li>BigDecimal</li>
+<li>AtomicLong</li>
+<li>AtomicInteger</li>
+<li>AtomicBoolean - 'true' or 'false'</li>
+<li>Locale - separated by underscores, en_GB_VARIANT</li>
+<li>Class - using the class name, using the rename handler</li>
+<li>Package - using the package name</li>
+<li>Currency - using the three letter code</li>
+<li>TimeZone - using the ID</li>
+<li>UUID - using the toString() form</li>
+<li>URL - using the toString() form</li>
+<li>URI - using the toString() form</li>
+<li>InetAddress - using the host address</li>
+<li>File - using the toString() form</li>
+<li>Date - yyyy-MM-dd'T'HH:mm:ss.SSSZ</li>
+<li>Calendar - yyyy-MM-dd'T'HH:mm:ss.SSSZ, Gregorian only</li>
+<li>Instant</li>
+<li>Duration</li>
+<li>LocalDate</li>
+<li>LocalTime</li>
+<li>LocalDateTime</li>
+<li>OffsetTime</li>
+<li>OffsetDateTime</li>
+<li>ZonedDateTime</li>
+<li>Year</li>
+<li>YearMonth</li>
+<li>MonthDay</li>
+<li>Period</li>
+<li>ZoneOffset</li>
+<li>ZoneId</li>
+<li>Enum subclasses - using name(), annotations can override</li>
+</ul>
+<p>
+Note that the JSR-310 date types are supported in three different package namespaces -
+'java.time', 'javax.time' and 'org.threeten.bp'.
+</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>
+<p>
+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>
+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>
+
+<subsection name="Annotation based conversion">
+<p>
+If there is no registered converter for a type, then a search by annotation is performed.
+This will search for the <code>ToString</code> and <code>FromString</code> annotation on the type.
+These annotations will indicate which method should be called to perform the conversion.
+</p>
+<pre class="source">
+public class Distance {
+
+  @FromString
+  public static Distance parse(String str) { ... }
+
+  @ToString
+  public String getStandardOutput() { ... }
+
+}
+</pre>
+<p>
+To be valid, the class must contain one <code>ToString</code> annotation and one <code>FromString</code> annotation.
+The <code>ToString</code> annotation must be an instance method taking no parameters and returning a String.
+The <code>FromString</code> annotation must be either a static method or a constructor taking a String parameter and
+returning the correct type.
+If the annotations are not found on the target class, then superclasses are searched, followed by immediate parent interfaces.
+</p>
+<p>
+Sometimes, you want to provide to/from string conversions for interfaces.
+In Java SE 8 this can be done using static methods on interfaces.
+However in earlier versions, a separate "factory" class is necessary.
+This can also be annotated:
+</p>
+<pre class="source">
+ at FromStringFactory(factory = DistanceFactory.class)
+public interface Distance {
+
+  @ToString
+  String standardFormat();
+
+}
+
+public class Metres implements Distance {
+
+  @Override
+  public String standardFormat() { ... }
+
+}
+
+public class DistanceFactory {
+
+  @FromString
+  public static Distance parseDistance(String str) { ... }
+
+}
+</pre>
+<p>
+The <code>FromStringFactory</code> annotation points at the factory class that will provide the factory method.
+Although intended for use with interfaces, it can also be used on the target class or any superclass.
+Note that only the immediate parent interfaces of a class will be searched.
+</p>
+<p>
+The effective type of the converter in use is the type that declares the <code>FromString</code>
+or <code>FromStringFactory</code> annotation.
+This can be used by serialization systems to determine the best type of the value to send.
+One use case is to declare annotations on a public superclass and have all the subclasses be package scoped.
+Using the effective type, the package scoped subclasses remain out of the serialized form and
+off the public API.
+</p>
+</subsection>
+
+<subsection name="Rename handler">
+<p>
+Most large bodies of code will end up renaming classes and enum constants at some point.
+The <code>RenameHandler</code> class provides a convenient central place to track this.
+</p>
+<p>
+If the <code>RenameHandler</code> is setup with details of a rename, then an old class name
+or enum constant can be read in and will be automatically converted.
+</p>
+</subsection>
+
+<subsection name="Rationale">
+<p>
+The concept is that other open source libraries, as well as your application code, will implement these two annotations.
+For open source projects, a key point is that adding the annotations is a compile-time only event.
+The Joda-Convert jar file is not needed by your users unless they want to use conversion.
+If they don't want to use Joda-Convert then the annotations are effectively ignored.
+</p>
+<p>
+Joda-Time v2.0 and Joda-Money contain these annotations.
+In both cases, the dependency is optional at runtime for users of the projects.
+(Note that Scala does not honour the optional behaviour.)
+</p>
+</subsection>
+
+</section>
+</body>
+</document>
diff --git a/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java b/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java
index ce53587..aebb6cd 100644
--- a/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java
+++ b/src/test/java/org/joda/convert/DistanceMethodConstructorCharSequence.java
@@ -1,46 +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;
-
-/**
- * Example class with annotated constructor and method.
- */
-public class DistanceMethodConstructorCharSequence {
-
-    /** Amount. */
-    final int amount;
-
-    public DistanceMethodConstructorCharSequence(int amount) {
-        this.amount = amount;
-    }
-
-    @FromString
-    public DistanceMethodConstructorCharSequence(CharSequence amount) {
-        String amt = amount.toString().substring(0, amount.length() - 1);
-        this.amount = Integer.parseInt(amt);
-    }
-
-    @ToString
-    public String print() {
-        return amount + "m";
-    }
-
-    @Override
-    public String toString() {
-        return "Distance[" + amount + "m]";
-    }
-
-}
+/*
+ *  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;
+
+/**
+ * Example class with annotated constructor and method.
+ */
+public class DistanceMethodConstructorCharSequence {
+
+    /** Amount. */
+    final int amount;
+
+    public DistanceMethodConstructorCharSequence(int amount) {
+        this.amount = amount;
+    }
+
+    @FromString
+    public DistanceMethodConstructorCharSequence(CharSequence amount) {
+        String amt = amount.toString().substring(0, amount.length() - 1);
+        this.amount = Integer.parseInt(amt);
+    }
+
+    @ToString
+    public String print() {
+        return amount + "m";
+    }
+
+    @Override
+    public String toString() {
+        return "Distance[" + amount + "m]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java b/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java
index 57aa2b4..085a2ec 100644
--- a/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java
+++ b/src/test/java/org/joda/convert/DistanceMethodMethodCharSequence.java
@@ -1,46 +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;
-
-/**
- * Example class with annotated methods.
- */
-public class DistanceMethodMethodCharSequence {
-
-    /** Amount. */
-    final int amount;
-
-    @FromString
-    public static DistanceMethodMethodCharSequence parse(CharSequence amount) {
-        String amt = amount.toString().substring(0, amount.length() - 1);
-        return new DistanceMethodMethodCharSequence(Integer.parseInt(amt));
-    }
-
-    public DistanceMethodMethodCharSequence(int amount) {
-        this.amount = amount;
-    }
-
-    @ToString
-    public String print() {
-        return amount + "m";
-    }
-
-    @Override
-    public String toString() {
-        return "Distance[" + amount + "m]";
-    }
-
-}
+/*
+ *  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;
+
+/**
+ * Example class with annotated methods.
+ */
+public class DistanceMethodMethodCharSequence {
+
+    /** Amount. */
+    final int amount;
+
+    @FromString
+    public static DistanceMethodMethodCharSequence parse(CharSequence amount) {
+        String amt = amount.toString().substring(0, amount.length() - 1);
+        return new DistanceMethodMethodCharSequence(Integer.parseInt(amt));
+    }
+
+    public DistanceMethodMethodCharSequence(int amount) {
+        this.amount = amount;
+    }
+
+    @ToString
+    public String print() {
+        return amount + "m";
+    }
+
+    @Override
+    public String toString() {
+        return "Distance[" + amount + "m]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java b/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java
index 1349fe3..a0ba165 100644
--- a/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java
+++ b/src/test/java/org/joda/convert/DistanceNoAnnotationsCharSequence.java
@@ -1,48 +1,48 @@
-/*
- *  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;
-
-/**
- * Example class with no annotations.
- */
-public class DistanceNoAnnotationsCharSequence {
-
-    /** Amount. */
-    final int amount;
-
-    public static DistanceNoAnnotationsCharSequence parse(CharSequence amount) {
-        return new DistanceNoAnnotationsCharSequence(amount);
-    }
-
-    public DistanceNoAnnotationsCharSequence(int amount) {
-        this.amount = amount;
-    }
-
-    public DistanceNoAnnotationsCharSequence(CharSequence amount) {
-        String amt = amount.toString().substring(0, amount.length() - 1);
-        this.amount = Integer.parseInt(amt);
-    }
-
-    public String print() {
-        return amount + "m";
-    }
-
-    @Override
-    public String toString() {
-        return "Distance[" + amount + "m]";
-    }
-
-}
+/*
+ *  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;
+
+/**
+ * Example class with no annotations.
+ */
+public class DistanceNoAnnotationsCharSequence {
+
+    /** Amount. */
+    final int amount;
+
+    public static DistanceNoAnnotationsCharSequence parse(CharSequence amount) {
+        return new DistanceNoAnnotationsCharSequence(amount);
+    }
+
+    public DistanceNoAnnotationsCharSequence(int amount) {
+        this.amount = amount;
+    }
+
+    public DistanceNoAnnotationsCharSequence(CharSequence amount) {
+        String amt = amount.toString().substring(0, amount.length() - 1);
+        this.amount = Integer.parseInt(amt);
+    }
+
+    public String print() {
+        return amount + "m";
+    }
+
+    @Override
+    public String toString() {
+        return "Distance[" + amount + "m]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/DistanceWithFactory.java b/src/test/java/org/joda/convert/DistanceWithFactory.java
index 9c73a04..a631733 100644
--- a/src/test/java/org/joda/convert/DistanceWithFactory.java
+++ b/src/test/java/org/joda/convert/DistanceWithFactory.java
@@ -1,37 +1,37 @@
-/*
- *  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;
-
-/**
- * Example class with no annotations.
- */
- at FromStringFactory(factory = DistanceWithFactoryFactory.class)
-public class DistanceWithFactory {
-
-    /** Amount. */
-    final int amount;
-
-    public DistanceWithFactory(int amount) {
-        this.amount = amount;
-    }
-
-    @ToString
-    @Override
-    public String toString() {
-        return amount + "m";
-    }
-
-}
+/*
+ *  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;
+
+/**
+ * Example class with no annotations.
+ */
+ at FromStringFactory(factory = DistanceWithFactoryFactory.class)
+public class DistanceWithFactory {
+
+    /** Amount. */
+    final int amount;
+
+    public DistanceWithFactory(int amount) {
+        this.amount = amount;
+    }
+
+    @ToString
+    @Override
+    public String toString() {
+        return amount + "m";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java b/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java
index 3631531..21b0c5b 100644
--- a/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java
+++ b/src/test/java/org/joda/convert/DistanceWithFactoryFactory.java
@@ -1,29 +1,29 @@
-/*
- *  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;
-
-/**
- * Example factory.
- */
-public class DistanceWithFactoryFactory {
-
-    @FromString
-    public static DistanceWithFactory parse(String amount) {
-        amount = amount.substring(0, amount.length() - 1);
-        return new DistanceWithFactory(Integer.parseInt(amount));
-    }
-
-}
+/*
+ *  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;
+
+/**
+ * Example factory.
+ */
+public class DistanceWithFactoryFactory {
+
+    @FromString
+    public static DistanceWithFactory parse(String amount) {
+        amount = amount.substring(0, amount.length() - 1);
+        return new DistanceWithFactory(Integer.parseInt(amount));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/MockDistanceStringConverter.java b/src/test/java/org/joda/convert/MockDistanceStringConverter.java
index a98fdaa..c78f846 100644
--- a/src/test/java/org/joda/convert/MockDistanceStringConverter.java
+++ b/src/test/java/org/joda/convert/MockDistanceStringConverter.java
@@ -28,6 +28,7 @@ public enum MockDistanceStringConverter implements StringConverter<DistanceMetho
      * @param object  the object to convert, not null
      * @return the converted string, may be null but generally not
      */
+    @Override
     public String convertToString(DistanceMethodMethod object) {
         return object.print();
     }
@@ -38,6 +39,7 @@ public enum MockDistanceStringConverter implements StringConverter<DistanceMetho
      * @param str  the string to convert, not null
      * @return the converted integer, may be null but generally not
      */
+    @Override
     public DistanceMethodMethod convertFromString(Class<? extends DistanceMethodMethod> cls, String str) {
         return DistanceMethodMethod.parse(str);
     }
diff --git a/src/test/java/org/joda/convert/MockIntegerStringConverter.java b/src/test/java/org/joda/convert/MockIntegerStringConverter.java
index 47b4cb2..4dadc7a 100644
--- a/src/test/java/org/joda/convert/MockIntegerStringConverter.java
+++ b/src/test/java/org/joda/convert/MockIntegerStringConverter.java
@@ -28,6 +28,7 @@ public enum MockIntegerStringConverter implements StringConverter<Integer> {
      * @param object  the object to convert, not null
      * @return the converted string, may be null but generally not
      */
+    @Override
     public String convertToString(Integer object) {
         return object.toString();
     }
@@ -38,6 +39,7 @@ public enum MockIntegerStringConverter implements StringConverter<Integer> {
      * @param str  the string to convert, not null
      * @return the converted integer, may be null but generally not
      */
+    @Override
     public Integer convertFromString(Class<? extends Integer> cls, String str) {
         return new Integer(str);
     }
diff --git a/src/test/java/org/joda/convert/test1/Test1Interface.java b/src/test/java/org/joda/convert/Status.java
similarity index 75%
copy from src/test/java/org/joda/convert/test1/Test1Interface.java
copy to src/test/java/org/joda/convert/Status.java
index a20f12e..4cd1bd5 100644
--- a/src/test/java/org/joda/convert/test1/Test1Interface.java
+++ b/src/test/java/org/joda/convert/Status.java
@@ -1,28 +1,26 @@
-/*
- *  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.test1;
-
-import org.joda.convert.ToString;
-
-/**
- * Example interface with annotated methods.
- */
-public interface Test1Interface {
-
-    @ToString
-    String print();
-
-}
+/*
+ *  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;
+
+/**
+ * Mock enum used to test renames.
+ */
+public enum Status {
+
+    VALID,
+    INVALID;
+
+}
diff --git a/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java
index c6f84e3..b388847 100644
--- a/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestBooleanArrayStringConverterFactory.java
@@ -1,46 +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)));
-    }
-
-}
+/*
+ *  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
index 0d73041..386fda9 100644
--- a/src/test/java/org/joda/convert/TestBooleanObjectArrayStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestBooleanObjectArrayStringConverterFactory.java
@@ -1,47 +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)));
-    }
-
-}
+/*
+ *  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
index dcfc92e..82c2135 100644
--- a/src/test/java/org/joda/convert/TestByteObjectArrayStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestByteObjectArrayStringConverterFactory.java
@@ -1,46 +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)));
-    }
-
-}
+/*
+ *  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
index 8e6bc67..c1ab8a7 100644
--- a/src/test/java/org/joda/convert/TestCharObjectArrayStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestCharObjectArrayStringConverterFactory.java
@@ -1,49 +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)));
-    }
-
-}
+/*
+ *  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 427dfbe..9639ec0 100644
--- a/src/test/java/org/joda/convert/TestJDKStringConverters.java
+++ b/src/test/java/org/joda/convert/TestJDKStringConverters.java
@@ -17,6 +17,7 @@ package org.joda.convert;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
 import java.math.BigDecimal;
@@ -246,6 +247,18 @@ public class TestJDKStringConverters {
     }
 
     @Test
+    public void test_Class_withRename() {
+        try {
+            JDKStringConverter.CLASS.convertFromString(Class.class, "org.foo.StringConvert");
+            fail();
+        } catch (RuntimeException ex) {
+            // expected
+        }
+        RenameHandler.INSTANCE.renamedType("org.foo.StringConvert", StringConvert.class);
+        assertEquals(StringConvert.class, JDKStringConverter.CLASS.convertFromString(Class.class, "org.foo.StringConvert"));
+    }
+
+    @Test
     public void test_Package() {
         JDKStringConverter test = JDKStringConverter.PACKAGE;
         doTest(test, Package.class, Locale.class.getPackage(), "java.util");
@@ -398,15 +411,35 @@ public class TestJDKStringConverters {
 
     @Test
     public void test_Enum() {
-        JDKStringConverter test = JDKStringConverter.ENUM;
-        assertEquals(Enum.class, test.getType());
+        TypedStringConverter<RoundingMode> test = StringConvert.create().findTypedConverter(RoundingMode.class);
+        assertEquals(RoundingMode.class, test.getEffectiveType());
         assertEquals("CEILING", test.convertToString(RoundingMode.CEILING));
         assertEquals(RoundingMode.CEILING, test.convertFromString(RoundingMode.class, "CEILING"));
     }
 
     @Test(expected=RuntimeException.class)
     public void test_Enum_invalidConstant() {
-        JDKStringConverter.ENUM.convertFromString(RoundingMode.class, "RUBBISH");
+        TypedStringConverter<RoundingMode> test = StringConvert.create().findTypedConverter(RoundingMode.class);
+        test.convertFromString(RoundingMode.class, "RUBBISH");
+    }
+
+    @Test
+    public void test_Enum_withRename() {
+        TypedStringConverter<Status> test = StringConvert.create().findTypedConverter(Status.class);
+        assertEquals("VALID", test.convertToString(Status.VALID));
+        assertEquals("INVALID", test.convertToString(Status.INVALID));
+        assertEquals(Status.VALID, test.convertFromString(Status.class, "VALID"));
+        assertEquals(Status.INVALID, test.convertFromString(Status.class, "INVALID"));
+        try {
+            test.convertFromString(Status.class, "OK");
+            fail();
+        } catch (RuntimeException ex) {
+            // expected
+        }
+        RenameHandler.INSTANCE.renamedEnum("OK", Status.VALID);
+        assertEquals(Status.VALID, test.convertFromString(Status.class, "OK"));
+        assertEquals(Status.VALID, test.convertFromString(Status.class, "VALID"));
+        assertEquals(Status.INVALID, test.convertFromString(Status.class, "INVALID"));
     }
 
     //-----------------------------------------------------------------------
diff --git a/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java b/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java
index bbc4c66..f54ffd9 100644
--- a/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestNumericArrayStringConverterFactory.java
@@ -1,112 +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)));
-    }
-
-}
+/*
+ *  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
index 3fde3f1..e53404d 100644
--- a/src/test/java/org/joda/convert/TestNumericObjectArrayStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestNumericObjectArrayStringConverterFactory.java
@@ -1,117 +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)));
-    }
-
-}
+/*
+ *  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 f3a6580..b408564 100644
--- a/src/test/java/org/joda/convert/TestStringConvert.java
+++ b/src/test/java/org/joda/convert/TestStringConvert.java
@@ -16,9 +16,9 @@
 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.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.math.RoundingMode;
@@ -28,6 +28,7 @@ import org.joda.convert.test1.Test1Class;
 import org.joda.convert.test2.Test2Class;
 import org.joda.convert.test2.Test2Interface;
 import org.joda.convert.test3.Test3Class;
+import org.joda.convert.test3.Test3SuperClass;
 import org.joda.convert.test4.Test4Class;
 import org.joda.convert.test4.Test4Interface;
 import org.junit.Test;
@@ -40,8 +41,9 @@ public class TestStringConvert {
     @Test
     public void test_constructor() {
         StringConvert test = new StringConvert();
-        StringConverter<?> conv = test.findConverter(Integer.class);
+        TypedStringConverter<?> conv = test.findTypedConverter(Integer.class);
         assertEquals(true, conv instanceof JDKStringConverter);
+        assertEquals(Integer.class, conv.getEffectiveType());
     }
 
     @Test
@@ -121,11 +123,6 @@ public class TestStringConvert {
     }
 
     @Test
-    public void test_convertToString_withType_inherit2() {
-        assertEquals("CEILING", StringConvert.INSTANCE.convertToString(Enum.class, RoundingMode.CEILING));
-    }
-
-    @Test
     public void test_convertToString_withType_null() {
         assertEquals(null, StringConvert.INSTANCE.convertToString(Integer.class, null));
     }
@@ -211,9 +208,10 @@ public class TestStringConvert {
         DistanceMethodMethod d = new DistanceMethodMethod(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(DistanceMethodMethod.class, "25m").amount);
-        StringConverter<DistanceMethodMethod> conv = test.findConverter(DistanceMethodMethod.class);
+        TypedStringConverter<DistanceMethodMethod> conv = test.findTypedConverter(DistanceMethodMethod.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
         assertSame(conv, test.findConverter(DistanceMethodMethod.class));
+        assertEquals(DistanceMethodMethod.class, conv.getEffectiveType());
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
 
@@ -223,9 +221,10 @@ public class TestStringConvert {
         DistanceMethodMethodCharSequence d = new DistanceMethodMethodCharSequence(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(DistanceMethodMethodCharSequence.class, "25m").amount);
-        StringConverter<DistanceMethodMethodCharSequence> conv = test.findConverter(DistanceMethodMethodCharSequence.class);
+        TypedStringConverter<DistanceMethodMethodCharSequence> conv = test.findTypedConverter(DistanceMethodMethodCharSequence.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
         assertSame(conv, test.findConverter(DistanceMethodMethodCharSequence.class));
+        assertEquals(DistanceMethodMethodCharSequence.class, conv.getEffectiveType());
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
 
@@ -235,9 +234,10 @@ public class TestStringConvert {
         DistanceMethodConstructor d = new DistanceMethodConstructor(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(DistanceMethodConstructor.class, "25m").amount);
-        StringConverter<DistanceMethodConstructor> conv = test.findConverter(DistanceMethodConstructor.class);
+        TypedStringConverter<DistanceMethodConstructor> conv = test.findTypedConverter(DistanceMethodConstructor.class);
         assertEquals(true, conv instanceof MethodConstructorStringConverter<?>);
         assertSame(conv, test.findConverter(DistanceMethodConstructor.class));
+        assertEquals(DistanceMethodConstructor.class, conv.getEffectiveType());
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
 
@@ -247,9 +247,10 @@ public class TestStringConvert {
         DistanceMethodConstructorCharSequence d = new DistanceMethodConstructorCharSequence(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(DistanceMethodConstructorCharSequence.class, "25m").amount);
-        StringConverter<DistanceMethodConstructorCharSequence> conv = test.findConverter(DistanceMethodConstructorCharSequence.class);
+        TypedStringConverter<DistanceMethodConstructorCharSequence> conv = test.findTypedConverter(DistanceMethodConstructorCharSequence.class);
         assertEquals(true, conv instanceof MethodConstructorStringConverter<?>);
         assertSame(conv, test.findConverter(DistanceMethodConstructorCharSequence.class));
+        assertEquals(DistanceMethodConstructorCharSequence.class, conv.getEffectiveType());
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
 
@@ -259,8 +260,9 @@ public class TestStringConvert {
         SubMethodMethod d = new SubMethodMethod(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(SubMethodMethod.class, "25m").amount);
-        StringConverter<SubMethodMethod> conv = test.findConverter(SubMethodMethod.class);
+        TypedStringConverter<SubMethodMethod> conv = test.findTypedConverter(SubMethodMethod.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
+        assertEquals(SubMethodMethod.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(SubMethodMethod.class));
     }
 
@@ -270,8 +272,9 @@ public class TestStringConvert {
         SubMethodConstructor d = new SubMethodConstructor("25m");
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(SubMethodConstructor.class, "25m").amount);
-        StringConverter<SubMethodConstructor> conv = test.findConverter(SubMethodConstructor.class);
+        TypedStringConverter<SubMethodConstructor> conv = test.findTypedConverter(SubMethodConstructor.class);
         assertEquals(true, conv instanceof MethodConstructorStringConverter<?>);
+        assertEquals(SubMethodConstructor.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(SubMethodConstructor.class));
     }
 
@@ -281,8 +284,9 @@ public class TestStringConvert {
         SuperFactorySuper d = new SuperFactorySuper(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(SuperFactorySuper.class, "25m").amount);
-        StringConverter<SuperFactorySuper> conv = test.findConverter(SuperFactorySuper.class);
+        TypedStringConverter<SuperFactorySuper> conv = test.findTypedConverter(SuperFactorySuper.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
+        assertEquals(SuperFactorySuper.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(SuperFactorySuper.class));
     }
 
@@ -294,9 +298,10 @@ public class TestStringConvert {
         SuperFactorySuper fromStr = test.convertFromString(SuperFactorySuper.class, "8m");
         assertEquals(d.amount, fromStr.amount);
         assertEquals(true, fromStr instanceof SuperFactorySub);
-        StringConverter<SuperFactorySuper> conv = test.findConverter(SuperFactorySuper.class);
+        TypedStringConverter<SuperFactorySub> conv = test.findTypedConverter(SuperFactorySub.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
-        assertSame(conv, test.findConverter(SuperFactorySuper.class));
+        assertEquals(SuperFactorySuper.class, conv.getEffectiveType());
+        assertSame(conv, test.findConverter(SuperFactorySub.class));
     }
 
     @Test
@@ -345,8 +350,9 @@ public class TestStringConvert {
         DistanceWithFactory d = new DistanceWithFactory(25);
         assertEquals("25m", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(DistanceWithFactory.class, "25m").amount);
-        StringConverter<DistanceWithFactory> conv = test.findConverter(DistanceWithFactory.class);
+        TypedStringConverter<DistanceWithFactory> conv = test.findTypedConverter(DistanceWithFactory.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
+        assertEquals(DistanceWithFactory.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(DistanceWithFactory.class));
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
@@ -357,8 +363,9 @@ public class TestStringConvert {
         Test1Class d = new Test1Class(25);
         assertEquals("25g", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(Test1Class.class, "25g").amount);
-        StringConverter<Test1Class> conv = test.findConverter(Test1Class.class);
+        TypedStringConverter<Test1Class> conv = test.findTypedConverter(Test1Class.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
+        assertEquals(Test1Class.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(Test1Class.class));
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
@@ -369,8 +376,9 @@ public class TestStringConvert {
         Test2Class d = new Test2Class(25);
         assertEquals("25g", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(Test2Class.class, "25g").amount);
-        StringConverter<Test2Class> conv = test.findConverter(Test2Class.class);
+        TypedStringConverter<Test2Class> conv = test.findTypedConverter(Test2Class.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
+        assertEquals(Test2Interface.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(Test2Class.class));
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
@@ -381,8 +389,9 @@ public class TestStringConvert {
         Test2Class d = new Test2Class(25);
         assertEquals("25g", test.convertToString(d));
         assertEquals("25g", test.convertFromString(Test2Interface.class, "25g").print());
-        StringConverter<Test2Interface> conv = test.findConverter(Test2Interface.class);
+        TypedStringConverter<Test2Interface> conv = test.findTypedConverter(Test2Interface.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
+        assertEquals(Test2Interface.class, conv.getEffectiveType());
         assertSame(conv, test.findConverter(Test2Interface.class));
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
@@ -393,9 +402,10 @@ public class TestStringConvert {
         Test3Class d = new Test3Class(25);
         assertEquals("25g", test.convertToString(d));
         assertEquals(d.amount, test.convertFromString(Test3Class.class, "25g").amount);
-        StringConverter<Test3Class> conv = test.findConverter(Test3Class.class);
+        TypedStringConverter<Test3Class> conv = test.findTypedConverter(Test3Class.class);
         assertEquals(true, conv instanceof MethodsStringConverter<?>);
         assertSame(conv, test.findConverter(Test3Class.class));
+        assertEquals(Test3SuperClass.class, conv.getEffectiveType());
         assertEquals(true, conv.toString().startsWith("RefectionStringConverter"));
     }
 
@@ -491,6 +501,18 @@ public class TestStringConvert {
     }
 
     //-----------------------------------------------------------------------
+    @Test
+    public void test_convert_Enum_overrideDefaultWithConverter() {
+        StringConvert test = new StringConvert();
+        test.register(Validity.class, ValidityStringConverter.INSTANCE);
+        assertEquals("VALID", test.convertToString(Validity.class, Validity.VALID));
+        assertEquals("INVALID", test.convertToString(Validity.class, Validity.INVALID));
+        assertEquals(Validity.VALID, test.convertFromString(Validity.class, "VALID"));
+        assertEquals(Validity.INVALID, test.convertFromString(Validity.class, "INVALID"));
+        assertEquals(Validity.VALID, test.convertFromString(Validity.class, "OK"));
+    }
+
+    //-----------------------------------------------------------------------
     @Test(expected=IllegalArgumentException.class)
     public void test_register_classNotNull() {
         StringConvert.INSTANCE.register(null, MockIntegerStringConverter.INSTANCE);
@@ -519,11 +541,13 @@ public class TestStringConvert {
 
     //-------------------------------------------------------------------------
     ToStringConverter<DistanceNoAnnotations> DISTANCE_TO_STRING_CONVERTER = new ToStringConverter<DistanceNoAnnotations>() {
+        @Override
         public String convertToString(DistanceNoAnnotations object) {
             return object.toString();
         }
     };
     FromStringConverter<DistanceNoAnnotations> DISTANCE_FROM_STRING_CONVERTER = new FromStringConverter<DistanceNoAnnotations>() {
+        @Override
         public DistanceNoAnnotations convertFromString(Class<? extends DistanceNoAnnotations> cls, String str) {
             return DistanceNoAnnotations.parse(str);
         }
@@ -559,6 +583,12 @@ public class TestStringConvert {
         test.register(DistanceNoAnnotations.class, DISTANCE_TO_STRING_CONVERTER, null);
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void test_registerFactory_cannotChangeSingleton() {
+        StringConvert.INSTANCE.register(
+            DistanceNoAnnotations.class, DISTANCE_TO_STRING_CONVERTER, DISTANCE_FROM_STRING_CONVERTER);
+    }
+
     //-------------------------------------------------------------------------
     @Test
     public void test_registerMethods() {
@@ -602,6 +632,29 @@ public class TestStringConvert {
         test.registerMethods(DistanceNoAnnotations.class, "toString", null);
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void test_registerMethods_noSuchToStringMethod() {
+        StringConvert test = new StringConvert();
+        test.registerMethods(DistanceNoAnnotations.class, "rubbishName", "parse");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void test_registerMethods_invalidToStringMethod() {
+        StringConvert test = new StringConvert();
+        test.registerMethods(Thread.class, "currentThread", "toString");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void test_registerMethods_noSuchFromStringMethod() {
+        StringConvert test = new StringConvert();
+        test.registerMethods(DistanceNoAnnotations.class, "toString", "rubbishName");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void ttest_registerMethods_cannotChangeSingleton() {
+        StringConvert.INSTANCE.registerMethods(DistanceNoAnnotationsCharSequence.class, "toString", "parse");
+    }
+
     @Test
     public void test_registerMethods_classAlreadyRegistered() {
       StringConvert test = new StringConvert();
@@ -646,6 +699,17 @@ public class TestStringConvert {
         test.registerMethodConstructor(DistanceNoAnnotations.class, null);
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void test_registerMethodConstructor_noSuchConstructor() {
+        StringConvert test = new StringConvert();
+        test.registerMethodConstructor(Enum.class, "toString");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void ttest_registerMethodConstructor_cannotChangeSingleton() {
+        StringConvert.INSTANCE.registerMethodConstructor(DistanceNoAnnotationsCharSequence.class, "toString");
+    }
+
     @Test
     public void test_registerMethodConstructor_classAlreadyRegistered() {
       StringConvert test = new StringConvert();
diff --git a/src/test/java/org/joda/convert/TestStringConverterFactory.java b/src/test/java/org/joda/convert/TestStringConverterFactory.java
index 884926a..75788db 100644
--- a/src/test/java/org/joda/convert/TestStringConverterFactory.java
+++ b/src/test/java/org/joda/convert/TestStringConverterFactory.java
@@ -1,61 +1,72 @@
-/*
- *  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;
-        }
-        
-    }
-
-}
+/*
+ *  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 org.junit.Test;
+
+/**
+ * Test StringConvert factory.
+ */
+public class TestStringConverterFactory {
+
+    @Test
+    public void test_constructor() {
+        StringConvert test = new StringConvert(true, new Factory1());
+        assertEquals(DistanceMethodMethod.class, test.findTypedConverter(DistanceMethodMethod.class).getEffectiveType());
+    }
+
+    @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());
+        assertEquals(DistanceMethodMethod.class, test.findTypedConverter(DistanceMethodMethod.class).getEffectiveType());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void test_registerFactory_null() {
+        StringConvert test = new StringConvert();
+        test.registerFactory(null);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void test_registerFactory_cannotChangeSingleton() {
+        StringConvert.INSTANCE.registerFactory(new Factory1());
+    }
+
+    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/Test1Interface.java b/src/test/java/org/joda/convert/Validity.java
similarity index 75%
copy from src/test/java/org/joda/convert/test1/Test1Interface.java
copy to src/test/java/org/joda/convert/Validity.java
index a20f12e..14dcf7c 100644
--- a/src/test/java/org/joda/convert/test1/Test1Interface.java
+++ b/src/test/java/org/joda/convert/Validity.java
@@ -1,28 +1,26 @@
-/*
- *  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.test1;
-
-import org.joda.convert.ToString;
-
-/**
- * Example interface with annotated methods.
- */
-public interface Test1Interface {
-
-    @ToString
-    String print();
-
-}
+/*
+ *  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;
+
+/**
+ * Mock enum with a converter.
+ */
+public enum Validity {
+
+    VALID,
+    INVALID;
+
+}
diff --git a/src/test/java/org/joda/convert/MockIntegerStringConverter.java b/src/test/java/org/joda/convert/ValidityStringConverter.java
similarity index 63%
copy from src/test/java/org/joda/convert/MockIntegerStringConverter.java
copy to src/test/java/org/joda/convert/ValidityStringConverter.java
index 47b4cb2..ecf5566 100644
--- a/src/test/java/org/joda/convert/MockIntegerStringConverter.java
+++ b/src/test/java/org/joda/convert/ValidityStringConverter.java
@@ -1,45 +1,51 @@
-/*
- *  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;
-
-/**
- * Conversion between an {@code Integer} and a {@code String}.
- */
-public enum MockIntegerStringConverter implements StringConverter<Integer> {
-
-    /** Singleton instance. */
-    INSTANCE;
-
-    /**
-     * Converts the {@code Integer} to a {@code String}.
-     * @param object  the object to convert, not null
-     * @return the converted string, may be null but generally not
-     */
-    public String convertToString(Integer object) {
-        return object.toString();
-    }
-
-    /**
-     * Converts the {@code String} to an {@code Integer}.
-     * @param cls  the class to convert to, not null
-     * @param str  the string to convert, not null
-     * @return the converted integer, may be null but generally not
-     */
-    public Integer convertFromString(Class<? extends Integer> cls, String str) {
-        return new Integer(str);
-    }
-
-}
+/*
+ *  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;
+
+/**
+ * Conversion between an {@code Validity} and a {@code String}.
+ */
+public enum ValidityStringConverter implements StringConverter<Validity> {
+
+    /** Singleton instance. */
+    INSTANCE;
+
+    /**
+     * Converts the {@code Validity} to a {@code String}.
+     * @param object  the object to convert, not null
+     * @return the converted string, may be null but generally not
+     */
+    @Override
+    public String convertToString(Validity object) {
+        return object.name();
+    }
+
+    /**
+     * Converts the {@code String} to an {@code Validity}.
+     * @param cls  the class to convert to, not null
+     * @param str  the string to convert, not null
+     * @return the converted integer, may be null but generally not
+     */
+    @Override
+    public Validity convertFromString(Class<? extends Validity> cls, String str) {
+        // handle renamed constant
+        if (str.equals("OK")) {
+            return Validity.VALID;
+        }
+        return Validity.valueOf(str);
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test1/Test1Class.java b/src/test/java/org/joda/convert/test1/Test1Class.java
index 964dc70..26df6bd 100644
--- a/src/test/java/org/joda/convert/test1/Test1Class.java
+++ b/src/test/java/org/joda/convert/test1/Test1Class.java
@@ -1,47 +1,48 @@
-/*
- *  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.test1;
-
-import org.joda.convert.FromString;
-
-/**
- * Example class with annotated methods.
- */
-public class Test1Class implements Test1Interface {
-
-    /** Amount. */
-    public final int amount;
-
-    @FromString
-    public static Test1Class parse(String amount) {
-        amount = amount.substring(0, amount.length() - 1);
-        return new Test1Class(Integer.parseInt(amount));
-    }
-
-    public Test1Class(int amount) {
-        this.amount = amount;
-    }
-
-    public String print() {
-        return amount + "g";
-    }
-
-    @Override
-    public String toString() {
-        return "Weight[" + amount + "g]";
-    }
-
-}
+/*
+ *  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.test1;
+
+import org.joda.convert.FromString;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test1Class implements Test1Interface {
+
+    /** Amount. */
+    public final int amount;
+
+    @FromString
+    public static Test1Class parse(String amount) {
+        amount = amount.substring(0, amount.length() - 1);
+        return new Test1Class(Integer.parseInt(amount));
+    }
+
+    public Test1Class(int amount) {
+        this.amount = amount;
+    }
+
+    @Override
+    public String print() {
+        return amount + "g";
+    }
+
+    @Override
+    public String toString() {
+        return "Weight[" + amount + "g]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test1/Test1Interface.java b/src/test/java/org/joda/convert/test1/Test1Interface.java
index a20f12e..55bba18 100644
--- a/src/test/java/org/joda/convert/test1/Test1Interface.java
+++ b/src/test/java/org/joda/convert/test1/Test1Interface.java
@@ -1,28 +1,28 @@
-/*
- *  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.test1;
-
-import org.joda.convert.ToString;
-
-/**
- * Example interface with annotated methods.
- */
-public interface Test1Interface {
-
-    @ToString
-    String print();
-
-}
+/*
+ *  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.test1;
+
+import org.joda.convert.ToString;
+
+/**
+ * Example interface with annotated methods.
+ */
+public interface Test1Interface {
+
+    @ToString
+    String print();
+
+}
diff --git a/src/test/java/org/joda/convert/test2/Test2Class.java b/src/test/java/org/joda/convert/test2/Test2Class.java
index df90aac..74ba1bd 100644
--- a/src/test/java/org/joda/convert/test2/Test2Class.java
+++ b/src/test/java/org/joda/convert/test2/Test2Class.java
@@ -1,39 +1,40 @@
-/*
- *  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.test2;
-
-/**
- * Example class with annotated methods.
- */
-public class Test2Class implements Test2Interface {
-
-    /** Amount. */
-    public final int amount;
-
-    public Test2Class(int amount) {
-        this.amount = amount;
-    }
-
-    public String print() {
-        return amount + "g";
-    }
-
-    @Override
-    public String toString() {
-        return "Weight[" + amount + "g]";
-    }
-
-}
+/*
+ *  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.test2;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test2Class implements Test2Interface {
+
+    /** Amount. */
+    public final int amount;
+
+    public Test2Class(int amount) {
+        this.amount = amount;
+    }
+
+    @Override
+    public String print() {
+        return amount + "g";
+    }
+
+    @Override
+    public String toString() {
+        return "Weight[" + amount + "g]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test2/Test2Factory.java b/src/test/java/org/joda/convert/test2/Test2Factory.java
index c5fe8e9..bc9d2c4 100644
--- a/src/test/java/org/joda/convert/test2/Test2Factory.java
+++ b/src/test/java/org/joda/convert/test2/Test2Factory.java
@@ -1,31 +1,31 @@
-/*
- *  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.test2;
-
-import org.joda.convert.FromString;
-
-/**
- * Example class with annotated methods.
- */
-public class Test2Factory {
-
-    @FromString
-    public static Test2Class parse(String amount) {
-        amount = amount.substring(0, amount.length() - 1);
-        return new Test2Class(Integer.parseInt(amount));
-    }
-
-}
+/*
+ *  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.test2;
+
+import org.joda.convert.FromString;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test2Factory {
+
+    @FromString
+    public static Test2Class parse(String amount) {
+        amount = amount.substring(0, amount.length() - 1);
+        return new Test2Class(Integer.parseInt(amount));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test2/Test2Interface.java b/src/test/java/org/joda/convert/test2/Test2Interface.java
index d68189a..daf2940 100644
--- a/src/test/java/org/joda/convert/test2/Test2Interface.java
+++ b/src/test/java/org/joda/convert/test2/Test2Interface.java
@@ -1,30 +1,30 @@
-/*
- *  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.test2;
-
-import org.joda.convert.FromStringFactory;
-import org.joda.convert.ToString;
-
-/**
- * Example interface with annotated methods.
- */
- at FromStringFactory(factory = Test2Factory.class)
-public interface Test2Interface {
-
-    @ToString
-    String print();
-
-}
+/*
+ *  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.test2;
+
+import org.joda.convert.FromStringFactory;
+import org.joda.convert.ToString;
+
+/**
+ * Example interface with annotated methods.
+ */
+ at FromStringFactory(factory = Test2Factory.class)
+public interface Test2Interface {
+
+    @ToString
+    String print();
+
+}
diff --git a/src/test/java/org/joda/convert/test3/Test3Class.java b/src/test/java/org/joda/convert/test3/Test3Class.java
index 45d2627..6686392 100644
--- a/src/test/java/org/joda/convert/test3/Test3Class.java
+++ b/src/test/java/org/joda/convert/test3/Test3Class.java
@@ -1,40 +1,40 @@
-/*
- *  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.test3;
-
-/**
- * Example class with annotated methods.
- */
-public class Test3Class extends Test3SuperClass implements Test3Interface {
-
-    /** Amount. */
-    public final int amount;
-
-    public Test3Class(int amount) {
-        this.amount = amount;
-    }
-
-    @Override
-    public String print() {
-        return amount + "g";
-    }
-
-    @Override
-    public String toString() {
-        return "Weight[" + amount + "g]";
-    }
-
-}
+/*
+ *  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.test3;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test3Class extends Test3SuperClass implements Test3Interface {
+
+    /** Amount. */
+    public final int amount;
+
+    public Test3Class(int amount) {
+        this.amount = amount;
+    }
+
+    @Override
+    public String print() {
+        return amount + "g";
+    }
+
+    @Override
+    public String toString() {
+        return "Weight[" + amount + "g]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test3/Test3Factory.java b/src/test/java/org/joda/convert/test3/Test3Factory.java
index d3e2719..c9c5829 100644
--- a/src/test/java/org/joda/convert/test3/Test3Factory.java
+++ b/src/test/java/org/joda/convert/test3/Test3Factory.java
@@ -1,30 +1,30 @@
-/*
- *  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.test3;
-
-import org.joda.convert.FromString;
-
-/**
- * Example class with annotated methods.
- */
-public class Test3Factory {
-
-    @FromString
-    public static Test3Interface parse(String amount) {
-        throw new UnsupportedOperationException();
-    }
-
-}
+/*
+ *  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.test3;
+
+import org.joda.convert.FromString;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test3Factory {
+
+    @FromString
+    public static Test3Interface parse(String amount) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test3/Test3Interface.java b/src/test/java/org/joda/convert/test3/Test3Interface.java
index 06aab3f..1421c12 100644
--- a/src/test/java/org/joda/convert/test3/Test3Interface.java
+++ b/src/test/java/org/joda/convert/test3/Test3Interface.java
@@ -1,31 +1,31 @@
-/*
- *  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.test3;
-
-import org.joda.convert.FromStringFactory;
-import org.joda.convert.ToString;
-
-/**
- * Example interface with annotated methods.
- */
- at FromStringFactory(factory = Test3Factory.class)
-public interface Test3Interface {
-
-    @ToString
-    @Override
-    String toString();
-
-}
+/*
+ *  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.test3;
+
+import org.joda.convert.FromStringFactory;
+import org.joda.convert.ToString;
+
+/**
+ * Example interface with annotated methods.
+ */
+ at FromStringFactory(factory = Test3Factory.class)
+public interface Test3Interface {
+
+    @ToString
+    @Override
+    String toString();
+
+}
diff --git a/src/test/java/org/joda/convert/test3/Test3SuperClass.java b/src/test/java/org/joda/convert/test3/Test3SuperClass.java
index 83ff91b..a560cf1 100644
--- a/src/test/java/org/joda/convert/test3/Test3SuperClass.java
+++ b/src/test/java/org/joda/convert/test3/Test3SuperClass.java
@@ -1,35 +1,35 @@
-/*
- *  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.test3;
-
-import org.joda.convert.FromString;
-import org.joda.convert.ToString;
-
-/**
- * Example class with annotated methods.
- */
-public abstract class Test3SuperClass {
-
-    @FromString
-    public static Test3SuperClass parse(String amount) {
-        amount = amount.substring(0, amount.length() - 1);
-        return new Test3Class(Integer.parseInt(amount));
-    }
-
-    @ToString
-    public abstract String print();
-
-}
+/*
+ *  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.test3;
+
+import org.joda.convert.FromString;
+import org.joda.convert.ToString;
+
+/**
+ * Example class with annotated methods.
+ */
+public abstract class Test3SuperClass {
+
+    @FromString
+    public static Test3SuperClass parse(String amount) {
+        amount = amount.substring(0, amount.length() - 1);
+        return new Test3Class(Integer.parseInt(amount));
+    }
+
+    @ToString
+    public abstract String print();
+
+}
diff --git a/src/test/java/org/joda/convert/test4/Test4Class.java b/src/test/java/org/joda/convert/test4/Test4Class.java
index a386ce0..11d4ca5 100644
--- a/src/test/java/org/joda/convert/test4/Test4Class.java
+++ b/src/test/java/org/joda/convert/test4/Test4Class.java
@@ -1,39 +1,40 @@
-/*
- *  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.test4;
-
-/**
- * Example class with annotated methods.
- */
-public class Test4Class implements Test4Interface {
-
-    /** Amount. */
-    public final int amount;
-
-    public Test4Class(int amount) {
-        this.amount = amount;
-    }
-
-    public String print() {
-        return amount + "g";
-    }
-
-    @Override
-    public String toString() {
-        return "Weight[" + amount + "g]";
-    }
-
-}
+/*
+ *  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.test4;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test4Class implements Test4Interface {
+
+    /** Amount. */
+    public final int amount;
+
+    public Test4Class(int amount) {
+        this.amount = amount;
+    }
+
+    @Override
+    public String print() {
+        return amount + "g";
+    }
+
+    @Override
+    public String toString() {
+        return "Weight[" + amount + "g]";
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test4/Test4Factory.java b/src/test/java/org/joda/convert/test4/Test4Factory.java
index dff11fd..53ed03e 100644
--- a/src/test/java/org/joda/convert/test4/Test4Factory.java
+++ b/src/test/java/org/joda/convert/test4/Test4Factory.java
@@ -1,37 +1,37 @@
-/*
- *  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.test4;
-
-import org.joda.convert.FromString;
-
-/**
- * Example class with annotated methods.
- */
-public class Test4Factory {
-
-    @FromString
-    public static Test4Interface parseInterface(String amount) {
-        amount = amount.substring(0, amount.length() - 1);
-        return new Test4Class(Integer.parseInt(amount));
-    }
-
-    @FromString
-    public static Test4Class parseClass(String amount) {
-        amount = amount.substring(0, amount.length() - 1);
-        return new Test4Class(Integer.parseInt(amount));
-    }
-
-}
+/*
+ *  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.test4;
+
+import org.joda.convert.FromString;
+
+/**
+ * Example class with annotated methods.
+ */
+public class Test4Factory {
+
+    @FromString
+    public static Test4Interface parseInterface(String amount) {
+        amount = amount.substring(0, amount.length() - 1);
+        return new Test4Class(Integer.parseInt(amount));
+    }
+
+    @FromString
+    public static Test4Class parseClass(String amount) {
+        amount = amount.substring(0, amount.length() - 1);
+        return new Test4Class(Integer.parseInt(amount));
+    }
+
+}
diff --git a/src/test/java/org/joda/convert/test4/Test4Interface.java b/src/test/java/org/joda/convert/test4/Test4Interface.java
index 8602f5a..6d592bf 100644
--- a/src/test/java/org/joda/convert/test4/Test4Interface.java
+++ b/src/test/java/org/joda/convert/test4/Test4Interface.java
@@ -1,30 +1,30 @@
-/*
- *  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.test4;
-
-import org.joda.convert.FromStringFactory;
-import org.joda.convert.ToString;
-
-/**
- * Example interface with annotated methods.
- */
- at FromStringFactory(factory = Test4Factory.class)
-public interface Test4Interface {
-
-    @ToString
-    String print();
-
-}
+/*
+ *  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.test4;
+
+import org.joda.convert.FromStringFactory;
+import org.joda.convert.ToString;
+
+/**
+ * Example interface with annotated methods.
+ */
+ at FromStringFactory(factory = Test4Factory.class)
+public interface Test4Interface {
+
+    @ToString
+    String print();
+
+}

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