public void register(Class<? extends LiquibaseDataType> dataTypeClass) {
    try {
      LiquibaseDataType example = dataTypeClass.newInstance();
      List<String> names = new ArrayList<String>();
      names.add(example.getName());
      names.addAll(Arrays.asList(example.getAliases()));

      Comparator<Class<? extends LiquibaseDataType>> comparator =
          new Comparator<Class<? extends LiquibaseDataType>>() {
            @Override
            public int compare(
                Class<? extends LiquibaseDataType> o1, Class<? extends LiquibaseDataType> o2) {
              try {
                return -1
                    * new Integer(o1.newInstance().getPriority())
                        .compareTo(o2.newInstance().getPriority());
              } catch (Exception e) {
                throw new UnexpectedLiquibaseException(e);
              }
            }
          };

      for (String name : names) {
        name = name.toLowerCase();
        if (registry.get(name) == null) {
          registry.put(name, new ArrayList<Class<? extends LiquibaseDataType>>());
        }
        List<Class<? extends LiquibaseDataType>> classes = registry.get(name);
        classes.add(dataTypeClass);
        Collections.sort(classes, comparator);
      }
    } catch (Exception e) {
      throw new UnexpectedLiquibaseException(e);
    }
  }
  public LiquibaseDataType fromDescription(String dataTypeDefinition, Database database) {
    String dataTypeName = dataTypeDefinition;
    if (dataTypeName.matches(".+\\(.*\\).*")) {
      dataTypeName = dataTypeName.replaceFirst("\\s*\\(.*\\)", "");
    }
    if (dataTypeName.matches(".+\\{.*")) {
      dataTypeName = dataTypeName.replaceFirst("\\s*\\{.*", "");
    }
    boolean autoIncrement = false;
    if (dataTypeName.endsWith(" identity")) {
      dataTypeName = dataTypeName.replaceFirst(" identity$", "");
      autoIncrement = true;
    }

    // unquote delimited identifiers
    final String[][] quotePairs =
        new String[][] {
          {"\"", "\""}, // double quotes
          {"[", "]"}, // square brackets (a la mssql)
          {"`", "`"}, // backticks (a la mysql)
          {"'", "'"} // single quotes
        };
    for (String[] quotePair : quotePairs) {
      String openQuote = quotePair[0];
      String closeQuote = quotePair[1];
      if (dataTypeName.startsWith(openQuote)) {
        int indexOfCloseQuote = dataTypeName.indexOf(closeQuote, openQuote.length());
        if (indexOfCloseQuote != -1
            && dataTypeName.indexOf(closeQuote, indexOfCloseQuote + closeQuote.length()) == -1) {
          dataTypeName =
              dataTypeName.substring(openQuote.length(), indexOfCloseQuote)
                  + dataTypeName.substring(
                      indexOfCloseQuote + closeQuote.length(), dataTypeName.length());
          break;
        }
      }
    }

    String additionalInfo = null;
    if (dataTypeName.toLowerCase().startsWith("bit varying")
        || dataTypeName.toLowerCase().startsWith("character varying")) {
      // not going to do anything. Special case for postgres in our tests, need to better support
      // handling these types of differences
    } else {
      String[] splitTypeName = dataTypeName.split("\\s+", 2);
      dataTypeName = splitTypeName[0];
      if (splitTypeName.length > 1) {
        additionalInfo = splitTypeName[1];
      }
    }

    Collection<Class<? extends LiquibaseDataType>> classes =
        registry.get(dataTypeName.toLowerCase());

    LiquibaseDataType liquibaseDataType = null;
    if (classes == null) {
      if (dataTypeName.toUpperCase().startsWith("INTERVAL")) {
        liquibaseDataType = new UnknownType(dataTypeDefinition);
      } else {
        liquibaseDataType = new UnknownType(dataTypeName);
      }
    } else {

      Iterator<Class<? extends LiquibaseDataType>> iterator = classes.iterator();
      do {
        try {
          liquibaseDataType = iterator.next().newInstance();
        } catch (Exception e) {
          throw new UnexpectedLiquibaseException(e);
        }
      } while ((database != null) && !liquibaseDataType.supports(database) && iterator.hasNext());
    }
    if ((database != null) && !liquibaseDataType.supports(database)) {
      throw new UnexpectedLiquibaseException(
          "Could not find type for "
              + liquibaseDataType.toString()
              + " for databaes "
              + database.getShortName());
    }
    if (liquibaseDataType == null) {
      liquibaseDataType = new UnknownType(dataTypeName);
    }
    liquibaseDataType.setAdditionalInformation(additionalInfo);

    if (dataTypeDefinition.matches(".+\\s*\\(.*")) {
      String paramStrings = dataTypeDefinition.replaceFirst(".*?\\(", "").replaceFirst("\\).*", "");
      String[] params = paramStrings.split(",");
      for (String param : params) {
        param = StringUtils.trimToNull(param);
        if (param != null) {
          liquibaseDataType.addParameter(param);
        }
      }
    }

    /*
    The block below seems logically incomplete.
    It will always end up putting the second word after the entire type name
    e.g. character varying will become CHARACTER VARYING varying

    //try to something like "int(11) unsigned" or int unsigned but not "varchar(11 bytes)"
    String lookingForAdditionalInfo = dataTypeDefinition;
    lookingForAdditionalInfo = lookingForAdditionalInfo.replaceFirst("\\(.*\\)", "");
    if (lookingForAdditionalInfo.contains(" ")) {
        liquibaseDataType.setAdditionalInformation(lookingForAdditionalInfo.split(" ", 2)[1]);
    }*/

    if (dataTypeDefinition.matches(".*\\{.*")) {
      String paramStrings = dataTypeDefinition.replaceFirst(".*?\\{", "").replaceFirst("\\}.*", "");
      String[] params = paramStrings.split(",");
      for (String param : params) {
        param = StringUtils.trimToNull(param);
        if (param != null) {
          String[] paramAndValue = param.split(":", 2);
          try {
            ObjectUtil.setProperty(liquibaseDataType, paramAndValue[0], paramAndValue[1]);
          } catch (Exception e) {
            throw new RuntimeException(
                "Unknown property "
                    + paramAndValue[0]
                    + " for "
                    + liquibaseDataType.getClass().getName()
                    + " "
                    + liquibaseDataType.toString());
          }
        }
      }
    }

    if (autoIncrement && liquibaseDataType instanceof IntType) {
      ((IntType) liquibaseDataType).setAutoIncrement(true);
    }
    if (autoIncrement && liquibaseDataType instanceof BigIntType) {
      ((BigIntType) liquibaseDataType).setAutoIncrement(true);
    }

    liquibaseDataType.finishInitialization(dataTypeDefinition);

    return liquibaseDataType;
  }