Merge pull request #437 from aguibert/108-backports

Version 1.0.8 backports
diff --git a/etc/checkstyle.xml b/etc/checkstyle.xml
index 766b1b6..9c180fb 100644
--- a/etc/checkstyle.xml
+++ b/etc/checkstyle.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2019, 2020 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
@@ -78,8 +78,6 @@
 
     <module name="SuppressWarningsFilter"/>
     <module name="TreeWalker">
-        <property name="cacheFile" value="${checkstyle.cache.file}"/>
-
         <module name="SuppressionCommentFilter">
             <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
             <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
@@ -91,8 +89,8 @@
         <!-- See http://checkstyle.sf.net/config_javadoc.html -->
         <module name="JavadocMethod">
             <property name="scope" value="protected"/>
-            <property name="allowUndeclaredRTE" value="true"/>
-            <property name="allowMissingPropertyJavadoc" value="true"/>
+            <property name="allowMissingReturnTag" value="true"/>
+            <property name="allowMissingParamTags" value="true"/>
         </module>
         <module name="JavadocType">
             <property name="scope" value="protected"/>
@@ -121,7 +119,7 @@
         <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
         <module name="RedundantImport"/>
         <module name="ImportOrder">
-            <property name="groups" value="java, javax, org.eclipse.yasson"/>
+            <property name="groups" value="java, jakarta, javax, org.eclipse.yasson"/>
             <property name="ordered" value="true"/>
             <property name="separated" value="true"/>
             <property name="option" value="bottom"/>
diff --git a/pom.xml b/pom.xml
index 2ec825b..cee815d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -506,7 +506,7 @@
                         <dependency>
                             <groupId>com.puppycrawl.tools</groupId>
                             <artifactId>checkstyle</artifactId>
-                            <version>8.18</version>
+                            <version>8.29</version>
                             <exclusions>
                                 <exclusion>
                                     <groupId>com.sun</groupId>
diff --git a/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java b/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
index 57948a4..280a1e5 100644
--- a/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
+++ b/src/main/java/org/eclipse/yasson/internal/ComponentMatcher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020 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
@@ -137,7 +137,6 @@
      * @param customization       with component info
      * @return serializer optional
      */
-    @SuppressWarnings("unchecked")
     public Optional<SerializerBinding<?>> getSerializerBinding(Type propertyRuntimeType,
                                                                ComponentBoundCustomization customization) {
 
@@ -154,7 +153,6 @@
      * @param customization       customization with component info
      * @return serializer optional
      */
-    @SuppressWarnings("unchecked")
     public Optional<DeserializerBinding<?>> getDeserializerBinding(Type propertyRuntimeType,
                                                                    ComponentBoundCustomization customization) {
         if (customization == null || customization.getDeserializerBinding() == null) {
@@ -196,12 +194,46 @@
     }
 
     private <T extends AbstractComponentBinding> Optional<T> searchComponentBinding(Type runtimeType, Function<ComponentBindings, T> supplier) {
-        for (ComponentBindings componentBindings : userComponents.values()) {
-            final T component = supplier.apply(componentBindings);
-            if (component != null && matches(runtimeType, componentBindings.getBindingType())) {
-                return Optional.of(component);
+        // First check if there is an exact match
+        ComponentBindings binding = userComponents.get(runtimeType);
+        if (binding != null) {
+            Optional<T> match = getMatchingBinding(runtimeType, binding, supplier);
+            if (match.isPresent()) {
+               return match;
             }
         }
+        
+        if (runtimeType instanceof Class) {
+            Class<?> runtimeClass = (Class<?>) runtimeType;
+            // Check if any interfaces have a match
+            for (Class<?> ifc : runtimeClass.getInterfaces()) {
+                ComponentBindings ifcBinding = userComponents.get(ifc);
+                if (ifcBinding != null) {
+                  Optional<T> match = getMatchingBinding(ifc, ifcBinding, supplier);
+                  if (match.isPresent()) {
+                      return match;
+                  }
+                }
+            }
+            
+            // check if the superclass has a match
+            Class<?> superClass = runtimeClass.getSuperclass();
+            if (superClass != null && superClass != Object.class) {
+                Optional<T> superBinding = searchComponentBinding(superClass, supplier);
+                if (superBinding.isPresent()) {
+                    return superBinding;
+                }
+            }
+        }
+        
+        return Optional.empty();
+    }
+    
+    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())) {
+            return Optional.of(component);
+        }
         return Optional.empty();
     }
 
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java b/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java
index 9f2fd22..a12273a 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/DefaultSerializers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020 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.math.BigInteger;
 import java.net.URI;
 import java.net.URL;
+import java.nio.file.Path;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -118,6 +119,8 @@
                         new SerializerProviderWrapper(OptionalIntTypeSerializer::new, OptionalIntTypeDeserializer::new));
         serializers.put(OptionalLong.class,
                         new SerializerProviderWrapper(OptionalLongTypeSerializer::new, OptionalLongTypeDeserializer::new));
+        serializers.put(Path.class,
+                        new SerializerProviderWrapper(PathTypeSerializer::new, PathTypeDeserializer::new));
         serializers.put(Short.class, new SerializerProviderWrapper(ShortTypeSerializer::new, ShortTypeDeserializer::new));
         serializers.put(Short.TYPE, new SerializerProviderWrapper(ShortTypeSerializer::new, ShortTypeDeserializer::new));
         serializers.put(String.class, new SerializerProviderWrapper(StringTypeSerializer::new, StringTypeDeserializer::new));
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java
index b277223..51b0269 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/MapDeserializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020 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,8 +16,12 @@
 import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 import javax.json.bind.serializer.JsonbDeserializer;
 import javax.json.stream.JsonParser;
@@ -48,7 +52,6 @@
      *
      * @param builder {@link DeserializerBuilder} used to build this instance
      */
-    @SuppressWarnings({"unchecked", "rawtypes"})
     protected MapDeserializer(DeserializerBuilder builder) {
         super(builder);
         mapValueRuntimeType = getRuntimeType() instanceof ParameterizedType
@@ -67,6 +70,13 @@
     }
 
     private Map getMapImpl(Class ifcType, DeserializerBuilder builder) {
+        if (ConcurrentMap.class.isAssignableFrom(ifcType)) {
+            if (SortedMap.class.isAssignableFrom(ifcType) || NavigableMap.class.isAssignableFrom(ifcType)) {
+                return new ConcurrentSkipListMap<>();
+            } else {
+                return new ConcurrentHashMap<>();
+            }
+        }
         // SortedMap, NavigableMap
         if (SortedMap.class.isAssignableFrom(ifcType)) {
             Class<?> defaultMapImplType = builder.getJsonbContext().getConfigProperties().getDefaultMapImplType();
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeDeserializer.java
new file mode 100644
index 0000000..87d231a
--- /dev/null
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeDeserializer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 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.serializer;
+
+import java.lang.reflect.Type;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.eclipse.yasson.internal.Unmarshaller;
+import org.eclipse.yasson.internal.model.customization.Customization;
+
+public class PathTypeDeserializer extends AbstractValueTypeDeserializer<Path> {
+    public PathTypeDeserializer(Customization customization) {
+        super(Path.class, customization);
+    }
+    
+    @Override
+    protected Path deserialize(String jsonValue, Unmarshaller unmarshaller, Type rtType) {
+        return Paths.get(jsonValue);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeSerializer.java
new file mode 100644
index 0000000..491ca13
--- /dev/null
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/PathTypeSerializer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 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.serializer;
+
+import java.nio.file.Path;
+
+import javax.json.stream.JsonGenerator;
+
+import org.eclipse.yasson.internal.Marshaller;
+import org.eclipse.yasson.internal.model.customization.Customization;
+
+public class PathTypeSerializer extends AbstractValueTypeSerializer<Path> {
+    public PathTypeSerializer(Customization customization) {
+        super(customization);
+    }
+
+    @Override
+    protected void serialize(Path obj, JsonGenerator generator, Marshaller marshaller) {
+        generator.write(obj.toString());
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java
index d73ba0e..2756fbd 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeDeserializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020 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
diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java
index 4c2b9f4..1d4ba39 100644
--- a/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java
+++ b/src/main/java/org/eclipse/yasson/internal/serializer/ZoneIdTypeSerializer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020 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
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java
index 25871c0..f4ac39d 100644
--- a/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/collections/CollectionsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020 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,15 +12,36 @@
 
 package org.eclipse.yasson.defaultmapping.collections;
 
-import org.junit.jupiter.api.*;
-import static org.junit.jupiter.api.Assertions.*;
 import static org.eclipse.yasson.Jsonbs.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentNavigableMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 
 import org.eclipse.yasson.TestTypeToken;
 import org.eclipse.yasson.defaultmapping.generics.model.Circle;
-
-import java.math.BigDecimal;
-import java.util.*;
+import org.junit.jupiter.api.Test;
 
 /**
  * Default mapping arrays/collections/enums tests.
@@ -255,4 +276,50 @@
         assertEquals("abc", result.get("first"));
         assertEquals("def", result.get("second"));
     }
+    
+    public static class ConcurrentMapContainer {
+    	public ConcurrentMap<String, String> concurrentMap;
+    	public ConcurrentHashMap<String,String> concurrentHashMap;
+    	public ConcurrentNavigableMap<String, String> concurrentNavigableMap;
+    	public ConcurrentSkipListMap<String, String> concurrentSkipListMap;
+    }
+    
+    @Test
+    public void testConcurrentMaps() {
+    	// ConcurrentMap
+    	ConcurrentMapContainer c = new ConcurrentMapContainer();
+    	c.concurrentMap = new ConcurrentHashMap<String, String>();
+    	c.concurrentMap.put("foo", "fooVal");
+    	c.concurrentMap.put("bar", "barVal");
+    	String expectedJson = "{\"concurrentMap\":{\"bar\":\"barVal\",\"foo\":\"fooVal\"}}";
+    	assertEquals(expectedJson, defaultJsonb.toJson(c));
+    	assertEquals(c.concurrentMap, defaultJsonb.fromJson(expectedJson, ConcurrentMapContainer.class).concurrentMap);
+    	
+    	// ConcurrentHashMap
+    	c = new ConcurrentMapContainer();
+    	c.concurrentHashMap = new ConcurrentHashMap<String, String>();
+    	c.concurrentHashMap.put("foo", "fooVal2");
+    	c.concurrentHashMap.put("bar", "barVal2");
+    	expectedJson = "{\"concurrentHashMap\":{\"bar\":\"barVal2\",\"foo\":\"fooVal2\"}}";
+    	assertEquals(expectedJson, defaultJsonb.toJson(c));
+    	assertEquals(c.concurrentHashMap, defaultJsonb.fromJson(expectedJson, ConcurrentMapContainer.class).concurrentHashMap);
+    	
+    	// ConcurrentNavigableMap
+    	c = new ConcurrentMapContainer();
+    	c.concurrentNavigableMap = new ConcurrentSkipListMap<String, String>();
+    	c.concurrentNavigableMap.put("foo", "fooVal3");
+    	c.concurrentNavigableMap.put("bar", "barVal3");
+    	expectedJson = "{\"concurrentNavigableMap\":{\"bar\":\"barVal3\",\"foo\":\"fooVal3\"}}";
+    	assertEquals(expectedJson, defaultJsonb.toJson(c));
+    	assertEquals(c.concurrentNavigableMap, defaultJsonb.fromJson(expectedJson, ConcurrentMapContainer.class).concurrentNavigableMap);
+    	
+    	// ConcurrentSkipListMap
+    	c = new ConcurrentMapContainer();
+    	c.concurrentSkipListMap = new ConcurrentSkipListMap<String, String>();
+    	c.concurrentSkipListMap.put("foo", "fooVal4");
+    	c.concurrentSkipListMap.put("bar", "barVal4");
+    	expectedJson = "{\"concurrentSkipListMap\":{\"bar\":\"barVal4\",\"foo\":\"fooVal4\"}}";
+    	assertEquals(expectedJson, defaultJsonb.toJson(c));
+    	assertEquals(c.concurrentSkipListMap, defaultJsonb.fromJson(expectedJson, ConcurrentMapContainer.class).concurrentSkipListMap);
+    }
 }
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 6002377..9a2211a 100644
--- a/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/dates/DatesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020 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
diff --git a/src/test/java/org/eclipse/yasson/defaultmapping/typeConvertors/DefaultSerializersTest.java b/src/test/java/org/eclipse/yasson/defaultmapping/typeConvertors/DefaultSerializersTest.java
index 20a4f83..74475e4 100644
--- a/src/test/java/org/eclipse/yasson/defaultmapping/typeConvertors/DefaultSerializersTest.java
+++ b/src/test/java/org/eclipse/yasson/defaultmapping/typeConvertors/DefaultSerializersTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020 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
@@ -13,6 +13,7 @@
 package org.eclipse.yasson.defaultmapping.typeConvertors;
 
 import org.junit.jupiter.api.*;
+
 import static org.junit.jupiter.api.Assertions.*;
 import static org.eclipse.yasson.Jsonbs.*;
 
@@ -24,6 +25,9 @@
 import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbConfig;
 import javax.json.bind.config.BinaryDataStrategy;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Base64;
 import java.util.UUID;
 
@@ -108,7 +112,7 @@
         result = jsonb.fromJson(base64UrlEncodedJson, ByteArrayWrapper.class);
         assertArrayEquals(array, result.array);
     }
-
+    
     @Test
     public void testUUID() {
         UUID uuid = UUID.randomUUID();
@@ -116,4 +120,23 @@
         UUID result = defaultJsonb.fromJson(json, UUID.class);
         assertEquals(uuid, result);
     }
+    
+    @Test
+    public void serializeObjectWithPth() {
+        
+        Path expectedPath = Paths.get("/tmp/hello/me.txt");
+        String expectedPathString = expectedPath.toString().replace("\\", "\\\\");        
+        String expectedJson = "{\"path\":\"" + expectedPathString + "\"}";
+        final ObjectWithPath objectWithPath = new ObjectWithPath();
+        objectWithPath.path = expectedPath;
+        final String s = defaultJsonb.toJson(objectWithPath);
+        assertEquals(expectedJson, s);
+        
+        ObjectWithPath actualObject = defaultJsonb.fromJson(expectedJson, ObjectWithPath.class);
+        assertEquals(expectedPath, actualObject.path);
+    }
+    
+    public static class ObjectWithPath {
+        public Path path;
+    }
 }
diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
index 8336d2f..b35f184 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, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020 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,11 +12,13 @@
 
 package org.eclipse.yasson.serializers;
 
-import org.junit.jupiter.api.*;
-import static org.junit.jupiter.api.Assertions.*;
-import static org.eclipse.yasson.Jsonbs.*;
-
 import static java.util.Collections.singletonMap;
+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.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.StringReader;
 import java.lang.reflect.Type;
@@ -39,6 +41,9 @@
 import javax.json.bind.config.PropertyOrderStrategy;
 import javax.json.bind.serializer.DeserializationContext;
 import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
+import javax.json.bind.serializer.SerializationContext;
+import javax.json.stream.JsonGenerator;
 import javax.json.stream.JsonParser;
 
 import org.eclipse.yasson.TestTypeToken;
@@ -64,6 +69,7 @@
 import org.eclipse.yasson.serializers.model.SimpleContainer;
 import org.eclipse.yasson.serializers.model.StringWrapper;
 import org.eclipse.yasson.serializers.model.SupertypeSerializerPojo;
+import org.junit.jupiter.api.Test;
 
 /**
  * @author Roman Grigoriadi
@@ -514,4 +520,81 @@
         crateInner.crateInnerBigDec = BigDecimal.TEN;
         return crateInner;
     }
+    
+    public static class Foo { }
+
+    public static class Bar extends Foo { }
+    
+    public static class Baz extends Bar { }
+
+    public static class FooSerializer implements JsonbSerializer<Foo> {
+      public void serialize(Foo obj, JsonGenerator generator, SerializationContext ctx) {
+        generator.write("foo");
+      }
+    }
+
+    public static class BazSerializer implements JsonbSerializer<Baz> {
+      public void serialize(Baz obj, JsonGenerator generator, SerializationContext ctx) {
+        generator.write("baz");
+      }
+    }
+    
+    /**
+     * Test for issue: https://github.com/quarkusio/quarkus/issues/8925
+     * Ensure that if multiple customizations (serializer, deserializer, or adapter) are applied 
+     * for different types in the same class hierarchy, we use the customization for the most 
+     * specific type in the class hierarchy.
+     */
+    @Test
+    public void testSerializerMatching() {
+      Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
+          .withSerializers(new FooSerializer(), new BazSerializer()));
+      assertEquals("\"foo\"", jsonb.toJson(new Foo()));
+      // Since 'Bar' does not have its own serializer, it should use 
+      // the next serializer in the tree (FooSerializer)
+      assertEquals("\"foo\"", jsonb.toJson(new Bar()));
+      assertEquals("\"baz\"", jsonb.toJson(new Baz()));
+    }
+    
+    public static interface One { }
+    public static interface Two { }
+    public static interface Three { }
+    
+    public static class OneTwo implements One, Two { }
+    public static class OneTwoThree implements One, Two, Three { }
+    
+    public static class OneSerializer implements JsonbSerializer<One> {
+      public void serialize(One obj, JsonGenerator generator, SerializationContext ctx) {
+        generator.write("one");
+      }
+    }
+    
+    public static class TwoSerializer implements JsonbSerializer<Two> {
+      public void serialize(Two obj, JsonGenerator generator, SerializationContext ctx) {
+        generator.write("two");
+      }
+    }
+    
+    public static class ThreeSerializer implements JsonbSerializer<Three> {
+      public void serialize(Three obj, JsonGenerator generator, SerializationContext ctx) {
+        generator.write("three");
+      }
+    }
+    
+    @Test
+    public void testSerializerMatchingInterfaces01() {
+      Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
+          .withSerializers(new OneSerializer(), new TwoSerializer(), new ThreeSerializer()));
+      assertEquals("\"one\"", jsonb.toJson(new OneTwo()));
+      assertEquals("\"one\"", jsonb.toJson(new OneTwoThree()));
+    }
+    
+    @Test
+    public void testSerializerMatchingInterfaces02() {
+      Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
+          .withSerializers(new ThreeSerializer(), new TwoSerializer()));
+      assertEquals("\"two\"", jsonb.toJson(new OneTwo()));
+      assertEquals("\"two\"", jsonb.toJson(new OneTwoThree()));
+    }
+    
 }