public Set<SavingsAccountCharge> fromSavingsProduct(final SavingsProduct savingsProduct) {

    final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<SavingsAccountCharge>();
    Set<Charge> productCharges = savingsProduct.charges();
    for (Charge charge : productCharges) {
      ChargeTimeType chargeTime = null;
      if (charge.getChargeTime() != null) {
        chargeTime = ChargeTimeType.fromInt(charge.getChargeTime());
      }
      if (chargeTime != null && chargeTime.isOnSpecifiedDueDate()) {
        continue;
      }

      ChargeCalculationType chargeCalculation = null;
      if (charge.getChargeCalculation() != null) {
        chargeCalculation = ChargeCalculationType.fromInt(charge.getChargeCalculation());
      }
      final boolean status = true;
      final SavingsAccountCharge savingsAccountCharge =
          SavingsAccountCharge.createNewWithoutSavingsAccount(
              charge,
              charge.getAmount(),
              chargeTime,
              chargeCalculation,
              null,
              status,
              charge.getFeeOnMonthDay(),
              charge.feeInterval());
      savingsAccountCharges.add(savingsAccountCharge);
    }
    return savingsAccountCharges;
  }
  private void validateSavingsCharges(
      final Set<SavingsAccountCharge> charges, final String productCurrencyCode) {
    final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
    final DataValidatorBuilder baseDataValidator =
        new DataValidatorBuilder(dataValidationErrors).resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
    boolean isOneWithdrawalPresent = false;
    boolean isOneAnnualPresent = false;
    for (SavingsAccountCharge charge : charges) {
      if (!charge.hasCurrencyCodeOf(productCurrencyCode)) {
        baseDataValidator
            .reset()
            .parameter("currency")
            .value(charge.getCharge().getId())
            .failWithCodeNoParameterAddedToErrorCode("currency.and.charge.currency.not.same");
      }

      if (charge.isWithdrawalFee()) {
        if (isOneWithdrawalPresent) {
          baseDataValidator
              .reset()
              .failWithCodeNoParameterAddedToErrorCode(
                  "multiple.withdrawal.fee.per.account.not.supported");
        }
        isOneWithdrawalPresent = true;
      }

      if (charge.isAnnualFee()) {
        if (isOneAnnualPresent) {
          baseDataValidator
              .reset()
              .failWithCodeNoParameterAddedToErrorCode(
                  "multiple.annual.fee.per.account.not.supported");
        }
        isOneAnnualPresent = true;
      }
    }
    if (!dataValidationErrors.isEmpty()) {
      throw new PlatformApiDataValidationException(dataValidationErrors);
    }
  }
  public Set<SavingsAccountCharge> fromParsedJson(final JsonElement element) {

    final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<>();

    if (element.isJsonObject()) {
      final JsonObject topLevelJsonElement = element.getAsJsonObject();
      final String dateFormat =
          this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
      final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
      if (topLevelJsonElement.has(chargesParamName)
          && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
        final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
        for (int i = 0; i < array.size(); i++) {

          final JsonObject savingsChargeElement = array.get(i).getAsJsonObject();

          final Long id =
              this.fromApiJsonHelper.extractLongNamed(idParamName, savingsChargeElement);
          final Long chargeId =
              this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement);
          final BigDecimal amount =
              this.fromApiJsonHelper.extractBigDecimalNamed(
                  amountParamName, savingsChargeElement, locale);
          final Integer chargeTimeType =
              this.fromApiJsonHelper.extractIntegerNamed(
                  chargeTimeTypeParamName, savingsChargeElement, locale);
          final Integer chargeCalculationType =
              this.fromApiJsonHelper.extractIntegerNamed(
                  chargeCalculationTypeParamName, savingsChargeElement, locale);
          final LocalDate dueDate =
              this.fromApiJsonHelper.extractLocalDateNamed(
                  dueAsOfDateParamName, savingsChargeElement, dateFormat, locale);
          final MonthDay feeOnMonthDay =
              this.fromApiJsonHelper.extractMonthDayNamed(
                  feeOnMonthDayParamName, savingsChargeElement);
          final Integer feeInterval =
              this.fromApiJsonHelper.extractIntegerNamed(
                  feeIntervalParamName, savingsChargeElement, locale);

          if (id == null) {
            final Charge chargeDefinition =
                this.chargeRepository.findOneWithNotFoundDetection(chargeId);
            final ChargeTimeType chargeTime = null;
            if (chargeTimeType != null) {
              ChargeTimeType.fromInt(chargeTimeType);
            }
            final ChargeCalculationType chargeCalculation = null;
            if (chargeCalculationType != null) {
              ChargeCalculationType.fromInt(chargeCalculationType);
            }
            final SavingsAccountCharge savingsAccountCharge =
                SavingsAccountCharge.createNewWithoutSavingsAccount(
                    chargeDefinition,
                    amount,
                    chargeTime,
                    chargeCalculation,
                    dueDate,
                    true,
                    feeOnMonthDay,
                    feeInterval);
            savingsAccountCharges.add(savingsAccountCharge);
          } else {
            final Long savingsAccountChargeId = id;
            final SavingsAccountCharge savingsAccountCharge =
                this.savingsAccountChargeRepository.findOne(savingsAccountChargeId);
            if (savingsAccountCharge == null) {
              throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId);
            }

            savingsAccountCharge.update(amount, dueDate, null, null);

            savingsAccountCharges.add(savingsAccountCharge);
          }
        }
      }
    }

    return savingsAccountCharges;
  }
  public Set<SavingsAccountCharge> fromParsedJson(
      final JsonElement element, final String productCurrencyCode) {

    final Set<SavingsAccountCharge> savingsAccountCharges = new HashSet<SavingsAccountCharge>();

    if (element.isJsonObject()) {
      final JsonObject topLevelJsonElement = element.getAsJsonObject();
      final String dateFormat =
          this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
      final String monthDayFormat =
          this.fromApiJsonHelper.extractMonthDayFormatParameter(topLevelJsonElement);
      final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
      if (topLevelJsonElement.has(chargesParamName)
          && topLevelJsonElement.get(chargesParamName).isJsonArray()) {
        final JsonArray array = topLevelJsonElement.get(chargesParamName).getAsJsonArray();
        for (int i = 0; i < array.size(); i++) {

          final JsonObject savingsChargeElement = array.get(i).getAsJsonObject();

          final Long id =
              this.fromApiJsonHelper.extractLongNamed(idParamName, savingsChargeElement);
          final Long chargeId =
              this.fromApiJsonHelper.extractLongNamed(chargeIdParamName, savingsChargeElement);
          final BigDecimal amount =
              this.fromApiJsonHelper.extractBigDecimalNamed(
                  amountParamName, savingsChargeElement, locale);
          final Integer chargeTimeType =
              this.fromApiJsonHelper.extractIntegerNamed(
                  chargeTimeTypeParamName, savingsChargeElement, locale);
          final Integer chargeCalculationType =
              this.fromApiJsonHelper.extractIntegerNamed(
                  chargeCalculationTypeParamName, savingsChargeElement, locale);
          final LocalDate dueDate =
              this.fromApiJsonHelper.extractLocalDateNamed(
                  dueAsOfDateParamName, savingsChargeElement, dateFormat, locale);

          final MonthDay feeOnMonthDay =
              this.fromApiJsonHelper.extractMonthDayNamed(
                  feeOnMonthDayParamName, savingsChargeElement, monthDayFormat, locale);
          final Integer feeInterval =
              this.fromApiJsonHelper.extractIntegerNamed(
                  feeIntervalParamName, savingsChargeElement, locale);

          if (id == null) {
            final Charge chargeDefinition =
                this.chargeRepository.findOneWithNotFoundDetection(chargeId);

            if (!chargeDefinition.isSavingsCharge()) {
              final String errorMessage =
                  "Charge with identifier "
                      + chargeDefinition.getId()
                      + " cannot be applied to Savings product.";
              throw new ChargeCannotBeAppliedToException(
                  "savings.product", errorMessage, chargeDefinition.getId());
            }

            ChargeTimeType chargeTime = null;
            if (chargeTimeType != null) {
              chargeTime = ChargeTimeType.fromInt(chargeTimeType);
            }

            ChargeCalculationType chargeCalculation = null;
            if (chargeCalculationType != null) {
              chargeCalculation = ChargeCalculationType.fromInt(chargeCalculationType);
            }

            final boolean status = true;
            final SavingsAccountCharge savingsAccountCharge =
                SavingsAccountCharge.createNewWithoutSavingsAccount(
                    chargeDefinition,
                    amount,
                    chargeTime,
                    chargeCalculation,
                    dueDate,
                    status,
                    feeOnMonthDay,
                    feeInterval);
            savingsAccountCharges.add(savingsAccountCharge);
          } else {
            final Long savingsAccountChargeId = id;
            final SavingsAccountCharge savingsAccountCharge =
                this.savingsAccountChargeRepository.findOne(savingsAccountChargeId);
            if (savingsAccountCharge == null) {
              throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId);
            }

            savingsAccountCharge.update(amount, dueDate, feeOnMonthDay, feeInterval);

            savingsAccountCharges.add(savingsAccountCharge);
          }
        }
      }
    }

    this.validateSavingsCharges(savingsAccountCharges, productCurrencyCode);
    return savingsAccountCharges;
  }