You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2023/06/06 09:45:20 UTC

[fineract] 03/15: FINERACT-1724: Further upgrades

This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git

commit abb5d4abb5a2a46c5ff07239259c9639fd22efcb
Author: Arnold Galovics <ga...@gmail.com>
AuthorDate: Tue May 30 10:23:13 2023 +0200

    FINERACT-1724: Further upgrades
---
 fineract-core/dependencies.gradle                  |  1 +
 fineract-provider/build.gradle                     |  8 ++--
 .../cob/listener/AbstractLoanItemListener.java     | 11 +++--
 .../cache/PlatformCacheConfiguration.java          |  3 +-
 .../core/config/OAuth2SecurityConfig.java          | 16 +++++--
 .../infrastructure/core/config/SecurityConfig.java | 20 +++++---
 .../sampling/output/SamplingScheduler.java         |  7 +--
 .../core/service/database/RoutingDataSource.java   |  2 +-
 .../jobs/ScheduledJobRunnerConfig.java             | 27 ++++++++---
 .../jobs/config/FineractBatchConfiguration.java    | 32 +++++++++++++
 .../domain/CalendarInstanceRepository.java         |  2 +-
 .../src/main/resources/META-INF/orm.xml            |  8 ++--
 .../tenant/parts/0109_spring_batch_5_upgrade.xml   | 54 +++++++++++++++++++++-
 .../listener/LoanItemListenerStepDefinitions.java  |  3 +-
 14 files changed, 154 insertions(+), 40 deletions(-)

diff --git a/fineract-core/dependencies.gradle b/fineract-core/dependencies.gradle
index 89bfa9b49..f2b0c9bef 100644
--- a/fineract-core/dependencies.gradle
+++ b/fineract-core/dependencies.gradle
@@ -28,6 +28,7 @@ dependencies {
     implementation(
             'org.springframework.boot:spring-boot-starter-web',
             'org.springframework.boot:spring-boot-starter-security',
+            'org.springframework.boot:spring-boot-starter-validation',
             'jakarta.ws.rs:jakarta.ws.rs-api',
             'org.glassfish.jersey.media:jersey-media-multipart',
 
diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle
index 291f0b0f2..90a732426 100644
--- a/fineract-provider/build.gradle
+++ b/fineract-provider/build.gradle
@@ -155,10 +155,10 @@ dependencies {
     driver 'mysql:mysql-connector-java:8.0.32'
 }
 
-//URLClassLoader loader = GroovyObject.class.classLoader
-//configurations.driver.each {File file ->
-//    loader.addURL(file.toURL())
-//}
+URLClassLoader loader = GroovyObject.class.classLoader
+configurations.driver.each {File file ->
+    loader.addURL(file.toURL())
+}
 
 task createDB {
     description= "Creates the MariaDB Database. Needs database name to be passed (like: -PdbName=someDBname)"
diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java b/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java
index b2606e889..d02179180 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/cob/listener/AbstractLoanItemListener.java
@@ -37,6 +37,7 @@ import org.springframework.batch.core.annotation.OnSkipInProcess;
 import org.springframework.batch.core.annotation.OnSkipInRead;
 import org.springframework.batch.core.annotation.OnSkipInWrite;
 import org.springframework.batch.core.annotation.OnWriteError;
+import org.springframework.batch.item.Chunk;
 import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.support.TransactionCallbackWithoutResult;
 import org.springframework.transaction.support.TransactionTemplate;
@@ -79,25 +80,25 @@ public abstract class AbstractLoanItemListener {
     }
 
     @OnWriteError
-    public void onWriteError(Exception e, @NotNull List<? extends Loan> items) {
-        List<Long> loanIds = items.stream().map(AbstractPersistableCustom::getId).toList();
+    public void onWriteError(Exception e, @NotNull Chunk<? extends Loan> items) {
+        List<Long> loanIds = items.getItems().stream().map(AbstractPersistableCustom::getId).toList();
         log.warn("Error was triggered during writing of Loans (ids={}) due to: {}", loanIds, ThrowableSerialization.serialize(e));
 
         updateAccountLockWithError(loanIds, "Loan (id: %d) writing is failed", e);
     }
 
     @OnSkipInRead
-    public void onSkipInRead(@NotNull Exception e) {
+    public void onSkipInRead(@NotNull Throwable e) {
         log.warn("Skipping was triggered during read!");
     }
 
     @OnSkipInProcess
-    public void onSkipInProcess(@NotNull Loan item, @NotNull Exception e) {
+    public void onSkipInProcess(@NotNull Loan item, @NotNull Throwable e) {
         log.warn("Skipping was triggered during processing of Loan (id={})", item.getId());
     }
 
     @OnSkipInWrite
-    public void onSkipInWrite(@NotNull Loan item, @NotNull Exception e) {
+    public void onSkipInWrite(@NotNull Loan item, @NotNull Throwable e) {
         log.warn("Skipping was triggered during writing of Loan (id={})", item.getId());
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/cache/PlatformCacheConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/cache/PlatformCacheConfiguration.java
index 742a7d3e7..ba8a10c9f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/cache/PlatformCacheConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/cache/PlatformCacheConfiguration.java
@@ -22,14 +22,13 @@ import org.apache.fineract.infrastructure.cache.service.RuntimeDelegatingCacheMa
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.CacheManager;
 import org.springframework.cache.annotation.CachingConfigurer;
-import org.springframework.cache.annotation.CachingConfigurerSupport;
 import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
 @Configuration
 @EnableCaching
-public class PlatformCacheConfiguration extends CachingConfigurerSupport implements CachingConfigurer {
+public class PlatformCacheConfiguration implements CachingConfigurer {
 
     @Autowired
     private RuntimeDelegatingCacheManager delegatingCacheManager;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
index 8c3b88ec2..9a6c59213 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
@@ -38,7 +38,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.http.HttpMethod;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.core.GrantedAuthority;
@@ -57,7 +57,7 @@ import org.springframework.security.web.context.SecurityContextHolderFilter;
 
 @Configuration
 @ConditionalOnProperty("fineract.security.oauth.enabled")
-@EnableGlobalMethodSecurity(prePostEnabled = true)
+@EnableMethodSecurity
 public class OAuth2SecurityConfig {
 
     @Autowired
@@ -76,9 +76,8 @@ public class OAuth2SecurityConfig {
 
 
     @Bean
-    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+    public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
         http //
-                .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
                 .securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
                     auth
                             .requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
@@ -90,7 +89,14 @@ public class OAuth2SecurityConfig {
                             .requestMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() //
                             .requestMatchers("/api/*/twofactor").fullyAuthenticated() //
                             .requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
-                }) //
+                });
+        return http.build();
+    }
+
+    @Bean
+    public SecurityFilterChain FilterChain(HttpSecurity http) throws Exception {
+        http //
+                .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
                 .exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint()))
                 .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
                         .authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
index 955f293c7..a1899b5c2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
@@ -40,7 +40,7 @@ import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.ProviderManager;
 import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.http.SessionCreationPolicy;
 import org.springframework.security.crypto.factory.PasswordEncoderFactories;
@@ -53,7 +53,7 @@ import org.springframework.security.web.context.SecurityContextHolderFilter;
 
 @Configuration
 @ConditionalOnProperty("fineract.security.basicauth.enabled")
-@EnableGlobalMethodSecurity(prePostEnabled = true)
+@EnableMethodSecurity
 public class SecurityConfig {
 
     @Autowired
@@ -78,9 +78,8 @@ public class SecurityConfig {
 
 
     @Bean
-    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+    public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
         http //
-                .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
                 .securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
                     auth
                             .requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
@@ -94,13 +93,20 @@ public class SecurityConfig {
                             .requestMatchers("/api/*/twofactor").fullyAuthenticated() //
                             .requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
                 }) //
-                .httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())) //
+                .httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())); //
+        return http.build();
+    }
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+        http //
+                .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
                 .sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
                 .addFilterAfter(fineractInstanceModeApiFilter, SecurityContextHolderFilter.class) //
                 .addFilterAfter(tenantAwareBasicAuthenticationFilter(), FineractInstanceModeApiFilter.class) //
                 .addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) //
-                .addFilterAfter(loanCOBApiFilter, InsecureTwoFactorAuthenticationFilter.class)
-                .addFilterBefore(idempotencyStoreFilter, ExceptionTranslationFilter.class);
+                .addFilterAfter(loanCOBApiFilter, InsecureTwoFactorAuthenticationFilter.class) //
+                .addFilterBefore(idempotencyStoreFilter, ExceptionTranslationFilter.class); //
 
         if (serverProperties.getSsl().isEnabled()) {
             http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/performance/sampling/output/SamplingScheduler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/performance/sampling/output/SamplingScheduler.java
index 98e2cf156..4e5c1645f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/performance/sampling/output/SamplingScheduler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/performance/sampling/output/SamplingScheduler.java
@@ -20,8 +20,8 @@ package org.apache.fineract.infrastructure.core.diagnostics.performance.sampling
 
 import static java.util.stream.Collectors.toMap;
 
+import java.time.Duration;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.infrastructure.core.diagnostics.performance.sampling.core.SamplingConfiguration;
@@ -54,8 +54,9 @@ public class SamplingScheduler implements InitializingBean {
             log.warn("Reset period for sampling cannot be smaller than 10 seconds, setting back the minimum 10");
             resetPeriodInSec = 10;
         }
-        PeriodicTrigger trigger = new PeriodicTrigger(resetPeriodInSec, TimeUnit.SECONDS);
-        trigger.setInitialDelay(resetPeriodInSec);
+        Duration resetPeriodInSecDuration = Duration.ofSeconds(resetPeriodInSec);
+        PeriodicTrigger trigger = new PeriodicTrigger(resetPeriodInSecDuration);
+        trigger.setInitialDelay(resetPeriodInSecDuration);
         taskScheduler.schedule(this::printAndResetPeriodically, trigger);
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/RoutingDataSource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/RoutingDataSource.java
index ab618bcd1..d75fadcd8 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/RoutingDataSource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/RoutingDataSource.java
@@ -36,7 +36,7 @@ import org.springframework.stereotype.Service;
  * The {@link RoutingDataSourceService} is responsible for returning the appropriate {@link DataSource} for the tenant
  * of this request.
  */
-@Service(value = "routingDataSource")
+@Service(value = "dataSource")
 @Primary
 public class RoutingDataSource extends AbstractDataSource {
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java
index 34d50aa71..fb092c3b7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/ScheduledJobRunnerConfig.java
@@ -25,8 +25,11 @@ import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourc
 import org.springframework.batch.core.configuration.JobRegistry;
 import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
 import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
+import org.springframework.batch.core.explore.JobExplorer;
+import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
 import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
 import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer;
 import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
 import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
@@ -34,7 +37,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.transaction.PlatformTransactionManager;
 
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @EnableBatchProcessing
 public class ScheduledJobRunnerConfig {
 
@@ -49,19 +52,31 @@ public class ScheduledJobRunnerConfig {
     }
 
     @Bean
-    public JobRepositoryFactoryBean jobRepositoryFactoryBean(RoutingDataSource routingDataSource,
-            PlatformTransactionManager transactionManager) throws Exception {
+    public Jackson2ExecutionContextStringSerializer executionContextSerializer() {
+        return new Jackson2ExecutionContextStringSerializer();
+    }
+
+    @Bean
+    public JobRepository jobRepository(RoutingDataSource routingDataSource,
+                                       PlatformTransactionManager transactionManager) throws Exception {
         JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
         factory.setDataSource(routingDataSource);
         factory.setTransactionManager(transactionManager);
         factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
+        factory.setSerializer(executionContextSerializer());
         factory.afterPropertiesSet();
-        return factory;
+        return factory.getObject();
     }
 
     @Bean
-    public JobRepository jobRepository(JobRepositoryFactoryBean factory) throws Exception {
-        return factory.getObject();
+    public JobExplorer jobExplorer(RoutingDataSource routingDataSource,
+                                   PlatformTransactionManager transactionManager) throws Exception {
+        JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
+        jobExplorerFactoryBean.setDataSource(routingDataSource);
+        jobExplorerFactoryBean.setTransactionManager(transactionManager);
+        jobExplorerFactoryBean.setSerializer(executionContextSerializer());
+        jobExplorerFactoryBean.afterPropertiesSet();
+        return jobExplorerFactoryBean.getObject();
     }
 
     @Bean
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractBatchConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractBatchConfiguration.java
new file mode 100644
index 000000000..14e0e5546
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/config/FineractBatchConfiguration.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.jobs.config;
+
+import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
+import org.springframework.batch.core.repository.ExecutionContextSerializer;
+import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer;
+
+
+//@Configuration(proxyBeanMethods = false)
+public class FineractBatchConfiguration extends DefaultBatchConfiguration {
+    @Override
+    protected ExecutionContextSerializer getExecutionContextSerializer() {
+        return new Jackson2ExecutionContextStringSerializer();
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstanceRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstanceRepository.java
index 037b70243..bbce01c36 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstanceRepository.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/CalendarInstanceRepository.java
@@ -60,7 +60,7 @@ public interface CalendarInstanceRepository extends JpaRepository<CalendarInstan
      * EntityType = 3 is for loan
      */
 
-    @Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan ln WHERE ln.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND ln.loanStatus IN :loanStatuses ")
+    @Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan loan WHERE loan.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND loan.loanStatus IN :loanStatuses ")
     Integer countOfLoansSyncedWithCalendar(@Param("calendarId") Long calendarId, @Param("loanStatuses") Collection<Integer> loanStatuses);
 
 }
diff --git a/fineract-provider/src/main/resources/META-INF/orm.xml b/fineract-provider/src/main/resources/META-INF/orm.xml
index 1eb26c9cc..b54608dee 100644
--- a/fineract-provider/src/main/resources/META-INF/orm.xml
+++ b/fineract-provider/src/main/resources/META-INF/orm.xml
@@ -29,10 +29,10 @@
     <persistence-unit-metadata>
         <persistence-unit-defaults>
             <delimited-identifiers/>
-            <entity-listeners>
-                <entity-listener
-                    class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />
-            </entity-listeners>
+<!--            <entity-listeners>-->
+<!--                <entity-listener-->
+<!--                    class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />-->
+<!--            </entity-listeners>-->
         </persistence-unit-defaults>
     </persistence-unit-metadata>
 
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0109_spring_batch_5_upgrade.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0109_spring_batch_5_upgrade.xml
index 9755e739a..1508a7c52 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0109_spring_batch_5_upgrade.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0109_spring_batch_5_upgrade.xml
@@ -30,6 +30,40 @@
         <dropColumn tableName="BATCH_JOB_EXECUTION" columnName="JOB_CONFIGURATION_LOCATION"/>
     </changeSet>
     <changeSet author="fineract" id="2" context="postgresql">
+        <sql>
+            UPDATE BATCH_JOB_EXECUTION_PARAMS
+            SET STRING_VAL = TO_CHAR(DATE_VAL, 'YYYY-MM-DDTHH:MM:SSZ')
+            WHERE TYPE_CD = 'DATE'
+        </sql>
+        <sql>
+            UPDATE BATCH_JOB_EXECUTION_PARAMS
+            SET STRING_VAL = CAST(LONG_VAL AS CHAR)
+            WHERE TYPE_CD = 'LONG'
+        </sql>
+        <sql>
+            UPDATE BATCH_JOB_EXECUTION_PARAMS
+            SET STRING_VAL = CAST(DOUBLE_VAL AS CHAR)
+            WHERE TYPE_CD = 'DOUBLE'
+        </sql>
+    </changeSet>
+    <changeSet author="fineract" id="2" context="mysql">
+        <sql>
+            UPDATE BATCH_JOB_EXECUTION_PARAMS
+            SET STRING_VAL = DATE_FORMAT(DATE_VAL, 'YYYY-MM-DDTHH:MM:SSZ')
+            WHERE TYPE_CD = 'DATE'
+        </sql>
+        <sql>
+            UPDATE BATCH_JOB_EXECUTION_PARAMS
+            SET STRING_VAL = LONG_VAL::text
+            WHERE TYPE_CD = 'LONG'
+        </sql>
+        <sql>
+            UPDATE BATCH_JOB_EXECUTION_PARAMS
+            SET STRING_VAL = DOUBLE_VAL::text
+            WHERE TYPE_CD = 'DOUBLE'
+        </sql>
+    </changeSet>
+    <changeSet author="fineract" id="4" context="postgresql">
         <!--
             org/springframework/batch/core/migration/5.0/migration-postgresql.sql
         -->
@@ -58,7 +92,7 @@
 
         </sql>
     </changeSet>
-    <changeSet author="fineract" id="3" context="mysql">
+    <changeSet author="fineract" id="4" context="mysql">
         <!--
             org/springframework/batch/core/migration/5.0/migration-mysql.sql
         -->
@@ -75,4 +109,22 @@
             ALTER TABLE BATCH_JOB_EXECUTION_PARAMS CHANGE COLUMN STRING_VAL PARAMETER_VALUE VARCHAR(2500);
         </sql>
     </changeSet>
+    <changeSet author="fineract" id="5">
+        <update tableName="BATCH_JOB_EXECUTION_PARAMS">
+            <column name="PARAMETER_TYPE" value="java.lang.Long"/>
+            <where>PARAMETER_TYPE='LONG'</where>
+        </update>
+        <update tableName="BATCH_JOB_EXECUTION_PARAMS">
+            <column name="PARAMETER_TYPE" value="java.lang.String"/>
+            <where>PARAMETER_TYPE='STRING'</where>
+        </update>
+        <update tableName="BATCH_JOB_EXECUTION_PARAMS">
+            <column name="PARAMETER_TYPE" value="java.lang.Double"/>
+            <where>PARAMETER_TYPE='DOUBLE'</where>
+        </update>
+        <update tableName="BATCH_JOB_EXECUTION_PARAMS">
+            <column name="PARAMETER_TYPE" value="java.util.Date"/>
+            <where>PARAMETER_TYPE='DATE'</where>
+        </update>
+    </changeSet>
 </databaseChangeLog>
diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java
index 2e7f1b659..e3f4ca94a 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/cob/listener/LoanItemListenerStepDefinitions.java
@@ -38,6 +38,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
 import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.mockito.Mockito;
+import org.springframework.batch.item.Chunk;
 import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.support.TransactionTemplate;
@@ -107,7 +108,7 @@ public class LoanItemListenerStepDefinitions implements En {
         });
 
         When("LoanItemListener.onWriteError method executed", () -> {
-            loanItemListener.onWriteError(exception, List.of(loan));
+            loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan)));
         });
 
         Then("LoanItemListener.onWriteError result should match", () -> {