Merge pull request #112 from jungm/jdk-21

Build on JDK 21
diff --git a/johnzon-core/pom.xml b/johnzon-core/pom.xml
index 00cf51c..4253a8f 100644
--- a/johnzon-core/pom.xml
+++ b/johnzon-core/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -46,10 +46,6 @@
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
 
diff --git a/johnzon-distribution/pom.xml b/johnzon-distribution/pom.xml
index f91dc17..ba1abae 100644
--- a/johnzon-distribution/pom.xml
+++ b/johnzon-distribution/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/johnzon-jaxrs/pom.xml b/johnzon-jaxrs/pom.xml
index 3ca4a65..75123b2 100644
--- a/johnzon-jaxrs/pom.xml
+++ b/johnzon-jaxrs/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -74,10 +74,6 @@
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
 
diff --git a/johnzon-json-extras/pom.xml b/johnzon-json-extras/pom.xml
index 0a31375..be54f8f 100644
--- a/johnzon-json-extras/pom.xml
+++ b/johnzon-json-extras/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -48,12 +48,4 @@
     </dependency>
   </dependencies>
 
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
-    </plugins>
-  </build>
 </project>
diff --git a/johnzon-jsonb/pom.xml b/johnzon-jsonb/pom.xml
index 6416111..9d59a7b 100644
--- a/johnzon-jsonb/pom.xml
+++ b/johnzon-jsonb/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -113,10 +113,6 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
-      <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
         <configuration>
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbMappings.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbMappings.java
index b399eb8..21a2384 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbMappings.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbMappings.java
@@ -49,7 +49,6 @@
         }
 
         polymorphismHandler.validateJsonbPolymorphismAnnotations(original.clazz);
-        polymorphismHandler.populateTypeInfoCache(original.clazz);
         return new ClassMapping(
                 original.clazz, original.factory, original.getters, original.setters,
                 original.adapter, original.reader, original.writer, original.anyGetter,
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismHandler.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismHandler.java
index 36f1aed..48a5de6 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismHandler.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismHandler.java
@@ -38,47 +38,46 @@
     private final Map<Class<?>, JsonbPolymorphismTypeInfo> typeInfoCache = new HashMap<>();
 
     public boolean hasPolymorphism(Class<?> clazz) {
-        return Meta.getAnnotation((AnnotatedElement) clazz, JsonbTypeInfo.class) != null || getParentWithTypeInfo(clazz) != null;
+        return getOrCreatePolymorphismTypeInfo(clazz) != null;
     }
 
     public Map.Entry<String, String>[] getPolymorphismPropertiesToSerialize(Class<?> clazz, Collection<String> otherProperties) {
         List<Map.Entry<String, String>> result = new ArrayList<>();
 
-        Class<?> current = clazz;
-        while (current != null) {
-            // Only try to resolve types when there's a JsonbTypeInfo Annotation present on the current type, Meta.getAnnotation tries to
-            // walk up parents by itself until it finds the given Annotation and could incorrectly cause JsonbExceptions to be thrown
-            // (multiple JsonbTypeInfos with same key found even if thats not actually the case)
-            JsonbTypeInfo typeInfo = Meta.getAnnotation((AnnotatedElement) current, JsonbTypeInfo.class);
-            if (typeInfo != null) {
-                if (otherProperties.contains(typeInfo.key())) {
-                    throw new JsonbException("JsonbTypeInfo key '" + typeInfo.key() + "' collides with other properties in json");
+        JsonbPolymorphismTypeInfo polymorphismTypeInfo = getOrCreatePolymorphismTypeInfo(clazz);
+        while (polymorphismTypeInfo != null) {
+            if (polymorphismTypeInfo.hasSubtypeInformation()) {
+                if (otherProperties.contains(polymorphismTypeInfo.getTypeKey())) {
+                    throw new JsonbException("JsonbTypeInfo key '" + polymorphismTypeInfo.getTypeKey() + "' collides with other properties in json");
                 }
 
                 String bestMatchingAlias = null;
-                for (JsonbSubtype subtype : typeInfo.value()) {
-                    if (subtype.type().isAssignableFrom(clazz)) {
-                        bestMatchingAlias = subtype.alias();
+                for (Map.Entry<String, Class<?>> aliasToType : polymorphismTypeInfo.getAliases().entrySet()) {
+                    String alias = aliasToType.getKey();
+                    Class<?> type = aliasToType.getValue();
 
-                        if (clazz == subtype.type()) { // Exact match found, no need to continue further
+                    if (type.isAssignableFrom(clazz)) {
+                        bestMatchingAlias = alias;
+
+                        if (clazz == type) { // Exact match found, no need to continue further
                             break;
                         }
                     }
                 }
 
                 if (bestMatchingAlias != null) {
-                    result.add(0, Map.entry(typeInfo.key(), bestMatchingAlias));
+                    result.add(0, Map.entry(polymorphismTypeInfo.getTypeKey(), bestMatchingAlias));
                 }
             }
 
-            current = getParentWithTypeInfo(current);
+            polymorphismTypeInfo = polymorphismTypeInfo.getFirstParent();
         }
 
         return result.toArray(Map.Entry[]::new);
     }
 
     public Class<?> getTypeToDeserialize(JsonObject jsonObject, Class<?> clazz) {
-        JsonbPolymorphismTypeInfo typeInfo = typeInfoCache.get(clazz);
+        JsonbPolymorphismTypeInfo typeInfo = getOrCreatePolymorphismTypeInfo(clazz);
         if (typeInfo == null) {
             return clazz;
         }
@@ -101,21 +100,74 @@
         return result;
     }
 
-    public void populateTypeInfoCache(Class<?> clazz) {
+    /**
+     * Looks up a {@link JsonbPolymorphismTypeInfo} from the cache or creates it for the given <code>clazz</code> if it supports polymorphism.
+     * This is the case if either one of these conditions is truthy:
+     * <ul>
+     *     <li><code>clazz</code> has an {@link JsonbTypeInfo} annotation</li>
+     *     <li>any class in the type hierarchy of <code>clazz</code> has an {@link JsonbTypeInfo} annotation</li>
+     * </ul>
+     * @param clazz Class to inspect
+     * @return {@link JsonbPolymorphismTypeInfo} if the class supports polymorphism, <code>null</code> otherwise
+     */
+    public JsonbPolymorphismTypeInfo getOrCreatePolymorphismTypeInfo(Class<?> clazz) {
         if (typeInfoCache.containsKey(clazz)) {
-            return;
+            return typeInfoCache.get(clazz);
         }
 
-        final JsonbTypeInfo annotation = Meta.getAnnotation((AnnotatedElement) clazz, JsonbTypeInfo.class);
-        if (annotation != null) {
-            typeInfoCache.put(clazz, new JsonbPolymorphismTypeInfo(annotation));
+        JsonbPolymorphismTypeInfo result = null;
+        JsonbTypeInfo directAnnotation = Meta.getAnnotation((AnnotatedElement) clazz, JsonbTypeInfo.class);
+        if (directAnnotation != null) {
+            result = new JsonbPolymorphismTypeInfo(clazz, directAnnotation);
         }
+
+        List<JsonbPolymorphismTypeInfo> parents = new ArrayList<>();
+        List<Class<?>> candidates = List.of(clazz);
+        while (!candidates.isEmpty()) {
+            // Parents have been found on previous level -> don't walk inheritance tree further to avoid processing the same classes twice
+            if (!parents.isEmpty()) {
+                break;
+            }
+
+            List<Class<?>> candidatesNextLevel = new ArrayList<>();
+            for (Class<?> current : candidates) {
+                if (current.getSuperclass() != null) {
+                    candidatesNextLevel.add(current.getSuperclass());
+
+                    if (Meta.getAnnotation((AnnotatedElement) current.getSuperclass(), JsonbTypeInfo.class) != null) {
+                        parents.add(getOrCreatePolymorphismTypeInfo(current.getSuperclass()));
+                    }
+                }
+
+                for (Class<?> iface : current.getInterfaces()) {
+                    candidatesNextLevel.add(iface);
+
+                    if (Meta.getAnnotation((AnnotatedElement) iface, JsonbTypeInfo.class) != null) {
+                        parents.add(getOrCreatePolymorphismTypeInfo(iface));
+                    }
+                }
+            }
+
+            candidates = candidatesNextLevel;
+        }
+
+        if (!parents.isEmpty()) {
+            if (result == null) {
+                result = new JsonbPolymorphismTypeInfo(clazz, null);
+            }
+
+            result.getParents().addAll(parents);
+        }
+
+        typeInfoCache.put(clazz, result);
+        return result;
     }
 
     /**
      * Validates {@link JsonbTypeInfo} annotation on clazz and its parents (superclass/interfaces),
      * see {@link JsonbPolymorphismHandler#validateSubtypeCompatibility(Class)}, {@link JsonbPolymorphismHandler#validateOnlyOneParentWithTypeInfo(Class)}
      * and {@link JsonbPolymorphismHandler#validateNoTypeInfoKeyCollision(Class)}
+     *
      * @param classToValidate Class to validate
      * @throws JsonbException validation failed
      */
@@ -132,15 +184,18 @@
      * @throws JsonbException validation failed
      */
     protected void validateSubtypeCompatibility(Class<?> classToValidate) {
-        JsonbTypeInfo typeInfo = Meta.getAnnotation((AnnotatedElement) classToValidate, JsonbTypeInfo.class);
-        if (typeInfo == null) {
+        JsonbPolymorphismTypeInfo polymorphismTypeInfo = getOrCreatePolymorphismTypeInfo(classToValidate);
+        if (polymorphismTypeInfo == null || !polymorphismTypeInfo.hasSubtypeInformation()) {
             return;
         }
 
-        for (JsonbSubtype subtype : typeInfo.value()) {
-            if (!classToValidate.isAssignableFrom(subtype.type())) {
-                throw new JsonbException("JsonbSubtype '" + subtype.alias() + "'" +
-                        " (" + subtype.type().getName() + ") is not a subclass of " + classToValidate);
+        for (Map.Entry<String, Class<?>> aliasToType : polymorphismTypeInfo.getAliases().entrySet()) {
+            String alias = aliasToType.getKey();
+            Class<?> type = aliasToType.getValue();
+
+            if (!classToValidate.isAssignableFrom(type)) {
+                throw new JsonbException("JsonbSubtype '" + alias + "'" +
+                        " (" + type.getName() + ") is not a subclass of " + classToValidate);
             }
         }
     }
@@ -152,17 +207,10 @@
      * @throws JsonbException validation failed
      */
     protected void validateOnlyOneParentWithTypeInfo(Class<?> classToValidate) {
-        boolean found = classToValidate.getSuperclass() != null && Meta.getAnnotation((AnnotatedElement) classToValidate.getSuperclass(), JsonbTypeInfo.class) != null;
-
-        for (Class<?> iface : classToValidate.getInterfaces()) {
-            if (iface != null && Meta.getAnnotation((AnnotatedElement) iface, JsonbTypeInfo.class) != null) {
-                if (found) {
-                    throw new JsonbException("More than one interface/superclass of " + classToValidate.getName() +
-                            " has JsonbTypeInfo Annotation");
-                }
-
-                found = true;
-            }
+        JsonbPolymorphismTypeInfo polymorphismTypeInfo = getOrCreatePolymorphismTypeInfo(classToValidate);
+        if (polymorphismTypeInfo != null && polymorphismTypeInfo.getParents().size() > 1) {
+            throw new JsonbException("More than one interface/superclass of " + classToValidate.getName() +
+                    " has JsonbTypeInfo Annotation");
         }
     }
 
@@ -175,34 +223,15 @@
      */
     protected void validateNoTypeInfoKeyCollision(Class<?> classToValidate) {
         Map<String, Class<?>> keyToDefiningClass = new HashMap<>();
-
-        Class<?> current = classToValidate;
+        JsonbPolymorphismTypeInfo current = getOrCreatePolymorphismTypeInfo(classToValidate);
         while (current != null) {
-            final JsonbTypeInfo annotation = Meta.getAnnotation((AnnotatedElement) current, JsonbTypeInfo.class);
-            if (annotation != null) {
-                String key = annotation.key();
-                final Class<?> existing = keyToDefiningClass.put(key, current);
-                if (existing != null) {
-                    throw new JsonbException("JsonbTypeInfo key '" + key + "' found more than once in type hierarchy of " + classToValidate
-                            + " (first defined in " + existing.getName() + ", then defined again in " + current.getName() + ")");
-                }
+            final Class<?> existing = keyToDefiningClass.put(current.getTypeKey(), current.getClazz());
+            if (existing != null) {
+                throw new JsonbException("JsonbTypeInfo key '" + current.getTypeKey() + "' found more than once in type hierarchy of " + classToValidate
+                        + " (first defined in " + existing.getName() + ", then defined again in " + current.getClazz().getName() + ")");
             }
 
-            current = getParentWithTypeInfo(current);
+            current = current.getFirstParent();
         }
     }
-
-    protected Class<?> getParentWithTypeInfo(Class<?> clazz) {
-        if (clazz.getSuperclass() != null && Meta.getAnnotation((AnnotatedElement) clazz.getSuperclass(), JsonbTypeInfo.class) != null) {
-            return clazz.getSuperclass();
-        }
-
-        for (Class<?> iface : clazz.getInterfaces()) {
-            if (Meta.getAnnotation((AnnotatedElement) iface, JsonbTypeInfo.class) != null) {
-                return iface;
-            }
-        }
-
-        return null;
-    }
 }
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTypeInfo.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTypeInfo.java
index 15f5c71..d5eafec 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTypeInfo.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTypeInfo.java
@@ -20,14 +20,30 @@
 
 import jakarta.json.bind.annotation.JsonbSubtype;
 import jakarta.json.bind.annotation.JsonbTypeInfo;
+
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class JsonbPolymorphismTypeInfo {
+    private final List<JsonbPolymorphismTypeInfo> parents;
+    private final Class<?> clazz;
+
     private final String typeKey;
     private final Map<String, Class<?>> aliases;
 
-    protected JsonbPolymorphismTypeInfo(JsonbTypeInfo annotation) {
+    protected JsonbPolymorphismTypeInfo(Class<?> clazz, JsonbTypeInfo annotation) {
+        this.parents = new ArrayList<>();
+        this.clazz = clazz;
+
+        if (annotation == null) {
+            this.typeKey = null;
+            this.aliases = null;
+
+            return;
+        }
+
         this.typeKey = annotation.key();
 
         aliases = new HashMap<>();
@@ -36,6 +52,10 @@
         }
     }
 
+    public boolean hasSubtypeInformation() {
+        return typeKey != null;
+    }
+
     public String getTypeKey() {
         return typeKey;
     }
@@ -43,4 +63,20 @@
     public Map<String, Class<?>> getAliases() {
         return aliases;
     }
+
+    public Class<?> getClazz() {
+        return clazz;
+    }
+
+    public List<JsonbPolymorphismTypeInfo> getParents() {
+        return parents;
+    }
+
+    public JsonbPolymorphismTypeInfo getFirstParent() {
+        if (parents.isEmpty()) {
+            return null;
+        }
+
+        return parents.get(0);
+    }
 }
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTest.java
index 87d8389..7fcc019 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/polymorphism/JsonbPolymorphismTest.java
@@ -42,6 +42,17 @@
     @Rule public JsonbRule jsonb = new JsonbRule();
 
     @Test
+    public void testNestedSerialization() {
+        Labrador labrador = new Labrador();
+        labrador.dogAge = 3;
+        labrador.labradorName = "john";
+        AnimalWrapper wrapper = new AnimalWrapper();
+        wrapper.animal = labrador;
+
+        assertEquals("{\"animal\":{\"@animal\":\"dog\",\"@dog\":\"labrador\",\"dogAge\":3,\"labradorName\":\"john\"}}", jsonb.toJson(wrapper));
+    }
+
+    @Test
     public void testSerialization() {
         Labrador labrador = new Labrador();
         labrador.dogAge = 3;
@@ -100,6 +111,10 @@
 
     }
 
+    public static class AnimalWrapper {
+        public Animal animal;
+    }
+
     @JsonbTypeInfo(key = "@animal", value = @JsonbSubtype(alias = "dog", type = Dog.class))
     public interface Animal {
     }
@@ -136,4 +151,17 @@
             return localDate;
         }
     }
+
+    @Test
+    public void typeInfoNotOnDirectParent() {
+        ConcreteSomething something = new ConcreteSomething();
+        assertEquals("{\"@type\":\"concrete\"}", jsonb.toJson(something));
+    }
+
+    @JsonbTypeInfo(
+            @JsonbSubtype(alias = "concrete", type = ConcreteSomething.class)
+    )
+    public static abstract class AbstractTopLevelSomething { }
+    public static abstract class AbstractMiddleLevelSomething extends AbstractTopLevelSomething { }
+    public static class ConcreteSomething extends AbstractMiddleLevelSomething { }
 }
diff --git a/johnzon-jsonlogic/pom.xml b/johnzon-jsonlogic/pom.xml
index e2a4752..9f98eab 100644
--- a/johnzon-jsonlogic/pom.xml
+++ b/johnzon-jsonlogic/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -49,10 +49,6 @@
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/johnzon-jsonschema/pom.xml b/johnzon-jsonschema/pom.xml
index d4e6504..84ff549 100644
--- a/johnzon-jsonschema/pom.xml
+++ b/johnzon-jsonschema/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -63,10 +63,6 @@
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
 
diff --git a/johnzon-mapper/pom.xml b/johnzon-mapper/pom.xml
index a97e686..e40b9b6 100644
--- a/johnzon-mapper/pom.xml
+++ b/johnzon-mapper/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -85,10 +85,6 @@
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index cf44c5c..c06f38d 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
@@ -192,12 +192,6 @@
                     generator.writeStartObject();
                 }
 
-                if (classMapping.serializedPolymorphicProperties != null) {
-                    for (Map.Entry<String, String> polymorphicProperty : classMapping.serializedPolymorphicProperties) {
-                        generator.write(polymorphicProperty.getKey(), polymorphicProperty.getValue());
-                    }
-                }
-
                 final boolean writeEnd = doWriteObjectBody(object, ignoredProperties, jsonPointer, generator);
                 if (writeEnd && writeBody) {
                     generator.writeEnd();
@@ -376,6 +370,12 @@
             return true;
         }
 
+        if (classMapping.serializedPolymorphicProperties != null) {
+            for (Map.Entry<String, String> polymorphicProperty : classMapping.serializedPolymorphicProperties) {
+                generator.write(polymorphicProperty.getKey(), polymorphicProperty.getValue());
+            }
+        }
+
         for (final Map.Entry<String, Mappings.Getter> getterEntry : classMapping.getters.entrySet()) {
             final Mappings.Getter getter = getterEntry.getValue();
             if (ignored != null && ignored.contains(getterEntry.getKey())) {
diff --git a/johnzon-maven-plugin/pom.xml b/johnzon-maven-plugin/pom.xml
index 115e3da..2b28f36 100644
--- a/johnzon-maven-plugin/pom.xml
+++ b/johnzon-maven-plugin/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
 
   <artifactId>johnzon-maven-plugin</artifactId>
diff --git a/johnzon-osgi/pom.xml b/johnzon-osgi/pom.xml
index f384edf..d1fb102 100644
--- a/johnzon-osgi/pom.xml
+++ b/johnzon-osgi/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/johnzon-websocket/pom.xml b/johnzon-websocket/pom.xml
index a86963e..7d78159 100644
--- a/johnzon-websocket/pom.xml
+++ b/johnzon-websocket/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -164,10 +164,6 @@
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
         <executions>
           <execution>
diff --git a/pom.xml b/pom.xml
index 8179c7c..74a2c59 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
   <groupId>org.apache.johnzon</groupId>
   <artifactId>johnzon</artifactId>
   <packaging>pom</packaging>
-  <version>2.0.0-SNAPSHOT</version>
+  <version>2.0.1-SNAPSHOT</version>
   <name>Apache Johnzon</name>
   <description>Apache Johnzon is an implementation of JSR-353 (JavaTM API for JSON Processing).</description>
   <inceptionYear>2014</inceptionYear>
@@ -38,7 +38,8 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-    <project.build.outputTimestamp>10</project.build.outputTimestamp>
+    <project.build.outputTimestamp>1698151225</project.build.outputTimestamp>
+    <maven.compiler.release>11</maven.compiler.release>
 
     <jakarta-jsonp-api.version>2.1.1</jakarta-jsonp-api.version>
     <jakarta-jsonb-api.version>3.0.0</jakarta-jsonb-api.version>
@@ -118,7 +119,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-source-plugin</artifactId>
-          <version>3.3.0</version>
+          <version>3.2.1</version>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
@@ -205,7 +206,6 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
-          <release>11</release>
           <encoding>${project.build.sourceEncoding}</encoding>
           <showDeprecation>true</showDeprecation>
           <showWarnings>true</showWarnings>
@@ -760,6 +760,12 @@
       </properties>
       <roles><role>PMC</role></roles>
     </developer>
+
+    <developer>
+      <id>jungm</id>
+      <name>Markus Jung</name>
+      <email>jungm AT apache.org</email>
+    </developer>
   </developers>
 
   <contributors>
diff --git a/src/site/markdown/download.md b/src/site/markdown/download.md
index aaf449e..a89f09c 100644
--- a/src/site/markdown/download.md
+++ b/src/site/markdown/download.md
@@ -28,7 +28,7 @@
 
 ## KEYS for verifying Apache releases
 
-Please use the Johnzon [KEYS](https://www.apache.org/dist/johnzon/KEYS) file to validate our releases.
+Please use the Johnzon [KEYS](https://www.apache.org/dyn/closer.lua/johnzon/KEYS) file to validate our releases.
 Read more about [how we sign Apache Releases](http://www.apache.org/info/verification.html)
 
 
@@ -36,26 +36,40 @@
 
 ## Johnzon-2.0.x
 
-Apache Johnzon 2.0.x implements the JSON-P 2.1 and JSON-B 3.0 specifications which on a level of JavaEE 10. This version is not backward compatible due to the namespace change from `javax` to `jakarta`. 
+Apache Johnzon 2.0.x implements the JSON-P 2.1 and JSON-B 3.0 specifications which are in line with the Jakarta EE Platform 10. This version is not backward compatible due to the namespace change from `javax` to `jakarta`. 
 Apache Johnzon does not implement Jakarta EE 9 per se, because there was no change in terms of APIs except the namespace change. 
 So we decided to use Apache Johnzon 1.2.x bellow and publish a Jakarta compatible version using bytecode transformation. All artifacts can be used with the classifier `jakarta`.
 
-#### Source
+#### Binaries
+Binaries should be obtained from [maven central](https://repo.maven.apache.org/maven2/org/apache/johnzon/).
 
-This version is currently only available as snapshot. 
-We are still actively working on passing the TCK but so far most of the implementation is ready.
-
-## Johnzon-1.2.x
-
-Apache Johnzon 1.2.x implements the JSON-P 1.1 and JSON-B 1.0 specifications which on a level of JavaEE 8.
 
 #### Source
 Should you want to build any of the above binaries, this source bundle is the right one and covers them all.
+* [apache-johnzon-2.0.0-src.zip](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-2.0.0/apache-johnzon-2.0.0-src.zip)
+* [apache-johnzon-2.0.0-src.zip.sha512](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-2.0.0/apache-johnzon-2.0.0-src.zip.sha512)
+* [apache-johnzon-2.0.0-src.zip.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-2.0.0/apache-johnzon-2.0.0-src.zip.asc)
+* [apache-johnzon-2.0.0-src.tar.gz](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-2.0.0/apache-johnzon-2.0.0-src.tar.gz)
+* [apache-johnzon-2.0.0-src.tar.gz.sha512](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-2.0.0/apache-johnzon-2.0.0-src.tar.gz.sha512)
+* [apache-johnzon-2.0.0-src.tar.gz.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-2.0.0/apache-johnzon-2.0.0-src.tar.gz.asc)
 
-* [johnzon-1.2.20-source-release.zip](https://www.apache.org/dyn/closer.lua/1.2.20/johnzon-1.2.20-source-release.zip)
-* [johnzon-1.2.20-source-release.zip.sha512](https://www.apache.org/dist/johnzon/1.2.20/johnzon-1.2.20-source-release.zip.sha512)
-* [johnzon-1.2.20-source-release.zip.asc](https://www.apache.org/dist/johnzon/1.2.20/johnzon-1.2.20-source-release.zip.asc)
+## Johnzon-1.2.x
 
+Apache Johnzon 1.2.x implements the JSON-P 1.1 and JSON-B 1.0 specifications which are in line with the Jakarta EE Platform 8.
+
+
+#### Binaries
+Binaries should be obtained from [maven central](https://repo.maven.apache.org/maven2/org/apache/johnzon/).
+
+
+#### Source
+Should you want to build any of the above binaries, this source bundle is the right one and covers them all.
+* [apache-johnzon-1.2.21-src.zip](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.2.21/apache-johnzon-1.2.21-src.zip)
+* [apache-johnzon-1.2.21-src.zip.sha512](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.2.21/apache-johnzon-1.2.21-src.zip.sha512)
+* [apache-johnzon-1.2.21-src.zip.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.2.21/apache-johnzon-1.2.21-src.zip.asc)
+* [apache-johnzon-1.2.21-src.tar.gz](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.2.21/apache-johnzon-1.2.21-src.tar.gz)
+* [apache-johnzon-1.2.21-src.tar.gz.sha512](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.2.21/apache-johnzon-1.2.21-src.tar.gz.sha512)
+* [apache-johnzon-1.2.21-src.tar.gz.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.2.21/apache-johnzon-1.2.21-src.tar.gz.asc)
 
 ## Johnzon-1.0.x
 
@@ -66,16 +80,21 @@
 The binary distribution contains all Johnzon modules.
 
 * [apache-johnzon-1.0.2-bin.zip](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.zip)
-* [apache-johnzon-1.0.2-bin.zip.sha256](https://www.apache.org/dist/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.zip.sha256)
-* [apache-johnzon-1.0.2-bin.zip.asc](https://www.apache.org/dist/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.zip.asc)
+* [apache-johnzon-1.0.2-bin.zip.sha256](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.zip.sha256)
+* [apache-johnzon-1.0.2-bin.zip.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.zip.asc)
+* [apache-johnzon-1.0.2-bin.tar.gz](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.tar.gz)
+* [apache-johnzon-1.0.2-bin.tar.gz.sha256](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.tar.gz.sha256)
+* [apache-johnzon-1.0.2-bin.tar.gz.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-bin.tar.gz.asc)
 
 #### Source
 Should you want to build any of the above binaries, this source bundle is the right one and covers them all.
 
-* [johnzon-1.0.2-source-release.zip](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-source-release.zip)
-* [johnzon-1.0.2-source-release.zip.sha256](https://www.apache.org/dist/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-source-release.zip.sha256)
-* [johnzon-1.0.2-source-release.zip.asc](https://www.apache.org/dist/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-source-release.zip.asc)
-
+* [apache-johnzon-1.0.2-src.zip](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-src.zip)
+* [apache-johnzon-1.0.2-src.zip.sha256](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-src.zip.sha256)
+* [apache-johnzon-1.0.2-src.zip.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-src.zip.asc)
+* [apache-johnzon-1.0.2-src.tar.gz](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-src.tar.gz)
+* [apache-johnzon-1.0.2-src.tar.gz.sha256](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-src.tar.gz.sha256)
+* [apache-johnzon-1.0.2-src.tar.gz.asc](https://www.apache.org/dyn/closer.lua/johnzon/johnzon-1.0.2/apache-johnzon-1.0.2-src.tar.gz.asc)
 -------
 
 ### Maven Dependencies
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 0cc87b8..105bb84 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -24,7 +24,7 @@
 ## Status
 
 Apache Johnzon is a Top Level Project at the Apache Software Foundation (ASF).
-It fully implements the JSON-P_1.1 (JSR-353) and JSON-B_1.0 (JSR-367) specifications.
+It fully implements the [JSON-P 2.1](https://jakarta.ee/specifications/jsonp/2.1/) and [JSON-B 3.0](https://jakarta.ee/specifications/jsonb/3.0/) specifications.
 
 ## Get started
 
@@ -40,18 +40,21 @@
 </dependency>
 ]]></pre>
 
-This is the implementation of the JSON-P 1.1 specification. 
+This is the implementation of the JSON-P 2.1 specification. 
 You'll surely want to add the API as dependency too:
 
 <pre class="prettyprint linenums"><![CDATA[
 <dependency>
-  <groupId>org.apache.geronimo.specs</groupId>
-  <artifactId>geronimo-json_1.1_spec</artifactId>
-  <version>${jsonspecversion}</version>
+  <groupId>jakarta.json</groupId>
+  <artifactId>jakarta.json-api</artifactId>
+  <version>2.1.2</version>
   <scope>provided</scope> <!-- or compile if your environment doesn't provide it -->
 </dependency>
 ]]></pre>
 
+**Please note**: The jakarta JSON-P API jar has [hardcoded parsson](https://github.com/jakartaee/jsonp-api/blob/2.1.2/api/src/main/java/jakarta/json/spi/JsonProvider.java#L74-L79) as the default JSON-P implementation.
+This might cause unintended behaviour in cases where standard Java service loading is not possible.
+
 #### Johnzon Factory Configurations
 
 ##### JsonGeneratorFactory
@@ -65,6 +68,8 @@
 
 ### JSON-P Strict Compliance (stable)
 
+**This has been removed with Johnzon 2.0.x, johnzon-core is now JSON-P compliant by default.**
+
 <pre class="prettyprint linenums"><![CDATA[
 <dependency>
   <groupId>org.apache.johnzon</groupId>
@@ -328,7 +333,7 @@
 Note: as you can see you mainly just need to define a service with the id johnzon (same as in openejb-jar.xml)
 and you can reference other instances using $id for services and @id for resources.
 
-### JSON-B (JSON-B 1.0 compliant)
+### JSON-B (JSON-B 3.0 compliant)
 
 Johnzon provides a module johnzon-jsonb implementing JSON-B standard based on Johnzon Mapper.
 
@@ -353,6 +358,8 @@
 * johnzon.accessMode: custom access mode, note that it can disable some JSON-B feature (annotations support).
 * johnzon.accessModeDelegate: delegate access mode used by JsonbAccessModel. Enables to enrich default access mode.
 * johnzon.failOnMissingCreatorValues: should the mapping fail when a `@JsonbCreator` misses some values.
+* johnzon.use-biginteger-stringadapter: Whether or not `BigInteger` is mapped as a string. `true` by default, set to `false` to ensure strict JSON-B 3 compliance
+* johnzon.use-bigdecimal-stringadapter: Whether or not `BigDecimal` is mapped as a string. `true` by default, set to `false` to ensure strict JSON-B 3 compliance
 
 TIP: more in JohnzonBuilder class.
 
diff --git a/src/site/site.xml b/src/site/site.xml
index 5d5b845..5d5efa7 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -74,9 +74,9 @@
       <item name="Home" href="/index.html"/>
       <item name="Download" href="./download.html"/>
       <item name="Javadoc" href="/apidocs/index.html"/>
-      <item name="Source Code" href="/source-repository.html"/>
+      <item name="Source Code" href="/scm.html"/>
       <item name="Changelog" href="/changelog.html"/>
-      <item name="Mailing Lists" href="/mail-lists.html"/>
+      <item name="Mailing Lists" href="/mailing-lists.html"/>
     </menu>
     
     <menu name="Old Releases">
diff --git a/tck/jsonb/pom.xml b/tck/jsonb/pom.xml
index 880acaf..578adb5 100644
--- a/tck/jsonb/pom.xml
+++ b/tck/jsonb/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>tck</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/tck/jsonp/pom.xml b/tck/jsonp/pom.xml
index 8b5c048..012b3ce 100644
--- a/tck/jsonp/pom.xml
+++ b/tck/jsonp/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>tck</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/tck/pom.xml b/tck/pom.xml
index 01aff41..0b253f1 100644
--- a/tck/pom.xml
+++ b/tck/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>johnzon</artifactId>
     <groupId>org.apache.johnzon</groupId>
-    <version>2.0.0-SNAPSHOT</version>
+    <version>2.0.1-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>