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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 9f4f1d4f17 FINERACT-2094: Update to Java 21
9f4f1d4f17 is described below

commit 9f4f1d4f177888ff8ff06775731fdfb817e5cd10
Author: Victor Romero <[email protected]>
AuthorDate: Tue Apr 15 01:37:10 2025 -0600

    FINERACT-2094: Update to Java 21
    
    modernize locale instantiations (fixes an error found by the modernizer 
plugin) - use Locale.of() instead of new Locale()
    
    use recommended gradle toolchain syntax to specify Java class file format 
version see 
https://docs.gradle.org/current/userguide/java_plugin.html#toolchain_and_compatibility
    
    mark html5 for later fix (it's the default)
    
    use dummy byte arrays to work around mockito exception
    
    ```
    org.mockito.exceptions.base.MockitoException:
    Mockito cannot mock this class: class java.nio.ByteBuffer.
    
    If you're not sure why you're getting this error, please open an issue on 
GitHub.
    
    Java               : 21
    JVM vendor name    : Ubuntu
    JVM vendor version : 21.0.6+7-Ubuntu-122.04.1
    JVM name           : OpenJDK 64-Bit Server VM
    JVM version        : 21.0.6+7-Ubuntu-122.04.1
    JVM info           : mixed mode, sharing
    OS name            : Linux
    OS version         : 5.15.0-136-generic
    
    You are seeing this disclaimer because Mockito is configured to create 
inlined mocks.
    You can learn about inline mocks and their limitations under item #39 of 
the Mockito class javadoc.
    
    Underlying exception : org.mockito.exceptions.base.MockitoException: 
Unsupported settings with this type 'java.nio.ByteBuffer'
            at 
app//org.apache.fineract.infrastructure.event.external.jobs.SendAsynchronousEventsTaskletTest.givenBatchSize2WhenEventSendFailsThenExecutionStops(SendAsynchronousEventsTaskletTest.java:170)
            at [email protected]/java.lang.reflect.Method.invoke(Method.java:580)
            at [email protected]/java.util.ArrayList.forEach(ArrayList.java:1596)
            at [email protected]/java.util.ArrayList.forEach(ArrayList.java:1596)
    Caused by: org.mockito.exceptions.base.MockitoException: Unsupported 
settings with this type 'java.nio.ByteBuffer'
            at app//net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
            at 
app//net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
            at app//net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
            at 
app//net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
            ... 4 more
    ```
    
    see also: 
https://stackoverflow.com/questions/47046996/java-lang-unsupportedoperationexception-when-mocking-java-nio-bytebuffer-class
    
    wrap byte arrays with ByteBuffer
    
    fix:
    
    ```
    
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:148:
 error: incompatible types: byte[] cannot be converted to ByteBuffer
                    "anidempotencyKey", "aSchema", "dummy".getBytes());
                                                                   ^
    
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:170:
 error: incompatible types: byte[] cannot be converted to ByteBuffer
                    "anidempotencyKey", "aSchema", "dummy".getBytes());
                                                                   ^
    
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:189:
 error: incompatible types: byte[] cannot be converted to ByteBuffer
                    "anidempotencyKey", "aSchema", "dummy".getBytes());
                                                                   ^
    
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:210:
 error: incompatible types: byte[] cannot be converted to ByteBuffer
                    "anidempotencyKey", "aSchema", "dummy".getBytes());
    ```
    
    ...and use StandardCharsets with getBytes
---
 .github/workflows/build-docker-mariadb.yml               |  4 ++--
 .github/workflows/build-docker-postgresql.yml            |  4 ++--
 .github/workflows/build-documentation.yml                |  4 ++--
 .../workflows/build-embeddable-progressive-loan-jar.yml  |  4 ++--
 .github/workflows/build-mariadb.yml                      |  4 ++--
 .github/workflows/build-mysql.yml                        |  4 ++--
 .github/workflows/build-postgresql.yml                   |  4 ++--
 .github/workflows/build-tests.yml                        |  4 ++--
 .github/workflows/publish-dockerhub.yml                  |  4 ++--
 .github/workflows/smoke-activemq.yml                     |  4 ++--
 .github/workflows/smoke-kafka.yml                        |  4 ++--
 .github/workflows/sonarqube.yml                          |  4 ++--
 .gitpod.yml                                              |  2 ++
 README.md                                                |  6 +++---
 build.gradle                                             | 16 +++++++---------
 custom/docker/build.gradle                               |  2 +-
 .../domain/AbstractAuditableWithUTCDateTimeCustom.java   |  8 ++++----
 .../core/domain/AbstractPersistableCustom.java           |  4 ++--
 .../core/serialization/GoogleGsonSerializerHelper.java   |  2 +-
 .../core/serialization/JsonParserHelper.java             |  2 +-
 .../domain/BasicPasswordEncodablePlatformUser.java       |  4 ++--
 fineract-provider/build.gradle                           |  2 +-
 .../bulkimport/importhandler/helper/DateSerializer.java  |  2 +-
 .../portfolio/loanaccount/service/LoanAssemblerImpl.java |  4 ++--
 .../external/jobs/SendAsynchronousEventsTaskletTest.java |  9 +++++----
 25 files changed, 56 insertions(+), 55 deletions(-)

diff --git a/.github/workflows/build-docker-mariadb.yml 
b/.github/workflows/build-docker-mariadb.yml
index 7b45bdc6b5..f8625dc7fc 100644
--- a/.github/workflows/build-docker-mariadb.yml
+++ b/.github/workflows/build-docker-mariadb.yml
@@ -12,10 +12,10 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-docker-postgresql.yml 
b/.github/workflows/build-docker-postgresql.yml
index 5f2b10894f..c342e2248c 100644
--- a/.github/workflows/build-docker-postgresql.yml
+++ b/.github/workflows/build-docker-postgresql.yml
@@ -12,10 +12,10 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-documentation.yml 
b/.github/workflows/build-documentation.yml
index 5af33dc148..8591cd85a8 100644
--- a/.github/workflows/build-documentation.yml
+++ b/.github/workflows/build-documentation.yml
@@ -12,10 +12,10 @@ jobs:
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-embeddable-progressive-loan-jar.yml 
b/.github/workflows/build-embeddable-progressive-loan-jar.yml
index 6e8890e417..6e3f034486 100644
--- a/.github/workflows/build-embeddable-progressive-loan-jar.yml
+++ b/.github/workflows/build-embeddable-progressive-loan-jar.yml
@@ -10,10 +10,10 @@ jobs:
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-mariadb.yml 
b/.github/workflows/build-mariadb.yml
index 5a79d65345..d792127f09 100644
--- a/.github/workflows/build-mariadb.yml
+++ b/.github/workflows/build-mariadb.yml
@@ -28,10 +28,10 @@ jobs:
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle and Validate Wrapper
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-mysql.yml 
b/.github/workflows/build-mysql.yml
index b5b70003f6..bfd2638624 100644
--- a/.github/workflows/build-mysql.yml
+++ b/.github/workflows/build-mysql.yml
@@ -28,10 +28,10 @@ jobs:
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle and Validate Wrapper
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-postgresql.yml 
b/.github/workflows/build-postgresql.yml
index 0e8a5f14e1..3ac9695c6f 100644
--- a/.github/workflows/build-postgresql.yml
+++ b/.github/workflows/build-postgresql.yml
@@ -29,10 +29,10 @@ jobs:
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle and Validate Wrapper
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/build-tests.yml 
b/.github/workflows/build-tests.yml
index 169d2e7552..f577565856 100644
--- a/.github/workflows/build-tests.yml
+++ b/.github/workflows/build-tests.yml
@@ -12,10 +12,10 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/publish-dockerhub.yml 
b/.github/workflows/publish-dockerhub.yml
index d13f4f02b9..75c67aa007 100644
--- a/.github/workflows/publish-dockerhub.yml
+++ b/.github/workflows/publish-dockerhub.yml
@@ -18,10 +18,10 @@ jobs:
         with:
           fetch-depth: 0
 
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
 
       - name: Setup Gradle
diff --git a/.github/workflows/smoke-activemq.yml 
b/.github/workflows/smoke-activemq.yml
index 5624986643..aa4a8a15dc 100644
--- a/.github/workflows/smoke-activemq.yml
+++ b/.github/workflows/smoke-activemq.yml
@@ -12,10 +12,10 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/smoke-kafka.yml 
b/.github/workflows/smoke-kafka.yml
index 3c69261916..d24665edd7 100644
--- a/.github/workflows/smoke-kafka.yml
+++ b/.github/workflows/smoke-kafka.yml
@@ -12,10 +12,10 @@ jobs:
       - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml
index be390601ed..9309d00560 100644
--- a/.github/workflows/sonarqube.yml
+++ b/.github/workflows/sonarqube.yml
@@ -22,10 +22,10 @@ jobs:
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
         with:
           fetch-depth: 0
-      - name: Set up JDK 17
+      - name: Set up JDK 21
         uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
         with:
-          java-version: '17'
+          java-version: '21'
           distribution: 'zulu'
       - name: Setup Gradle and Validate Wrapper
         uses: 
gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
diff --git a/.gitpod.yml b/.gitpod.yml
index 085a7b4ecb..d6630775c0 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -19,6 +19,8 @@
 # https://www.gitpod.io
 # https://www.gitpod.io/docs/41_Config_Gitpod_File/
 # https://github.com/gitpod-io/workspace-images/tree/master/mysql
+#
+# FIXME - dead code? see 
https://github.com/apache/fineract/pull/4590#issuecomment-2809760331
 
 image: gitpod/workspace-mysql:2022-08-04-13-40-17
 ports:
diff --git a/README.md b/README.md
index e047b4d4f1..7a56d6b7fc 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ If you are interested in contributing to this project, but 
perhaps don't quite k
 
 REQUIREMENTS
 ============
-* `Java >= 17` (Azul Zulu JVM is tested by our CI on GitHub Actions)
+* `Java >= 21` (Azul Zulu JVM is tested by our CI on GitHub Actions)
 * MariaDB `11.5.2`
 
 You can run the required version of the database server in a container, 
instead of having to install it, like this:
@@ -38,7 +38,7 @@ and stop and destroy it like this:
 
 <br>Beware that this database container database keeps its state inside the 
container and not on the host filesystem.  It is lost when you destroy (rm) 
this container.  This is typically fine for development.  See [Caveats: Where 
to Store Data on the database container 
documentation](https://hub.docker.com/_/mariadb) re. how to make it persistent 
instead of ephemeral.<br>
 
-Tomcat v9 is only required if you wish to deploy the Fineract WAR to a 
separate external servlet container.  Note that you do not require to install 
Tomcat to develop Fineract, or to run it in production if you use the 
self-contained JAR, which transparently embeds a servlet container using Spring 
Boot.  (Until FINERACT-730, Tomcat 7/8 were also supported, but now Tomcat 9 is 
required.)
+Tomcat v10 is only required if you wish to deploy the Fineract WAR to a 
separate external servlet container.  Note that you do not require to install 
Tomcat to develop Fineract, or to run it in production if you use the 
self-contained JAR, which transparently embeds a servlet container using Spring 
Boot.  (Until FINERACT-730, Tomcat 7/8 were also supported, but now Tomcat 10 
is required.)
 
 <br>IMPORTANT: If you use MySQL or MariaDB
 ============
@@ -137,7 +137,7 @@ FINERACT_SECURITY_2FA_ENABLED=true
 ============
 1. Clone the repository or download and extract the archive file to your local 
directory.
 2. Run `./gradlew :fineract-war:clean :fineract-war:war` to build a 
traditional WAR file which will be created at `fineract-war/build/libs` 
directory.
-3. Deploy this WAR to your Tomcat v9 Servlet Container.
+3. Deploy this WAR to your Tomcat v10 Servlet Container.
 
 We recommend using the JAR instead of the WAR file deployment, because it's 
much easier.
 
diff --git a/build.gradle b/build.gradle
index d2c71b738d..5c13996326 100644
--- a/build.gradle
+++ b/build.gradle
@@ -355,8 +355,10 @@ configure(project.fineractJavaProjects) {
     apply plugin: 'idea'
 
     java {
-        sourceCompatibility = JavaVersion.VERSION_17
-        targetCompatibility = JavaVersion.VERSION_17
+        toolchain {
+            languageVersion = JavaLanguageVersion.of(21)
+            vendor = JvmVendorSpec.AZUL
+        }
         withSourcesJar()
         withJavadocJar()
     }
@@ -402,11 +404,6 @@ configure(project.fineractJavaProjects) {
 
     group = 'org.apache.fineract'
 
-    /* define the valid syntax level for source files */
-    // sourceCompatibility = JavaVersion.VERSION_17
-    // /* define binary compatibility version */
-    // targetCompatibility = JavaVersion.VERSION_17
-
     /* 
http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle
 */
     sourceSets.main.output.resourcesDir = sourceSets.main.java.classesDirectory
     sourceSets.test.output.resourcesDir = sourceSets.test.java.classesDirectory
@@ -741,10 +738,11 @@ configure(project.fineractJavaProjects) {
     tasks.withType(Javadoc) {
         options.addStringOption('Xdoclint:none', '-quiet')
         options.encoding = 'UTF-8'
+        // FIXME - html5 is the default since sometime before Java 17
         // Disable strict checking to prevent build failures on invalid javadoc
         options.addBooleanOption('html5', true)
-        // Add this if you're using Java 17 records or other modern features
-        if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
+        // Add this if you're using Java 21 records or other modern features
+        if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_21)) {
             options.addBooleanOption('html5', true)
         }
         // Ignore any errors during javadoc generation
diff --git a/custom/docker/build.gradle b/custom/docker/build.gradle
index 28b9415f36..15aab0f998 100644
--- a/custom/docker/build.gradle
+++ b/custom/docker/build.gradle
@@ -24,7 +24,7 @@ apply from: 
"${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.dependencie
 
 jib {
     from {
-        image = 'azul/zulu-openjdk-alpine:17'
+        image = 'azul/zulu-openjdk-alpine:21'
         platforms {
             platform {
                 architecture = 
System.getProperty("os.arch").equals("aarch64")?"arm64":"amd64"
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java
index 6612602bfd..1107fdbf82 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java
@@ -53,19 +53,19 @@ public abstract class 
AbstractAuditableWithUTCDateTimeCustom<T extends Serializa
     private static final long serialVersionUID = 141481953116476081L;
 
     @Column(name = CREATED_BY_DB_FIELD, updatable = false, nullable = false)
-    @Setter(onMethod = @__(@Override))
+    @Setter(onMethod_ = @Override)
     private Long createdBy;
 
     @Column(name = CREATED_DATE_DB_FIELD, updatable = false, nullable = false)
-    @Setter(onMethod = @__(@Override))
+    @Setter(onMethod_ = @Override)
     private OffsetDateTime createdDate;
 
     @Column(name = LAST_MODIFIED_BY_DB_FIELD, nullable = false)
-    @Setter(onMethod = @__(@Override))
+    @Setter(onMethod_ = @Override)
     private Long lastModifiedBy;
 
     @Column(name = LAST_MODIFIED_DATE_DB_FIELD, nullable = false)
-    @Setter(onMethod = @__(@Override))
+    @Setter(onMethod_ = @Override)
     private OffsetDateTime lastModifiedDate;
 
     @Override
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractPersistableCustom.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractPersistableCustom.java
index 7c0813fdca..ae4744d424 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractPersistableCustom.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractPersistableCustom.java
@@ -54,12 +54,12 @@ public abstract class AbstractPersistableCustom<T extends 
Serializable> implemen
 
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    @Getter(onMethod = @__(@Override))
+    @Getter(onMethod_ = @Override)
     private T id;
 
     @Transient
     @Setter(value = AccessLevel.NONE)
-    @Getter(onMethod = @__(@Override))
+    @Getter(onMethod_ = @Override)
     private boolean isNew = true;
 
     @PrePersist
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/GoogleGsonSerializerHelper.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/GoogleGsonSerializerHelper.java
index 234a0046ee..1d2b9d56f0 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/GoogleGsonSerializerHelper.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/GoogleGsonSerializerHelper.java
@@ -105,7 +105,7 @@ public final class GoogleGsonSerializerHelper {
     public static void registerTypeAdapters(final GsonBuilder builder) {
         builder.registerTypeAdapter(java.util.Date.class, new DateAdapter());
         builder.registerTypeAdapter(LocalDate.class, new LocalDateAdapter());
-        // NOTE: was missing, necessary for GSON serialization with JDK 17's 
restrictive module access
+        // NOTE: was missing, necessary for GSON serialization with JDK 21's 
restrictive module access
         builder.registerTypeAdapter(LocalTime.class, new LocalTimeAdapter());
         builder.registerTypeAdapter(ZonedDateTime.class, new 
JodaDateTimeAdapter());
         builder.registerTypeAdapter(MonthDay.class, new JodaMonthDayAdapter());
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java
index e0573cd7c0..c48cc0a9b4 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/serialization/JsonParserHelper.java
@@ -819,7 +819,7 @@ public class JsonParserHelper {
                     dataValidationErrors);
         }
 
-        return new Locale(languageCode.toLowerCase(), 
courntryCode.toUpperCase(), variantCode);
+        return Locale.of(languageCode.toLowerCase(), 
courntryCode.toUpperCase(), variantCode);
     }
 
     private Locale extractLocaleValue(final JsonObject object) {
diff --git 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/domain/BasicPasswordEncodablePlatformUser.java
 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/domain/BasicPasswordEncodablePlatformUser.java
index bddb8141ef..943703ead3 100644
--- 
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/domain/BasicPasswordEncodablePlatformUser.java
+++ 
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/domain/BasicPasswordEncodablePlatformUser.java
@@ -32,9 +32,9 @@ public class BasicPasswordEncodablePlatformUser implements 
PlatformUser {
 
     @Getter
     private Long id;
-    @Getter(onMethod = @__(@Override))
+    @Getter(onMethod_ = @Override)
     private String username;
-    @Getter(onMethod = @__(@Override))
+    @Getter(onMethod_ = @Override)
     private String password;
 
     @Override
diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle
index 755ac5f32e..9150bf963d 100644
--- a/fineract-provider/build.gradle
+++ b/fineract-provider/build.gradle
@@ -258,7 +258,7 @@ bootJar {
 
 jib {
     from {
-        image = 'azul/zulu-openjdk-alpine:17'
+        image = 'azul/zulu-openjdk-alpine:21'
         platforms {
             platform {
                 architecture = 
System.getProperty("os.arch").equals("aarch64")?"arm64":"amd64"
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/helper/DateSerializer.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/helper/DateSerializer.java
index 85f0147c87..bf83256b2e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/helper/DateSerializer.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/helper/DateSerializer.java
@@ -46,7 +46,7 @@ public class DateSerializer implements 
JsonSerializer<LocalDate> {
     public JsonElement serialize(LocalDate src, Type typeOfSrc, 
JsonSerializationContext context) {
         DateTimeFormatter formatter;
         if (StringUtils.isNotEmpty(localeCode)) {
-            formatter = DateTimeFormatter.ofPattern(dateFormat, new 
Locale(localeCode));
+            formatter = DateTimeFormatter.ofPattern(dateFormat, 
Locale.of(localeCode));
         } else {
             formatter = DateTimeFormatter.ofPattern(dateFormat);
         }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
index 6d8ff28723..3938f6e785 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssemblerImpl.java
@@ -890,7 +890,7 @@ public class LoanAssemblerImpl implements LoanAssembler {
         loan.setClosedOnDate(withdrawnOn);
         loan.setClosedBy(currentUser);
 
-        final Locale locale = new Locale(command.locale());
+        final Locale locale = Locale.of(command.locale());
         final DateTimeFormatter fmt = 
DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
 
         actualChanges.put(Loan.PARAM_STATUS, 
LoanEnumerations.status(loan.getStatus()));
@@ -912,7 +912,7 @@ public class LoanAssemblerImpl implements LoanAssembler {
         loan.setClosedOnDate(rejectedOn);
         loan.setClosedBy(currentUser);
 
-        final Locale locale = new Locale(command.locale());
+        final Locale locale = Locale.of(command.locale());
         final DateTimeFormatter fmt = 
DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
 
         actualChanges.put(Loan.PARAM_STATUS, 
LoanEnumerations.status(loan.getStatus()));
diff --git 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java
 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java
index eee2cb04ba..550997db74 100644
--- 
a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java
+++ 
b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.util.ArrayList;
@@ -145,7 +146,7 @@ class SendAsynchronousEventsTaskletTest {
                 createExternalEventView("aType", "aCategory", "aSchema", new 
byte[0], "aIdempotencyKey", 1L));
         // Dummy Message
         MessageV1 dummyMessage = new MessageV1(1L, "aSource", "aType", 
"nocategory", "aCreateDate", "aBusinessDate", "aTenantId",
-                "anidempotencyKey", "aSchema", Mockito.mock(ByteBuffer.class));
+                "anidempotencyKey", "aSchema", 
ByteBuffer.wrap("dummy".getBytes(StandardCharsets.UTF_8)));
 
         when(repository.findByStatusOrderByBusinessDateAscIdAsc(Mockito.any(), 
Mockito.any())).thenReturn(events);
         
when(messageFactory.createMessage(Mockito.any())).thenReturn(dummyMessage);
@@ -167,7 +168,7 @@ class SendAsynchronousEventsTaskletTest {
                 createExternalEventView("aType", "aCategory", "aSchema", new 
byte[0], "aIdempotencyKey", 1L),
                 createExternalEventView("aType", "aCategory", "aSchema", new 
byte[0], "aIdempotencyKey", 1L));
         MessageV1 dummyMessage = new MessageV1(1L, "aSource", "aType", 
"nocategory", "aCreateDate", "aBusinessDate", "aTenantId",
-                "anidempotencyKey", "aSchema", Mockito.mock(ByteBuffer.class));
+                "anidempotencyKey", "aSchema", 
ByteBuffer.wrap("dummy".getBytes(StandardCharsets.UTF_8)));
         when(repository.findByStatusOrderByBusinessDateAscIdAsc(Mockito.any(), 
Mockito.any())).thenReturn(events);
         
when(messageFactory.createMessage(Mockito.any())).thenReturn(dummyMessage);
         
when(byteBufferConverter.convert(Mockito.any(ByteBuffer.class))).thenReturn(new 
byte[0]);
@@ -186,7 +187,7 @@ class SendAsynchronousEventsTaskletTest {
         List<ExternalEventView> events = Arrays
                 .asList(createExternalEventView("aType", "aCategory", 
"aSchema", new byte[0], "aIdempotencyKey", 1L));
         MessageV1 dummyMessage = new MessageV1(1L, "aSource", "aType", 
"nocategory", "aCreateDate", "aBusinessDate", "aTenantId",
-                "anidempotencyKey", "aSchema", Mockito.mock(ByteBuffer.class));
+                "anidempotencyKey", "aSchema", 
ByteBuffer.wrap("dummy".getBytes(StandardCharsets.UTF_8)));
         when(repository.findByStatusOrderByBusinessDateAscIdAsc(Mockito.any(), 
Mockito.any())).thenReturn(events);
         
when(messageFactory.createMessage(Mockito.any())).thenReturn(dummyMessage);
         
when(byteBufferConverter.convert(Mockito.any(ByteBuffer.class))).thenReturn(new 
byte[0]);
@@ -207,7 +208,7 @@ class SendAsynchronousEventsTaskletTest {
         List<ExternalEventView> events = Arrays
                 .asList(createExternalEventView("aType", "aCategory", 
"aSchema", new byte[0], "aIdempotencyKey", null));
         MessageV1 dummyMessage = new MessageV1(1L, "aSource", "aType", 
"nocategory", "aCreateDate", "aBusinessDate", "aTenantId",
-                "anidempotencyKey", "aSchema", Mockito.mock(ByteBuffer.class));
+                "anidempotencyKey", "aSchema", 
ByteBuffer.wrap("dummy".getBytes(StandardCharsets.UTF_8)));
         when(repository.findByStatusOrderByBusinessDateAscIdAsc(Mockito.any(), 
Mockito.any())).thenReturn(events);
         
when(messageFactory.createMessage(Mockito.any())).thenReturn(dummyMessage);
         byte[] byteMsg = new byte[0];

Reply via email to