diff --git a/build.gradle b/build.gradle index 5f2d9d9ed..655e26457 100644 --- a/build.gradle +++ b/build.gradle @@ -166,7 +166,7 @@ allprojects { mavenCentral() } - configurations.all { + configurations.configureEach { resolutionStrategy { dependencySubstitution { // Substitution is to resolve CVE-2025-12183 @@ -392,7 +392,7 @@ configure(project.fineractJavaProjects) { } // Add performance optimizations - configurations.all { + configurations.configureEach { resolutionStrategy { cacheChangingModulesFor 0, 'seconds' cacheDynamicVersionsFor 0, 'seconds' @@ -440,40 +440,40 @@ configure(project.fineractJavaProjects) { configurations { api.setCanBeResolved(true) } - tasks.withType(Copy) { + tasks.withType(Copy).configureEach { duplicatesStrategy = DuplicatesStrategy.EXCLUDE } - tasks.withType(JavaCompile) { + tasks.withType(JavaCompile).configureEach { options.compilerArgs += [ - "-Xlint:cast", - "-Xlint:auxiliaryclass", - "-Xlint:dep-ann", - "-Xlint:divzero", - "-Xlint:empty", - "-Xlint:exports", - "-Xlint:fallthrough", - "-Xlint:finally", - "-Xlint:module", - "-Xlint:opens", - "-Xlint:options", - "-Xlint:overloads", - "-Xlint:overrides", - "-Xlint:path", - "-Xlint:processing", - "-Xlint:removal", - "-Xlint:requires-automatic", - "-Xlint:requires-transitive-automatic", - "-Xlint:try", - "-Xlint:varargs", - "-Xlint:preview", - "-Xlint:static", - // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code - // and during an IntelliJ recompilation, it fails - //"-Werror", - "-Xmaxwarns", - "1500", - "-Xmaxerrs", - "1500" + "-Xlint:cast", + "-Xlint:auxiliaryclass", + "-Xlint:dep-ann", + "-Xlint:divzero", + "-Xlint:empty", + "-Xlint:exports", + "-Xlint:fallthrough", + "-Xlint:finally", + "-Xlint:module", + "-Xlint:opens", + "-Xlint:options", + "-Xlint:overloads", + "-Xlint:overrides", + "-Xlint:path", + "-Xlint:processing", + "-Xlint:removal", + "-Xlint:requires-automatic", + "-Xlint:requires-transitive-automatic", + "-Xlint:try", + "-Xlint:varargs", + "-Xlint:preview", + "-Xlint:static", + // -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code + // and during an IntelliJ recompilation, it fails + //"-Werror", + "-Xmaxwarns", + "1500", + "-Xmaxerrs", + "1500" ] // TODO FINERACT-959 (gradually) enable -Xlint:all (see "javac -help -X") @@ -759,11 +759,13 @@ configure(project.fineractJavaProjects) { ] } - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - options.encoding = 'UTF-8' - // Ignore any errors during javadoc generation - failOnError = false + tasks.withType(Javadoc).tap { + configureEach { + options.addStringOption('Xdoclint:none', '-quiet') + options.encoding = 'UTF-8' + // Ignore any errors during javadoc generation + failOnError = false + } } } @@ -899,17 +901,21 @@ cyclonedxBom { includeLicenseText = true } -task printSourceSetInformation() { - doLast{ +tasks.register('printSourceSetInformation') { + doLast { sourceSets.each { srcSet -> - println "["+srcSet.name+"]" - print "-->Source directories: "+srcSet.allJava.srcDirs+"\n" - print "-->Output directories: "+srcSet.output.classesDirs.files+"\n" + println "[" + srcSet.name + "]" + print "-->Source directories: " + srcSet.allJava.srcDirs + "\n" + print "-->Output directories: " + srcSet.output.classesDirs.files + "\n" print "-->Compile classpath:\n" srcSet.compileClasspath.files.each { - print " "+it.path+"\n" + print " " + it.path + "\n" } println "" } } } + +tasks.withType(Checkstyle).configureEach { + exclude("**/*.avsc") +} diff --git a/fineract-client-feign/src/main/java/org/apache/fineract/client/feign/services/DocumentsApiFixed.java b/fineract-client-feign/src/main/java/org/apache/fineract/client/feign/services/DocumentsApiFixed.java index de3f7934a..39fd22156 100644 --- a/fineract-client-feign/src/main/java/org/apache/fineract/client/feign/services/DocumentsApiFixed.java +++ b/fineract-client-feign/src/main/java/org/apache/fineract/client/feign/services/DocumentsApiFixed.java @@ -28,8 +28,9 @@ import org.apache.fineract.client.models.PostEntityTypeEntityIdDocumentsResponse import org.apache.fineract.client.models.PutEntityTypeEntityIdDocumentsResponse; /** - * This class was originally generated by OpenAPI Generator (https://openapi-generator.tech), but then had to be - * manually edited to manually fix https://issues.apache.org/jira/browse/FINERACT-1227. If we could fix our OpenAPI / + * This class was originally generated by OpenAPI Generator, but then had + * to be manually edited to manually fix + * FINERACT-1227. If we could fix our OpenAPI / * Swagger YAML generation from the JAX RS and OpenAPI annotation to have the correct notation for binary document files * and images, then this could be removed again. */ @@ -40,16 +41,6 @@ public interface DocumentsApiFixed { * the document description : Description of the document file : The file to be uploaded Mandatory Fields : file and * description * - * @param entityType - * entityType (required) - * @param entityId - * entityId (required) - * @param file - * (required) - * @param name - * name (optional) - * @param description - * description (optional) * @return PostEntityTypeEntityIdDocumentsResponse */ @RequestLine("POST /v1/{entityType}/{entityId}/documents") @@ -120,18 +111,6 @@ public interface DocumentsApiFixed { * Update a Document Note: A document is updated using a Multi-part form upload Body Parts name Name or summary of * the document description Description of the document file The file to be uploaded * - * @param entityType - * entityType (required) - * @param entityId - * entityId (required) - * @param documentId - * documentId (required) - * @param file - * (optional) - * @param name - * name (optional) - * @param description - * description (optional) * @return PutEntityTypeEntityIdDocumentsResponse */ @RequestLine("PUT /v1/{entityType}/{entityId}/documents/{documentId}") diff --git a/fineract-command/src/main/java/org/apache/fineract/command/persistence/mapping/CommandJsonMapper.java b/fineract-command/src/main/java/org/apache/fineract/command/persistence/mapping/CommandJsonMapper.java index 7ff101321..06574c401 100644 --- a/fineract-command/src/main/java/org/apache/fineract/command/persistence/mapping/CommandJsonMapper.java +++ b/fineract-command/src/main/java/org/apache/fineract/command/persistence/mapping/CommandJsonMapper.java @@ -34,6 +34,7 @@ final class CommandJsonMapper { private static final String CLASS_ATTRIBUTE = "@class"; private final ObjectMapper mapper; + @SuppressWarnings("unchecked") public T map(JsonNode source) { if (source == null) { return null; diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/configuration/RetryConfigurationAssembler.java b/fineract-core/src/main/java/org/apache/fineract/commands/configuration/RetryConfigurationAssembler.java index b79223ee1..87af40366 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/configuration/RetryConfigurationAssembler.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/configuration/RetryConfigurationAssembler.java @@ -56,7 +56,7 @@ public class RetryConfigurationAssembler { public Retry getRetryConfigurationForExecuteCommand() { Class[] exceptionList = fineractProperties.getRetry().getInstances().getExecuteCommand().getRetryExceptions(); - RetryConfig.Builder configBuilder = buildCommonExecuteCommandConfiguration(); + RetryConfig.Builder configBuilder = buildCommonExecuteCommandConfiguration(); if (exceptionList != null) { configBuilder.retryOnException(ex -> { @@ -71,7 +71,7 @@ public class RetryConfigurationAssembler { public Retry getRetryConfigurationForBatchApiWithEnclosingTransaction() { Class[] exceptionList = fineractProperties.getRetry().getInstances().getExecuteCommand().getRetryExceptions(); - RetryConfig.Builder configBuilder = buildCommonExecuteCommandConfiguration(); + RetryConfig.Builder configBuilder = buildCommonExecuteCommandConfiguration(); if (exceptionList != null) { configBuilder.retryOnException(ex -> { @@ -89,10 +89,10 @@ public class RetryConfigurationAssembler { return registry.retry(BATCH_RETRY, config); } - private RetryConfig.Builder buildCommonExecuteCommandConfiguration() { + private RetryConfig.Builder buildCommonExecuteCommandConfiguration() { var props = fineractProperties.getRetry().getInstances().getExecuteCommand(); - RetryConfig.Builder configBuilder = RetryConfig.custom().maxAttempts(props.getMaxAttempts()); + RetryConfig.Builder configBuilder = RetryConfig.custom().maxAttempts(props.getMaxAttempts()); if (props.getWaitDuration() != null && props.getWaitDuration().toMillis() >= 0) { if (Boolean.TRUE.equals(props.getEnableExponentialBackoff())) { @@ -111,7 +111,7 @@ public class RetryConfigurationAssembler { } public Retry getRetryConfigurationForCommandResultPersistence() { - RetryConfig.Builder configBuilder = buildCommonExecuteCommandConfiguration(); + RetryConfig.Builder configBuilder = buildCommonExecuteCommandConfiguration(); configBuilder.retryOnException(e -> e instanceof RuntimeException && !(e instanceof CommandResultPersistenceException)); diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ApiFacingEnum.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ApiFacingEnum.java index 9b73a7f90..55298cf89 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ApiFacingEnum.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ApiFacingEnum.java @@ -34,10 +34,12 @@ public interface ApiFacingEnum & ApiFacingEnum> { } default StringEnumOptionData getValueAsStringEnumOptionData() { - return new StringEnumOptionData(((Enum) this).name(), getCode(), getHumanReadableName()); + return new StringEnumOptionData(this.name(), getCode(), getHumanReadableName()); } String getCode(); String getHumanReadableName(); + + String name(); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java index 5b74dfcd3..a629c78db 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/JsonCommand.java @@ -540,7 +540,7 @@ public final class JsonCommand { */ public boolean booleanPrimitiveValueOfParameterNamed(final String parameterName) { final Boolean value = this.fromApiJsonHelper.extractBooleanNamed(parameterName, this.parsedCommand); - return ObjectUtils.defaultIfNull(value, Boolean.FALSE); + return ObjectUtils.getIfNull(value, Boolean.FALSE); } public boolean isChangeInArrayParameterNamed(final String parameterName, final String[] existingValue) { diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java index 3234a0bd7..b8468ebc6 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/DataValidatorBuilder.java @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import lombok.Getter; import net.fortuna.ical4j.model.property.RRule; import net.fortuna.ical4j.validate.ValidationException; import org.apache.commons.collections4.CollectionUtils; @@ -40,6 +41,7 @@ import org.springframework.util.ObjectUtils; public class DataValidatorBuilder { public static final String VALID_INPUT_SEPARATOR = "_"; + @Getter private final List dataValidationErrors; private String resource; private String parameter; @@ -78,10 +80,6 @@ public class DataValidatorBuilder { return !dataValidationErrors.isEmpty(); } - public List getDataValidationErrors() { - return dataValidationErrors; - } - public DataValidatorBuilder resource(final String resource) { this.resource = resource; return this; @@ -629,7 +627,13 @@ public class DataValidatorBuilder { return this; } - final List list = (List) this.value; + if (!(this.value instanceof List list)) { + String validationErrorCode = "validation.msg." + this.resource + "." + this.parameter + ".is.not.list"; + String defaultEnglishMessage = "The parameter `" + this.parameter + "` should be a list."; + final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode, defaultEnglishMessage, this.parameter); + this.dataValidationErrors.add(error); + return this; + } if (CollectionUtils.isEmpty(list)) { String validationErrorCode = "validation.msg." + this.resource + "." + this.parameter + ".cannot.be.empty"; String defaultEnglishMessage = "The parameter `" + this.parameter + "` cannot be empty. You must select at least one."; diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableCustom.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableCustom.java index 9f9bfa23d..c0085fe90 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableCustom.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableCustom.java @@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.core.domain; import jakarta.persistence.Column; import jakarta.persistence.MappedSuperclass; +import java.io.Serial; import java.time.LocalDateTime; import java.util.Optional; import org.springframework.data.domain.Auditable; @@ -32,15 +33,11 @@ import org.springframework.data.jpa.domain.AbstractAuditable; * instead of LocalDateTime for created and modified. * * Abstract base class for auditable entities. Stores the audit values in persistent fields. - * - * @param - * the auditing type. Typically some kind of user. - * @param - * the type of the auditing type's identifier */ @MappedSuperclass public abstract class AbstractAuditableCustom extends AbstractPersistableCustom implements Auditable { + @Serial private static final long serialVersionUID = 141481953116476081L; @Column(name = "createdby_id") diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/ErrorHandler.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/ErrorHandler.java index c7e3cb62c..01cbe8861 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/ErrorHandler.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/exception/ErrorHandler.java @@ -116,6 +116,7 @@ public final class ErrorHandler { private final DefaultExceptionMapper defaultExceptionMapper; @NotNull + @SuppressWarnings("unchecked") public ExceptionMapper findMostSpecificExceptionHandler(T exception) { Class clazz = exception.getClass(); do { @@ -123,23 +124,19 @@ public final class ErrorHandler { Set fineractErrorMappers = createSet(ctx.getBeanNamesForType(FineractExceptionMapper.class)); SetUtils.SetView intersection = SetUtils.intersection(exceptionMappers, fineractErrorMappers); if (!intersection.isEmpty()) { - // noinspection unchecked return (ExceptionMapper) ctx.getBean(intersection.iterator().next()); } if (!exceptionMappers.isEmpty()) { - // noinspection unchecked return (ExceptionMapper) ctx.getBean(exceptionMappers.iterator().next()); } clazz = clazz.getSuperclass(); } while (!clazz.equals(Exception.class)); - // noinspection unchecked return (ExceptionMapper) defaultExceptionMapper; } /** * Returns an object of ErrorInfo type containing the information regarding the raised error. * - * @param exception * @return ErrorInfo */ public ErrorInfo handle(@NotNull RuntimeException exception) { diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/producer/ExternalEventProducer.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/producer/ExternalEventProducer.java index 4f4143a4e..983875843 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/producer/ExternalEventProducer.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/event/external/producer/ExternalEventProducer.java @@ -28,9 +28,7 @@ public interface ExternalEventProducer { * Sends the created ExternalEvents * * @param partitions - * is a Map> partitions, the key here the id of the aggregated root. The value is list - * of external events belong to the same key, serialized into byte array - * @throws AcknowledgementTimeoutException + * The value is list of external events belong to the same key, serialized into byte array */ void sendEvents(Map> partitions) throws AcknowledgementTimeoutException; } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java index e8c2bbe91..694a65aa6 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java @@ -27,11 +27,9 @@ import java.util.regex.Pattern; import lombok.Getter; /** - * Utility to assemble the WHERE clause of an SQL query without the risk of SQL injection. - * - *

- * When using this utility instead of manually assembling SQL queries, then {@link SqlValidator} should not be required - * anymore. (Correctly using this means only ever passing completely fixed String literals to .) + * Utility to assemble the WHERE clause of an SQL query without the risk of SQL injection. When using this utility + * instead of manually assembling SQL queries, then SqlValidator should not be required anymore. (Correctly using this + * means only ever passing completely fixed String literals to .) * * @author Michael Vorburger */ @@ -67,9 +65,6 @@ public class SQLBuilder { throw new IllegalArgumentException("criteria cannot be null"); } String trimmedCriteria = criteria.trim(); - if (trimmedCriteria.isEmpty()) { - throw new IllegalArgumentException("criteria cannot be null"); - } if (trimmedCriteria.contains("?")) { throw new IllegalArgumentException( "criteria cannot contain a '?' (that is automatically added at the end): " + trimmedCriteria); @@ -89,7 +84,7 @@ public class SQLBuilder { "criteria cannot contain more than 1 space (between column name and operator): " + trimmedCriteria); } if (!operator.equals("=") && !operator.equals("<") && !operator.equals(">") && !operator.equals("<=") && !operator.equals(">=") - && !operator.equals("<>") && !operator.equals("LIKE") && !operator.equals("like") && !operator.toLowerCase().equals("is")) { + && !operator.equals("<>") && !operator.equalsIgnoreCase("like") && !operator.equalsIgnoreCase("is")) { // add support for SQL's BETWEEN and IN, if/when ever needed.. (it's // a little more than just adding above, as it can have multiple // arguments) @@ -97,7 +92,7 @@ public class SQLBuilder { } // TODO: Would be better to use SqlOperator functionality to handle - if (sb.length() > 0) { + if (!sb.isEmpty()) { sb.append(whereLogicalOperator.getSqlStr()); } sb.append(trimmedCriteria); @@ -124,7 +119,7 @@ public class SQLBuilder { } public void addSubOperation(Consumer subOperation) { - if (sb.length() > 0) { + if (!sb.isEmpty()) { sb.append(WhereLogicalOperator.AND.getSqlStr()); } sb.append(" ( "); @@ -138,8 +133,8 @@ public class SQLBuilder { * @return SQL WHERE clause, almost always starting with " WHERE ..." (unless no criteria, then empty) */ public String getSQLTemplate() { - if (sb.length() > 0) { - return " WHERE " + sb.toString(); + if (!sb.isEmpty()) { + return " WHERE " + sb; } return ""; } @@ -178,7 +173,7 @@ public class SQLBuilder { } else if (currentArg == null) { whereClause.append("null"); } else { - whereClause.append(String.valueOf(currentArg)); + whereClause.append(currentArg); } whereClause.append("]"); } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java index 1d1002c75..f5067ae6c 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnClosureType.java @@ -19,11 +19,12 @@ package org.apache.fineract.portfolio.savings; import java.util.Arrays; +import lombok.Getter; /** - * An enumeration of different options available on account closure {@link FixedDepositAccount} & - * {@link RecurringDepositAccount}. + * An enumeration of different options available on account closure */ +@Getter public enum DepositAccountOnClosureType { INVALID(0, "depositAccountClosureType.invalid"), // @@ -40,31 +41,18 @@ public enum DepositAccountOnClosureType { this.code = code; } - public Integer getValue() { - return this.value; - } - - public String getCode() { - return this.code; - } - public static DepositAccountOnClosureType fromInt(final Integer v) { if (v == null) { return INVALID; } - switch (v) { - case 100: - return WITHDRAW_DEPOSIT; - case 200: - return TRANSFER_TO_SAVINGS; - case 300: - return REINVEST_PRINCIPAL_AND_INTEREST; - case 400: - return REINVEST_PRINCIPAL_ONLY; - default: - return INVALID; - } + return switch (v) { + case 100 -> WITHDRAW_DEPOSIT; + case 200 -> TRANSFER_TO_SAVINGS; + case 300 -> REINVEST_PRINCIPAL_AND_INTEREST; + case 400 -> REINVEST_PRINCIPAL_ONLY; + default -> INVALID; + }; } // TODO: why not just use the enum values... just more boilerplate code here!! diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java index ee293757d..e1a0d84aa 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountOnHoldTransactionType.java @@ -18,9 +18,12 @@ */ package org.apache.fineract.portfolio.savings; +import lombok.Getter; + /** - * An enumeration of on hold transactions that can occur on a {@link SavingsAccount}. + * An enumeration of on hold transactions that can occur on SavingsAccount. */ +@Getter public enum DepositAccountOnHoldTransactionType { INVALID(0, "deposutAccountOnHoldTransactionType.invalid"), // @@ -35,27 +38,16 @@ public enum DepositAccountOnHoldTransactionType { this.code = code; } - public Integer getValue() { - return this.value; - } - - public String getCode() { - return this.code; - } - public static DepositAccountOnHoldTransactionType fromInt(final Integer v) { if (v == null) { return INVALID; } - switch (v) { - case 1: - return HOLD; - case 2: - return RELEASE; - default: - return INVALID; - } + return switch (v) { + case 1 -> HOLD; + case 2 -> RELEASE; + default -> INVALID; + }; } // TODO: why not just use the enum values... just more boilerplate code here!! diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java index 95790cf0d..c11de1c1d 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/DepositAccountType.java @@ -18,11 +18,13 @@ */ package org.apache.fineract.portfolio.savings; -import org.apache.commons.lang3.StringUtils; +import lombok.Getter; +import org.apache.commons.lang3.Strings; /** - * An enumeration of different transactions that can occur on a {@link SavingsAccount}. + * An enumeration of different transactions that can occur on a SavingsAccount. */ +@Getter public enum DepositAccountType { INVALID(0, "depositAccountType.invalid"), // @@ -40,31 +42,18 @@ public enum DepositAccountType { this.code = code; } - public Integer getValue() { - return this.value; - } - - public String getCode() { - return this.code; - } - public static DepositAccountType fromInt(final Integer v) { if (v == null) { return INVALID; } - switch (v) { - case 100: - return SAVINGS_DEPOSIT; - case 200: - return FIXED_DEPOSIT; - case 300: - return RECURRING_DEPOSIT; - case 400: - return CURRENT_DEPOSIT; - default: - return INVALID; - } + return switch (v) { + case 100 -> SAVINGS_DEPOSIT; + case 200 -> FIXED_DEPOSIT; + case 300 -> RECURRING_DEPOSIT; + case 400 -> CURRENT_DEPOSIT; + default -> INVALID; + }; } // TODO: why not just use the enum values... just more boilerplate code here!! @@ -94,19 +83,15 @@ public enum DepositAccountType { @Override public String toString() { - return StringUtils.replace(code, "_", SPACE); + return Strings.CS.replace(code, "_", SPACE); } public String resourceName() { - switch (this) { - case FIXED_DEPOSIT: - return DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME; - case RECURRING_DEPOSIT: - return DepositsApiConstants.RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME; - case SAVINGS_DEPOSIT: - return DepositsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; - default: - return "INVALID"; - } + return switch (this) { + case FIXED_DEPOSIT -> DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME; + case RECURRING_DEPOSIT -> DepositsApiConstants.RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME; + case SAVINGS_DEPOSIT -> DepositsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; + default -> "INVALID"; + }; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java index af1034abc..51b15c0cf 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java @@ -24,10 +24,11 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; +import lombok.Getter; import org.apache.fineract.portfolio.TransactionEntryType; /** - * An enumeration of different transactions that can occur on a {@link SavingsAccount}. + * An enumeration of different transactions that can occur on a SavingsAccount. */ public enum SavingsAccountTransactionType { @@ -56,7 +57,9 @@ public enum SavingsAccountTransactionType { .collect(Collectors.toMap(SavingsAccountTransactionType::getValue, v -> v)); private final int value; + @Getter private final String code; + @Getter private final TransactionEntryType entryType; SavingsAccountTransactionType(final Integer value, final String code, TransactionEntryType entryType) { @@ -77,14 +80,6 @@ public enum SavingsAccountTransactionType { return this.value; } - public String getCode() { - return this.code; - } - - public TransactionEntryType getEntryType() { - return entryType; - } - public boolean isCreditEntryType() { return entryType != null && entryType.isCredit(); } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java index bed16288e..f64de2bcd 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductData.java @@ -23,6 +23,8 @@ import java.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Map; +import lombok.Getter; +import lombok.Setter; import org.apache.fineract.accounting.common.AccountingRuleType; import org.apache.fineract.accounting.glaccount.data.GLAccountData; import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper; @@ -38,24 +40,40 @@ import org.apache.fineract.portfolio.tax.data.TaxGroupData; */ public final class SavingsProductData implements Serializable { + @Getter private final Long id; + @Getter private final String name; private final String shortName; private final String description; + @Getter private final CurrencyData currency; + @Getter private final BigDecimal nominalAnnualInterestRate; + @Getter private final EnumOptionData interestCompoundingPeriodType; + @Getter private final EnumOptionData interestPostingPeriodType; + @Getter private final EnumOptionData interestCalculationType; + @Getter private final EnumOptionData interestCalculationDaysInYearType; + @Getter private final BigDecimal minRequiredOpeningBalance; + @Getter private final Integer lockinPeriodFrequency; + @Getter private final EnumOptionData lockinPeriodFrequencyType; + @Getter private final boolean withdrawalFeeForTransfers; + @Getter private final boolean allowOverdraft; + @Getter private final BigDecimal overdraftLimit; + @Getter private final BigDecimal minRequiredBalance; private final boolean enforceMinRequiredBalance; + @Getter private final BigDecimal maxAllowedLienLimit; private final boolean lienAllowed; private final BigDecimal minBalanceForInterestCalculation; @@ -63,6 +81,8 @@ public final class SavingsProductData implements Serializable { private final BigDecimal minOverdraftForInterestCalculation; private final boolean withHoldTax; private final TaxGroupData taxGroup; + @Setter + @Getter private String depositAccountType = null; private final String accountMappingForPayment; @@ -171,10 +191,6 @@ public final class SavingsProductData implements Serializable { /** * Returns a {@link SavingsProductData} that contains and exist {@link SavingsProductData} data with further * template data for dropdowns. - * - * @param taxGroupOptions - * TODO - * @param accountMapping */ public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection currencyOptions, final Collection interestCompoundingPeriodTypeOptions, @@ -220,7 +236,6 @@ public final class SavingsProductData implements Serializable { final Map> accountingMappingOptions = null; final Collection chargeOptions = null; final Collection penaltyOptions = null; - final String accountMappingForPayment = null; return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.shortName, existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType, @@ -505,10 +520,9 @@ public final class SavingsProductData implements Serializable { @Override public boolean equals(final Object obj) { - if (!(obj instanceof SavingsProductData)) { + if (!(obj instanceof SavingsProductData productData)) { return false; } - final SavingsProductData productData = (SavingsProductData) obj; return productData.id.compareTo(this.id) == 0; } @@ -517,78 +531,6 @@ public final class SavingsProductData implements Serializable { return this.id.hashCode(); } - public String getName() { - return this.name; - } - - public String getDepositAccountType() { - return depositAccountType; - } - - public void setDepositAccountType(String depositAccountType) { - this.depositAccountType = depositAccountType; - } - - public BigDecimal getNominalAnnualInterestRate() { - return nominalAnnualInterestRate; - } - - public CurrencyData getCurrency() { - return currency; - } - - public Integer getLockinPeriodFrequency() { - return lockinPeriodFrequency; - } - - public EnumOptionData getLockinPeriodFrequencyType() { - return lockinPeriodFrequencyType; - } - - public BigDecimal getOverdraftLimit() { - return overdraftLimit; - } - - public BigDecimal getMinRequiredOpeningBalance() { - return minRequiredOpeningBalance; - } - - public EnumOptionData getInterestCompoundingPeriodType() { - return interestCompoundingPeriodType; - } - - public EnumOptionData getInterestPostingPeriodType() { - return interestPostingPeriodType; - } - - public EnumOptionData getInterestCalculationType() { - return interestCalculationType; - } - - public EnumOptionData getInterestCalculationDaysInYearType() { - return interestCalculationDaysInYearType; - } - - public boolean isAllowOverdraft() { - return allowOverdraft; - } - - public BigDecimal getMinRequiredBalance() { - return minRequiredBalance; - } - - public BigDecimal getMaxAllowedLienLimit() { - return maxAllowedLienLimit; - } - - public Long getId() { - return id; - } - - public boolean isWithdrawalFeeForTransfers() { - return withdrawalFeeForTransfers; - } - public boolean isCashBasedAccountingEnabled() { return AccountingRuleType.CASH_BASED.getValue().toString().equals(this.accountingRule.getValue()); } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountStatusType.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountStatusType.java index c2c18598d..ffe2fefaf 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountStatusType.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountStatusType.java @@ -18,9 +18,12 @@ */ package org.apache.fineract.portfolio.savings.domain; +import lombok.Getter; + /** - * Enum representation of {@link SavingsAccount} status states. + * Enum representation of SavingsAccount status states. */ +@Getter public enum SavingsAccountStatusType { INVALID(0, "savingsAccountStatusType.invalid"), // @@ -39,41 +42,19 @@ public enum SavingsAccountStatusType { private final String code; public static SavingsAccountStatusType fromInt(final Integer type) { - - SavingsAccountStatusType enumeration = SavingsAccountStatusType.INVALID; - switch (type) { - case 100: - enumeration = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL; - break; - case 200: - enumeration = SavingsAccountStatusType.APPROVED; - break; - case 300: - enumeration = SavingsAccountStatusType.ACTIVE; - break; - case 303: - enumeration = SavingsAccountStatusType.TRANSFER_IN_PROGRESS; - break; - case 304: - enumeration = SavingsAccountStatusType.TRANSFER_ON_HOLD; - break; - case 400: - enumeration = SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT; - break; - case 500: - enumeration = SavingsAccountStatusType.REJECTED; - break; - case 600: - enumeration = SavingsAccountStatusType.CLOSED; - break; - case 700: - enumeration = SavingsAccountStatusType.PRE_MATURE_CLOSURE; - break; - case 800: - enumeration = SavingsAccountStatusType.MATURED; - break; - } - return enumeration; + return switch (type) { + case 100 -> SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL; + case 200 -> SavingsAccountStatusType.APPROVED; + case 300 -> SavingsAccountStatusType.ACTIVE; + case 303 -> SavingsAccountStatusType.TRANSFER_IN_PROGRESS; + case 304 -> SavingsAccountStatusType.TRANSFER_ON_HOLD; + case 400 -> SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT; + case 500 -> SavingsAccountStatusType.REJECTED; + case 600 -> SavingsAccountStatusType.CLOSED; + case 700 -> SavingsAccountStatusType.PRE_MATURE_CLOSURE; + case 800 -> SavingsAccountStatusType.MATURED; + default -> SavingsAccountStatusType.INVALID; + }; } SavingsAccountStatusType(final Integer value, final String code) { @@ -85,14 +66,6 @@ public enum SavingsAccountStatusType { return this.value.equals(state.getValue()); } - public Integer getValue() { - return this.value; - } - - public String getCode() { - return this.code; - } - public boolean isSubmittedAndPendingApproval() { return this.value.equals(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue()); } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java index 9e19bf1d0..e36337a84 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java @@ -18,9 +18,12 @@ */ package org.apache.fineract.portfolio.savings.domain; +import lombok.Getter; + /** - * Enum representation of {@link SavingsAccount} sub-status states. + * Enum representation of SavingsAccount sub-status states. */ +@Getter public enum SavingsAccountSubStatusEnum { NONE(0, "SavingsAccountSubStatusEnum.none"), // @@ -38,26 +41,15 @@ public enum SavingsAccountSubStatusEnum { SavingsAccountSubStatusEnum enumeration = SavingsAccountSubStatusEnum.NONE; if (null != type) { - switch (type) { - case 100: - enumeration = SavingsAccountSubStatusEnum.INACTIVE; - break; - case 200: - enumeration = SavingsAccountSubStatusEnum.DORMANT; - break; - case 300: - enumeration = SavingsAccountSubStatusEnum.ESCHEAT; - break; - case 400: - enumeration = SavingsAccountSubStatusEnum.BLOCK; - break; - case 500: - enumeration = SavingsAccountSubStatusEnum.BLOCK_CREDIT; - break; - case 600: - enumeration = SavingsAccountSubStatusEnum.BLOCK_DEBIT; - break; - } + enumeration = switch (type) { + case 100 -> SavingsAccountSubStatusEnum.INACTIVE; + case 200 -> SavingsAccountSubStatusEnum.DORMANT; + case 300 -> SavingsAccountSubStatusEnum.ESCHEAT; + case 400 -> SavingsAccountSubStatusEnum.BLOCK; + case 500 -> SavingsAccountSubStatusEnum.BLOCK_CREDIT; + case 600 -> SavingsAccountSubStatusEnum.BLOCK_DEBIT; + default -> enumeration; + }; } return enumeration; } @@ -71,14 +63,6 @@ public enum SavingsAccountSubStatusEnum { return this.value.equals(state.getValue()); } - public Integer getValue() { - return this.value; - } - - public String getCode() { - return this.code; - } - public boolean isSubStatusInactive() { return this.value.equals(SavingsAccountSubStatusEnum.INACTIVE.getValue()); } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionDataSummaryWrapper.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionDataSummaryWrapper.java index 2655c256a..b0c23c8e5 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionDataSummaryWrapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionDataSummaryWrapper.java @@ -26,8 +26,7 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData; import org.springframework.stereotype.Component; /** - * A wrapper for dealing with side-effect free functionality related to a {@link SavingsAccount}'s - * {@link SavingsAccountTransaction}'s. + * A wrapper for dealing with side-effect free functionality related to a SavingsAccountTransaction. */ @Component public final class SavingsAccountTransactionDataSummaryWrapper { diff --git a/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesReadServiceTest.java b/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesReadServiceTest.java index 9286f8c7c..81a3ba7b4 100644 --- a/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesReadServiceTest.java +++ b/fineract-investor/src/test/java/org/apache/fineract/investor/service/ExternalAssetOwnerLoanProductAttributesReadServiceTest.java @@ -21,7 +21,6 @@ package org.apache.fineract.investor.service; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -42,6 +41,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -64,9 +64,9 @@ public class ExternalAssetOwnerLoanProductAttributesReadServiceTest { private ExternalAssetOwnerLoanProductAttributesReadService underTest; - private int offset = 0; + private static final int OFFSET = 0; - private int limit = 100; + private static final int LIMIT = 100; @BeforeEach public void setUp() { @@ -80,11 +80,12 @@ public class ExternalAssetOwnerLoanProductAttributesReadServiceTest { // given ExternalAssetOwnerLoanProductAttributes attributes = Mockito.mock(ExternalAssetOwnerLoanProductAttributes.class); ExternalTransferLoanProductAttributesData data = Mockito.mock(ExternalTransferLoanProductAttributesData.class); - PageRequest pageRequest = PageRequest.of(offset, limit, Sort.by("id").ascending()); + PageRequest pageRequest = PageRequest.of(OFFSET, LIMIT, Sort.by("id").ascending()); org.springframework.data.domain.Page attributesPage = new PageImpl<>(List.of(attributes), pageRequest, 1); - when(externalAssetOwnerLoanProductAttributesRepository.findAll(any(Specification.class), eq(pageRequest))) + when(externalAssetOwnerLoanProductAttributesRepository + .findAll(ArgumentMatchers.>any(), eq(pageRequest))) .thenReturn(attributesPage); when(loanProductRepository.existsById(loanProductId)).thenReturn(true); when(mapper.mapLoanProductAttributes(attributes)).thenReturn(data); @@ -95,7 +96,7 @@ public class ExternalAssetOwnerLoanProductAttributesReadServiceTest { // then assertEquals(1, result.getTotalFilteredRecords()); - assertEquals(data, result.getPageItems().get(0)); + assertEquals(data, result.getPageItems().getFirst()); verify(loanProductRepository, times(1)).existsById(loanProductId); verify(mapper, times(1)).mapLoanProductAttributes(attributes); } @@ -105,11 +106,12 @@ public class ExternalAssetOwnerLoanProductAttributesReadServiceTest { // given Long loanProductId = 1L; ExternalAssetOwnerLoanProductAttributes attributes = Mockito.mock(ExternalAssetOwnerLoanProductAttributes.class); - PageRequest pageRequest = PageRequest.of(offset, limit, Sort.by("id").ascending()); + PageRequest pageRequest = PageRequest.of(OFFSET, LIMIT, Sort.by("id").ascending()); org.springframework.data.domain.Page attributesPage = new PageImpl<>(List.of(attributes), pageRequest, 0); - when(externalAssetOwnerLoanProductAttributesRepository.findAll(any(Specification.class), eq(pageRequest))) + when(externalAssetOwnerLoanProductAttributesRepository + .findAll(ArgumentMatchers.>any(), eq(pageRequest))) .thenReturn(attributesPage); when(loanProductRepository.existsById(loanProductId)).thenReturn(true); when(mapper.mapLoanProductAttributes(attributes)).thenReturn(null); @@ -120,8 +122,9 @@ public class ExternalAssetOwnerLoanProductAttributesReadServiceTest { // then assertEquals(1, result.getTotalFilteredRecords()); - assertNull(result.getPageItems().get(0)); - verify(externalAssetOwnerLoanProductAttributesRepository, times(1)).findAll(any(Specification.class), eq(pageRequest)); + assertNull(result.getPageItems().getFirst()); + verify(externalAssetOwnerLoanProductAttributesRepository, times(1)) + .findAll(ArgumentMatchers.>any(), eq(pageRequest)); verify(loanProductRepository, times(1)).existsById(loanProductId); verify(mapper, times(1)).mapLoanProductAttributes(attributes); }