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 2014/11/11 11:51:45 UTC

incubator-johnzon git commit: JOHNZON-22 supporting private constructors in Mapper

Repository: incubator-johnzon
Updated Branches:
  refs/heads/master 8bc901361 -> 6fa150059


JOHNZON-22 supporting private constructors in Mapper


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

Branch: refs/heads/master
Commit: 6fa15005996dc00df5439d467a2d75ac9f250600
Parents: 8bc9013
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Tue Nov 11 11:51:17 2014 +0100
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Tue Nov 11 11:51:17 2014 +0100

----------------------------------------------------------------------
 .../java/org/apache/johnzon/mapper/Mapper.java  | 46 ++++++++++----------
 .../apache/johnzon/mapper/MapperBuilder.java    | 15 ++++++-
 .../johnzon/mapper/reflection/Mappings.java     | 29 ++++++++++--
 .../johnzon/mapper/MapperEnhancedTest.java      |  2 +-
 .../org/apache/johnzon/mapper/MapperTest.java   | 19 ++++++++
 5 files changed, 82 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6fa15005/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index a28156e..77d7c7f 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -74,20 +74,23 @@ public class Mapper {
     protected final boolean close;
     protected final ConcurrentMap<Type, Converter<?>> converters;
     protected final int version;
+    private final boolean hiddenConstructorSupported;
     protected boolean skipNull;
     protected boolean skipEmptyArray;
 
     public Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory,
                   final boolean doClose, final Map<Class<?>, Converter<?>> converters,
-                  final int version, final Comparator<String> attributeOrder, boolean skipNull, boolean skipEmptyArray) {
+                  final int version, final Comparator<String> attributeOrder, boolean skipNull, boolean skipEmptyArray,
+                  final boolean hiddenConstructorSupported) {
         this.readerFactory = readerFactory;
         this.generatorFactory = generatorFactory;
         this.close = doClose;
         this.converters = new ConcurrentHashMap<Type, Converter<?>>(converters);
         this.version = version;
-        this.mappings = new Mappings(attributeOrder);
+        this.mappings = new Mappings(attributeOrder, hiddenConstructorSupported);
         this.skipNull = skipNull;
         this.skipEmptyArray = skipEmptyArray;
+        this.hiddenConstructorSupported = hiddenConstructorSupported;
     }
 
     private static JsonGenerator writePrimitives(final JsonGenerator generator, final Object value) {
@@ -418,9 +421,7 @@ public class Mapper {
     private <T> T mapObject(final Type clazz, final JsonReader reader) {
         try {
             return (T) buildObject(clazz, reader.readObject());
-        } catch (final InstantiationException e) {
-            throw new MapperException(e);
-        } catch (final IllegalAccessException e) {
+        } catch (final Exception e) {
             throw new MapperException(e);
         } finally {
             if (close) {
@@ -437,9 +438,7 @@ public class Mapper {
         }
         try {
             return mapCollection(mapping, reader.readArray());
-        } catch (final InstantiationException e) {
-            throw new MapperException(e);
-        } catch (final IllegalAccessException e) {
+        } catch (final Exception e) {
             throw new MapperException(e);
         } finally {
             if (close) {
@@ -464,9 +463,7 @@ public class Mapper {
         }
         try {
             return mapCollection(mapping, reader.readArray());
-        } catch (final InstantiationException e) {
-            throw new MapperException(e);
-        } catch (final IllegalAccessException e) {
+        } catch (final Exception e) {
             throw new MapperException(e);
         } finally {
             if (close) {
@@ -488,9 +485,7 @@ public class Mapper {
     private <T> T[] mapArray(final Class<T> clazz, final JsonReader reader) {
         try {
             return (T[]) buildArrayWithComponentType(reader.readArray(), clazz);
-        } catch (final InstantiationException e) {
-            throw new MapperException(e);
-        } catch (final IllegalAccessException e) {
+        } catch (final Exception e) {
             throw new MapperException(e);
         } finally {
             if (close) {
@@ -499,7 +494,7 @@ public class Mapper {
         }
     }
 
-    private Object buildObject(final Type type, final JsonObject object) throws InstantiationException, IllegalAccessException {
+    private Object buildObject(final Type type, final JsonObject object) throws Exception {
         final Mappings.ClassMapping classMapping = mappings.findOrCreateClassMapping(type);
 
         if (classMapping == null) {
@@ -534,15 +529,18 @@ public class Mapper {
                         }
                         return map;
                     }
-                } else {
-                    throw new MapperException("Can't map " + type + ", not a map and no Mapping found");
                 }
-            } else {
-                throw new MapperException("Can't map " + type);
             }
         }
+        if (classMapping == null) {
+            throw new MapperException("Can't map " + type);
+        }
+
+        if (classMapping.constructor == null) {
+            throw new IllegalArgumentException(classMapping.clazz.getName() + " can't be nistantiated by Johnzon, this is a write only class");
+        }
 
-        final Object t = classMapping.clazz.newInstance();
+        final Object t = classMapping.constructor.newInstance();
         for (final Map.Entry<String, Mappings.Setter> setter : classMapping.setters.entrySet()) {
             final JsonValue jsonValue = object.get(setter.getKey());
             final Mappings.Setter value = setter.getValue();
@@ -564,7 +562,7 @@ public class Mapper {
         return t;
     }
 
-    private Object toObject(final JsonValue jsonValue, final Type type) throws InstantiationException, IllegalAccessException {
+    private Object toObject(final JsonValue jsonValue, final Type type) throws Exception {
         if (jsonValue == null || jsonValue == JsonValue.NULL) {
             return null;
         }
@@ -641,7 +639,7 @@ public class Mapper {
         throw new MapperException("Unable to parse " + jsonValue + " to " + type);
     }
 
-    private Object buildArray(final Type type, final JsonArray jsonArray) throws IllegalAccessException, InstantiationException {
+    private Object buildArray(final Type type, final JsonArray jsonArray) throws Exception {
         if (Class.class.isInstance(type)) {
             final Class clazz = Class.class.cast(type);
             if (clazz.isArray()) {
@@ -664,7 +662,7 @@ public class Mapper {
         throw new UnsupportedOperationException("type " + type + " not supported");
     }
 
-    private <T> Collection<T> mapCollection(final Mappings.CollectionMapping mapping, final JsonArray jsonArray) throws InstantiationException, IllegalAccessException {
+    private <T> Collection<T> mapCollection(final Mappings.CollectionMapping mapping, final JsonArray jsonArray) throws Exception {
         final Collection collection;
 
         if (SortedSet.class == mapping.raw) {
@@ -687,7 +685,7 @@ public class Mapper {
         return collection;
     }
 
-    private Object buildArrayWithComponentType(final JsonArray jsonArray, final Class<?> componentType) throws InstantiationException, IllegalAccessException {
+    private Object buildArrayWithComponentType(final JsonArray jsonArray, final Class<?> componentType) throws Exception {
         final Object array = Array.newInstance(componentType, jsonArray.size());
         int i = 0;
         for (final JsonValue value : jsonArray) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6fa15005/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 b20fdbd..3b6a92f 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
@@ -76,6 +76,7 @@ public class MapperBuilder {
     private JsonReaderFactory readerFactory;
     private JsonGeneratorFactory generatorFactory;
     private boolean doCloseOnStreams = false;
+    private boolean supportHiddenConstructor = true;
     private int version = -1;
     private Comparator<String> attributeOrder = null;
     private boolean skipNull = true;
@@ -94,7 +95,19 @@ public class MapperBuilder {
             }
         }
 
-        return new Mapper(readerFactory, generatorFactory, doCloseOnStreams, converters, version, attributeOrder, skipNull, skipEmptyArray);
+        return new Mapper(
+                readerFactory, generatorFactory,
+                doCloseOnStreams,
+                converters,
+                version,
+                attributeOrder,
+                skipNull, skipEmptyArray,
+                supportHiddenConstructor);
+    }
+
+    public MapperBuilder setSupportHiddenConstructor(final boolean supportHiddenConstructor) {
+        this.supportHiddenConstructor = supportHiddenConstructor;
+        return this;
     }
 
     public MapperBuilder setAttributeOrder(final Comparator<String> attributeOrder) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6fa15005/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
index 55aacdc..a82b948 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
@@ -26,7 +26,9 @@ import org.apache.johnzon.mapper.MapperException;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
@@ -48,12 +50,31 @@ public class Mappings {
         public final Class<?> clazz;
         public final Map<String, Getter> getters;
         public final Map<String, Setter> setters;
+        public final Constructor<?> constructor;
 
         protected ClassMapping(final Class<?> clazz,
-                               final Map<String, Getter> getters, final Map<String, Setter> setters) {
+                               final Map<String, Getter> getters, final Map<String, Setter> setters,
+                               final boolean acceptHiddenConstructor) {
             this.clazz = clazz;
             this.getters = getters;
             this.setters = setters;
+            this.constructor = findConstructor(acceptHiddenConstructor);
+        }
+
+        private Constructor<?> findConstructor(final boolean acceptHiddenConstructor) {
+            for (final Constructor<?> c : clazz.getDeclaredConstructors()) {
+                if (c.getParameterTypes().length == 0) {
+                    if (!Modifier.isPublic(c.getModifiers()) && acceptHiddenConstructor) {
+                        c.setAccessible(true);
+                    }
+                    return c;
+                }
+            }
+            try {
+                return clazz.getConstructor();
+            } catch (final NoSuchMethodException e) {
+                return null; // readOnly class
+            }
         }
     }
 
@@ -111,9 +132,11 @@ public class Mappings {
     protected final ConcurrentMap<Type, ClassMapping> classes = new ConcurrentHashMap<Type, ClassMapping>();
     protected final ConcurrentMap<Type, CollectionMapping> collections = new ConcurrentHashMap<Type, CollectionMapping>();
     protected final Comparator<String> fieldOrdering;
+    private final boolean supportHiddenConstructors;
 
-    public Mappings(final Comparator<String> attributeOrder) {
+    public Mappings(final Comparator<String> attributeOrder, final boolean supportHiddenConstructors) {
         this.fieldOrdering = attributeOrder;
+        this.supportHiddenConstructors = supportHiddenConstructors;
     }
 
     public <T> CollectionMapping findCollectionMapping(final ParameterizedType genericType) {
@@ -248,7 +271,7 @@ public class Mappings {
                 }
             }
 
-            return new ClassMapping(clazz, getters, setters);
+            return new ClassMapping(clazz, getters, setters, supportHiddenConstructors);
         } catch (final IntrospectionException e) {
             throw new MapperException(e);
         }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6fa15005/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperEnhancedTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperEnhancedTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperEnhancedTest.java
index 97ce8b0..30bbee5 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperEnhancedTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperEnhancedTest.java
@@ -141,7 +141,7 @@ public class MapperEnhancedTest {
         assertEquals(json, sw.toString());
     }
 
-    @Test(expected = UnsupportedOperationException.class)
+    @Test(expected = MapperException.class)
     public void needConvertersForComplexTypes() {
         final String str = "{" +
             "\"bd\":-456.4567890987654321,\"string\":\"some \\t \\u0001 unicode: ÖÄÜ pppন􏿿\"," +

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6fa15005/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
index 4d9cb24..c94d397 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
@@ -270,6 +270,13 @@ public class MapperTest {
         assertEquals(json, stream.toString());
     }
 
+    @Test
+    public void privateConstructor() {
+        final HiddenConstructor value = new MapperBuilder().setSupportHiddenConstructor(true).build()
+                .readObject(new ByteArrayInputStream("{\"value\":1}".getBytes()), HiddenConstructor.class);
+        assertEquals(1, value.value);
+    }
+
     public static class TheObject {
         private String name;
         private int integer;
@@ -496,4 +503,16 @@ public class MapperTest {
             return toString(text);
         }
     }
+
+    public static class HiddenConstructor {
+        private int value;
+
+        private HiddenConstructor() {
+            // no-op
+        }
+
+        public void setValue(final int value) {
+            this.value = value;
+        }
+    }
 }