public void validate() {
    final List<ApiParameterError> dataValidationErrors = new ArrayList<>();

    final DataValidatorBuilder baseDataValidator =
        new DataValidatorBuilder(dataValidationErrors).resource("clientnote");

    baseDataValidator
        .reset()
        .parameter("note")
        .value(this.note)
        .notBlank()
        .notExceedingLengthOf(1000);

    if (!dataValidationErrors.isEmpty()) {
      throw new PlatformApiDataValidationException(
          "validation.msg.validation.errors.exist",
          "Validation errors exist.",
          dataValidationErrors);
    }
  }
  @Transactional
  @Override
  public CommandProcessingResult update(final Long productId, final JsonCommand command) {

    try {
      this.context.authenticatedUser();
      final SavingsProduct product = this.savingProductRepository.findOne(productId);
      if (product == null) {
        throw new SavingsProductNotFoundException(productId);
      }

      this.fromApiJsonDataValidator.validateForUpdate(command.json(), product);

      final Map<String, Object> changes = product.update(command);

      if (changes.containsKey(chargesParamName)) {
        final Set<Charge> savingsProductCharges =
            this.savingsProductAssembler.assembleListOfSavingsProductCharges(
                command, product.currency().getCode());
        final boolean updated = product.update(savingsProductCharges);
        if (!updated) {
          changes.remove(chargesParamName);
        }
      }

      if (changes.containsKey(taxGroupIdParamName)) {
        final TaxGroup taxGroup = this.savingsProductAssembler.assembleTaxGroup(command);
        product.setTaxGroup(taxGroup);
        if (product.withHoldTax() && product.getTaxGroup() == null) {
          final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
          final DataValidatorBuilder baseDataValidator =
              new DataValidatorBuilder(dataValidationErrors)
                  .resource(SAVINGS_PRODUCT_RESOURCE_NAME);
          final Long taxGroupId = null;
          baseDataValidator.reset().parameter(taxGroupIdParamName).value(taxGroupId).notBlank();
          throw new PlatformApiDataValidationException(dataValidationErrors);
        }
      }

      // accounting related changes
      final boolean accountingTypeChanged = changes.containsKey(accountingRuleParamName);
      final Map<String, Object> accountingMappingChanges =
          this.accountMappingWritePlatformService.updateSavingsProductToGLAccountMapping(
              product.getId(),
              command,
              accountingTypeChanged,
              product.getAccountingType(),
              DepositAccountType.SAVINGS_DEPOSIT);
      changes.putAll(accountingMappingChanges);

      if (!changes.isEmpty()) {
        this.savingProductRepository.saveAndFlush(product);
      }

      return new CommandProcessingResultBuilder() //
          .withEntityId(product.getId()) //
          .with(changes)
          .build();
    } catch (final DataAccessException e) {
      handleDataIntegrityIssues(command, e.getMostSpecificCause(), e);
      return CommandProcessingResult.empty();
    } catch (final PersistenceException dve) {
      Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
      handleDataIntegrityIssues(command, throwable, dve);
      return CommandProcessingResult.empty();
    }
  }