protected void validate(HttpServletRequest request, HttpServletResponse response, Form form) {
    super.validate(request, response, form);

    Field confirmPasswordField = form.getField("confirmPassword");

    if (confirmPasswordField != null && confirmPasswordField.isEnabled()) {
      // ensure passwords match:
      String password = form.getFieldValue("password");
      String confirmPassword = form.getFieldValue("confirmPassword");

      if (!password.equals(confirmPassword) && confirmPasswordField.isRequired()) {
        String key = "stormpath.web.register.form.errors.passwordMismatch";
        String msg = i18n(request, key);
        throw new MismatchedPasswordException(msg);
      }
    }
  }
  private Map<String, Object> getCustomData(HttpServletRequest request, Form form) {
    // Custom fields are either declared as form fields which shouldn't not be account fields or
    // through a customField attribute
    Map<String, Object> result = new LinkedHashMap<String, Object>();

    for (Field field : form.getFields()) {
      // Field is not part of the default account properties then is a custom field
      if (!field.getName().equals(getCsrfTokenManager().getTokenName())
          && !ACCOUNT_PROPERTIES.contains(field.getName())) {
        result.put(field.getName(), field.getValue());
      }
    }

    Object customData = getFieldValueResolver().getAllFields(request).get("customData");
    if (customData instanceof Map) {
      //noinspection unchecked
      result.putAll((Map<? extends String, ?>) customData);
    } // If not a map ignore, the spec doesn't cover this case

    return result;
  }
  @Override
  protected ViewModel onValidSubmit(HttpServletRequest req, HttpServletResponse resp, Form form)
      throws Exception {

    // Create a new Account instance that will represent the submitted user information:
    Account account = client.instantiate(Account.class);

    String value = form.getFieldValue("email");
    if (value != null) {
      account.setEmail(value);
    }

    value = form.getFieldValue("username");
    if (value != null) {
      account.setUsername(value);
    }

    value = form.getFieldValue("password");
    if (value != null) {
      account.setPassword(value);
    }

    value = form.getFieldValue("givenName");
    account.setGivenName(value != null ? value : "UNKNOWN");

    value = form.getFieldValue("middleName");
    if (value != null) {
      account.setMiddleName(value);
    }

    value = form.getFieldValue("surname");
    account.setSurname(value != null ? value : "UNKNOWN");

    account.getCustomData().putAll(getCustomData(req, form));

    // Get the Stormpath Application instance corresponding to this web app:
    Application app = ApplicationResolver.INSTANCE.getApplication(req);

    if (preRegisterHandler != null) {
      if (!preRegisterHandler.handle(req, resp, account)) {
        return null;
      }
    }

    AccountStore accountStore = accountStoreResolver.getAccountStore(req, resp);

    if (accountStore == null) {
      // now persist the new account, and ensure our account reference points to the newly
      // created/returned instance:
      account = app.createAccount(account);
    } else {
      final Account[] accountHolder = new Account[] {account};

      accountStore.accept(
          new AccountStoreVisitorAdapter() {
            @Override
            public void visit(Directory directory) {
              Account createdAccount = directory.createAccount(accountHolder[0]);
              accountHolder[0] = createdAccount;
            }

            @Override
            public void visit(Organization organization) {
              Account createdAccount = organization.createAccount(accountHolder[0]);
              accountHolder[0] = createdAccount;
            }
          });

      account = accountHolder[0];
    }

    publishRequestEvent(new DefaultRegisteredAccountRequestEvent(req, resp, account));

    if (postRegisterHandler != null) {
      if (!postRegisterHandler.handle(req, resp, account)) {
        return null;
      }
    }

    AccountStatus status = account.getStatus();

    if (isJsonPreferred(req, resp)) {
      //noinspection unchecked
      return new DefaultViewModel(
          STORMPATH_JSON_VIEW_NAME,
          java.util.Collections.singletonMap(
              "account", accountModelFactory.toMap(account, Collections.EMPTY_LIST)));
    }

    if (status == AccountStatus.ENABLED) {
      if (autoLogin) {
        // the user does not need to verify their email address, so just assume they are
        // authenticated
        // (since they specified their password during registration):
        final AuthenticationResult result = new TransientAuthenticationResult(account);
        this.authenticationResultSaver.set(req, resp, result);
      } else {
        return new DefaultViewModel(loginUri + "?status=created").setRedirect(true);
      }
    } else if (status == AccountStatus.UNVERIFIED) {
      return new DefaultViewModel(loginUri + "?status=unverified").setRedirect(true);
    }
    return new DefaultViewModel(nextUri).setRedirect(true);
  }