You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2019/08/16 12:07:57 UTC

[johnzon] branch master updated: JOHNZON-255 JOHNZON-256 JOHNZON-257 JOHNZON-258 JOHNZON-259 disable enummap/enumset deserialization by default (jsonb tck) + support some container impl deserialization without falling back on the generic interface

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

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/johnzon.git


The following commit(s) were added to refs/heads/master by this push:
     new cf35aff  JOHNZON-255 JOHNZON-256 JOHNZON-257 JOHNZON-258 JOHNZON-259 disable enummap/enumset deserialization by default (jsonb tck) + support some container impl deserialization without falling back on the generic interface
cf35aff is described below

commit cf35affe65d8a4a4789071b86d04423a8ab41a03
Author: Romain Manni-Bucau <rm...@apache.org>
AuthorDate: Fri Aug 16 14:07:52 2019 +0200

    JOHNZON-255 JOHNZON-256 JOHNZON-257 JOHNZON-258 JOHNZON-259 disable enummap/enumset deserialization by default (jsonb tck) + support some container impl deserialization without falling back on the generic interface
---
 .../java/org/apache/johnzon/jsonb/JohnzonBuilder.java |  4 ++++
 .../java/org/apache/johnzon/mapper/MapperBuilder.java |  9 ++++++++-
 .../java/org/apache/johnzon/mapper/MapperConfig.java  |  9 ++++++++-
 .../org/apache/johnzon/mapper/MappingParserImpl.java  | 19 ++++++++++++++-----
 .../main/java/org/apache/johnzon/mapper/Mappings.java | 13 ++++++++++++-
 .../org/apache/johnzon/mapper/MapperConfigTest.java   |  2 +-
 .../src/test/java/org/superbiz/ExtendMappingTest.java |  2 +-
 src/site/markdown/index.md                            |  9 +++++++++
 8 files changed, 57 insertions(+), 10 deletions(-)

diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
index 431e589..6f7572e 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -141,8 +141,12 @@ public class JohnzonBuilder implements JsonbBuilder {
             config = new JsonbConfig();
         }
 
+        // todo: global spec toggle to disable all these ones at once?
         builder.setUseBigDecimalForObjectNumbers(
                 config.getProperty("johnzon.use-big-decimal-for-object").map(this::toBool).orElse(true));
+        builder.setSupportEnumContainerDeserialization( // https://github.com/eclipse-ee4j/jakartaee-tck/issues/103
+                config.getProperty("johnzon.support-enum-container-deserialization")
+                        .map(this::toBool).orElse(false));
 
         final boolean ijson = config.getProperty(JsonbConfig.STRICT_IJSON)
                 .map(Boolean.class::cast)
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index d17468e..b05667c 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -145,6 +145,7 @@ public class MapperBuilder {
     private Boolean deduplicateObjects = null;
     private boolean useJsRange;
     private boolean useBigDecimalForObjectNumbers;
+    private boolean supportEnumContainerDeserialization = true;
 
     public Mapper build() {
         if (readerFactory == null || generatorFactory == null) {
@@ -256,7 +257,8 @@ public class MapperBuilder {
                         treatByteArrayAsBase64, treatByteArrayAsBase64URL, readAttributeBeforeWrite,
                         accessMode, encoding, attributeOrder, enforceQuoteString, failOnUnknownProperties,
                         serializeValueFilter, useBigDecimalForFloats, deduplicateObjects,
-                        interfaceImplementationMapping, useJsRange, useBigDecimalForObjectNumbers),
+                        interfaceImplementationMapping, useJsRange, useBigDecimalForObjectNumbers,
+                        supportEnumContainerDeserialization),
                 closeables);
     }
 
@@ -528,4 +530,9 @@ public class MapperBuilder {
         this.useBigDecimalForObjectNumbers = value;
         return this;
     }
+
+    public MapperBuilder setSupportEnumContainerDeserialization(final boolean supportEnumContainerDeserialization) {
+        this.supportEnumContainerDeserialization = supportEnumContainerDeserialization;
+        return this;
+    }
 }
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
index 18184d0..1f3eafb 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
@@ -58,6 +58,7 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig implements Cloneable {
     private final boolean treatByteArrayAsBase64;
     private final boolean treatByteArrayAsBase64URL;
     private final boolean readAttributeBeforeWrite;
+    private final boolean supportEnumMapDeserialization; // for tck
     private final AccessMode accessMode;
     private final Charset encoding;
     private final ConcurrentMap<AdapterKey, Adapter<?, ?>> adapters;
@@ -94,7 +95,8 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig implements Cloneable {
                         final Boolean deduplicateObjects,
                         final Map<Class<?>, Class<?>> interfaceImplementationMapping,
                         final boolean useJsRange,
-                        final boolean useBigDecimalForObjectNumbers) {
+                        final boolean useBigDecimalForObjectNumbers,
+                        final boolean supportEnumMapDeserialization) {
     //CHECKSTYLE:ON
         this.objectConverterWriters = objectConverterWriters;
         this.objectConverterReaders = objectConverterReaders;
@@ -109,6 +111,7 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig implements Cloneable {
         this.encoding = encoding;
         this.useJsRange = useJsRange;
         this.useBigDecimalForObjectNumbers = useBigDecimalForObjectNumbers;
+        this.supportEnumMapDeserialization = supportEnumMapDeserialization;
 
         // handle Adapters
         this.adapters = adapters;
@@ -342,4 +345,8 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig implements Cloneable {
     public Boolean isDeduplicateObjects() {
         return deduplicateObjects;
     }
+
+    public boolean isSupportEnumContainerDeserialization() {
+        return supportEnumMapDeserialization;
+    }
 }
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
index 76b5329..a182a5a 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
@@ -55,6 +55,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.NavigableMap;
@@ -264,13 +265,15 @@ public class MappingParserImpl implements MappingParser {
                     final Class<?> raw = Class.class.cast(aType.getRawType());
 
                     final Map map;
-                    if (LinkedHashMap.class == raw) {
-                        map = new LinkedHashMap();
-                    } else if (SortedMap.class.isAssignableFrom(raw) || NavigableMap.class == raw || TreeMap.class == raw) {
+                    if (SortedMap.class.isAssignableFrom(raw) || NavigableMap.class == raw || TreeMap.class == raw) {
                         map = config.getAttributeOrder() == null ? new TreeMap() : new TreeMap(config.getAttributeOrder());
                     } else if (ConcurrentMap.class.isAssignableFrom(raw)) {
                         map = new ConcurrentHashMap(object.size());
                     } else if (EnumMap.class.isAssignableFrom(raw)) {
+                        if (!config.isSupportEnumContainerDeserialization()) {
+                            throw new MapperException("JSON-B forbids EnumMap deserialization, " +
+                                    "set supportEnumMapDeserialization=true to disable that arbitrary limitation");
+                        }
                         map = new EnumMap(Class.class.cast(fieldArgTypes[0]));
                     } else if (Map.class.isAssignableFrom(raw)) {
                         map = new LinkedHashMap(object.size()); // todo: configurable from config.getNewDefaultMap()?
@@ -303,7 +306,7 @@ public class MappingParserImpl implements MappingParser {
                     }
                 }
             } else if (Map.class == type || HashMap.class == type || LinkedHashMap.class == type) {
-                final LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
+                final Map<String, Object> map = new LinkedHashMap<String, Object>();
                 for (final Map.Entry<String, JsonValue> value : object.entrySet()) {
                     map.put(value.getKey(), toObject(null, value.getValue(), Object.class, null, jsonPointer, Object.class));
                 }
@@ -923,9 +926,11 @@ public class MappingParserImpl implements MappingParser {
             collection = new ArrayList<T>(jsonArray.size());
         } else if (LinkedHashSet.class == mapping.raw) {
             collection = new LinkedHashSet<T>(jsonArray.size());
+        } else if (LinkedList.class == mapping.raw) {
+            collection = new LinkedList<T>();
         } else if (Deque.class == mapping.raw || ArrayDeque.class == mapping.raw) {
             collection = new ArrayDeque(jsonArray.size());
-        } else if (Queue.class == mapping.raw || PriorityQueue.class == mapping.raw) {
+        } else if (PriorityQueue.class == mapping.raw) {
             collection = new PriorityQueue(jsonArray.size());
         } else {
             throw new IllegalStateException("not supported collection type: " + mapping.raw.getName());
@@ -941,6 +946,10 @@ public class MappingParserImpl implements MappingParser {
         }
 
         if (EnumSet.class == mapping.raw) {
+            if (!config.isSupportEnumContainerDeserialization()) {
+                throw new MapperException("Enum container deserialization disabled, " +
+                        "set supportEnumContainerDeserialization=true to enable it");
+            }
             if (collection.isEmpty()) {
                 return EnumSet.noneOf(Class.class.cast(mapping.arg));
             } else if (collection.size() == 1) {
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
index e60e8f8..1e7ea18 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
@@ -42,13 +42,16 @@ import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.PriorityQueue;
 import java.util.Queue;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -295,7 +298,15 @@ public class Mappings {
         if (fieldArgTypes.length == 1 && Class.class.isInstance(raw)) {
             final Class<?> r = Class.class.cast(raw);
             final Class<?> collectionType;
-            if (List.class.isAssignableFrom(r)) {
+            if (PriorityQueue.class.isAssignableFrom(r)) {
+                collectionType = PriorityQueue.class;
+            } else if (LinkedHashSet.class.isAssignableFrom(r)) {
+                collectionType = LinkedHashSet.class;
+            } else if (LinkedList.class.isAssignableFrom(r)) {
+                collectionType = LinkedList.class;
+            } else if (TreeSet.class.isAssignableFrom(r)) {
+                collectionType = TreeSet.class;
+            } else if (List.class.isAssignableFrom(r)) {
                 collectionType = List.class;
             } else if (SortedSet.class.isAssignableFrom(r)) {
                 collectionType = SortedSet.class;
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
index e770b7d..3becb92 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
@@ -169,7 +169,7 @@ public class MapperConfigTest {
                                 new FieldAccessMode(true, true),
                                 Charset.forName("UTF-8"),
                                 null,
-                                false, false, null, false, false, emptyMap(), true, false);
+                                false, false, null, false, false, emptyMap(), true, false, true);
     }
 
 
diff --git a/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java b/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
index bbfdc31..559302a 100644
--- a/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
+++ b/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
@@ -66,7 +66,7 @@ public class ExtendMappingTest {
                     -1, true, true, true, false, false, false,
                     new FieldAccessMode(false, false),
                     Charset.forName("UTF-8"), String::compareTo, false, false, null, false, false,
-                    emptyMap(), true, false));
+                    emptyMap(), true, false, true));
         }
 
         @Override
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 7e97dc1..0dd4b7b 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -306,6 +306,15 @@ However it supports some specific properties to wire to the native johnzon confi
 One example is `johnzon.interfaceImplementationMapping` which will support a `Map<Class,Class>` to map interfaces to implementations
 to use for deserialization.
 
+JsonbConfig specific properties:
+
+* johnzon.use-big-decimal-for-object: true to use BigDecimal for numbers not typed (Object), false to adjust the type to the number size, true by default.
+* johnzon.support-enum-container-deserialization: prevent EnumMap/EnumSet instantiation, true by default.
+* johnzon.attributeOrder: Comparator instance to sort properties by name.
+* johnzon.deduplicateObjects: should instances be deduplicated.
+
+TIP: more in JohnzonBuilder class.
+
 #### Integration with `JsonValue`
 
 You can use some optimization to map a `JsonObject` to a POJO using Johnzon `JsonValueReader` and `JsonValueWriter`: