diff --git a/build.gradle b/build.gradle index 6362b1b1d..d5298707f 100644 --- a/build.gradle +++ b/build.gradle @@ -418,13 +418,14 @@ configure(project.fineractJavaProjects) { ] } - // Configuration for the spotless plugin - // https://github.com/diffplug/spotless/tree/main/plugin-gradle + dependencies { spotbugsPlugins 'jp.skypencil.findbugs.slf4j:bug-pattern:1.5.0@jar' - spotbugs 'com.github.spotbugs:spotbugs:4.2.2' + spotbugs 'com.github.spotbugs:spotbugs:4.4.1' } + // Configuration for the spotless plugin + // https://github.com/diffplug/spotless/tree/main/plugin-gradle spotless { java { targetExclude '**/build/**', '**/bin/**', '**/out/**' diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java index d1e5c0f19..e2b028809 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java @@ -19,6 +19,7 @@ package org.apache.fineract.commands.service; import com.google.gson.JsonElement; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.time.ZonedDateTime; import java.util.Random; import org.apache.fineract.commands.domain.CommandSource; @@ -52,6 +53,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio private final CommandProcessingService processAndLogCommandService; private final SchedulerJobRunnerReadService schedulerJobRunnerReadService; private static final Logger LOG = LoggerFactory.getLogger(PortfolioCommandSourceWritePlatformServiceImpl.class); + private static final Random random = new Random(); @Autowired public PortfolioCommandSourceWritePlatformServiceImpl(final PlatformSecurityContext context, @@ -66,6 +68,8 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio @Override @SuppressWarnings("AvoidHidingCauseException") + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public CommandProcessingResult logCommandSource(final CommandWrapper wrapper) { boolean isApprovedByChecker = false; @@ -112,7 +116,6 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio * Else sleep for a random time (between 1 to 10 seconds) and continue **/ try { - Random random = new Random(); int randomNum = random.nextInt(maxIntervalBetweenRetries + 1); Thread.sleep(1000 + (randomNum * 1000)); numberOfRetries = numberOfRetries + 1; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/ContentRepositoryUtils.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/ContentRepositoryUtils.java index e9f03e5c6..d79a98e89 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/ContentRepositoryUtils.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/documentmanagement/contentrepository/ContentRepositoryUtils.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.documentmanagement.contentrepository; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -187,6 +188,9 @@ public final class ContentRepositoryUtils { /** * Generate a random String. */ + + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public static String generateRandomString() { final String characters = "abcdefghijklmnopqrstuvwxyz123456789"; // length is a random number between 5 to 16 diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/Sender.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/Sender.java index 312a59ef0..650a8f69d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/Sender.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/gcm/domain/Sender.java @@ -55,6 +55,7 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.BufferedReader; import java.io.Closeable; import java.io.IOException; @@ -168,6 +169,9 @@ public class Sender { * @throws IOException * if message could not be sent. */ + + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public Result send(Message message, String to, int retries) throws IOException { int attempt = 0; Result result; @@ -316,6 +320,8 @@ public class Sender { * @throws IOException * if message could not be sent. */ + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public MulticastResult send(Message message, List regIds, int retries) throws IOException { int attempt = 0; MulticastResult multicastResult; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java index 76baba468..a971b5410 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerTriggerListener.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.jobs.service; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Random; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; @@ -36,6 +37,7 @@ import org.springframework.stereotype.Component; public class SchedulerTriggerListener implements TriggerListener { private static final Logger LOG = LoggerFactory.getLogger(SchedulerTriggerListener.class); + private static final Random random = new Random(); private final SchedularWritePlatformService schedularService; private final TenantDetailsService tenantDetailsService; @@ -58,6 +60,8 @@ public class SchedulerTriggerListener implements TriggerListener { } @Override + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public boolean vetoJobExecution(final Trigger trigger, final JobExecutionContext context) { final String tenantIdentifier = trigger.getJobDataMap().getString(SchedulerServiceConstants.TENANT_IDENTIFIER); final FineractPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantIdentifier); @@ -81,7 +85,6 @@ public class SchedulerTriggerListener implements TriggerListener { LOG.warn("vetoJobExecution() not able to acquire the lock to update job running status at retry {} (of {}) for JobKey: {}", numberOfRetries, maxNumberOfRetries, jobKey, exception); try { - Random random = new Random(); int randomNum = random.nextInt(maxIntervalBetweenRetries + 1); Thread.sleep(1000 + (randomNum * 1000)); numberOfRetries = numberOfRetries + 1; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSchedularServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSchedularServiceImpl.java index 4f6044ab9..3779f01db 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSchedularServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSchedularServiceImpl.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.service; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -55,6 +56,7 @@ import org.springframework.util.CollectionUtils; public class LoanSchedularServiceImpl implements LoanSchedularService { private static final Logger LOG = LoggerFactory.getLogger(LoanSchedularServiceImpl.class); + private static final Random random = new Random(); private final ConfigurationDomainService configurationDomainService; private final LoanReadPlatformService loanReadPlatformService; @@ -123,6 +125,8 @@ public class LoanSchedularServiceImpl implements LoanSchedularService { @Override @CronTarget(jobName = JobName.RECALCULATE_INTEREST_FOR_LOAN) + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public void recalculateInterest() throws JobExecutionException { Integer maxNumberOfRetries = ThreadLocalContextUtil.getTenant().getConnection().getMaxRetriesOnDeadlock(); Integer maxIntervalBetweenRetries = ThreadLocalContextUtil.getTenant().getConnection().getMaxIntervalBetweenRetries(); @@ -150,7 +154,6 @@ public class LoanSchedularServiceImpl implements LoanSchedularService { // Else sleep for a random time (between 1 to 10 // seconds) and continue try { - Random random = new Random(); int randomNum = random.nextInt(maxIntervalBetweenRetries + 1); Thread.sleep(1000 + (randomNum * 1000)); numberOfRetries = numberOfRetries + 1; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/RecalculateInterestPoster.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/RecalculateInterestPoster.java index 7a867057a..0a1a938ab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/RecalculateInterestPoster.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/RecalculateInterestPoster.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.service; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -37,6 +38,7 @@ import org.springframework.stereotype.Component; public class RecalculateInterestPoster implements Callable { private static final Logger LOG = LoggerFactory.getLogger(RecalculateInterestPoster.class); + private static final Random random = new Random(); private Collection loanIds; private LoanWritePlatformService loanWritePlatformService; @@ -50,6 +52,8 @@ public class RecalculateInterestPoster implements Callable { } @Override + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public Void call() throws JobExecutionException { Integer maxNumberOfRetries = ThreadLocalContextUtil.getTenant().getConnection().getMaxRetriesOnDeadlock(); Integer maxIntervalBetweenRetries = ThreadLocalContextUtil.getTenant().getConnection().getMaxIntervalBetweenRetries(); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AuditIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AuditIntegrationTest.java index cb51d9a25..484f27b6a 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/AuditIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/AuditIntegrationTest.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.integrationtests; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; @@ -45,6 +46,7 @@ public class AuditIntegrationTest { private RequestSpecification requestSpec; private ClientHelper clientHelper; private AuditHelper auditHelper; + private static final Random rand = new Random(); /** * Sets up the essential settings for the TEST like contentType, expectedStatusCode. It uses the '@BeforeEach' @@ -105,6 +107,8 @@ public class AuditIntegrationTest { } @Test + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public void checkAuditsWithLimitParam() { // Create client final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); @@ -117,7 +121,6 @@ public class AuditIntegrationTest { this.clientHelper.reactivateClient(clientId); } - Random rand = new Random(); for (int i = 0; i < 3; i++) { // limit contains a number between 1-8 int limit = rand.nextInt(7) + 1; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientTest.java index 94751141b..f467c8279 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientTest.java @@ -20,6 +20,7 @@ package org.apache.fineract.integrationtests; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.restassured.builder.RequestSpecBuilder; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.http.ContentType; @@ -38,6 +39,7 @@ public class ClientTest { private ResponseSpecification responseSpec; private RequestSpecification requestSpec; private ClientHelper clientHelper; + private static final Random rand = new Random(); @BeforeEach public void setup() { @@ -149,9 +151,10 @@ public class ClientTest { @SuppressWarnings("unchecked") @Test + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public void testPendingOnlyClientRequest() { - Random rand = new Random(); // Add a few clients to the server and activate a random amount of them for (int i = 0; i < 15; i++) { final Integer clientId = ClientHelper.createClientAsEntity(this.requestSpec, this.responseSpec); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/IntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/IntegrationTest.java index 131932644..7a0989048 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/IntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/IntegrationTest.java @@ -31,6 +31,7 @@ import com.google.common.truth.StringSubject; import com.google.common.truth.Subject; import com.google.common.truth.Truth; import com.google.common.truth.Truth8; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.math.BigDecimal; import java.util.Optional; import java.util.Random; @@ -76,6 +77,8 @@ public abstract class IntegrationTest { return FineractClient.DATE_FORMAT; } + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") protected String random() { return Long.toString(random.nextLong()); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java index d29d3226a..d2ee39677 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/SchedulerJobHelper.java @@ -147,7 +147,7 @@ public class SchedulerJobHelper { * @author Michael Vorburger.ch */ public void executeAndAwaitJob(String jobName) { - final Duration timeout = Duration.ofSeconds(180); + final Duration timeout = Duration.ofMinutes(3); final Duration pause = Duration.ofSeconds(1); DateTimeFormatter df = DateTimeFormatter.ISO_INSTANT; // FINERACT-926 Instant beforeExecuteTime = now().truncatedTo(ChronoUnit.SECONDS); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java index 18bedd0b3..b04520724 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/Utils.java @@ -23,6 +23,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.fail; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.path.json.JsonPath; @@ -57,6 +58,7 @@ public final class Utils { } private static final Logger LOG = LoggerFactory.getLogger(Utils.class); + private static final Random random = new Random(); public static final String TENANT_PARAM_NAME = "tenantIdentifier"; public static final String DEFAULT_TENANT = "default"; @@ -196,12 +198,13 @@ public final class Utils { return reformattedStr; } + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public static String randomStringGenerator(final String prefix, final int len, final String sourceSetString) { final int lengthOfSource = sourceSetString.length(); - final Random rnd = new Random(); final StringBuilder sb = new StringBuilder(len); for (int i = 0; i < len; i++) { - sb.append(sourceSetString.charAt(rnd.nextInt(lengthOfSource))); + sb.append(sourceSetString.charAt(random.nextInt(lengthOfSource))); } return prefix + sb.toString(); } @@ -214,10 +217,12 @@ public final class Utils { return randomStringGenerator(prefix, lenOfRandomSuffix); } + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public static Long randomNumberGenerator(final int expectedLength) { final String source = "1234567890"; final int lengthofSource = source.length(); - final Random random = new Random(); + StringBuilder stringBuilder = new StringBuilder(expectedLength); for (int i = 0; i < expectedLength; i++) { stringBuilder.append(source.charAt(random.nextInt(lengthofSource))); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/WorkingDaysHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/WorkingDaysHelper.java index b9ef3b54e..56be68ad1 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/WorkingDaysHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/WorkingDaysHelper.java @@ -19,6 +19,7 @@ package org.apache.fineract.integrationtests.common; import com.google.gson.Gson; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.util.HashMap; @@ -34,6 +35,7 @@ public final class WorkingDaysHelper { private static final Logger LOG = LoggerFactory.getLogger(WorkingDaysHelper.class); private static final String WORKINGDAYS_URL = "/fineract-provider/api/v1/workingdays"; + private static final Random random = new Random(); public static Object updateWorkingDays(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { final String UPDATE_WORKINGDAYS_URL = WORKINGDAYS_URL + "?" + Utils.TENANT_IDENTIFIER; @@ -49,21 +51,25 @@ public final class WorkingDaysHelper { jsonAttributeToGetback); } + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public static String updateWorkingDaysAsJson() { final HashMap map = new HashMap<>(); map.put("recurrence", "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR,SA,SU"); map.put("locale", "en"); - map.put("repaymentRescheduleType", new Random().nextInt(4) + 1); + map.put("repaymentRescheduleType", random.nextInt(4) + 1); map.put("extendTermForDailyRepayments", false); LOG.info("map : {}", map); return new Gson().toJson(map); } + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public static String updateWorkingDayWithWrongRecur() { final HashMap map = new HashMap<>(); map.put("recurrence", "FREQ=WEEKLY;INTERVAL=1;BYDAY=MP,TI,TE,TH"); map.put("locale", "en"); - map.put("repaymentRescheduleType", new Random().nextInt(4) + 1); + map.put("repaymentRescheduleType", random.nextInt(4) + 1); map.put("extendTermForDailyRepayments", false); LOG.info("map : {}", map); return new Gson().toJson(map); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/provisioning/ProvisioningHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/provisioning/ProvisioningHelper.java index e65483344..ace93e8e9 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/provisioning/ProvisioningHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/provisioning/ProvisioningHelper.java @@ -19,6 +19,7 @@ package org.apache.fineract.integrationtests.common.provisioning; import com.google.gson.Gson; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -32,10 +33,14 @@ import org.apache.fineract.integrationtests.common.accounting.Account; public final class ProvisioningHelper { + private static final Random rand = new Random(); + private ProvisioningHelper() { } + @SuppressFBWarnings(value = { + "DMI_RANDOM_USED_ONLY_ONCE" }, justification = "False positive for random object created and used only once") public static Map createProvisioingCriteriaJson(ArrayList loanProducts, ArrayList categories, Account liability, Account expense) { final HashMap map = new HashMap<>(); @@ -44,7 +49,7 @@ public final class ProvisioningHelper { DateFormat simple = new SimpleDateFormat("dd MMMM yyyy"); String formattedString = simple .format(Date.from(Utils.getLocalDateOfTenant().atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant())); - Random rand = new Random(); + String criteriaName = "General Provisioning Criteria" + formattedString + rand.nextLong(); map.put("criteriaName", criteriaName); map.put("locale", "en");