Merge pull request #671 from lvydra/issue655

[655] java.sql.Time throws java.lang.UnsupportedOperationException when serialized
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..6718d4e
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,21 @@
+version: 2
+updates:
+  - package-ecosystem: github-actions
+    directory: /
+    schedule:
+      interval: daily
+  
+  - package-ecosystem: maven
+    directory: /
+    schedule:
+      interval: daily
+  
+  - package-ecosystem: maven
+    directory: /yasson-jmh
+    schedule:
+      interval: weekly
+  
+  - package-ecosystem: maven
+    directory: /yasson-tck
+    schedule:
+      interval: weekly
\ No newline at end of file
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 3b21094..e39f36e 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2021, 2026 Oracle and/or its affiliates. All rights reserved.
 #
 # This program and the accompanying materials are made available under the
 # terms of the Eclipse Public License v. 2.0 which is available at
@@ -12,24 +12,38 @@
 
 name: Yasson
 
-on: [push, pull_request]
+on:
+  push:
+    branches:
+      - 'main'
+      - '*-RELEASE'
+  pull_request:
+    branches:
+      - 'main'
+      - '*-RELEASE'
 
 jobs:
   build:
-    name: Test on JDK ${{ matrix.java_version }}
+    name: Test on JDK ${{ matrix.java_version }} locale ${{ matrix.locale }}
     runs-on: ubuntu-latest
 
     strategy:
       matrix:
-        java_version: [ 11, 17, 21 ]
+        java_version: [ 17, 21, 25 ]
+        include:
+          - locale: en_US
+          # Use a different locale when running against one of the java versions
+          # to ensure we correctly write tests that account for localization differences.
+          - locale: de_AT
+            java_version: 21
 
     steps:
       - name: Checkout for build
-        uses: actions/checkout@v4
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
         with:
           fetch-depth: 0
       - name: Set up compile JDK
-        uses: actions/setup-java@v4
+        uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
         with: #Compile java needs to be the highest to ensure proper compilation of the multi-release jar
           distribution: 'temurin'
           java-version: 17
@@ -37,10 +51,18 @@
       - name: Copyright
         run: bash etc/copyright.sh
       - name: Checkstyle
-        run: mvn -B checkstyle:checkstyle -Pstaging
+        run: mvn -B checkstyle:checkstyle
       - name: Yasson install
-        run: mvn -U -C clean install -Pstaging -DskipTests
+        run: mvn -U -C clean install -DskipTests
+      - name: Yasson jmh package
+        run: mvn -U -C -f yasson-jmh/pom.xml clean package
       - name: Yasson tests
-        run: mvn -U -B -C -Dmaven.javadoc.skip=true -Pstaging verify
-      - name: JSONB-API TCK
-        run: cd yasson-tck && mvn -U -B test -DargLine="-Djava.locale.providers=COMPAT" -Pstaging
+        run: |
+          export LANG_TAG="${{ matrix.locale }}"
+          mvn -U -B -C \
+            -Dmaven.javadoc.skip=true \
+            -Duser.language="${LANG_TAG%%_*}" \
+            -Duser.country="${LANG_TAG##*_}" \
+            verify
+      - name: Jakarta JSON-B TCK
+        run: cd yasson-tck && mvn -U -B test -DargLine="-Djava.locale.providers=COMPAT"
diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
new file mode 100644
index 0000000..7977c1f
--- /dev/null
+++ b/.github/workflows/performance.yml
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2026 Eclipse Foundation and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0 which is available at
+# http://www.eclipse.org/legal/epl-2.0,
+# or the Eclipse Distribution License v. 1.0 which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+#
+
+# This workflow performs performance testing using JMH.
+# It is intended to be run on a schedule (e.g. weekly) to track performance over time, but can also be triggered manually when needed.
+# Persist results to github pages for continuous line graphs and regression alerts.
+
+name: Performance
+
+on:
+    schedule:
+        # Runs every Tuesday at 4:13 AM UTC (avoid peak hours for better performance results)
+        - cron: '13 4 * * 2' 
+    workflow_dispatch:
+    
+jobs:
+    performance:
+        name: Run JMH performance tests
+        runs-on: ubuntu-latest
+
+        steps:
+            - name: Checkout for performance
+              uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+              with:
+                fetch-depth: 0
+            - name: Set up compile JDK
+              uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
+              with: #Compile java needs to be the highest to ensure proper compilation of the multi-release jar
+                distribution: 'temurin'
+                java-version: 17
+                cache: 'maven'
+            - name: Compile Yasson
+              run: |
+                mvn -U -C clean install -DskipTests
+            - name: Run JMH performance tests
+              run: |
+                cd yasson-jmh
+                mvn -U -B clean package
+                java -jar target/yasson-jmh.jar -rf json -rff jmh-result.json
+            - name: Persist JMH results
+              uses: benchmark-action/github-action-benchmark@52576c92bccf6ac60c8223ec7eb2565637cae9ba # v1.22.1
+              with:
+                name: Java JMH Benchmark
+                tool: 'jmh'
+                output-file-path: yasson-jmh/jmh-result.json
+                github-token: ${{ secrets.GITHUB_TOKEN }}
+            
+                # Enable deployment to GitHub Pages for continuous line graphs
+                auto-push: true
+                comment-on-alert: true       # Creates a comment if performance degrades
+                fail-on-alert: true          # Fails the workflow run on regression
+                alert-threshold: '200%'      # Triggers an alert if execution time doubles
+
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
new file mode 100644
index 0000000..fb7b194
--- /dev/null
+++ b/.github/workflows/verify.yml
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2026 Eclipse Foundation and/or its affiliates. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v. 2.0 which is available at
+# http://www.eclipse.org/legal/epl-2.0,
+# or the Eclipse Distribution License v. 1.0 which is available at
+# http://www.eclipse.org/org/documents/edl-v10.php.
+#
+# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+#
+
+# This workflow is used to verify this project against staged versions of the API and TCK. 
+# It is not intended to be used for regular CI builds, but rather as a manual workflow that can be triggered when needed.
+
+name: Verify
+
+on:
+    workflow_dispatch:
+        inputs:
+            jsonb_version:
+                description: 'The version of the TCK to verify against (e.g. 3.1.0-M1)'
+                required: true
+
+jobs:
+    verify:
+        name: Verify against staged API or TCK
+        runs-on: ubuntu-latest
+
+        steps:
+            - name: Checkout for verify
+              uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+              with:
+                fetch-depth: 0
+            - name: Set up compile JDK
+              uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0
+              with: #Compile java needs to be the highest to ensure proper compilation of the multi-release jar
+                distribution: 'temurin'
+                java-version: 17
+                cache: 'maven'
+            - name: Compile Yasson
+              run: |
+                mvn -U -C clean install \
+                    -Pstaged \
+                    -Djakarta.json.bind.version=${{ github.event.inputs.jsonb_version }} \
+                    -DskipTests
+            - name: Run TCK
+              run: |
+                cd yasson-tck
+                mvn -U -B test \
+                    -Pstaged \
+                    -Djakarta.json.bind.version=${{ github.event.inputs.jsonb_version }} \
+                    -Djsonb.tck.version=${{ github.event.inputs.jsonb_version }} \
+                    -DargLine="-Djava.locale.providers=COMPAT"
diff --git a/.gitignore b/.gitignore
index 3160630..7cd0fac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,7 @@
 .project
 .idea/
 .settings/
-/.DS_Store
+.DS_Store
+bin/
+.envrc
+.vscode/
diff --git a/README.md b/README.md
index 374a9db..f2f959a 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
 # Eclipse Yasson
 
-[![Maven Central](https://img.shields.io/maven-central/v/org.eclipse/yasson.svg?label=Maven%20Central)](https://mvnrepository.com/artifact/org.eclipse/yasson)
-[![Jakarta Staging (Snapshots)](https://img.shields.io/nexus/s/https/jakarta.oss.sonatype.org/org.eclipse/yasson.svg)](https://jakarta.oss.sonatype.org/content/repositories/staging/org/eclipse/yasson/)
+[![Maven Central](https://img.shields.io/maven-central/v/org.eclipse.yasson/yasson.svg?label=Maven%20Central)](https://mvnrepository.com/artifact/org.eclipse.yasson/yasson)
+<!-- TODO reenable once snapshots can be browsed via https://central.sonatype.com/service/rest/repository/browse/maven-snapshots
+[![Jakarta Staging (Snapshots)](https://img.shields.io/nexus/s/https/jakarta.oss.sonatype.org/org.eclipse.yasson/yasson.svg)](https://jakarta.oss.sonatype.org/content/repositories/staging/org/eclipse/yasson/yasson/)
+-->
 [![Gitter](https://badges.gitter.im/eclipse/yasson.svg)](https://gitter.im/eclipse/yasson)
-[![Javadocs](https://www.javadoc.io/badge/org.eclipse/yasson.svg)](https://www.javadoc.io/doc/org.eclipse/yasson)
-[![Build Status](https://github.com/eclipse-ee4j/yasson/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/eclipse-ee4j/yasson/actions/workflows/maven.yml?branch=master)
+[![Javadocs](https://www.javadoc.io/badge/org.eclipse.yasson/yasson.svg)](https://www.javadoc.io/doc/org.eclipse.yasson/yasson)
+[![Build Status](https://github.com/eclipse-ee4j/yasson/actions/workflows/maven.yml/badge.svg?branch=main)](https://github.com/eclipse-ee4j/yasson/actions/workflows/maven.yml?branch=main)
 [![License](https://img.shields.io/badge/License-EPL%202.0-green.svg)](https://opensource.org/licenses/EPL-2.0)
 
 Yasson is a Java framework which provides a standard binding layer between Java classes and JSON documents. This is similar to what JAXB is doing in the XML world. Yasson is an official reference implementation of JSON Binding ([JSR-367](https://jcp.org/en/jsr/detail?id=367)).
diff --git a/pom.xml b/pom.xml
index f3f048a..752bbf0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2016, 2024 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2016, 2026 Oracle and/or its affiliates. All rights reserved.
 
     This program and the accompanying materials are made available under the
     terms of the Eclipse Public License v. 2.0 which is available at
@@ -15,17 +15,17 @@
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
 
     <parent>
         <groupId>org.eclipse.ee4j</groupId>
         <artifactId>project</artifactId>
-        <version>1.0.9</version>
+        <version>2.0.5</version>
     </parent>
 
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.eclipse</groupId>
+    <groupId>org.eclipse.yasson</groupId>
     <artifactId>yasson</artifactId>
-    <version>3.0.4-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <packaging>jar</packaging>
     <name>Yasson</name>
 
@@ -34,33 +34,43 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <maven.compiler.release>11</maven.compiler.release>
-        <maven.compiler.testRelease>${maven.compiler.release}</maven.compiler.testRelease>
+
+        <maven.compiler.release>17</maven.compiler.release>
+        
+        <nexus.staging.repository>yasson-maven2-staging</nexus.staging.repository>
 
         <!--Dependencies-->
-        <hamcrest.version>2.2</hamcrest.version>
+        <hamcrest.version>3.0</hamcrest.version>
+        
+        <!-- Jakarta API -->
+        <!-- TODO finalize versions to EE 12 -->
         <jakarta.annotation-api.version>3.0.0</jakarta.annotation-api.version>
-        <jakarta.el-api.version>6.0.0</jakarta.el-api.version>
+        <jakarta.el-api.version>6.1.0-M2</jakarta.el-api.version>
         <jakarta.enterprise.cdi-api.version>4.1.0</jakarta.enterprise.cdi-api.version>
         <jakarta.interceptor-api.version>2.2.0</jakarta.interceptor-api.version>
-        <jakarta.json.bind.version>3.0.1</jakarta.json.bind.version>
+        <jakarta.json.bind.version>3.1.0-M1</jakarta.json.bind.version>
         <jakarta.json.version>2.1.3</jakarta.json.version>
-        <jakarta.parson.version>1.1.7</jakarta.parson.version>
-        <junit-jupiter.version>5.10.2</junit-jupiter.version>
-        <weld-se-core.version>6.0.0.Beta1</weld-se-core.version>
+
+        <!-- Jakarta Implementation -->
+        <!-- TODO update to EE 12 version-->
+        <jakarta.parson.version>1.1.9</jakarta.parson.version>
+
+        <!-- Test dependencies-->
+        <junit-jupiter.version>6.1.3</junit-jupiter.version>
+        <weld-se-core.version>6.0.4.Final</weld-se-core.version>
 
         <!--Plugins-->
         <build-helper-maven-plugin.version>3.6.0</build-helper-maven-plugin.version>
-        <buildnumber-maven-plugin.version>3.2.0</buildnumber-maven-plugin.version>
-        <spotbugs-maven-plugin.version>4.8.5.0</spotbugs-maven-plugin.version>
+        <buildnumber-maven-plugin.version>3.3.0</buildnumber-maven-plugin.version>
+        <spotbugs-maven-plugin.version>4.10.3.0</spotbugs-maven-plugin.version>
         <glassfish-copyright-maven-plugin.version>2.4</glassfish-copyright-maven-plugin.version>
         <maven-bundle-plugin.version>5.1.9</maven-bundle-plugin.version>
         <maven-checkstyle-plugin.version>3.3.1</maven-checkstyle-plugin.version>
-        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
+        <maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>
         <maven-enforcer-plugin.version>3.4.1</maven-enforcer-plugin.version>
         <maven-jar-plugin.version>3.4.1</maven-jar-plugin.version>
         <maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
-        <maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
+        <maven-surefire-plugin.version>3.5.6</maven-surefire-plugin.version>
     </properties>
 
     <dependencyManagement>
@@ -302,50 +312,6 @@
                 </plugins>
             </build>
         </profile>
-        <profile>
-            <id>jdk16</id>
-            <activation>
-                <jdk>[16,)</jdk>
-            </activation>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-compiler-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>default-testCompile</id>
-                                <configuration>
-                                    <release>16</release>
-                                    <testRelease>16</testRelease>
-                                    <compileSourceRoots>
-                                        <compileSourceRoot>${project.basedir}/src/test/java</compileSourceRoot>
-                                        <compileSourceRoot>${project.basedir}/src/test/java16</compileSourceRoot>
-                                    </compileSourceRoots>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-failsafe-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <goals>
-                                    <goal>integration-test</goal>
-                                    <goal>verify</goal>
-                                </goals>
-                            </execution>
-                        </executions>
-                        <configuration>
-                            <includes>
-                                <include>**/RecordTest.java</include>
-                            </includes>
-                        </configuration>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
     </profiles>
 
     <build>
@@ -356,39 +322,6 @@
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-compiler-plugin</artifactId>
                     <version>${maven-compiler-plugin.version}</version>
-                    <!-- defaults for compile and testCompile -->
-                    <executions>
-                        <execution>
-                            <id>default-compile</id>
-                            <goals>
-                                <goal>compile</goal>
-                            </goals>
-                            <configuration>
-                                <release>11</release>
-                                <source>11</source>
-                                <target>11</target>
-                            </configuration>
-                        </execution>
-                        <execution>
-                            <id>default-testCompile</id>
-                            <configuration>
-                                <release>11</release>
-                            </configuration>
-                        </execution>
-                        <execution>
-                            <id>multi-release-compile-16</id>
-                            <goals>
-                                <goal>compile</goal>
-                            </goals>
-                            <configuration>
-                                <release>16</release>
-                                <compileSourceRoots>
-                                    <compileSourceRoot>${project.basedir}/src/main/java16</compileSourceRoot>
-                                </compileSourceRoots>
-                                <multiReleaseOutput>true</multiReleaseOutput>
-                            </configuration>
-                        </execution>
-                    </executions>
                     <configuration>
                         <compilerArgs>
                             <arg>-Xlint:all</arg>
@@ -433,7 +366,7 @@
                     <artifactId>maven-javadoc-plugin</artifactId>
                     <version>${maven-javadoc-plugin.version}</version>
                     <configuration>
-                        <bottom><![CDATA[Copyright &#169; 2017, 2024 Oracle Corporation. All rights reserved.<br>]]></bottom>
+                        <bottom><![CDATA[Copyright &#169; 2017, 2026 Oracle Corporation. All rights reserved.<br>]]></bottom>
                     </configuration>
                 </plugin>
                 <plugin>
@@ -463,7 +396,7 @@
                                         java.beans;resolution:="optional",
                                         *
                                     </Import-Package>
-                                    <Require-Capability>osgi.ee;filter:="(&amp;(osgi.ee=JavaSE)(version=11))"</Require-Capability>
+                                    <Require-Capability>osgi.ee;filter:="(&amp;(osgi.ee=JavaSE)(version=17))"</Require-Capability>
                                 </instructions>
                             </configuration>
                         </execution>
@@ -486,7 +419,6 @@
                                 <excludes>
                                     <exclude>**/JavaxNamingExcludedTest.java</exclude>
                                     <exclude>**/AnnotationIntrospectorWithoutOptionalModulesTest.java</exclude>
-                                    <exclude>**/*Record*</exclude>
                                 </excludes>
                                 <argLine>
                                     <!--Remove when CDI is updated to support modules
@@ -532,7 +464,7 @@
                     <configuration>
                         <rules>
                             <requireJavaVersion>
-                                <version>[11,)</version>
+                                <version>[17,)</version>
                             </requireJavaVersion>
                             <requireMavenVersion>
                                 <version>[3.6.0,)</version>
diff --git a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
index 36c2943..2228c51 100644
--- a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
+++ b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -186,7 +186,9 @@
             }
         }
         if (jsonbCreator == null) {
-            jsonbCreator = ClassMultiReleaseExtension.findCreator(clazz, declaredConstructors, this, propertyNamingStrategy);
+            if (clazz.isRecord() && declaredConstructors.length == 1) {
+                jsonbCreator = createJsonbCreator(declaredConstructors[0], null, clazz, propertyNamingStrategy);
+            }
             if (jsonbCreator == null) {
                 jsonbCreator = constructorPropertiesIntrospector.getCreator(declaredConstructors);
             }
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
index 72653cf..f83ed39 100644
--- a/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
+++ b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -12,17 +12,6 @@
 
 package org.eclipse.yasson.internal;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.Optional;
-
-import jakarta.json.bind.JsonbException;
-import jakarta.json.bind.config.PropertyNamingStrategy;
-
-import org.eclipse.yasson.internal.model.JsonbCreator;
-import org.eclipse.yasson.internal.model.Property;
-
 /**
  * Search for instance creator from other sources.
  * Mainly intended to add extensibility for different java versions and new features.
@@ -33,27 +22,5 @@
         throw new IllegalStateException("This class cannot be instantiated");
     }
 
-    static boolean shouldTransformToPropertyName(Method method) {
-        return true;
-    }
-
-    static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
-        return false;
-    }
-
-    static JsonbCreator findCreator(Class<?> clazz,
-                                    Constructor<?>[] declaredConstructors,
-                                    AnnotationIntrospector introspector,
-                                    PropertyNamingStrategy propertyNamingStrategy) {
-        return null;
-    }
-
-    public static boolean isRecord(Class<?> clazz) {
-        return false;
-    }
-
-    public static Optional<JsonbException> exceptionToThrow(Class<?> clazz) {
-        return Optional.empty();
-    }
-
+    // Currently is unused - but could be used in the future.
 }
diff --git a/src/main/java/org/eclipse/yasson/internal/ClassParser.java b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
index 4adce65..b63dc00 100644
--- a/src/main/java/org/eclipse/yasson/internal/ClassParser.java
+++ b/src/main/java/org/eclipse/yasson/internal/ClassParser.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -198,14 +198,14 @@
         for (Method method : declaredMethods) {
             String name = method.getName();
             //isBridge method filters out methods inherited from interfaces
-            boolean isAccessorMethod = ClassMultiReleaseExtension.isSpecialAccessorMethod(method, classProperties)
+            boolean isAccessorMethod = isSpecialAccessorMethod(method, classProperties)
                     || isPropertyMethod(method);
             if (!isAccessorMethod || method.isBridge() || isSpecialCaseMethod(clazz, method)) {
                 continue;
             }
-            final String propertyName = ClassMultiReleaseExtension.shouldTransformToPropertyName(method)
-                    ? toPropertyMethod(name)
-                    : name;
+            final String propertyName = method.getDeclaringClass().isRecord()
+                    ? name
+                    : toPropertyMethod(name);
 
             registerMethod(propertyName, method, classElement, classProperties);
         }
@@ -265,6 +265,13 @@
         return isGetter(m) || isSetter(m);
     }
 
+    private static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
+        return method.getDeclaringClass().isRecord()
+                && method.getParameterCount() == 0
+                && !void.class.equals(method.getReturnType())
+                && classProperties.containsKey(method.getName());
+    }
+
     private static void parseFields(JsonbAnnotatedElement<Class<?>> classElement, Map<String, Property> classProperties) {
         Field[] declaredFields = AccessController.doPrivileged(
                 (PrivilegedAction<Field[]>) () -> classElement.getElement().getDeclaredFields());
diff --git a/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java b/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
index b4a2cf8..2763ea9 100644
--- a/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
+++ b/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
@@ -24,6 +24,7 @@
 
 import jakarta.json.bind.JsonbConfig;
 import jakarta.json.bind.adapter.JsonbAdapter;
+import jakarta.json.bind.annotation.JsonbTypeSerializer;
 import jakarta.json.bind.serializer.JsonbDeserializer;
 import jakarta.json.bind.serializer.JsonbSerializer;
 
@@ -142,9 +143,28 @@
                                                                ComponentBoundCustomization customization) {
 
         if (customization == null || customization.getSerializerBinding() == null) {
-            return searchComponentBinding(propertyRuntimeType, ComponentBindings::getSerializer);
+            return searchComponentBinding(propertyRuntimeType, ComponentBindings::getSerializer, this::getAnnotationBasedSerializer);
         }
-        return Optional.of(customization.getSerializerBinding());
+        final SerializerBinding<?> binding = customization.getSerializerBinding();
+
+        // If the binding type exactly matches the runtime type, use it (optimization)
+        if (binding.getBindingType().equals(propertyRuntimeType)) {
+            return Optional.of(binding);
+        }
+
+        // Special handling for Object type: search for more specific serializers based on runtime type
+        // This allows annotation-based or config-based serializers on concrete types to be found
+        // when the property is declared as Object but has a specific runtime type
+        if (Object.class.equals(binding.getBindingType())) {
+            final Optional<SerializerBinding<?>> moreSpecific = searchComponentBinding(propertyRuntimeType,
+                ComponentBindings::getSerializer, this::getAnnotationBasedSerializer);
+            if (moreSpecific.isPresent()) {
+                return moreSpecific;
+            }
+        }
+
+        // Use the customization binding (user explicitly configured it for this property)
+        return Optional.of(binding);
     }
 
     /**
@@ -175,7 +195,14 @@
         if (customization == null || customization.getSerializeAdapterBinding() == null) {
             return searchComponentBinding(propertyRuntimeType, ComponentBindings::getAdapterInfo);
         }
-        return Optional.of(customization.getSerializeAdapterBinding());
+        // Check if the customization's adapter binding matches the runtime type
+        AdapterBinding binding = customization.getSerializeAdapterBinding();
+        if (matches(propertyRuntimeType, binding.getBindingType())) {
+            return Optional.of(binding);
+        }
+        // The annotation-based adapter doesn't match the runtime type,
+        // fall through to search for a better match based on runtime type
+        return searchComponentBinding(propertyRuntimeType, ComponentBindings::getAdapterInfo);
     }
 
     /**
@@ -194,7 +221,19 @@
         return Optional.of(customization.getDeserializeAdapterBinding());
     }
 
-    private <T extends AbstractComponentBinding> Optional<T> searchComponentBinding(Type runtimeType, Function<ComponentBindings, T> supplier) {
+    /**
+     * Search for a component binding for the given runtime type.
+     *
+     * @param runtimeType         The runtime type to find a component for
+     * @param supplier            Function to extract the desired component from ComponentBindings
+     * @param annotationDiscovery Optional function for runtime annotation discovery (null if not applicable)
+     * @param <T>                 The type of component binding to search for
+     * @return Optional containing the component binding if found
+     */
+    private <T extends AbstractComponentBinding> Optional<T> searchComponentBinding(
+            Type runtimeType,
+            Function<ComponentBindings, T> supplier,
+            Function<Class<?>, Optional<T>> annotationDiscovery) {
         // First check if there is an exact match
         ComponentBindings binding = userComponents.get(runtimeType);
         if (binding != null) {
@@ -206,6 +245,15 @@
         
         Optional<Class<?>> runtimeClass = ReflectionUtils.getOptionalRawType(runtimeType);
         if (runtimeClass.isPresent()) {
+            // Check for annotation-based component on the runtime type itself
+            // Currently only used for @JsonbTypeSerializer during serialization
+            if (annotationDiscovery != null) {
+                Optional<T> annotationBased = annotationDiscovery.apply(runtimeClass.get());
+                if (annotationBased.isPresent()) {
+                    return annotationBased;
+                }
+            }
+
             // Check if any interfaces have a match
             for (Class<?> ifc : runtimeClass.get().getInterfaces()) {
                 ComponentBindings ifcBinding = userComponents.get(ifc);
@@ -220,7 +268,7 @@
             // check if the superclass has a match
             Class<?> superClass = runtimeClass.get().getSuperclass();
             if (superClass != null && superClass != Object.class) {
-                Optional<T> superBinding = searchComponentBinding(superClass, supplier);
+                Optional<T> superBinding = searchComponentBinding(superClass, supplier, annotationDiscovery);
                 if (superBinding.isPresent()) {
                     return superBinding;
                 }
@@ -229,7 +277,64 @@
         
         return Optional.empty();
     }
-    
+
+    // Convenience overload for components without annotation discovery (deserializers, adapters)
+    private <T extends AbstractComponentBinding> Optional<T> searchComponentBinding(
+            final Type runtimeType,
+            final Function<ComponentBindings, T> supplier) {
+        return searchComponentBinding(runtimeType, supplier, null);
+    }
+
+    /**
+     * Discovers and caches a serializer defined by @JsonbTypeSerializer annotation on a runtime type.
+     *
+     * <p>This method performs <strong>runtime</strong> annotation discovery during serialization,
+     * which is distinct from the build-time annotation introspection performed by AnnotationIntrospector.
+     * It is invoked when serializing a property where the runtime type is more specific than the
+     * declared type (e.g., a property declared as {@code Object} containing an instance of a class
+     * annotated with @JsonbTypeSerializer).</p>
+     *
+     * <p>Note: Only @JsonbTypeSerializer is checked, not @JsonbTypeAdapter or @JsonbTypeDeserializer,
+     * because:</p>
+     * <ul>
+     *   <li>Serializers are unidirectional (serialization only), so runtime discovery is complete</li>
+     *   <li>Deserializers don't apply - we lack runtime type information during deserialization</li>
+     *   <li>Adapters are bidirectional - discovering them only at runtime during serialization
+     *       would be incomplete since they couldn't be discovered during deserialization</li>
+     * </ul>
+     *
+     * @param clazz The runtime class to check for @JsonbTypeSerializer annotation
+     * @return SerializerBinding if annotation is present and successfully introspected, empty otherwise
+     */
+    private Optional<SerializerBinding<?>> getAnnotationBasedSerializer(final Class<?> clazz) {
+        // Check if the class has a @JsonbTypeSerializer annotation
+        final JsonbTypeSerializer annotation = clazz.getAnnotation(JsonbTypeSerializer.class);
+        if (annotation == null) {
+            return Optional.empty();
+        }
+
+        // Thread-safe get-or-create using compute
+       final SerializerBinding<?> binding = userComponents.compute(clazz, (type, bindings) -> {
+            // If already cached, return as-is
+            if (bindings != null && bindings.getSerializer() != null) {
+                return bindings;
+            }
+
+            // Create new serializer binding
+            final Class<? extends JsonbSerializer> serializerClass = annotation.value();
+            final JsonbSerializer<?> serializer = jsonbContext.getComponentInstanceCreator().getOrCreateComponent(serializerClass);
+            final SerializerBinding<?> newBinding = new SerializerBinding<>(clazz, serializer);
+
+            // Create or update ComponentBindings
+            if (bindings == null) {
+                return new ComponentBindings(clazz, newBinding, null, null);
+            }
+            return new ComponentBindings(clazz, newBinding, bindings.getDeserializer(), bindings.getAdapterInfo());
+        }).getSerializer();
+
+        return Optional.ofNullable(binding);
+    }
+
     private <T> Optional<T> getMatchingBinding(Type runtimeType, ComponentBindings binding, Function<ComponentBindings, T> supplier) {
         final T component = supplier.apply(binding);
         if (component != null && matches(runtimeType, binding.getBindingType())) {
diff --git a/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java b/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java
index 1c7cca1..d83850b 100644
--- a/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java
+++ b/src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java
@@ -262,6 +262,10 @@
                                                                         typeToSearch));
                 }
             }
+            // The expected type and the resolved type are the same, simply return the type
+            if (resolvedArgs[i].equals(typeToResolve)) {
+                return typeToResolve;
+            }
             if (resolvedArgs[i] instanceof ParameterizedType) {
                 resolvedArgs[i] = resolveTypeArguments((ParameterizedType) resolvedArgs[i], typeToSearch);
             } else if (unresolvedArg instanceof GenericArrayType) {
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java
index 822da18..d4358ab 100644
--- a/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java
+++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DefaultObjectInstanceCreator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -17,7 +17,6 @@
 import jakarta.json.bind.JsonbException;
 import jakarta.json.stream.JsonParser;
 
-import org.eclipse.yasson.internal.ClassMultiReleaseExtension;
 import org.eclipse.yasson.internal.DeserializationContextImpl;
 import org.eclipse.yasson.internal.ReflectionUtils;
 import org.eclipse.yasson.internal.properties.MessageKeys;
@@ -40,8 +39,11 @@
         if (clazz.isInterface()) {
             this.exception = new JsonbException(Messages.getMessage(MessageKeys.INFER_TYPE_FOR_UNMARSHALL, clazz.getName()));
         } else if (defaultConstructor == null) {
-            this.exception = ClassMultiReleaseExtension.exceptionToThrow(clazz)
-                    .orElse(new JsonbException(Messages.getMessage(MessageKeys.NO_DEFAULT_CONSTRUCTOR, clazz)));
+            if (clazz.isRecord() && clazz.getDeclaredConstructors().length > 1) {
+                this.exception = new JsonbException(Messages.getMessage(MessageKeys.RECORD_MULTIPLE_CONSTRUCTORS, clazz));
+            } else {
+                this.exception = new JsonbException(Messages.getMessage(MessageKeys.NO_DEFAULT_CONSTRUCTOR, clazz));
+            }
         } else {
             this.exception = null;
         }
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java
index 1f1bdab..6a6daca 100644
--- a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java
+++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java
@@ -180,15 +180,15 @@
             return typeDeserializer;
         }
         if (Collection.class.isAssignableFrom(rawType)) {
-            return createCollectionDeserializer(cachedItem, rawType, chain, propertyCustomization);
+            return createCollectionDeserializer(cachedItem, rawType, chain);
         } else if (Map.class.isAssignableFrom(rawType)) {
-            return createMapDeserializer(cachedItem, rawType, chain, propertyCustomization);
+            return createMapDeserializer(cachedItem, rawType, chain);
         } else if (rawType.isArray()) {
-            return createArrayDeserializer(cachedItem, rawType, chain, propertyCustomization);
+            return createArrayDeserializer(cachedItem, rawType, chain);
         } else if (type instanceof GenericArrayType) {
-            return createGenericArray(cachedItem, rawType, chain, propertyCustomization);
+            return createGenericArray(cachedItem, rawType, chain);
         } else if (Optional.class.isAssignableFrom(rawType)) {
-            return createOptionalDeserializer(chain, type, propertyCustomization, cachedItem);
+            return createOptionalDeserializer(chain, type, cachedItem);
         } else {
             return createObjectDeserializer(chain, type, propertyCustomization, classModel, rawType, cachedItem);
         }
@@ -262,8 +262,7 @@
 
     private ModelDeserializer<JsonParser> createCollectionDeserializer(CachedItem cachedItem,
                                                                        Class<?> rawType,
-                                                                       LinkedList<Type> chain,
-                                                                       Customization propertyCustomization) {
+                                                                       LinkedList<Type> chain) {
         Type type = cachedItem.type;
         Type colType = type instanceof ParameterizedType
                 ? ((ParameterizedType) type).getActualTypeArguments()[0]
@@ -284,8 +283,7 @@
 
     private ModelDeserializer<JsonParser> createMapDeserializer(CachedItem cachedItem,
                                                                 Class<?> rawType,
-                                                                LinkedList<Type> chain,
-                                                                Customization propertyCustomization) {
+                                                                LinkedList<Type> chain) {
         Type type = cachedItem.type;
         Type keyType = type instanceof ParameterizedType
                 ? ((ParameterizedType) type).getActualTypeArguments()[0]
@@ -298,9 +296,10 @@
                                                                    ClassCustomization.empty(),
                                                                    JustReturn.instance(),
                                                                    MAP_KEY_EVENTS);
+        ClassModel valueClassModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.resolveRawType(chain, valueType));
         ModelDeserializer<JsonParser> valueProcessor = typeProcessor(chain,
                                                                      valueType,
-                                                                     propertyCustomization,
+                                                                     valueClassModel.getClassCustomization(),
                                                                      JustReturn.instance());
 
         MapDeserializer mapDeserializer = new MapDeserializer(keyProcessor, valueProcessor);
@@ -315,14 +314,15 @@
 
     private ModelDeserializer<JsonParser> createArrayDeserializer(CachedItem cachedItem,
                                                                   Class<?> rawType,
-                                                                  LinkedList<Type> chain,
-                                                                  Customization propertyCustomization) {
+                                                                  LinkedList<Type> chain) {
         JsonbConfigProperties configProperties = jsonbContext.getConfigProperties();
         if (rawType.equals(byte[].class) && !configProperties.getBinaryDataStrategy().equals(BinaryDataStrategy.BYTE)) {
             String strategy = configProperties.getBinaryDataStrategy();
+            // Special case for byte[] with base64 encoding - use String's class customization
+            ClassModel stringModel = jsonbContext.getMappingContext().getOrCreateClassModel(String.class);
             ModelDeserializer<JsonParser> typeProcessor = typeProcessor(chain,
                                                                         String.class,
-                                                                        propertyCustomization,
+                                                                        stringModel.getClassCustomization(),
                                                                         JustReturn.instance());
             ModelDeserializer<JsonParser> base64Deserializer = ArrayInstanceCreator.createBase64Deserializer(strategy,
                                                                                                              typeProcessor);
@@ -331,22 +331,23 @@
             return nullChecker;
         }
         Class<?> arrayType = rawType.getComponentType();
+        ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(arrayType);
         ModelDeserializer<JsonParser> typeProcessor = typeProcessor(chain,
                                                                     arrayType,
-                                                                    propertyCustomization,
+                                                                    classModel.getClassCustomization(),
                                                                     JustReturn.instance());
         return createArrayCommonDeserializer(cachedItem, rawType, arrayType, typeProcessor);
     }
 
     private ModelDeserializer<JsonParser> createGenericArray(CachedItem cachedItem,
                                                              Class<?> rawType,
-                                                             LinkedList<Type> chain,
-                                                             Customization propertyCustomization) {
+                                                             LinkedList<Type> chain) {
         GenericArrayType type = (GenericArrayType) cachedItem.type;
         Class<?> component = ReflectionUtils.getRawType(type.getGenericComponentType());
+        ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(component);
         ModelDeserializer<JsonParser> typeProcessor = typeProcessor(chain,
                                                                     type.getGenericComponentType(),
-                                                                    propertyCustomization,
+                                                                    classModel.getClassCustomization(),
                                                                     JustReturn.instance());
         return createArrayCommonDeserializer(cachedItem, rawType, component, typeProcessor);
     }
@@ -365,12 +366,13 @@
 
     private OptionalDeserializer createOptionalDeserializer(LinkedList<Type> chain,
                                                             Type type,
-                                                            Customization propertyCustomization,
                                                             CachedItem cachedItem) {
         Type colType = type instanceof ParameterizedType
                 ? ((ParameterizedType) type).getActualTypeArguments()[0]
                 : Object.class;
-        ModelDeserializer<JsonParser> typeProcessor = typeProcessor(chain, colType, propertyCustomization, JustReturn.instance());
+        colType = ReflectionUtils.resolveType(chain, colType);
+        ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(colType));
+        ModelDeserializer<JsonParser> typeProcessor = typeProcessor(chain, colType, classModel.getClassCustomization(), JustReturn.instance());
         OptionalDeserializer optionalDeserializer = new OptionalDeserializer(typeProcessor, JustReturn.instance());
         models.put(cachedItem, optionalDeserializer);
         return optionalDeserializer;
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java b/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java
index c17f6ff..36bc251 100644
--- a/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java
+++ b/src/main/java/org/eclipse/yasson/internal/deserializer/YassonParser.java
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
- *
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
+ * 
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
  * http://www.eclipse.org/legal/epl-2.0,
@@ -87,6 +88,11 @@
     }
 
     @Override
+    public Event currentEvent() {
+        return context.getLastValueEvent();
+    }
+    
+    @Override
     public String getString() {
         return delegate.getString();
     }
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java
index 723cdbe..4e3704a 100644
--- a/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/DateDeserializer.java
@@ -13,13 +13,30 @@
 package org.eclipse.yasson.internal.deserializer.types;
 
 import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
 import java.util.Date;
 import java.util.Locale;
 
 /**
  * Deserializer of the {@link Date} type.
+ *
+ * <p>
+ * For date-only patterns (e.g., "yyyy-MM-dd"), this deserializer uses {@link DateTimeFormatter#parseBest} to detect the
+ * appropriate temporal type [ZonedDateTime, LocalDateTime, LocalDate, or YearMonth]
+ * and creates the Date object at midnight in the specified
+ * timezone. When no timezone is specified in the pattern, UTC is used as required by Jakarta JSON Binding specification
+ * section 3.5.
+ * </p>
+ * <p>
+ * critical, use {@link java.time.LocalDate} (recommended) or {@link java.sql.Date}.
+ * </p>
  */
 class DateDeserializer extends AbstractDateDeserializer<Date> {
 
@@ -45,13 +62,31 @@
     }
 
     private static Date parseWithOrWithoutZone(String jsonValue, DateTimeFormatter formatter) {
-        ZonedDateTime parsed;
-        if (formatter.getZone() == null) {
-            parsed = ZonedDateTime.parse(jsonValue, formatter.withZone(UTC));
+        final TemporalAccessor best = formatter.parseBest(jsonValue,
+                ZonedDateTime::from,
+                LocalDateTime::from,
+                LocalDate::from,
+                YearMonth::from);
+
+        // If no zone provided in string, use the formatter's zone or UTC per the Jakarta JSON Binding specification
+        // section 3.5
+        final ZoneId zone = formatter.getZone() != null ? formatter.getZone() : ZoneOffset.UTC;
+
+        // Determine the type of the best option
+        final Instant instant;
+        if (best instanceof ZonedDateTime) {
+            instant = ((ZonedDateTime) best).toInstant();
+        } else if (best instanceof LocalDateTime) {
+            instant = ((LocalDateTime) best).atZone(zone).toInstant();
+        } else if (best instanceof LocalDate) {
+            instant = LocalDate.from(best).atStartOfDay(zone).toInstant();
+        } else if (best instanceof YearMonth) {
+            instant = ((YearMonth) best).atDay(1).atStartOfDay(zone).toInstant();
         } else {
-            parsed = ZonedDateTime.parse(jsonValue, formatter);
+            // Fallback
+            instant = Instant.from(best);
         }
-        return Date.from(parsed.toInstant());
+        return Date.from(instant);
     }
 
 }
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java
index 26ea0fb..59b9425 100644
--- a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UriDeserializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -14,8 +14,13 @@
 
 import java.lang.reflect.Type;
 import java.net.URI;
+import java.net.URISyntaxException;
+
+import jakarta.json.bind.JsonbException;
 
 import org.eclipse.yasson.internal.DeserializationContextImpl;
+import org.eclipse.yasson.internal.properties.MessageKeys;
+import org.eclipse.yasson.internal.properties.Messages;
 
 /**
  * Deserializer of the {@link URI} type.
@@ -28,6 +33,10 @@
 
     @Override
     Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) {
-        return URI.create(value);
+        try {
+            return new URI(value);
+        } catch (URISyntaxException e) {
+            throw new JsonbException(Messages.getMessage(MessageKeys.URI_PARSE_ERROR, value), e);
+        }
     }
 }
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java
index 54cd2f3..018448f 100644
--- a/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/deserializer/types/UrlDeserializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,7 +16,11 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 
+import jakarta.json.bind.JsonbException;
+
 import org.eclipse.yasson.internal.DeserializationContextImpl;
+import org.eclipse.yasson.internal.properties.MessageKeys;
+import org.eclipse.yasson.internal.properties.Messages;
 
 /**
  * Deserializer of the {@link URL} type.
@@ -29,12 +33,10 @@
 
     @Override
     Object deserializeStringValue(String value, DeserializationContextImpl context, Type rType) {
-        URL url = null;
         try {
-            url = new URL(value);
+            return new URL(value);
         } catch (MalformedURLException e) {
-            e.printStackTrace();
+            throw new JsonbException(Messages.getMessage(MessageKeys.URL_PARSE_ERROR, value), e);
         }
-        return url;
     }
 }
diff --git a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java
index dfa9d64..f70210e 100644
--- a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java
+++ b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -79,6 +80,11 @@
     }
 
     @Override
+    public Event currentEvent() {
+        return iterators.peek().getValueEvent(getValue());
+    }
+    
+    @Override
     public String getString() {
         return iterators.peek().getString();
     }
@@ -104,6 +110,11 @@
     }
 
     @Override
+    public JsonValue getValue() {
+        return iterators.peek().getValue();
+    }
+
+    @Override
     public JsonObject getObject() {
         JsonStructureIterator current = iterators.peek();
         if (current instanceof JsonObjectIterator) {
@@ -115,15 +126,26 @@
         }
     }
 
+    @Override
+    public JsonArray getArray() {
+        JsonStructureIterator current = iterators.peek();
+        if (current instanceof JsonArrayIterator) {
+            iterators.pop();
+            return getValue().asJsonArray();
+        } else {
+            throw new JsonbException(Messages.getMessage(MessageKeys.INTERNAL_ERROR, "Outside of array context"));
+        }
+    }
+    
     private JsonNumber getJsonNumberValue() {
         JsonStructureIterator iterator = iterators.peek();
         JsonValue value = iterator.getValue();
         if (value.getValueType() != JsonValue.ValueType.NUMBER) {
-            throw iterator.createIncompatibleValueError();
+            throw new IllegalStateException(iterator.createIncompatibleValueError().getMessage());
         }
         return (JsonNumber) value;
     }
-
+    
     @Override
     public JsonLocation getLocation() {
         throw new JsonbException("Operation not supported");
diff --git a/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java b/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java
index 8cdbdde..af7765b 100644
--- a/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java
+++ b/src/main/java/org/eclipse/yasson/internal/model/ClassModel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -23,7 +23,6 @@
 
 import jakarta.json.bind.config.PropertyNamingStrategy;
 
-import org.eclipse.yasson.internal.ClassMultiReleaseExtension;
 import org.eclipse.yasson.internal.ReflectionUtils;
 import org.eclipse.yasson.internal.model.customization.ClassCustomization;
 import org.eclipse.yasson.internal.model.customization.StrategiesProvider;
@@ -191,7 +190,7 @@
         // Example: Deserialization into Map won't use this constructor, and therefore never needs to call this method.
         // Note: Null is a valid result and needs to be cached.
         if (!isInitialized.get()) {
-            if (ClassMultiReleaseExtension.isRecord(clazz)) {
+            if (clazz.isRecord()) {
                 //No default constructor should be used in case of records
                 defaultConstructor = null;
             } else {
diff --git a/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java b/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java
index d08377c..fde557a 100644
--- a/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java
+++ b/src/main/java/org/eclipse/yasson/internal/properties/MessageKeys.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -265,6 +265,14 @@
      */
     ZONE_PARSE_ERROR("zoneParseError"),
     /**
+     * There has been an error parsing a URI value.
+     */
+    URI_PARSE_ERROR("uriParseError"),
+    /**
+     * There has been an error parsing a URL value.
+     */
+    URL_PARSE_ERROR("urlParseError"),
+    /**
      * {@link JsonbTransient} was not the only annotation on class property.
      */
     JSONB_TRANSIENT_WITH_OTHER_ANNOTATIONS("jsonbTransientWithOtherAnnotations"),
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java
index 9b283fb..702d3f1 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/MapSerializer.java
@@ -16,6 +16,7 @@
 
 import jakarta.json.stream.JsonGenerator;
 
+import org.eclipse.yasson.internal.JsonbContext;
 import org.eclipse.yasson.internal.SerializationContextImpl;
 import org.eclipse.yasson.internal.serializer.types.TypeSerializers;
 
@@ -40,9 +41,15 @@
         return valueSerializer;
     }
 
-    static MapSerializer create(Class<?> keyClass, ModelSerializer keySerializer, ModelSerializer valueSerializer) {
+    static MapSerializer create(Class<?> keyClass, ModelSerializer keySerializer, ModelSerializer valueSerializer, JsonbContext jsonbContext) {
         if (TypeSerializers.isSupportedMapKey(keyClass)) {
-            return new StringKeyMapSerializer(keySerializer, valueSerializer);
+            //Issue #663: A custom JsonbSerializer is available for an already supported Map key. Serialization must
+            //not use normal key:value map. No further checking needed. Wrapping object needs to be used.
+            if (TypeSerializers.hasCustomJsonbSerializer(keyClass, jsonbContext)) {
+                return new ObjectKeyMapSerializer(keySerializer, valueSerializer);
+            } else {
+                return new StringKeyMapSerializer(keySerializer, valueSerializer);
+            }
         } else if (Object.class.equals(keyClass)) {
             return new DynamicMapSerializer(keySerializer, valueSerializer);
         }
@@ -79,7 +86,16 @@
                     }
                     Class<?> keyClass = key.getClass();
                     if (TypeSerializers.isSupportedMapKey(keyClass)) {
-                        continue;
+
+                        //Issue #663: A custom JsonbSerializer is available for an already supported Map key.
+                        //Serialization must not use normal key:value map. No further checking needed. Wrapping object
+                        //needs to be used.
+                        if (TypeSerializers.hasCustomJsonbSerializer(keyClass, context.getJsonbContext())) {
+                            suitable = false;
+                            break;
+                        } else {
+                            continue;
+                        }
                     }
                     //No other checks needed. Map is not suitable for normal key:value map. Wrapping object needs to be used.
                     suitable = false;
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java
index 522519b..9aa29a7 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java
@@ -302,8 +302,10 @@
         Type resolvedKey = ReflectionUtils.resolveType(chain, keyType);
         Class<?> rawClass = ReflectionUtils.getRawType(resolvedKey);
         ModelSerializer keySerializer = memberSerializer(chain, keyType, ClassCustomization.empty(), true);
-        ModelSerializer valueSerializer = memberSerializer(chain, valueType, propertyCustomization, false);
-        MapSerializer mapSerializer = MapSerializer.create(rawClass, keySerializer, valueSerializer);
+        Type resolvedValue = ReflectionUtils.resolveType(chain, valueType);
+        ClassModel valueClassModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(resolvedValue));
+        ModelSerializer valueSerializer = memberSerializer(chain, valueType, valueClassModel.getClassCustomization(), false);
+        MapSerializer mapSerializer = MapSerializer.create(rawClass, keySerializer, valueSerializer, jsonbContext);
         KeyWriter keyWriter = new KeyWriter(mapSerializer);
         NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter);
         return new NullSerializer(nullVisibilitySwitcher, propertyCustomization, jsonbContext);
@@ -313,7 +315,8 @@
                                                   Class<?> raw,
                                                   Customization propertyCustomization) {
         Class<?> arrayComponent = raw.getComponentType();
-        ModelSerializer modelSerializer = memberSerializer(chain, arrayComponent, propertyCustomization, false);
+        ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(arrayComponent);
+        ModelSerializer modelSerializer = memberSerializer(chain, arrayComponent, classModel.getClassCustomization(), false);
         ModelSerializer arraySerializer = ArraySerializer.create(raw, jsonbContext, modelSerializer);
         KeyWriter keyWriter = new KeyWriter(arraySerializer);
         NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter);
@@ -325,7 +328,8 @@
                                                          Customization propertyCustomization) {
         Class<?> raw = ReflectionUtils.getRawType(type);
         Class<?> component = ReflectionUtils.getRawType(((GenericArrayType) type).getGenericComponentType());
-        ModelSerializer modelSerializer = memberSerializer(chain, component, propertyCustomization, false);
+        ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(component);
+        ModelSerializer modelSerializer = memberSerializer(chain, component, classModel.getClassCustomization(), false);
         ModelSerializer arraySerializer = ArraySerializer.create(raw, jsonbContext, modelSerializer);
         KeyWriter keyWriter = new KeyWriter(arraySerializer);
         NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter);
@@ -339,7 +343,9 @@
         Type optType = type instanceof ParameterizedType
                 ? ((ParameterizedType) type).getActualTypeArguments()[0]
                 : Object.class;
-        ModelSerializer modelSerializer = memberSerializer(chain, optType, propertyCustomization, isKey);
+        Type resolvedOptType = ReflectionUtils.resolveType(chain, optType);
+        ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(resolvedOptType));
+        ModelSerializer modelSerializer = memberSerializer(chain, optType, classModel.getClassCustomization(), isKey);
         return new OptionalSerializer(modelSerializer);
     }
 
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java
index 1660473..b442538 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -15,8 +15,11 @@
 import java.sql.Timestamp;
 import java.time.Instant;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
 import java.util.Locale;
 
+import org.eclipse.yasson.internal.JsonbDateFormatter;
+
 /**
  * Serializer of the {@link Timestamp} type.
  */
@@ -25,7 +28,7 @@
     /**
      * Default Yasson {@link DateTimeFormatter}.
      */
-    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC);
+    private static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC);
 
     SqlTimestampSerializer(TypeSerializerBuilder serializerBuilder) {
         super(serializerBuilder);
@@ -38,6 +41,21 @@
 
     @Override
     protected String formatDefault(Timestamp value, Locale locale) {
-        return DEFAULT_FORMATTER.withLocale(locale).format(toInstant(value));
+        return DEFAULT_DATE_FORMATTER.withLocale(locale).format(toInstant(value));
+    }
+
+    @Override
+    protected String formatWithFormatter(Timestamp value, DateTimeFormatter formatter) {
+        return getZonedFormatter(formatter).format(toTemporalAccessor(value));
+    }
+
+    @Override
+    protected String formatStrictIJson(Timestamp value) {
+        return JsonbDateFormatter.IJSON_DATE_FORMATTER.withZone(UTC).format(toTemporalAccessor(value));
+    }
+
+    @Override
+    protected TemporalAccessor toTemporalAccessor(Timestamp value) {
+        return toInstant(value);
     }
 }
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java
index c25fc89..3d52abe 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java
@@ -53,6 +53,7 @@
 import jakarta.json.JsonString;
 import jakarta.json.JsonValue;
 import jakarta.json.bind.JsonbException;
+import jakarta.json.bind.serializer.JsonbSerializer;
 
 import org.eclipse.yasson.internal.JsonbContext;
 import org.eclipse.yasson.internal.model.customization.Customization;
@@ -154,6 +155,17 @@
     }
 
     /**
+     * Whether type has a custom {@link JsonbSerializer} implementation.
+     *
+     * @param clazz        type to serialize
+     * @param jsonbContext jsonb context
+     * @return whether a custom JsonSerializer for the type is available
+     */
+    public static boolean hasCustomJsonbSerializer(Class<?> clazz, JsonbContext jsonbContext) {
+        return jsonbContext.getComponentMatcher().getSerializerBinding(clazz, null).isPresent();
+    }
+
+    /**
      * Create new type serializer.
      *
      * @param clazz         type of the serializer
diff --git a/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java b/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
deleted file mode 100644
index 2f3d2dc..0000000
--- a/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v. 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
- */
-
-package org.eclipse.yasson.internal;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.Map;
-import java.util.Optional;
-
-import jakarta.json.bind.JsonbException;
-import jakarta.json.bind.config.PropertyNamingStrategy;
-
-import org.eclipse.yasson.internal.model.JsonbCreator;
-import org.eclipse.yasson.internal.model.Property;
-import org.eclipse.yasson.internal.properties.MessageKeys;
-import org.eclipse.yasson.internal.properties.Messages;
-
-/**
- * Search for instance creator from other sources.
- * Mainly intended to add extensibility for different java versions and new features.
- */
-public class ClassMultiReleaseExtension {
-
-    private ClassMultiReleaseExtension() {
-        throw new IllegalStateException("This class cannot be instantiated");
-    }
-
-    static boolean shouldTransformToPropertyName(Method method) {
-        return !method.getDeclaringClass().isRecord();
-    }
-
-    static boolean isSpecialAccessorMethod(Method method, Map<String, Property> classProperties) {
-        return isRecord(method.getDeclaringClass())
-                && method.getParameterCount() == 0
-                && !void.class.equals(method.getReturnType())
-                && classProperties.containsKey(method.getName());
-    }
-
-    static JsonbCreator findCreator(Class<?> clazz,
-                                    Constructor<?>[] declaredConstructors,
-                                    AnnotationIntrospector introspector,
-                                    PropertyNamingStrategy propertyNamingStrategy) {
-        if (clazz.isRecord()) {
-            if (declaredConstructors.length == 1) {
-                return introspector.createJsonbCreator(declaredConstructors[0], null, clazz, propertyNamingStrategy);
-            }
-        }
-        return null;
-    }
-
-    public static boolean isRecord(Class<?> clazz) {
-        return clazz.isRecord();
-    }
-
-    public static Optional<JsonbException> exceptionToThrow(Class<?> clazz) {
-        if (clazz.isRecord()) {
-            if (clazz.getDeclaredConstructors().length > 1) {
-                return Optional.of(new JsonbException(Messages.getMessage(MessageKeys.RECORD_MULTIPLE_CONSTRUCTORS, clazz)));
-            }
-        }
-        return Optional.empty();
-    }
-
-}
diff --git a/src/main/resources/yasson-messages.properties b/src/main/resources/yasson-messages.properties
index 4d22449..a059313 100644
--- a/src/main/resources/yasson-messages.properties
+++ b/src/main/resources/yasson-messages.properties
@@ -76,6 +76,8 @@
 unknownJsonProperty=Json property {0} can not be mapped to a class {1}.
 jsonbCreatorMissingProperty=JsonbCreator parameter {0} is missing in json document.
 zoneParseError=Cannot parse zone from json value: {0}
+uriParseError=Cannot parse URI from json value: {0}
+urlParseError=Cannot parse URL from json value: {0}
 jsonbTransientWithOtherAnnotations=JsonbTransient annotation cannot be used with other jsonb annotations on the same property.
 nonParametrizedType=Type: {0} is not a parametrized type.
 propertyNameClash=Property {0} clashes with property {1} by read or write name in class {2}.
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java
index 287afca..79ad21e 100644
--- a/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java
@@ -102,6 +102,10 @@
     public static class SqlDateFormatted {
         @JsonbDateFormat(value = "yyyy-MM-dd")
         public java.sql.Date sqlDate;
+        @JsonbDateFormat(value = "yyyy-MM-dd")
+        public java.util.Date utilDate;
+
+
     }
 
     @Test
@@ -126,7 +130,101 @@
         assertEquals("2018-01-31", result.sqlDate.toString());
         assertEquals("2018-01-31", result.utilDate.toString());
     }
-    
+
+    @Test
+    public void testMarshallSqlDateFormatted() {
+        final String date = "2026-02-25";
+        final String expectedJson = String.format("{\"sqlDate\":\"%1$s\",\"utilDate\":\"%1$s\"}", date);
+
+        final SqlDateFormatted sqlDateFormatted = new SqlDateFormatted();
+        sqlDateFormatted.sqlDate = java.sql.Date.valueOf(date);
+        // We use a java.sql.Date here as we want to test as if this was a Jakarta Persistence temporal date
+        sqlDateFormatted.utilDate = java.sql.Date.valueOf(date);
+        String jsonString = bindingJsonb.toJson(sqlDateFormatted);
+        assertEquals(expectedJson, jsonString);
+
+        // Unmarshal the object
+        final SqlDateFormatted result = bindingJsonb.fromJson(jsonString, SqlDateFormatted.class);
+        assertEquals(sqlDateFormatted.sqlDate, result.sqlDate);
+        // The Date objects will not be equal unless user.timezone is set to UTC. The sqlDateFormatted.utilDate is
+        // created at midnight in the current timezone (via valueOf()), while result.utilDate is created at midnight UTC
+        // per the JSON-B specification. To verify both represent the same calendar date, we convert each to LocalDate
+        // using its respective timezone: the original uses systemDefault(), the deserialized uses UTC.
+        assertEquals(Instant.ofEpochMilli(sqlDateFormatted.utilDate.getTime()).atZone(ZoneId.systemDefault()).toLocalDate(),
+                result.utilDate.toInstant().atZone(ZoneOffset.UTC).toLocalDate());
+    }
+
+    @Test
+    public void testUnmarshallSqlDateFormatted() {
+        final String date = "2026-02-25";
+        final String expectedString = String.format("{\"sqlDate\":\"%1$s\",\"utilDate\":\"%1$s\"}", date);
+
+        final SqlDateFormatted sqlDateFormatted = bindingJsonb.fromJson(expectedString, SqlDateFormatted.class);
+        assertEquals(date, sqlDateFormatted.sqlDate.toString());
+        // Convert java.util.Date to LocalDate for comparison
+        final LocalDate resultDate = sqlDateFormatted.utilDate.toInstant()
+                .atZone(ZoneOffset.UTC)
+                .toLocalDate();
+        assertEquals(LocalDate.parse(date),  resultDate);
+
+        // Unmarshal the object
+        final String result = bindingJsonb.toJson(sqlDateFormatted);
+        assertEquals(expectedString, result);
+    }
+
+    public static class YearMonthFormatted {
+        @JsonbDateFormat(value = "yyyy-MM")
+        public java.util.Date date;
+    }
+
+    @Test
+    public void testMarshallYearMonthFormat() {
+        final YearMonthFormatted yearMonthFormatted = new YearMonthFormatted();
+        yearMonthFormatted.date = java.sql.Date.valueOf("2026-02-25");
+        String jsonString = bindingJsonb.toJson(yearMonthFormatted);
+        assertEquals("{\"date\":\"2026-02\"}", jsonString);
+    }
+
+    @Test
+    public void testUnmarshallYearMonthFormat() {
+        final YearMonthFormatted yearMonthFormatted = bindingJsonb.fromJson(
+                "{\"date\":\"2026-02\"}",
+                YearMonthFormatted.class);
+        final LocalDate resultDate = yearMonthFormatted.date.toInstant()
+                .atZone(ZoneOffset.UTC)
+                .toLocalDate();
+        assertEquals(LocalDate.of(2026, 2, 1), resultDate);
+    }
+
+    @Test
+    public void testDateOnlyPatternEdgeCases() {
+        // Test various edge cases to ensure date values are preserved correctly
+        testDateRoundTrip("2028-03-01"); // Day after leap year
+        testDateRoundTrip("2026-12-31"); // Last day of year
+        testDateRoundTrip("2028-02-29"); // Leap year day
+        testDateRoundTrip("2027-01-01"); // First day of year
+        testDateRoundTrip("2028-01-31"); // Last day of January
+        testDateRoundTrip("2028-02-01"); // First day of February
+    }
+
+    private void testDateRoundTrip(final String date) {
+        final String json = String.format("{\"sqlDate\":\"%1$s\",\"utilDate\":\"%1$s\"}", date);
+
+        // Deserialize
+        final SqlDateFormatted deserialized = bindingJsonb.fromJson(json, SqlDateFormatted.class);
+
+        // Verify utilDate represents midnight UTC for the specified date
+        final LocalDate resultDate = deserialized.utilDate.toInstant()
+                .atZone(ZoneOffset.UTC)
+                .toLocalDate();
+        assertEquals(LocalDate.parse(date), resultDate, () -> String.format("Date should be %s when viewed in UTC", date));
+
+        // Verify JSON round-trip
+        final String roundTripped = bindingJsonb.toJson(deserialized);
+        assertEquals(json, roundTripped, () -> String.format("JSON should round-trip correctly for %s", date));
+    }
+
+
     @Test
     public void testSqlDateTimeZonesFormatted() {
         testSqlDateWithTZFormatted(TimeZone.getTimeZone(ZoneId.of("Europe/Sofia")));
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java
index 1362361..907eb05 100644
--- a/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java
@@ -12,13 +12,20 @@
 
 package org.eclipse.yasson.defaultmapping.generics;
 
+import static org.eclipse.yasson.Jsonbs.defaultJsonb;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertIterableEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.lang.reflect.Field;
 import java.lang.reflect.Type;
-import java.lang.reflect.WildcardType;
 import java.math.BigDecimal;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -30,8 +37,6 @@
 import jakarta.json.bind.Jsonb;
 import jakarta.json.bind.JsonbBuilder;
 import jakarta.json.bind.JsonbConfig;
-import java.lang.reflect.Field;
-import java.util.Collection;
 import org.eclipse.yasson.TestTypeToken;
 import org.eclipse.yasson.adapters.model.GenericBox;
 import org.eclipse.yasson.defaultmapping.generics.model.AnotherGenericTestClass;
@@ -48,24 +53,22 @@
 import org.eclipse.yasson.defaultmapping.generics.model.GenericArrayClass;
 import org.eclipse.yasson.defaultmapping.generics.model.GenericTestClass;
 import org.eclipse.yasson.defaultmapping.generics.model.GenericWithUnboundedWildcardClass;
+import org.eclipse.yasson.defaultmapping.generics.model.ListContainer;
+import org.eclipse.yasson.defaultmapping.generics.model.LowerBoundTypeVariableWithCollectionAttributeClass;
 import org.eclipse.yasson.defaultmapping.generics.model.MultiLevelExtendedGenericTestClass;
 import org.eclipse.yasson.defaultmapping.generics.model.MultipleBoundsContainer;
 import org.eclipse.yasson.defaultmapping.generics.model.MyCyclicGenericClass;
 import org.eclipse.yasson.defaultmapping.generics.model.PropagatedGenericClass;
 import org.eclipse.yasson.defaultmapping.generics.model.Shape;
 import org.eclipse.yasson.defaultmapping.generics.model.StaticCreatorContainer;
+import org.eclipse.yasson.defaultmapping.generics.model.TreeContainer;
+import org.eclipse.yasson.defaultmapping.generics.model.TreeElement;
 import org.eclipse.yasson.defaultmapping.generics.model.WildCardClass;
 import org.eclipse.yasson.defaultmapping.generics.model.WildcardMultipleBoundsClass;
 import org.eclipse.yasson.serializers.model.Box;
 import org.eclipse.yasson.serializers.model.Crate;
 import org.junit.jupiter.api.Test;
 
-import static org.eclipse.yasson.Jsonbs.defaultJsonb;
-import org.eclipse.yasson.defaultmapping.generics.model.LowerBoundTypeVariableWithCollectionAttributeClass;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 /**
  * This class contains JSONB default mapping generics tests.
  *
@@ -513,6 +516,40 @@
         final CollectionContainer result = defaultJsonb.fromJson(expectedJson, CollectionContainer.class);
         assertEquals(collectionContainer, result);
     }
+
+    @Test
+    public void genericUpperBoundContainer() throws Exception {
+        final String expectedJson = "{\"tree\":{\"children\":[{\"name\":\"child\"}],\"name\":\"parent\"}}";
+        final TreeContainer<TreeElement> container = new TreeContainer<>();
+        final TreeElement parent = new TreeElement("parent");
+        parent.setChildren(List.of(new TreeElement("child")));
+        container.setTree(parent);
+
+        // Use a new instance of Jsonb to avoid any caching
+        try (var jsonb = JsonbBuilder.create()) {
+            assertEquals(expectedJson, jsonb.toJson(container));
+            TreeContainer<TreeElement> result = jsonb.fromJson(expectedJson, new TestTypeToken<TreeContainer<TreeElement>>() {}.getType());
+            assertIterableEquals(container.getTree().getChildren(), result.getTree().getChildren());
+        }
+
+    }
+
+    @Test
+    public void genericUpperBoundContainerWithListContainer() throws Exception {
+        final String expectedJson = "{\"list\":[{\"children\":[{\"name\":\"child\"}],\"name\":\"parent\"}]}";
+        final ListContainer<TreeElement> container = new ListContainer<>();
+        final TreeElement parent = new TreeElement("parent");
+        parent.setChildren(List.of(new TreeElement("child")));
+        container.setList(List.of(parent));
+
+        // Use a new instance of Jsonb to avoid any caching
+        try (var jsonb = JsonbBuilder.create()) {
+            assertEquals(expectedJson, jsonb.toJson(container));
+            ListContainer<TreeElement> result = jsonb.fromJson(expectedJson, new TestTypeToken<ListContainer<TreeElement>>() {}.getType());
+            assertIterableEquals(container.getList(), result.getList());
+        }
+
+    }
     
     public interface FunctionalInterface<T> {
         T getValue();
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/ListContainer.java b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/ListContainer.java
new file mode 100644
index 0000000..44b128f
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/ListContainer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2025 IBM, Inc. and/or its affiliates.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.defaultmapping.generics.model;
+
+import java.util.List;
+
+/**
+ *
+ * @author <a href="mailto:jperkins@ibm.com">James R. Perkins</a>
+ */
+public class ListContainer<T> {
+
+    private List<T> list;
+
+    public List<T> getList() {
+        return list;
+    }
+
+    public void setList(List<T> list) {
+        this.list = list;
+    }
+
+}
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeContainer.java b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeContainer.java
new file mode 100644
index 0000000..f24662a
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeContainer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.defaultmapping.generics.model;
+
+/**
+ * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
+ */
+public class TreeContainer<T extends TreeTypeContainer<T>> {
+
+    private TreeTypeContainer<T> tree;
+
+    public TreeTypeContainer<T> getTree() {
+        return tree;
+    }
+
+    public void setTree(final TreeTypeContainer<T> tree) {
+        this.tree = tree;
+    }
+}
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeElement.java b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeElement.java
new file mode 100644
index 0000000..a8dd238
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeElement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.defaultmapping.generics.model;
+
+/**
+ * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
+ */
+public class TreeElement extends TreeTypeContainer<TreeElement> {
+
+    private String name;

+

+    public TreeElement() {

+    }

+
+    public TreeElement(final String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+

+    public void setName(final String name) {

+        this.name = name;

+    }

+

+    @Override

+    public boolean equals(Object o) {

+        if (this == o) {

+            return true;

+        }

+        if (o == null || getClass() != o.getClass()) {

+            return false;

+        }

+        

+        if (!super.equals(o)) {

+            return false;

+        }

+        

+        TreeElement that = (TreeElement) o;

+        return name != null ? name.equals(that.name) : that.name == null;

+    }

+}

diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeTypeContainer.java b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeTypeContainer.java
new file mode 100644
index 0000000..f649f7c
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/generics/model/TreeTypeContainer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.defaultmapping.generics.model;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
+ */
+public class TreeTypeContainer<T extends TreeTypeContainer<T>> {
+    private List<T> children;
+
+    public List<T> getChildren() {
+        return children;
+    }
+
+    public void setChildren(final List<T> children) {
+        this.children = children;
+    }
+

+    @Override

+    public boolean equals(Object o) {

+        if (this == o) {

+            return true;

+        }

+        if (o == null || getClass() != o.getClass()) {

+            return false;

+        }

+        

+        TreeTypeContainer<?> that = (TreeTypeContainer<?>) o;

+        if (children == null) {

+            return that.children == null;

+        }

+        

+        return children.containsAll(that.children) && that.children.containsAll(children); 

+    }

+}

diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java
index 4963b12..afd68ba 100644
--- a/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/specific/UnmarshallingUnsupportedTypesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -15,6 +15,8 @@
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.net.URI;
+import java.net.URL;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -30,6 +32,7 @@
 
 import org.eclipse.yasson.TestTypeToken;
 import org.eclipse.yasson.defaultmapping.generics.model.GenericTestClass;
+import org.eclipse.yasson.defaultmapping.generics.model.ScalarValueWrapper;
 import org.eclipse.yasson.defaultmapping.specific.model.ClassWithUnsupportedFields;
 import org.eclipse.yasson.defaultmapping.specific.model.CustomUnsupportedInterface;
 import org.eclipse.yasson.defaultmapping.specific.model.SupportedTypes;
@@ -69,7 +72,7 @@
         String expected = "{\"customInterface\":{\"value\":\"value1\"}}";
         assertEquals(expected, defaultJsonb.toJson(unsupported));
         try {
-        	defaultJsonb.fromJson(expected, ClassWithUnsupportedFields.class);
+            defaultJsonb.fromJson(expected, ClassWithUnsupportedFields.class);
             fail("Should report an error");
         } catch (JsonbException e) {
             assertTrue(e.getMessage().contains("Cannot infer a type"));
@@ -133,11 +136,11 @@
 
     @Test
     public void testMissingFieldIgnored() {
-    	assertThrows(JsonbException.class, () -> {
-	        Jsonb defaultConfig = JsonbBuilder.create(new JsonbConfig().setProperty(FAIL_ON_UNKNOWN_PROPERTIES, true));
-	        String json  = "{\"nestedPojo\":{\"integerValue\":10,\"missingField\":5},\"optionalLong\":11}";
-	        SupportedTypes result = defaultConfig.fromJson(json, SupportedTypes.class);
-    	});
+        assertThrows(JsonbException.class, () -> {
+            Jsonb defaultConfig = JsonbBuilder.create(new JsonbConfig().setProperty(FAIL_ON_UNKNOWN_PROPERTIES, true));
+            String json  = "{\"nestedPojo\":{\"integerValue\":10,\"missingField\":5},\"optionalLong\":11}";
+            SupportedTypes result = defaultConfig.fromJson(json, SupportedTypes.class);
+        });
     }
 
     @Test
@@ -223,11 +226,33 @@
         Type type = new TestTypeToken<GenericTestClass<OptionalLong, OptionalLong>>(){}.getType();
         assertFail("{\"field1\":\"\"}", type,"field1", Long.class); //We are reusing Long deserializer
     }
+    
+    @Test
+    public void testMalformedURL() {
+        Type type = new TestTypeToken<ScalarValueWrapper<URL>>(){}.getType();
+        try {
+            defaultJsonb.fromJson("{\"value\":\"www.oracle.com\"}", type);
+            fail("Expected to catch JsonbException but did not");
+        } catch (JsonbException e) {
+            assertTrue(e.getMessage().contains("Cannot parse URL") && e.getMessage().contains("www.oracle.com"));
+        }
+    }
+
+    @Test
+    public void testMalformedURI() {
+        Type type = new TestTypeToken<ScalarValueWrapper<URI>>(){}.getType();
+        try {
+            defaultJsonb.fromJson("{\"value\":\"www .oracle .com\"}", type);
+            fail("Expected to catch JsonbException but did not");
+        } catch (JsonbException e) {
+            assertTrue(e.getMessage().contains("Cannot parse URI") && e.getMessage().contains("www .oracle .com"));
+        }
+    }
 
     private void assertFail(String json, Type type, String failureProperty, Class<?> failurePropertyClass) {
         try {
-        	defaultJsonb.fromJson(json, type);
-            fail();
+            defaultJsonb.fromJson(json, type);
+            fail("Expected to catch JsonbException but did not");
         } catch (JsonbException e) {
             if(!e.getMessage().contains(failureProperty) || !e.getMessage().contains(failurePropertyClass.getName())) {
                 fail("Expected error message to contain '" + failureProperty + "' and '" + failurePropertyClass.getName() + "', but was: " +
diff --git a/src/test/java/org/eclipse/yasson/documented/DocumentationExampleTest.java b/src/test/java/org/eclipse/yasson/documented/DocumentationExampleTest.java
index d49e4a0..5012e78 100644
--- a/src/test/java/org/eclipse/yasson/documented/DocumentationExampleTest.java
+++ b/src/test/java/org/eclipse/yasson/documented/DocumentationExampleTest.java
@@ -351,7 +351,7 @@
         @JsonbDateFormat("dd.MM.yyyy")
         public LocalDate birthDate;
 
-        @JsonbNumberFormat("#0.00")
+        @JsonbNumberFormat(value = "#0.00", locale="en_US")
         public BigDecimal salary;
     }
     
@@ -375,24 +375,25 @@
 
         public LocalDate birthDate;
 
+        @JsonbNumberFormat(value = "#0.00", locale="en_US") // TODO: remove if withNumberFormat is added to JsonbConfig builder
         public BigDecimal salary;
     }
     
-    @Test
+    @Test //TODO https://github.com/eclipse-ee4j/yasson/issues/722
     public void testDateNumberFormats2() {
         Person10 p = new Person10();
         p.name = "Jason Bourne";
         p.birthDate = LocalDate.of(1999, 8, 7);
         p.salary = new BigDecimal("123.45678");
         Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()//
-                .withDateFormat("dd.MM.yyyy", null)); // TODO: why no withNumberFormat?
+                .withDateFormat("dd.MM.yyyy", null)); // TODO: add withNumberFormat if added to JsonbConfig builder
         String json = jsonb.toJson(p);
-        assertEquals("{\"birthDate\":\"07.08.1999\",\"name\":\"Jason Bourne\",\"salary\":123.45678}", json);
+        assertEquals("{\"birthDate\":\"07.08.1999\",\"name\":\"Jason Bourne\",\"salary\":\"123.46\"}", json);
         
-        Person9 after = jsonb.fromJson("{\"birthDate\":\"07.08.1999\",\"name\":\"Jason Bourne\",\"salary\":123.45678}", Person9.class);
+        Person9 after = jsonb.fromJson("{\"birthDate\":\"07.08.1999\",\"name\":\"Jason Bourne\",\"salary\":\"123.46\"}", Person9.class);
         assertEquals(p.name, after.name);
         assertEquals(p.birthDate, after.birthDate);
-        assertEquals(p.salary, after.salary);
+        assertEquals(new BigDecimal("123.46"), after.salary);
     }
     
     public static class Customer {
diff --git a/src/test/java/org/eclipse/yasson/internal/deserializer/YassonParserTest.java b/src/test/java/org/eclipse/yasson/internal/deserializer/YassonParserTest.java
new file mode 100644
index 0000000..c12787a
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/internal/deserializer/YassonParserTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2026 IBM and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.internal.deserializer;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.json.stream.JsonParser;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * The {@link jakarta.json.stream.JsonParser} interface has optional methods that 
+ * throw default UnsupportedOperationExceptions, but that must be implemented in
+ * order to pass the JSON-P TCK.  Since the YassonParser wraps a JsonParser we 
+ * must ensure that we implement these default methods and we cannot rely on the
+ * compiler to tell us if we missed one so this test will.
+ */
+public class YassonParserTest {
+
+    @Test
+    public void overrideDefaultMethodTest() {
+        List<Method> expectedMethods = Arrays.asList(JsonParser.class.getMethods());
+        
+        for(Method expectedMethod : expectedMethods) {
+            if(!expectedMethod.isDefault()) {
+                continue; //compiler will catch if we fail to implement
+            }
+
+            try {
+                YassonParser.class.getDeclaredMethod(expectedMethod.getName(), expectedMethod.getParameterTypes());
+            } catch (NoSuchMethodException e) {
+                fail("Expected YassonParser to override " + expectedMethod.getName() 
+                        + " but instead got " + e.getMessage());
+            }
+        }
+    }
+}
diff --git a/src/test/java/org/eclipse/yasson/jsonstructure/Issue673.java b/src/test/java/org/eclipse/yasson/jsonstructure/Issue673.java
new file mode 100644
index 0000000..be2a555
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/jsonstructure/Issue673.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.jsonstructure;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
+import jakarta.json.bind.annotation.JsonbSubtype;
+import jakarta.json.bind.annotation.JsonbTypeDeserializer;
+import jakarta.json.bind.annotation.JsonbTypeInfo;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.bind.serializer.JsonbDeserializer;
+import jakarta.json.stream.JsonParser;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.stream.Collectors;
+
+/**
+ * Test case for Issue #673: Custom deserializers with polymorphic types and JSON structure API.
+ *
+ * <p>This test validates the interaction between:
+ * <ul>
+ *   <li>Custom {@link JsonbDeserializer} implementations</li>
+ *   <li>Polymorphic type handling via {@link JsonbTypeInfo} and {@link JsonbSubtype}</li>
+ *   <li>JSON-P structure API ({@link JsonArray}, {@link JsonObject}, {@link JsonValue})</li>
+ * </ul>
+ *
+ * <p>The test ensures that custom deserializers can properly access and process JSON structure
+ * objects when deserializing complex types with polymorphic behavior.
+ *
+ * @see <a href="https://github.com/eclipse-ee4j/yasson/issues/673">Issue #673</a>
+ */
+public class Issue673 {
+    
+    /**
+     * Marker interface for objects that can be referenced.
+     * Implemented by both {@link Reference} and {@link IRIReference}.
+     */
+    public static interface Referenceable {
+
+    }
+
+    /**
+     * A reference object with a description field.
+     * Deserialized from JSON objects containing a "description" property.
+     */
+    public static class Reference implements Referenceable {
+
+        private String description;
+
+        public String getDescription() {
+            return description;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+    }
+
+    /**
+     * An IRI (Internationalized Resource Identifier) reference.
+     * Deserialized from JSON string values representing URIs.
+     */
+    public static class IRIReference implements Referenceable {
+
+        private String value;
+
+        public IRIReference() {}
+
+        public IRIReference(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+    }
+
+    /**
+     * Interface for location types with polymorphic deserialization support.
+     * Uses {@link JsonbTypeInfo} to determine concrete type based on "type" field in JSON.
+     */
+    @JsonbTypeInfo(key = "type", value = {
+        @JsonbSubtype(alias = Location.TYPE,
+                      type = Location.class)
+    })
+    public static interface LocationInterface {
+
+    }
+
+    /**
+     * Concrete location implementation with custom deserializers for complex fields.
+     *
+     * <p>Demonstrates:
+     * <ul>
+     *   <li>Array-to-string conversion via {@link TagsDeserializer}</li>
+     *   <li>Polymorphic reference deserialization via {@link ReferenceableDeserializer}</li>
+     * </ul>
+     */
+    public static class Location implements LocationInterface {
+
+        public final static String TYPE = "Location";
+
+        private String tags;
+        private Referenceable referenceable;
+
+        /**
+         * Gets the tags as a comma-separated string.
+         * Uses custom deserializer to convert JSON array to string.
+         *
+         * @return comma-separated tag string
+         */
+        @JsonbTypeDeserializer(TagsDeserializer.class)
+        public String getTags() {
+            return tags;
+        }
+
+        public void setTags(String tags) {
+            this.tags = tags;
+        }
+        
+        /**
+         * Gets the reference object.
+         * Uses custom deserializer to handle polymorphic deserialization
+         * from either string (IRI) or object (Reference) JSON values.
+         *
+         * @return the referenceable object
+         */
+        @JsonbTypeDeserializer(ReferenceableDeserializer.class)
+        public Referenceable getReference() {
+            return referenceable;
+        }
+
+        public void setReference(Referenceable referenceable) {
+            this.referenceable = referenceable;
+        }
+    }
+
+    /**
+     * Custom deserializer that converts a JSON array of strings into a comma-separated string.
+     *
+     * <p>Example JSON: {@code ["tag1", "tag2", "tag3"]} → {@code "tag1, tag2, tag3"}
+     *
+     * <p>This tests the ability to use {@link JsonParser#getArray()} to access
+     * JSON structure objects during deserialization.
+     */
+    public static class TagsDeserializer implements JsonbDeserializer<String> {
+        @Override
+        public String deserialize(JsonParser jp, DeserializationContext dc, Type type) {
+            final JsonValue v = jp.getArray();
+            if (v instanceof JsonArray) {
+                JsonArray arr = (JsonArray) v;
+                return arr.stream()
+                        .filter(JsonString.class::isInstance)
+                        .map(JsonString.class::cast)
+                        .map(JsonString::getString)
+                        .collect(Collectors.joining(", "));
+            }
+            return null;
+        }
+
+    }
+    
+    /**
+     * Custom deserializer that handles polymorphic deserialization of {@link Referenceable} objects.
+     *
+     * <p>Supports two JSON representations:
+     * <ul>
+     *   <li>String value → {@link IRIReference} (e.g., {@code "http://example.com"})</li>
+     *   <li>Object value → {@link Reference} (e.g., {@code {"description": "..."}})</li>
+     * </ul>
+     *
+     * <p>This tests the ability to:
+     * <ul>
+     *   <li>Use {@link JsonParser#getValue()} to access JSON structure objects</li>
+     *   <li>Recursively deserialize nested objects using {@link DeserializationContext#deserialize}</li>
+     *   <li>Create new parsers from JSON-P structure objects</li>
+     * </ul>
+     */
+    public static class ReferenceableDeserializer implements JsonbDeserializer<Referenceable> {
+
+        @Override
+        public Referenceable deserialize(JsonParser jp, DeserializationContext dc, Type type) {
+            final JsonValue v = jp.getValue();
+            if (v instanceof JsonString) {
+                JsonString str = (JsonString) v;
+                return new IRIReference(str.getString());
+            }
+            if (v instanceof JsonObject) {
+                JsonObject obj = (JsonObject) v;
+                return dc.deserialize(Reference.class,
+                        Json.createParserFactory(Collections.emptyMap())
+                                .createParser(obj));
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java b/src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java
new file mode 100644
index 0000000..c9a9836
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.jsonstructure;
+
+import jakarta.json.bind.annotation.JsonbTypeDeserializer;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.bind.serializer.JsonbDeserializer;
+import jakarta.json.stream.JsonParser;
+import java.lang.reflect.Type;
+import java.util.Objects;
+
+/**
+ * Test resources for Issue #707: YassonParser.isIntegralNumber throws JsonbException 
+ * instead of IllegalStateException.
+ * 
+ * This replicates the user's scenario where they want to handle both numeric and 
+ * string IDs by catching IllegalStateException when the value is not a number.
+ */
+public class Issue707 {
+    
+    /**
+     * Simple ID wrapper that can be created from either a long or a string.
+     */
+    public static class RequestId {
+        private final String value;
+        
+        private RequestId(String value) {
+            this.value = value;
+        }
+        
+        public static RequestId of(long id) {
+            return new RequestId(String.valueOf(id));
+        }
+        
+        public static RequestId of(String id) {
+            return new RequestId(id);
+        }
+        
+        public String getValue() {
+            return value;
+        }
+        
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            RequestId requestId = (RequestId) o;
+            return Objects.equals(value, requestId.value);
+        }
+        
+        @Override
+        public int hashCode() {
+            return Objects.hash(value);
+        }
+        
+        @Override
+        public String toString() {
+            return "RequestId{" + value + "}";
+        }
+    }
+    
+    /**
+     * Container class that uses a custom deserializer for the ID field.
+     */
+    public static class Request {
+        private RequestId id;
+        
+        @JsonbTypeDeserializer(RequestIdDeserializer.class)
+        public RequestId getId() {
+            return id;
+        }
+        
+        public void setId(RequestId id) {
+            this.id = id;
+        }
+    }
+    
+    /**
+     * Custom deserializer that handles both numeric and string IDs.
+     * This is the exact pattern from the issue report.
+     */
+    public static class RequestIdDeserializer implements JsonbDeserializer<RequestId> {
+        @Override
+        public RequestId deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
+            RequestId id = null;
+            try {
+                // Try to read as a number first
+                if (parser.isIntegralNumber()) {
+                    id = RequestId.of(parser.getLong());
+                } else {
+                    // Not an integral number, but is still a number
+                    id = RequestId.of(parser.getBigDecimal().toString());
+                }
+            } catch (IllegalStateException e) {
+                id = RequestId.of(parser.getString());
+            }
+            return id;
+        }
+    }
+}
+
diff --git a/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java b/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java
index f6d042a..8cf1779 100644
--- a/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java
+++ b/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -23,6 +24,7 @@
 import jakarta.json.JsonArrayBuilder;
 import jakarta.json.JsonObject;
 import jakarta.json.JsonObjectBuilder;
+import jakarta.json.bind.Jsonb;
 import jakarta.json.bind.JsonbBuilder;
 import jakarta.json.bind.JsonbConfig;
 import jakarta.json.spi.JsonProvider;
@@ -270,4 +272,119 @@
         assertEquals("String value 1", result.getInner().getInnerFirst());
         assertEquals("String value 2", result.getInner().getInnerSecond());
     }
+    
+    @Test
+    public void testGetValue() {
+        final String json = 
+        """
+        {
+            "type": "Location",
+            "reference": "dummy reference"
+        }
+        """;
+        
+        Jsonb jsonb = JsonbBuilder.create();
+        Issue673.LocationInterface result = jsonb.fromJson(json, Issue673.LocationInterface.class);
+            
+        assertNotNull(result);
+        assertTrue(result instanceof Issue673.Location);
+        Issue673.Location location = (Issue673.Location) result;
+
+        Issue673.Referenceable refAble = location.getReference();
+        assertNotNull(refAble);
+        assertFalse(refAble instanceof Issue673.Reference);
+        assertTrue(refAble instanceof Issue673.IRIReference);
+        Issue673.IRIReference ref = (Issue673.IRIReference) refAble;
+
+        assertEquals("dummy reference", ref.getValue());
+    }
+    
+    @Test
+    public void testGetArray() {
+        final String json = 
+        """
+        {
+            "type": "Location",
+            "tags": ["test1", "test2"]
+        }
+        """;
+        
+        Jsonb jsonb = JsonbBuilder.create();
+        Issue673.LocationInterface result = jsonb.fromJson(json, Issue673.LocationInterface.class);
+        
+        assertNotNull(result);
+        assertTrue(result instanceof Issue673.Location);
+        Issue673.Location location = (Issue673.Location) result;
+        
+        String tags = location.getTags();
+        assertNotNull(tags);
+
+        assertEquals("test1, test2", tags);
+    }
+
+    /**
+     * Test for Issue #707: isIntegralNumber() should throw IllegalStateException, not JsonbException
+     * when called on a non-numeric value.
+     *
+     * This test verifies that the user's code pattern from the issue works correctly:
+     * - When the value is a string, isIntegralNumber() throws IllegalStateException
+     * - The exception can be caught and the value read as a string
+     */
+    @Test
+    public void isIntegralNumberThrowsIllegalStateException() {
+        // Test with string ID - should catch IllegalStateException and handle gracefully
+        // This test uses fromJsonStructure to exercise JsonStructureToParserAdapter
+        JsonObjectBuilder objectBuilder = jsonProvider.createObjectBuilder();
+        objectBuilder.add("id", "abc123");
+        JsonObject jsonObject = objectBuilder.build();
+        
+        YassonJsonb jsonb = (YassonJsonb) JsonbBuilder.create();
+        Issue707.Request result = jsonb.fromJsonStructure(jsonObject, Issue707.Request.class);
+        
+        assertNotNull(result);
+        assertNotNull(result.getId());
+        assertEquals("abc123", result.getId().getValue());
+    }
+    
+    /**
+     * Test for Issue #707: Verify that an integral ID still works correctly.
+     */
+    @Test
+    public void isIntegralNumberWithNumericValue() {
+        // Test with numeric ID - should work without throwing any exception
+        // This test uses fromJsonStructure to exercise JsonStructureToParserAdapter
+        JsonObjectBuilder objectBuilder = jsonProvider.createObjectBuilder();
+        objectBuilder.add("id", 12345);
+        JsonObject jsonObject = objectBuilder.build();
+        
+        YassonJsonb jsonb = (YassonJsonb) JsonbBuilder.create();
+        Issue707.Request result = jsonb.fromJsonStructure(jsonObject, Issue707.Request.class);
+        
+        assertNotNull(result);
+        assertNotNull(result.getId());
+        assertEquals("12345", result.getId().getValue());
+    }
+    
+    /**
+     * Test for Issue #707: Verify that floating point numbers are handled correctly.
+     * isIntegralNumber() should return false for non-integral numbers.
+     * isIntegralNumber() should not throw an exception for floating point numbers.
+     */
+    @Test
+    public void isIntegralNumberWithFloatingPoint() {
+        // Test with floating point ID - isIntegralNumber() returns false,
+        // so the else block handles it as a string
+        // This test uses fromJsonStructure to exercise JsonStructureToParserAdapter
+        JsonObjectBuilder objectBuilder = jsonProvider.createObjectBuilder();
+        objectBuilder.add("id", 123.45);
+        JsonObject jsonObject = objectBuilder.build();
+        
+        YassonJsonb jsonb = (YassonJsonb) JsonbBuilder.create();
+        Issue707.Request result = jsonb.fromJsonStructure(jsonObject, Issue707.Request.class);
+        
+        assertNotNull(result);
+        assertNotNull(result.getId());
+        // The deserializer will read it as a string when isIntegralNumber() returns false
+        assertEquals("123.45", result.getId().getValue());
+    }
 }
diff --git a/src/test/java/org/eclipse/yasson/records/CarWithGenerics.java b/src/test/java/org/eclipse/yasson/records/CarWithGenerics.java
new file mode 100644
index 0000000..619817a
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/records/CarWithGenerics.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2025 IBM and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.records;
+
+public record CarWithGenerics<T> (String type, T color)  {
+}
diff --git a/src/test/java/org/eclipse/yasson/records/Color.java b/src/test/java/org/eclipse/yasson/records/Color.java
new file mode 100644
index 0000000..8744500
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/records/Color.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2025 IBM and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.records;
+    
+public record Color(String name, String code) {
+}
diff --git a/src/test/java/org/eclipse/yasson/records/RecordTest.java b/src/test/java/org/eclipse/yasson/records/RecordTest.java
index 2b6a61e..3c1b72a 100644
--- a/src/test/java/org/eclipse/yasson/records/RecordTest.java
+++ b/src/test/java/org/eclipse/yasson/records/RecordTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -15,6 +15,7 @@
 import jakarta.json.bind.JsonbException;
 
 import org.eclipse.yasson.Jsonbs;
+import org.eclipse.yasson.TestTypeToken;
 import org.eclipse.yasson.internal.properties.MessageKeys;
 import org.eclipse.yasson.internal.properties.Messages;
 import org.junit.jupiter.api.Test;
@@ -106,4 +107,16 @@
         assertThrows(JsonbException.class, () -> Jsonbs.defaultJsonb.fromJson(expected, CarWithDefaultConstructor.class));
     }
 
+    @Test
+    public void testRecordWithGenerics() {
+        CarWithGenerics<Color> car = new CarWithGenerics<>("skoda", new Color("green", "#00FF00"));
+        String expected = "{\"color\":{\"code\":\"#00FF00\",\"name\":\"green\"},\"type\":\"skoda\"}";
+
+        String json = Jsonbs.defaultJsonb.toJson(car);
+        assertThat(json, is(expected));
+        
+        CarWithGenerics<Color> deserialized = Jsonbs.defaultJsonb
+                .fromJson(expected, new TestTypeToken<CarWithGenerics<Color>>() {}.getType());
+        assertThat(deserialized, is(car));  
+    }
 }
diff --git a/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java b/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java
index 3961dd2..36131c2 100644
--- a/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java
+++ b/src/test/java/org/eclipse/yasson/serializers/MapToEntriesArraySerializerTest.java
@@ -13,12 +13,17 @@
 package org.eclipse.yasson.serializers;
 
 import org.junit.jupiter.api.*;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.*;
 
 import java.io.StringReader;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Locale;
@@ -851,6 +856,26 @@
         }
     }
 
+    public static class LocalDateSerializer implements JsonbSerializer<LocalDate> {
+
+        private static final DateTimeFormatter SHORT_FORMAT = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
+
+        @Override
+        public void serialize(LocalDate obj, JsonGenerator generator, SerializationContext ctx) {
+            generator.write(SHORT_FORMAT.format(obj));
+        }
+    }
+
+    public static class LocalDateDeserializer implements JsonbDeserializer<LocalDate> {
+
+        private static final DateTimeFormatter SHORT_FORMAT = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
+
+        @Override
+        public LocalDate deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
+            return LocalDate.parse(parser.getString(), SHORT_FORMAT);
+        }
+    }
+
     public static class MapObject<K, V> {
 
         private Map<K, V> values;
@@ -934,4 +959,53 @@
         MapObjectLocaleString resObject = jsonb.fromJson(json, MapObjectLocaleString.class);
         assertEquals(mapObject, resObject);
     }
+
+    public static class MapObjectLocalDateString extends MapObject<LocalDate, String> {};
+
+    private void verifyMapObjectCustomLocalDateStringSerialization(JsonObject jsonObject, MapObjectLocalDateString mapObject) {
+
+        // Expected serialization is: {"values":[{"key":"short-local-date","value":"string"},...]}
+        assertEquals(1, jsonObject.size());
+        assertNotNull(jsonObject.get("values"));
+        assertEquals(JsonValue.ValueType.ARRAY, jsonObject.get("values").getValueType());
+        JsonArray jsonArray = jsonObject.getJsonArray("values");
+        assertEquals(mapObject.getValues().size(), jsonArray.size());
+        MapObjectLocalDateString resObject = new MapObjectLocalDateString();
+        for (JsonValue jsonValue : jsonArray) {
+            assertEquals(JsonValue.ValueType.OBJECT, jsonValue.getValueType());
+            JsonObject entry = jsonValue.asJsonObject();
+            assertEquals(2, entry.size());
+            assertNotNull(entry.get("key"));
+            assertEquals(JsonValue.ValueType.STRING, entry.get("key").getValueType());
+            assertNotNull(entry.get("value"));
+            assertEquals(JsonValue.ValueType.STRING, entry.get("value").getValueType());
+            resObject.getValues().put(LocalDate.parse(entry.getString("key"), DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)), entry.getString("value"));
+        }
+        assertEquals(mapObject, resObject);
+    }
+
+    /**
+     * Test for issue #663...
+     * Test a LocalDate/String map as member in a custom class, using a custom LocalDate serializer and deserializer,
+     * even though there's a build-in {@link org.eclipse.yasson.internal.serializer.types.TypeSerializers#isSupportedMapKey(Class)}
+     */
+    @Test
+    public void testMapLocalDateKeyStringValueAsMember() {
+        Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
+                .withSerializers(new LocalDateSerializer())
+                .withDeserializers(new LocalDateDeserializer()));
+
+        MapObjectLocalDateString mapObject = new MapObjectLocalDateString();
+        mapObject.getValues().put(LocalDate.now(), "today");
+        mapObject.getValues().put(LocalDate.now().plusDays(1), "tomorrow");
+
+        String json = jsonb.toJson(mapObject);
+
+        JsonObject jsonObject = Json.createReader(new StringReader(json)).read().asJsonObject();
+        verifyMapObjectCustomLocalDateStringSerialization(jsonObject, mapObject);
+        MapObjectLocalDateString resObject = jsonb.fromJson(json, MapObjectLocalDateString.class);
+        assertEquals(mapObject, resObject);
+        // ensure the keys are of type java.time.LocalDate
+        assertThat(resObject.getValues().keySet().iterator().next(), instanceOf(LocalDate.class));
+    }
 }
diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
index fdae9a6..8214b88 100644
--- a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
+++ b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,6 +16,7 @@
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
+import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -35,6 +36,7 @@
 import jakarta.json.bind.JsonbBuilder;
 import jakarta.json.bind.JsonbConfig;
 import jakarta.json.bind.JsonbException;
+import jakarta.json.bind.annotation.JsonbTypeSerializer;
 import jakarta.json.bind.config.PropertyOrderStrategy;
 import jakarta.json.bind.serializer.DeserializationContext;
 import jakarta.json.bind.serializer.JsonbDeserializer;
@@ -79,6 +81,7 @@
 import static org.eclipse.yasson.Jsonbs.defaultJsonb;
 import static org.eclipse.yasson.Jsonbs.nullableJsonb;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
@@ -164,7 +167,7 @@
         JsonbConfig config = new JsonbConfig().withDeserializers(new CrateDeserializer());
         Jsonb jsonb = JsonbBuilder.create(config);
 
-        Box box = createPojoWithDates();
+        Box box = createPojoWithDates(getExpectedDate());
 
         String expected = "{\"boxStr\":\"Box string\",\"crate\":{\"crateInner\":{\"crateInnerBigDec\":10,\"crate_inner_str\":\"Single inner\",\"date\":\"14.05.2015 || 11:10:01\"},\"crateInnerList\":[{\"crateInnerBigDec\":10,\"crate_inner_str\":\"List inner 0\"},{\"crateInnerBigDec\":10,\"crate_inner_str\":\"List inner 1\"}],\"date\":\"2015-05-14T11:10:01\"},\"secondBoxStr\":\"Second box string\"}";
 
@@ -265,12 +268,18 @@
     }
 
     @Test
+    public void testSqlTimestampSerialization() {
+        Box box = createPojoWithTimestamp(new Timestamp(getExpectedDate().getTime()));
+        assertTrue(defaultJsonb.toJson(box).contains("\"timestamp\":\"05/14/2015 @ 11:10\""));
+    }
+
+    @Test
     public void testSerializationUsingConversion() {
         JsonbConfig config = new JsonbConfig().withSerializers(new CrateSerializerWithConversion());
         Jsonb jsonb = JsonbBuilder.create(config);
 
         String json = "{\"boxStr\":\"Box string\",\"crate\":{\"crateStr\":\"REPLACED crate str\",\"crateInner\":{\"crateInnerBigDec\":10,\"crate_inner_str\":\"Single inner\",\"date\":\"14.05.2015 || 11:10:01\"},\"crateInnerList\":[{\"crateInnerBigDec\":10,\"crate_inner_str\":\"List inner 0\"},{\"crateInnerBigDec\":10,\"crate_inner_str\":\"List inner 1\"}],\"crateBigDec\":54321,\"date-converted\":\"2015-05-14T11:10:01Z[UTC]\"},\"secondBoxStr\":\"Second box string\"}";
-        assertEquals(json, jsonb.toJson(createPojoWithDates()));
+        assertEquals(json, jsonb.toJson(createPojoWithDates(getExpectedDate())));
     }
 
     @Test
@@ -581,8 +590,13 @@
         }
     }
 
-    private static Box createPojoWithDates() {
-        Date date = getExpectedDate();
+    private static Box createPojoWithTimestamp(Timestamp timestamp) {
+        Box box = createPojo();
+        box.crate.timestamp = timestamp;
+        return box;
+    }
+
+    private static Box createPojoWithDates(Date date) {
         Box box = createPojo();
         box.crate.date = date;
         box.crate.crateInner.date = date;
@@ -595,7 +609,6 @@
         box.crate = new Crate();
         box.secondBoxStr = "Second box string";
 
-
         box.crate.crateInner = createCrateInner("Single inner");
 
         box.crate.crateInnerList = new ArrayList<>();
@@ -826,4 +839,92 @@
 
     }
 
+    /**
+     * Test that annotation-based serializers work when property is declared as Object
+     * but the runtime type has @JsonbTypeSerializer annotation.
+     * This is a regression test for issue #689.
+     */
+    @Test
+    public void testAnnotationBasedSerializerWithObjectTypedProperty() throws Exception {
+        try (Jsonb jsonb = JsonbBuilder.create()) {
+
+            final ObjectPropertyContainer container = new ObjectPropertyContainer();
+            final AnnotatedWithSerializerType objectInstance = new AnnotatedWithSerializerType();
+            objectInstance.value = "test";
+            container.annotatedAsObject = objectInstance;
+            container.annotatedConcrete = new AnnotatedWithSerializerType();
+            container.annotatedConcrete.value = "test2";
+
+            final String result = jsonb.toJson(container);
+
+            // Both properties should use the annotation-based serializer
+            final String expected = "{\"annotatedAsObject\":{\"valueField\":\"replaced value\"},\"annotatedConcrete\":{\"valueField\":\"replaced value\"}}";
+            assertEquals(expected, result);
+
+            // Deserialization: annotatedConcrete uses annotation-based deserializer
+            // annotatedAsObject is declared as Object so JSON-B creates a HashMap (expected behavior)
+            final ObjectPropertyContainer deserialized = jsonb.fromJson(expected, ObjectPropertyContainer.class);
+            //  In the JSON, the type looks like an object and therefore is a map
+            assertInstanceOf(Map.class, deserialized.annotatedAsObject, "Object property deserializes to Map");
+            final Map<?, ?> map =  (Map<?, ?>) deserialized.annotatedAsObject;
+            assertTrue(map.containsKey("valueField"));
+            assertEquals("replaced value", map.get("valueField"));
+            assertEquals("replaced value", deserialized.annotatedConcrete.value);
+        }
+    }
+
+    /**
+     * Test that field-level and method-level @JsonbTypeSerializer annotations work on Object-typed properties.
+     * This tests existing AnnotationIntrospector code (not runtime discovery).
+     */
+    @Test
+    public void testFieldAndMethodLevelSerializerOnObjectType() throws Exception {
+        try (Jsonb jsonb = JsonbBuilder.create()) {
+            final ObjectWithAnnotatedFields container = new ObjectWithAnnotatedFields();
+            container.fieldAnnotated = "test field";
+            container.setMethodAnnotated("test method");
+
+            final String result = jsonb.toJson(container);
+
+            // Both should use their respective serializers
+            final String expected = "{\"fieldAnnotated\":\"FIELD:test field\",\"methodAnnotated\":\"METHOD:test method\"}";
+            assertEquals(expected, result);
+        }
+    }
+
+    public static class ObjectWithAnnotatedFields {
+        @JsonbTypeSerializer(ObjectFieldSerializer.class)
+        public Object fieldAnnotated;
+
+        private Object methodAnnotated;
+
+        @JsonbTypeSerializer(ObjectMethodSerializer.class)
+        public Object getMethodAnnotated() {
+            return methodAnnotated;
+        }
+
+        public void setMethodAnnotated(Object methodAnnotated) {
+            this.methodAnnotated = methodAnnotated;
+        }
+    }
+
+    public static class ObjectFieldSerializer implements JsonbSerializer<Object> {
+        @Override
+        public void serialize(Object obj, JsonGenerator generator, SerializationContext ctx) {
+            generator.write("FIELD:" + obj.toString());
+        }
+    }
+
+    public static class ObjectMethodSerializer implements JsonbSerializer<Object> {
+        @Override
+        public void serialize(Object obj, JsonGenerator generator, SerializationContext ctx) {
+            generator.write("METHOD:" + obj.toString());
+        }
+    }
+
+    public static class ObjectPropertyContainer {
+        public Object annotatedAsObject;  // Declared as Object - this was the bug scenario
+        public AnnotatedWithSerializerType annotatedConcrete;  // Declared concretely - should always work
+    }
+
 }
diff --git a/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java b/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java
new file mode 100644
index 0000000..7cd1e3f
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2025 IBM and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.serializers;
+
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+import jakarta.json.bind.JsonbConfig;
+import jakarta.json.bind.annotation.JsonbTypeDeserializer;
+import jakarta.json.bind.config.BinaryDataStrategy;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.bind.serializer.JsonbDeserializer;
+import jakarta.json.stream.JsonParser;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests that {@link jakarta.json.bind.annotation.JsonbTypeDeserializer @JsonbTypeDeserializer} annotated types are
+ * properly detected and used when those types are used as elements/values in containers (Maps, Collections,
+ * Arrays, Optionals).
+ *
+ * @author <a href="mailto:jperkins@ibm.com">James R. Perkins</a>
+ */
+public class TypeDeserializerOnContainersTest {
+
+    // Test interface with type-level deserializer annotation
+    @JsonbTypeDeserializer(TestInterfaceDeserializer.class)
+    public interface TestInterface {
+        String getValue();
+    }
+
+    // Implementation of the test interface
+    public static class TestImpl implements TestInterface {
+        private final String value;
+
+        public TestImpl(final String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String getValue() {
+            return value;
+        }
+    }
+
+    // Custom deserializer for TestInterface
+    public static class TestInterfaceDeserializer implements JsonbDeserializer<TestInterface> {
+        @Override
+        public TestInterface deserialize(final JsonParser parser, final DeserializationContext ctx, final Type rtType) {
+            // Parse the JSON object to get the value field
+            Assertions.assertTrue(parser.hasNext(), "Expected the key name");
+            parser.next();
+            Assertions.assertTrue(parser.hasNext(), "Expected the value");
+            parser.next();
+            final String value = parser.getString();
+            Assertions.assertTrue(parser.hasNext(), "Expected the end of an object");
+            parser.next();
+            return new TestImpl("DESERIALIZED:" + value);
+        }
+    }
+
+    // Container classes for testing
+    public static class MapContainer {
+        public Map<String, TestInterface> map;
+        public Map<?, ?> questionKeyMap;
+        public Map<String, ?> questionValueMap;
+    }
+
+    public static class ListContainer {
+        public List<TestInterface> list;
+        public List<?> questionList;
+    }
+
+    public static class ArrayContainer {
+        public TestInterface[] array;
+    }
+
+    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+    public static class OptionalContainer {
+        public Optional<TestInterface> optional;
+        public Optional<?> questionOptional;
+    }
+
+    public static class ByteArrayContainer {
+        public byte[] data;
+    }
+
+    private Jsonb jsonb;
+
+    @BeforeEach
+    public void createJsonb() {
+        // Create a new Jsonb for each test to avoid type caching
+        jsonb = JsonbBuilder.create();
+    }
+
+    @AfterEach
+    public void closeJsonb() throws Exception {
+        if (jsonb != null) {
+            jsonb.close();
+        }
+    }
+
+    @Test
+    public void testTypeDeserializerOnMapValues() {
+        final String json = "{\"map\":{\"key1\":{\"value\":\"value1\"},\"key2\":{\"value\":\"value2\"}}, \"questionKeyMap\":{\"qKey1\":\"value1\",\"qKey2\":\"value2\"},\"questionValueMap\":{\"key1\":\"qValue1\",\"key2\":\"qValue2\"}}";
+
+        final MapContainer result = jsonb.fromJson(json, MapContainer.class);
+
+        Assertions.assertNotNull(result.map);
+        Assertions.assertEquals(2, result.map.size(), () -> String.format("Expected two entries got %s", result.map));
+        Assertions.assertEquals("DESERIALIZED:value1", result.map.get("key1").getValue());
+        Assertions.assertEquals("DESERIALIZED:value2", result.map.get("key2").getValue());
+
+        Assertions.assertNotNull(result.questionKeyMap);
+        Assertions.assertEquals(2, result.questionKeyMap.size(), () -> String.format("Expected two entries got %s", result.questionKeyMap));
+        Assertions.assertEquals("value1", result.questionKeyMap.get("qKey1"));
+        Assertions.assertEquals("value2", result.questionKeyMap.get("qKey2"));
+
+        Assertions.assertNotNull(result.questionValueMap);
+        Assertions.assertEquals(2, result.questionValueMap.size(), () -> String.format("Expected two entries got %s", result.questionValueMap));
+        Assertions.assertEquals("qValue1", result.questionValueMap.get("key1"));
+        Assertions.assertEquals("qValue2", result.questionValueMap.get("key2"));
+    }
+
+    @Test
+    public void testTypeDeserializerOnListElements() {
+        final String json = "{\"list\":[{\"value\":\"value1\"},{\"value\":\"value2\"}], \"questionList\": [\"value1\", \"value2\"]}";
+
+        final ListContainer result = jsonb.fromJson(json, ListContainer.class);
+
+        Assertions.assertNotNull(result.list);
+        Assertions.assertEquals(2, result.list.size(), () -> String.format("Expected two entries got %s", result.list));
+        Assertions.assertEquals("DESERIALIZED:value1", result.list.get(0).getValue());
+        Assertions.assertEquals("DESERIALIZED:value2", result.list.get(1).getValue());
+
+        Assertions.assertNotNull(result.questionList);
+        Assertions.assertEquals(2, result.questionList.size(), () -> String.format("Expected two entries got %s", result.questionList));
+        Assertions.assertEquals("value1", result.questionList.get(0));
+        Assertions.assertEquals("value2", result.questionList.get(1));
+    }
+
+    @Test
+    public void testTypeDeserializerOnArrayElements() {
+        final String json = "{\"array\":[{\"value\":\"value1\"},{\"value\":\"value2\"}]}";
+
+        final ArrayContainer result = jsonb.fromJson(json, ArrayContainer.class);
+
+        Assertions.assertNotNull(result.array);
+        Assertions.assertEquals(2, result.array.length, () -> String.format("Expected two entries got %s", Arrays.toString(result.array)));
+        Assertions.assertEquals("DESERIALIZED:value1", result.array[0].getValue());
+        Assertions.assertEquals("DESERIALIZED:value2", result.array[1].getValue());
+    }
+
+    @Test
+    public void testTypeDeserializerOnOptionalValue() {
+        final String json = "{\"optional\":{\"value\":\"value1\"},\"questionOptional\":\"value2\"}";
+
+        final OptionalContainer result = jsonb.fromJson(json, OptionalContainer.class);
+
+        Assertions.assertNotNull(result.optional);
+        Assertions.assertTrue(result.optional.isPresent(), "Expected value to be present, but the optional was empty.");
+        Assertions.assertEquals("DESERIALIZED:value1", result.optional.get().getValue());
+
+        Assertions.assertNotNull(result.questionOptional);
+        Assertions.assertTrue(result.questionOptional.isPresent(), "Expected value to be present, but the optional was empty.");
+        Assertions.assertEquals("value2", result.questionOptional.get());
+    }
+
+    @Test
+    public void testTypeDeserializerOnByteArray() {
+        final String json = "{\"data\":[1,2,3,4,5]}";
+
+        final ByteArrayContainer result = jsonb.fromJson(json, ByteArrayContainer.class);
+
+        Assertions.assertNotNull(result.data);
+        Assertions.assertEquals(5, result.data.length);
+        Assertions.assertArrayEquals(new byte[]{1, 2, 3, 4, 5}, result.data);
+    }
+
+    @Test
+    public void testTypeDeserializerOnByteArrayWithBase64() throws Exception {
+        try (Jsonb base64Jsonb = JsonbBuilder.create(new JsonbConfig()
+                .withBinaryDataStrategy(BinaryDataStrategy.BASE_64))) {
+
+            // "SGVsbG8=" is "Hello" in base64
+            final String json = "{\"data\":\"SGVsbG8=\"}";
+
+            final ByteArrayContainer result = base64Jsonb.fromJson(json, ByteArrayContainer.class);
+
+            Assertions.assertNotNull(result.data);
+            Assertions.assertArrayEquals("Hello".getBytes(), result.data);
+        }
+    }
+}
diff --git a/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java b/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java
new file mode 100644
index 0000000..89f3ff2
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2025 IBM and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.serializers;
+
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+import jakarta.json.bind.JsonbException;
+import jakarta.json.bind.annotation.JsonbTypeSerializer;
+import jakarta.json.bind.serializer.JsonbSerializer;
+import jakarta.json.bind.serializer.SerializationContext;
+import jakarta.json.stream.JsonGenerator;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests that {@link jakarta.json.bind.annotation.JsonbTypeSerializer @JsonbTypeSerializer} annotated types are
+ * properly detected and used when those types are used as elements/values in containers (Maps, Collections,
+ * Arrays, Optionals).
+ *
+ * @author <a href="mailto:jperkins@ibm.com">James R. Perkins</a>
+ */
+public class TypeSerializerOnContainersTest {
+
+    // Test interface with type-level serializer annotation
+    @JsonbTypeSerializer(TestInterfaceSerializer.class)
+    public interface TestInterface {
+        String getValue();
+    }
+
+    // Implementation of the test interface
+    public static class TestImpl implements TestInterface {
+        private final String value;
+
+        public TestImpl(final String value) {
+            this.value = value;
+        }
+
+        @Override
+        public String getValue() {
+            return value;
+        }
+    }
+
+    // Custom serializer for TestInterface
+    public static class TestInterfaceSerializer implements JsonbSerializer<TestInterface> {
+        @Override
+        public void serialize(final TestInterface obj, final JsonGenerator generator, final SerializationContext ctx) {
+            generator.write("SERIALIZED:" + obj.getValue());
+        }
+    }
+
+    // Container classes for testing
+    public static class MapContainer {
+        public final Map<String, TestInterface> map;
+        public final Map<?, ?> questionKeyMap;
+        public final Map<String, ?> questionValueMap;
+
+        public MapContainer(final Map<String, TestInterface> map, final Map<?, ?> questionKeyMap, final Map<String, ?> questionValueMap) {
+            this.map = map;
+            this.questionKeyMap = questionKeyMap;
+            this.questionValueMap = questionValueMap;
+        }
+    }
+
+    public static class ListContainer {
+        public final List<TestInterface> list;
+        public final List<?> questionList;
+
+        public ListContainer(final List<TestInterface> list, final List<?> questionList) {
+            this.list = list;
+            this.questionList = questionList;
+        }
+    }
+
+    public static class ArrayContainer {
+        public final TestInterface[] array;
+
+        public ArrayContainer(TestInterface[] array) {
+            this.array = array;
+        }
+    }
+
+    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+    public static class OptionalContainer {
+        public final Optional<TestInterface> optional;
+        public final Optional<?> questionOptional;
+
+        public OptionalContainer(final Optional<TestInterface> optional, final Optional<?> questionOptional) {
+            this.optional = optional;
+            this.questionOptional = questionOptional;
+        }
+    }
+
+    private Jsonb jsonb;
+
+    @BeforeEach
+    public void createJsonb() {
+        // Create a new Jsonb for each test to avoid type caching
+        jsonb = JsonbBuilder.create();
+    }
+
+    @AfterEach
+    public void closeJsonb() throws Exception {
+        if (jsonb != null) {
+            jsonb.close();
+        }
+    }
+
+    @Test
+    public void testTypeSerializerOnMapValues() {
+        final MapContainer container = new MapContainer(Map.of(
+                "key1", new TestImpl("value1"),
+                "key2", new TestImpl("value2")
+        ), Map.of("qKey1", "value1", "qKey2", "value2"),
+                Map.of("key1", "qValue1", "key2", "qValue2")
+        );
+
+        final JsonObject json = toJsonObject(container);
+        final JsonObject map = json.getJsonObject("map");
+        final JsonObject questionKeyMap = json.getJsonObject("questionKeyMap");
+        final JsonObject questionValueMap = json.getJsonObject("questionValueMap");
+
+        Supplier<String> errorMessage = () -> String.format("Expected value not found in %s", map);
+        Assertions.assertEquals("SERIALIZED:value1", map.getString("key1"), errorMessage);
+        Assertions.assertEquals("SERIALIZED:value2", map.getString("key2"), errorMessage);
+
+
+        errorMessage = () -> String.format("Expected value not found in %s", questionKeyMap);
+        Assertions.assertEquals("value1", questionKeyMap.getString("qKey1"), errorMessage);
+        Assertions.assertEquals("value2", questionKeyMap.getString("qKey2"), errorMessage);
+
+
+        errorMessage = () -> String.format("Expected value not found in %s", questionValueMap);
+        Assertions.assertEquals("qValue1", questionValueMap.getString("key1"), errorMessage);
+        Assertions.assertEquals("qValue2", questionValueMap.getString("key2"), errorMessage);
+    }
+
+    @Test
+    public void testTypeSerializerOnListElements() {
+        final ListContainer container = new ListContainer(List.of(
+                new TestImpl("value1"),
+                new TestImpl("value2")
+        ), List.of("qValue1", "qValue2"));
+
+        final JsonObject json = toJsonObject(container);
+        final JsonArray list = json.getJsonArray("list");
+        final JsonArray questionList = json.getJsonArray("questionList");
+
+        Supplier<String> errorMessage = () -> String.format("Expected value not found in %s", list);
+        Assertions.assertEquals(2, list.size(), () -> String.format("Expected a size of 2 in %s", list));
+        Assertions.assertEquals("SERIALIZED:value1", list.getString(0), errorMessage);
+        Assertions.assertEquals("SERIALIZED:value2", list.getString(1), errorMessage);
+
+        errorMessage = () -> String.format("Expected value not found in %s", questionList);
+        Assertions.assertEquals(2, questionList.size(), () -> String.format("Expected a size of 2 in %s", questionList));
+        Assertions.assertEquals("qValue1", questionList.getString(0), errorMessage);
+        Assertions.assertEquals("qValue2", questionList.getString(1), errorMessage);
+    }
+
+    @Test
+    public void testTypeSerializerOnArrayElements() {
+        final ArrayContainer container = new ArrayContainer(new TestInterface[] {
+                new TestImpl("value1"),
+                new TestImpl("value2")
+        });
+
+        final String json = jsonb.toJson(container);
+
+        Assertions.assertEquals("{\"array\":[\"SERIALIZED:value1\",\"SERIALIZED:value2\"]}", json);
+    }
+
+    @Test
+    public void testTypeSerializerOnOptionalValue() {
+        final OptionalContainer container = new OptionalContainer(Optional.of(new TestImpl("value1")), Optional.of("value2"));
+
+        final JsonObject json = toJsonObject(container);
+
+        Assertions.assertEquals("SERIALIZED:value1", json.getString("optional"));
+        Assertions.assertEquals("value2", json.getString("questionOptional"));
+    }
+
+    private JsonObject toJsonObject(final Object object) throws JsonbException {
+        final String value = jsonb.toJson(object);
+        try (
+                StringReader reader = new StringReader(value);
+                JsonReader jsonReader = Json.createReader(reader)
+        ) {
+            return jsonReader.readObject();
+        }
+    }
+}
diff --git a/src/test/java/org/eclipse/yasson/serializers/model/Crate.java b/src/test/java/org/eclipse/yasson/serializers/model/Crate.java
index 5cf67da..8243d22 100644
--- a/src/test/java/org/eclipse/yasson/serializers/model/Crate.java
+++ b/src/test/java/org/eclipse/yasson/serializers/model/Crate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,6 +16,7 @@
 import jakarta.json.bind.annotation.JsonbProperty;
 import jakarta.json.bind.annotation.JsonbTypeSerializer;
 import java.math.BigDecimal;
+import java.sql.Timestamp;
 import java.util.Date;
 import java.util.List;
 
@@ -36,6 +37,9 @@
     @JsonbDateFormat("dd.MM.yyy ^ HH:mm:ss")
     public Date date;
 
+    @JsonbDateFormat("MM/dd/yyy @ HH:mm")
+    public Timestamp timestamp;
+
     public AnnotatedWithSerializerType annotatedType;
 
     public AnnotatedGenericWithSerializerType<Crate> annotatedGenericType;
diff --git a/yasson-jmh/pom.xml b/yasson-jmh/pom.xml
index dcdd303..498d548 100644
--- a/yasson-jmh/pom.xml
+++ b/yasson-jmh/pom.xml
@@ -5,16 +5,25 @@
 
     <modelVersion>4.0.0</modelVersion>
 
+    <parent>
+        <groupId>org.eclipse.ee4j</groupId>
+        <artifactId>project</artifactId>
+        <version>2.0.5</version>
+    </parent>
+
     <groupId>org.eclipse.yasson</groupId>
     <artifactId>yasson-jmh</artifactId>
-    <version>1.0-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
     <description>This is a performance testing project for Yasson. It leverages a JMH technology.
         See https://openjdk.java.net/projects/code-tools/jmh/.
     </description>
 
     <properties>
-        <jmh.version>1.21</jmh.version>
-        <yasson.version>2.0.2-SNAPSHOT</yasson.version>
+        <maven.compiler.release>17</maven.compiler.release>
+
+        <jmh.version>1.37</jmh.version>
+        <yasson.version>${project.version}</yasson.version>
+        <maven-shade-plugin.version>3.6.2</maven-shade-plugin.version>
     </properties>
 
 
@@ -30,7 +39,7 @@
             <version>${jmh.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.eclipse</groupId>
+            <groupId>org.eclipse.yasson</groupId>
             <artifactId>yasson</artifactId>
             <version>${yasson.version}</version>
         </dependency>
@@ -54,16 +63,12 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>11</source>
-                    <target>11</target>
-                </configuration>
             </plugin>
             <!--run `java -jar yasson-jmh.jar -h` for help -->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-shade-plugin</artifactId>
-                <version>3.2.1</version>
+                <version>${maven-shade-plugin.version}</version>
                 <executions>
                     <execution>
                         <phase>package</phase>
diff --git a/yasson-tck/pom.xml b/yasson-tck/pom.xml
index bd0d76e..7ab61a9 100644
--- a/yasson-tck/pom.xml
+++ b/yasson-tck/pom.xml
@@ -5,27 +5,40 @@
 
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>org.eclipse</groupId>
+    <parent>
+        <groupId>org.eclipse.ee4j</groupId>
+        <artifactId>project</artifactId>
+        <version>2.0.5</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.eclipse.yasson</groupId>
     <artifactId>yasson-tck</artifactId>
-    <version>1.0.0-SNAPSHOT</version>
+    <version>3.1.0-SNAPSHOT</version>
 
     <properties>
-        <jsonb.tck.version>3.0.0</jsonb.tck.version>
-        <yasson.version>3.0.4-SNAPSHOT</yasson.version>
-        <jakarta.json.bind.version>3.0.1</jakarta.json.bind.version>
-        <jakarta.json.version>2.1.3</jakarta.json.version>
-        <maven.compiler.source>11</maven.compiler.source>
-        <maven.compiler.target>11</maven.compiler.target>
-    </properties>
+        <maven.compiler.release>17</maven.compiler.release>
 
-    <!-- TODO: Temporarily enable snapshot repository -->
-    <!-- This can be removed once an official release of jakarta.json.bind-tck is available -->
-    <repositories>
-        <repository>
-            <id>jakarta-snapshots</id>
-            <url>https://jakarta.oss.sonatype.org/content/repositories/staging/</url>
-        </repository>
-    </repositories>
+        <!-- API Versions -->
+        <!-- TODO update to EE 12 final versions -->
+        <jakarta.json.version>2.1.3</jakarta.json.version> <!-- EE10 -->
+        <jakarta.json.bind.version>3.1.0-M1</jakarta.json.bind.version>
+
+        <!-- IMPL Versions -->
+        <!-- TODO update to EE 12 final versions -->
+        <jsonb.tck.version>3.1.0-M1</jsonb.tck.version>
+        <yasson.version>${project.version}</yasson.version>
+
+        <!-- Test Versions -->
+        <junit-jupiter.version>6.1.1</junit-jupiter.version>
+        <weld-se-core.version>6.0.4.Final</weld-se-core.version>
+        <arquillian-junit5-container.version>1.10.2.Final</arquillian-junit5-container.version>
+
+        <!-- Plugin Versions -->
+        <maven-dependency-plugin.version>3.11.0</maven-dependency-plugin.version>
+        <maven-surefire-plugin.version>3.5.6</maven-surefire-plugin.version>
+        <maven-surefire-report-plugin.version>3.5.6</maven-surefire-report-plugin.version>
+    </properties>
 
     <dependencies>
         <dependency>
@@ -47,7 +60,7 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.eclipse</groupId>
+            <groupId>org.eclipse.yasson</groupId>
             <artifactId>yasson</artifactId>
             <version>${yasson.version}</version>
             <scope>test</scope>
@@ -55,13 +68,13 @@
         <dependency>
             <groupId>org.jboss.weld.se</groupId>
             <artifactId>weld-se-core</artifactId>
-            <version>6.0.0.Beta1</version>
+            <version>${weld-se-core.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.jboss.arquillian.junit5</groupId>
             <artifactId>arquillian-junit5-container</artifactId>
-            <version>1.8.0.Final</version>
+            <version>${arquillian-junit5-container.version}</version>
         </dependency>
     </dependencies>
 
@@ -70,7 +83,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-dependency-plugin</artifactId>
-                <version>3.6.1</version>
+                <version>${maven-dependency-plugin.version}</version>
                 <executions>
                     <execution>
                         <id>copy</id>
@@ -105,7 +118,7 @@
             </plugin>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>3.2.5</version>
+                <version>${maven-surefire-plugin.version}</version>
                 <configuration>
                     <trimStackTrace>false</trimStackTrace>
                     <failIfNoTests>true</failIfNoTests>
@@ -120,7 +133,7 @@
             </plugin>
             <plugin>
                 <artifactId>maven-surefire-report-plugin</artifactId>
-                <version>3.2.5</version>
+                <version>${maven-surefire-report-plugin.version}</version>
                 <executions>
                     <execution>
                         <id>post-unit-test</id>