Repository: johnzon
Updated Branches:
  refs/heads/master a7c03892d -> 2507062b0


JOHNZON-197 Support johnzon.interfaceImplementationMapping jsonb property (and 
mapper option)


Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/2507062b
Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/2507062b
Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/2507062b

Branch: refs/heads/master
Commit: 2507062b09ab6deaa5b05cc21f4854e61e6a1092
Parents: a7c0389
Author: Romain Manni-Bucau <[email protected]>
Authored: Mon Dec 17 17:36:48 2018 +0100
Committer: Romain Manni-Bucau <[email protected]>
Committed: Mon Dec 17 17:36:48 2018 +0100

----------------------------------------------------------------------
 .../jaxrs/ConfigurableJohnzonProvider.java      | 45 +++++++++++-----
 .../jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java   | 17 ++++++
 .../apache/johnzon/jsonb/JohnzonBuilder.java    |  3 ++
 .../johnzon/jsonb/InterfaceMappingTest.java     | 57 ++++++++++++++++++++
 .../apache/johnzon/mapper/MapperBuilder.java    |  9 +++-
 .../org/apache/johnzon/mapper/MapperConfig.java |  8 ++-
 .../org/apache/johnzon/mapper/Mappings.java     | 17 ++++--
 .../apache/johnzon/mapper/MapperConfigTest.java |  4 +-
 .../java/org/superbiz/ExtendMappingTest.java    | 11 ++--
 src/site/markdown/index.md                      |  6 ++-
 10 files changed, 148 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
index 30a452d..0d34696 100644
--- 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
+++ 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
@@ -18,20 +18,9 @@
  */
 package org.apache.johnzon.jaxrs;
 
-import org.apache.johnzon.mapper.MapperBuilder;
-import org.apache.johnzon.mapper.SerializeValueFilter;
-import org.apache.johnzon.mapper.access.AccessMode;
-import org.apache.johnzon.mapper.access.BaseAccessMode;
+import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toMap;
 
-import javax.json.JsonReaderFactory;
-import javax.json.stream.JsonGeneratorFactory;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -40,9 +29,24 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Type;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 
-import static java.util.Arrays.asList;
+import javax.json.JsonReaderFactory;
+import javax.json.stream.JsonGeneratorFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.johnzon.mapper.MapperBuilder;
+import org.apache.johnzon.mapper.SerializeValueFilter;
+import org.apache.johnzon.mapper.access.AccessMode;
+import org.apache.johnzon.mapper.access.BaseAccessMode;
 
 @Provider
 @Produces("application/json")
@@ -155,6 +159,19 @@ public class ConfigurableJohnzonProvider<T> implements 
MessageBodyWriter<T>, Mes
         builder.setAccessModeFieldFilteringStrategy(strategy);
     }
 
+    public void setInterfaceImplementationMapping(final Map<String, String> 
interfaceImplementationMapping) {
+        final ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
+        final Function<String, Class<?>> load = name -> {
+            try {
+                return loader.loadClass(name.trim());
+            } catch (final ClassNotFoundException e) {
+                throw new IllegalArgumentException(e);
+            }
+        };
+        
builder.setInterfaceImplementationMapping(interfaceImplementationMapping.entrySet().stream()
+            .collect(toMap(it -> load.apply(it.getKey()), it -> 
load.apply(it.getValue()))));
+    }
+
     public void setAccessModeFieldFilteringStrategyName(final String mode) {
         builder.setAccessModeFieldFilteringStrategyName(mode);
     }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
index 25cf998..b59b697 100644
--- 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
+++ 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
@@ -18,6 +18,8 @@
  */
 package org.apache.johnzon.jaxrs.jsonb.jaxrs;
 
+import static java.util.stream.Collectors.toMap;
+
 import javax.json.JsonStructure;
 import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbBuilder;
@@ -41,6 +43,7 @@ import java.io.Writer;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.Collection;
+import java.util.Map;
 import java.util.Properties;
 import java.util.function.Function;
 import java.util.logging.Logger;
@@ -130,6 +133,20 @@ public class JsonbJaxrsProvider<T> implements 
MessageBodyWriter<T>, MessageBodyR
         customized = true;
     }
 
+    public void setInterfaceImplementationMapping(final Map<String, String> 
interfaceImplementationMapping) {
+        final ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
+        final Function<String, Class<?>> load = name -> {
+            try {
+                return loader.loadClass(name.trim());
+            } catch (final ClassNotFoundException e) {
+                throw new IllegalArgumentException(e);
+            }
+        };
+        config.setProperty("johnzon.interfaceImplementationMapping", 
interfaceImplementationMapping.entrySet().stream()
+             .collect(toMap(it -> load.apply(it.getKey()), it -> 
load.apply(it.getValue()))));
+        customized = true;
+    }
+
     // actual impl
 
     @Override

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
----------------------------------------------------------------------
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 50be3ed..e533923 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
@@ -214,6 +214,9 @@ public class JohnzonBuilder implements JsonbBuilder {
         config.getProperty("johnzon.deduplicateObjects")
                 .map(v -> !Boolean.class.isInstance(v) ? 
Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v))
                 .ifPresent(builder::setDeduplicateObjects);
+        config.getProperty("johnzon.interfaceImplementationMapping")
+                .map(Map.class::cast)
+                .ifPresent(builder::setInterfaceImplementationMapping);
 
         final Map<AdapterKey, Adapter<?, ?>> defaultConverters = 
createJava8Converters(builder);
 

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/InterfaceMappingTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/InterfaceMappingTest.java
 
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/InterfaceMappingTest.java
new file mode 100644
index 0000000..c5bdc4e
--- /dev/null
+++ 
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/InterfaceMappingTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.jsonb;
+
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.JsonbConfig;
+
+import org.junit.Test;
+
+public class InterfaceMappingTest {
+    @Test
+    public void mapInterface() throws Exception {
+        try (final Jsonb jsonb = JsonbBuilder.create(new JsonbConfig()
+            .setProperty("johnzon.interfaceImplementationMapping", 
singletonMap(SomeItf.class, SomeImpl.class)))) {
+            assertEquals("ok", jsonb.fromJson("{\"value\":\"ok\"}", 
SomeItf.class).getValue());
+        }
+    }
+
+    public interface SomeItf {
+        String getValue();
+        void setValue(String value);
+    }
+
+    public static class SomeImpl implements SomeItf {
+        private String value;
+
+        @Override
+        public String getValue() {
+            return value;
+        }
+
+        @Override
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
----------------------------------------------------------------------
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 126ff0a..5d6debb 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
@@ -132,6 +132,7 @@ public class MapperBuilder {
     private Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaders = 
new HashMap<Class<?>, ObjectConverter.Reader<?>>();
     private Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters = 
new HashMap<Class<?>, ObjectConverter.Writer<?>>();
     private Map<Class<?>, String[]> ignoredForFields = new HashMap<Class<?>, 
String[]>();
+    private Map<Class<?>, Class<?>> interfaceImplementationMapping = new 
HashMap<>();
     private BaseAccessMode.FieldFilteringStrategy fieldFilteringStrategy = 
null;
     private boolean primitiveConverters;
     private boolean failOnUnknownProperties;
@@ -239,10 +240,16 @@ public class MapperBuilder {
                         skipNull, skipEmptyArray,
                         treatByteArrayAsBase64, treatByteArrayAsBase64URL, 
readAttributeBeforeWrite,
                         accessMode, encoding, attributeOrder, 
enforceQuoteString, failOnUnknownProperties,
-                        serializeValueFilter, useBigDecimalForFloats, 
deduplicateObjects),
+                        serializeValueFilter, useBigDecimalForFloats, 
deduplicateObjects,
+                        interfaceImplementationMapping),
                 closeables);
     }
 
+    public MapperBuilder setInterfaceImplementationMapping(final Map<Class<?>, 
Class<?>> interfaceImplementationMapping) {
+        this.interfaceImplementationMapping = interfaceImplementationMapping;
+        return this;
+    }
+
     public MapperBuilder setFailOnUnknownProperties(final boolean 
failOnUnknownProperties) {
         this.failOnUnknownProperties = failOnUnknownProperties;
         return this;

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
----------------------------------------------------------------------
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 44cea05..fd7d9db 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
@@ -67,6 +67,7 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
     private final SerializeValueFilter serializeValueFilter;
     private final boolean useBigDecimalForFloats;
     private final Boolean deduplicateObjects;
+    private final Map<Class<?>, Class<?>> interfaceImplementationMapping;
 
     private final Map<Class<?>, ObjectConverter.Writer<?>> 
objectConverterWriterCache;
     private final Map<Class<?>, ObjectConverter.Reader<?>> 
objectConverterReaderCache;
@@ -85,7 +86,8 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
                         final boolean enforceQuoteString, final boolean 
failOnUnknown,
                         final SerializeValueFilter serializeValueFilter,
                         final boolean useBigDecimalForFloats,
-                        final Boolean deduplicateObjects) {
+                        final Boolean deduplicateObjects,
+                        final Map<Class<?>, Class<?>> 
interfaceImplementationMapping) {
     //CHECKSTYLE:ON
         this.objectConverterWriters = objectConverterWriters;
         this.objectConverterReaders = objectConverterReaders;
@@ -103,6 +105,7 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
         this.enforceQuoteString = enforceQuoteString;
         this.failOnUnknown = failOnUnknown;
         this.serializeValueFilter = serializeValueFilter == null ? (name, 
value) -> false : serializeValueFilter;
+        this.interfaceImplementationMapping = interfaceImplementationMapping;
 
         this.objectConverterWriterCache = new HashMap<Class<?>, 
ObjectConverter.Writer<?>>(objectConverterWriters.size());
         this.objectConverterReaderCache = new HashMap<Class<?>, 
ObjectConverter.Reader<?>>(objectConverterReaders.size());
@@ -110,6 +113,9 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
         this.deduplicateObjects = deduplicateObjects;
     }
 
+    public Map<Class<?>, Class<?>> getInterfaceImplementationMapping() {
+        return interfaceImplementationMapping;
+    }
 
     public SerializeValueFilter getSerializeValueFilter() {
         return serializeValueFilter;

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
----------------------------------------------------------------------
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 b3dea58..d18d085 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
@@ -339,11 +339,22 @@ public class Mappings {
     public ClassMapping findOrCreateClassMapping(final Type clazz) {
         ClassMapping classMapping = classes.get(clazz);
         if (classMapping == null) {
-            if (!Class.class.isInstance(clazz) || 
Map.class.isAssignableFrom(Class.class.cast(clazz))) {
+            if (!Class.class.isInstance(clazz)) {
                 return null;
             }
-
-            classMapping = createClassMapping(Class.class.cast(clazz));
+            final Class asClass = Class.class.cast(clazz);
+            if (Map.class.isAssignableFrom(asClass) || asClass.isInterface()) {
+                final Class<?> mapping = 
config.getInterfaceImplementationMapping().get(clazz);
+                if (mapping != null) {
+                    classMapping = createClassMapping(mapping);
+                } else if (asClass.getName().startsWith("java.")) { // we'll 
not be able to map it with pojo rules
+                    return null;
+                } else { // assume that it can be written with pojo rules but 
not deserialized
+                    classMapping = createClassMapping(asClass);
+                }
+            } else {
+                classMapping = createClassMapping(asClass);
+            }
             final ClassMapping existing = classes.putIfAbsent(clazz, 
classMapping);
             if (existing != null) {
                 classMapping = existing;

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
----------------------------------------------------------------------
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 0a9cc7f..f1348fb 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
@@ -18,6 +18,8 @@
  */
 package org.apache.johnzon.mapper;
 
+import static java.util.Collections.emptyMap;
+
 import org.apache.johnzon.mapper.access.FieldAccessMode;
 import org.apache.johnzon.mapper.internal.AdapterKey;
 import org.junit.Assert;
@@ -166,7 +168,7 @@ public class MapperConfigTest {
                                 new FieldAccessMode(true, true),
                                 Charset.forName("UTF-8"),
                                 null,
-                                false, false, null, false, false);
+                                false, false, null, false, false, emptyMap());
     }
 
 

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java 
b/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
index 142ca18..5e55ddf 100644
--- a/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
+++ b/johnzon-mapper/src/test/java/org/superbiz/ExtendMappingTest.java
@@ -28,11 +28,11 @@ import org.junit.Test;
 
 import java.lang.reflect.Type;
 import java.nio.charset.Charset;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import static java.util.Collections.emptyMap;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -65,13 +65,8 @@ public class ExtendMappingTest {
                     new HashMap<Class<?>, ObjectConverter.Reader<?>>(),
                     -1, true, true, true, false, false, false,
                     new FieldAccessMode(false, false),
-                    Charset.forName("UTF-8"),
-                    new Comparator<String>() {
-                        @Override
-                        public int compare(final String o1, final String o2) {
-                            return o1.compareTo(o2);
-                        }
-                    }, false, false, null, false, false));
+                    Charset.forName("UTF-8"), String::compareTo, false, false, 
null, false, false,
+                    emptyMap()));
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/johnzon/blob/2507062b/src/site/markdown/index.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index eafd6e9..7ee99a3 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -296,7 +296,11 @@ Johnzon provides a module johnzon-jsonb implementing 
JSON-B standard based on Jo
 
 It fully reuses the JSON-B as API.
 
-### Websocket (beta)
+However it supports some specific properties to wire to the native johnzon 
configuration - see `JohnzonBuilder` for details.
+One example is `johnzon.interfaceImplementationMapping` which will support a 
`Map<Class,Class>` to map interfaces to implementations
+to use for deserialization. 
+
+### Websocket
 
 <pre class="prettyprint linenums"><![CDATA[
 <dependency>

Reply via email to